diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml new file mode 100644 index 0000000..5b16d59 --- /dev/null +++ b/.github/workflows/test-build.yml @@ -0,0 +1,23 @@ +name: Test Quarto Build + +on: + pull_request: + branches: [main] + push: + branches-ignore: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Quarto + uses: quarto-dev/quarto-actions/setup@v2 + + - name: Render site + run: quarto render --no-execute diff --git a/TODO.md b/TODO.md index 8de21a8..cf776b6 100644 --- a/TODO.md +++ b/TODO.md @@ -16,9 +16,14 @@ - [x] Website deployment issue to have a python environment (Arthur) - [x] Unify the overall view of each separate part of the website. + ## Deploy to www.compomics.com (after site checked) - [] Add root `CNAME` file containing `www.compomics.com` + list it under project resources in `_quarto.yml` - [] Set `site-url: https://www.compomics.com` in `_quarto.yml` - [] GitHub repo Settings → Pages: set custom domain `www.compomics.com`, then enable Enforce HTTPS - [] DNS at registrar: `www` CNAME → `compomics.github.io`; apex `compomics.com` → GitHub Pages A records (185.199.108-111.153) -- [] Flip DNS last (cuts over from old site, no fast rollback) \ No newline at end of file +- [] Flip DNS last (cuts over from old site, no fast rollback) + +## Todo after deployment + +- [] Modernise the classic "Bioinformatics for Proteomics" tutorial (`tutorials/posts/2026-06-01-bioinformatics-for-proteomics.qmd`). Ported as-is with 2014-era materials linked from Google Drive; deprecation warning kept in place until done. TODO: replace deprecated PRIDE XML with mzIdentML/mzTab (needs editing the module 3 slide decks, not just the page text); refresh slides/screenshots to current tool UIs; rehost slides + exercise resources off Google Drive; decide combined page vs per-module split; optionally write the missing MS1 (4.3) and targeted (4.4) quantification sections; update the functional-analysis module (module 2 pins no tools). Tool versions already bumped (PeptideShaker 3.0.11, SearchGUI 4.3.15). (Arthur) \ No newline at end of file diff --git a/_quarto.yml b/_quarto.yml index 15a0bca..bf4142d 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -1,6 +1,10 @@ project: type: website output-dir: _site + # Guard: fail the build loudly if the team page's inline memberData has a JS + # syntax error or a card with no data entry (both silently break card clicks). + pre-render: + - scripts/check-team-data.js render: - "**/*.qmd" - "**/*.md" @@ -40,8 +44,6 @@ website: href: publications/index.qmd - text: "Tutorials" href: tutorials/index.qmd - - text: "News" - href: news/index.qmd - icon: github href: https://github.com/compomics aria-label: GitHub diff --git a/assets/compomics.scss b/assets/compomics.scss index 4cf5f5f..46b5ab6 100644 --- a/assets/compomics.scss +++ b/assets/compomics.scss @@ -6,7 +6,7 @@ $font-family-heading: "Bricolage Grotesque", system-ui, sans-serif; $font-family-monospace: "JetBrains Mono", monospace; $headings-font-family: $font-family-heading; $headings-font-weight: 700; -$font-size-root: 13px; +$font-size-root: 14px; // Colour tokens ($ink, $cream, $line, $primary, $surface-hover, $icon-bg …) // are defined per-theme in compomics-light.scss / compomics-dark.scss @@ -331,293 +331,9 @@ blockquote { // Tools page styles live in tools/tools.scss (loaded site-wide via _quarto.yml, // same pattern as team/teams.scss). -// ── Team grid ──────────────────────────────────────────────────────────────── -.team-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); - gap: 2.2rem 1.4rem; - margin: 2.5rem 0; -} - -.team-card-wrap { - display: contents; -} - -.team-grid-selectors { - margin-bottom: 1.75rem; -} - -.team-card { - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - text-decoration: none; - color: inherit; - transition: transform 0.18s ease; - - appearance: none; - border: none; - background: transparent; - padding: 0; - cursor: pointer; - - &:hover { - transform: translateY(-5px); - text-decoration: none; - color: inherit; - - .team-photo { - filter: grayscale(0%); - border-color: $primary; - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18), 0 0 0 3px rgba(31, 95, 143, 0.12); - } - .team-name { color: $primary; } - } - - &.is-selected { - .team-photo { - filter: grayscale(0%); - border-color: $primary; - box-shadow: 0 0 0 4px rgba(31, 95, 143, 0.08); - } - - .team-name { color: $primary; } - } -} - -.team-photo { - width: 150px; - height: 150px; - border-radius: 50%; - object-fit: cover; - object-position: center top; - border: 1px solid $line; - box-shadow: none; - margin-bottom: 0.75rem; - display: block; - transition: filter 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; - filter: grayscale(12%); - - &:hover { filter: grayscale(0%); } -} - -.team-name { - font-family: $font-family-heading; - font-size: 1.02rem; - font-weight: 700; - color: $ink; - margin-bottom: 0.1rem; - line-height: 1.3; - height: calc(1.02rem * 1.3 * 2); - display: flex; - align-items: center; - justify-content: center; -} - -.team-role { - font-family: $font-family-sans-serif; - font-size: 0.74rem; - text-transform: uppercase; - letter-spacing: 0.06em; - color: $muted; - line-height: 1.35; -} - -.team-section-title { - font-family: $font-family-sans-serif; - font-size: 0.78rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.1em; - color: $muted; - margin: 3rem 0 0.5rem; - padding-bottom: 0.5rem; - border-bottom: 1px solid $line; -} - -.team-shell-intro { - max-width: none; - margin-bottom: 1rem; - - p { - margin: 0.35rem 0 0; - color: $muted; - font-size: 0.94rem; - line-height: 1.7; - } -} - -.team-detail-panel, -.team-profile-expander { - position: relative; - margin-top: 2rem; - padding: clamp(1.6rem, 3.5vw, 2.8rem); - border-radius: 1rem; - overflow: hidden; - border: 1px solid rgba(90, 167, 218, 0.20); - background: linear-gradient(135deg, #0d1f38, #142d50); - box-shadow: 0 24px 70px rgba(0, 0, 0, 0.32), 0 0 0 1px rgba(90, 167, 218, 0.08); - - &[hidden] { display: none; } - - &::before { - content: ""; - position: absolute; - inset: 0; - background: - radial-gradient(circle at top right, rgba(90, 167, 218, 0.22), rgba(90, 167, 218, 0) 42%), - linear-gradient(135deg, rgba(10, 20, 40, 0.20), rgba(10, 20, 40, 0.55)); - pointer-events: none; - } -} - -.team-profile-expander { - grid-column: 1 / -1; - margin-top: 0.5rem; - margin-bottom: 1rem; - display: grid; - gap: 1.15rem; - color: #f6f2ea; - - max-height: 0; - opacity: 0; - transition: max-height 0.45s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease; - - &::after { - content: ""; - position: absolute; - top: -8px; - left: var(--notch-x, 50%); - transform: translateX(-50%); - width: 0; - height: 0; - border-left: 8px solid transparent; - border-right: 8px solid transparent; - border-bottom: 8px solid #0d1f38; - pointer-events: none; - z-index: 2; - } -} - -.team-detail-copy { - position: relative; - z-index: 1; - display: grid; - gap: 1.15rem; - color: #f6f2ea; -} - -.team-detail-header { - display: grid; - gap: 0.35rem; - max-width: 72ch; -} - -.team-detail-eyebrow { - font-family: $font-family-sans-serif; - font-size: 0.72rem; - font-weight: 700; - letter-spacing: 0.14em; - text-transform: uppercase; - color: rgba(255, 255, 255, 0.72); -} - -.team-detail-header h3 { - margin: 0; - font-size: clamp(2rem, 4vw, 2.8rem); - color: #fff; - line-height: 1.08; -} - -.team-detail-role { - margin: 0; - color: rgba(255, 255, 255, 0.8); - font-size: 0.92rem; - letter-spacing: 0.03em; -} - -.team-detail-section { - max-width: 78ch; - padding-top: 0.35rem; - - h4 { - margin: 0 0 0.35rem; - color: rgba(255, 255, 255, 0.88); - font-family: $font-family-heading; - font-size: 0.9rem; - text-transform: none; - letter-spacing: -0.01em; - } - - p { - margin: 0; - color: rgba(255, 255, 255, 0.9); - line-height: 1.8; - font-size: 0.98rem; - } -} - -.team-pub-list { - display: flex; - flex-direction: column; - gap: 0.45rem; -} - -.team-pub-item { - display: inline-flex; - flex-wrap: wrap; - align-items: baseline; - gap: 0.25rem 0.6rem; - padding: 0.45rem 0.8rem 0.45rem 0.8rem; - border: 1px solid rgba(90, 167, 218, 0.28); - border-radius: 0.4rem; - background: rgba(255, 255, 255, 0.04); - max-width: fit-content; - text-decoration: none; - cursor: pointer; - transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; - - &::after { - content: "↗"; - font-size: 0.7rem; - color: rgba(90, 167, 218, 0.55); - align-self: center; - margin-left: 0.15rem; - transition: color 0.15s ease, transform 0.15s ease; - display: inline-block; - } - - &:hover { - border-color: rgba(90, 167, 218, 0.65); - background: rgba(90, 167, 218, 0.12); - box-shadow: 0 0 12px rgba(90, 167, 218, 0.18); - text-decoration: none; - - &::after { - color: rgba(90, 167, 218, 0.95); - transform: translate(1px, -1px); - } - } -} - -.team-pub-title { - font-family: $font-family-heading; - font-size: 0.88rem; - font-weight: 600; - color: rgba(255, 255, 255, 0.95); - line-height: 1.3; -} - -.team-pub-venue { - font-family: $font-family-sans-serif; - font-size: 0.72rem; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.08em; - color: rgba(90, 167, 218, 0.85); - white-space: nowrap; -} +// ── Team page styles live in team/teams.scss ──────────────────────────────── +// (grid, cards, and the profile expander were consolidated there so the two +// files no longer both style the team page) // ── Location section — single elegant panel, address + map ─────────────────── .location-section { diff --git a/assets/images/tools/callc.png b/assets/images/tools/callc.png new file mode 100644 index 0000000..d4f95d4 Binary files /dev/null and b/assets/images/tools/callc.png differ diff --git a/assets/images/tools/ideeplc.png b/assets/images/tools/ideeplc.png new file mode 100644 index 0000000..138ede6 Binary files /dev/null and b/assets/images/tools/ideeplc.png differ diff --git a/assets/images/tools/ptmvision.png b/assets/images/tools/ptmvision.png new file mode 100644 index 0000000..30c734e Binary files /dev/null and b/assets/images/tools/ptmvision.png differ diff --git a/news/index.qmd b/news/index.qmd deleted file mode 100644 index 73fd119..0000000 --- a/news/index.qmd +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "News" ---- - -```{=html} - -
- -``` diff --git a/news/posts/2024-06-01-welcome.qmd b/news/posts/2024-06-01-welcome.qmd deleted file mode 100644 index 4708003..0000000 --- a/news/posts/2024-06-01-welcome.qmd +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: "Welcome to the new CompOmics website" -date: 2026-06-09 -description: "Our new website is live." -categories: [announcement] ---- - -Welcome to the new CompOmics website, built with [Quarto](https://quarto.org). - -More news and updates will follow here. diff --git a/research/index.qmd b/research/index.qmd index 26e63ab..b86d4fa 100644 --- a/research/index.qmd +++ b/research/index.qmd @@ -9,38 +9,56 @@ toc: false
What we do

Research

We are a team of 26 enthusiastic computational biologists, bioinformaticians, and software developers who build methods and tools across the proteomics workflow. Our work spans peptide property prediction, mass spectrometry data analysis, data management, metadata standardization, and the large-scale reuse of public proteomics data.

-

Modern mass spectrometry can measure proteins with a unseen depth and throughput that increasingly exceeds our ability to interpret the resulting data. CompOmics works to close this gap. We develop open-source software, machine learning models, web resources, and community-oriented data standards that make proteomics data analysis faster, more accurate, and more reproducible. By keeping our tools and data resources openly available, we aim to support transparent, reusable, and scalable proteomics research for the wider community.

+

Modern mass spectrometry measures proteins at a depth and throughput that keeps growing faster than our ability to interpret the resulting data. CompOmics works on that interpretation problem. We develop open-source software, machine learning models, web resources, and data standards that make proteomics data analysis faster and more reproducible. We keep our tools and data resources openly available so that other groups can build on them directly instead of starting from scratch.

@@ -55,46 +73,41 @@ toc: false
- 01 +

Analyte prediction

-

Analyte prediction

-

Proteomics becomes more powerful when we can predict what a peptide should look like before it is measured. We develop machine learning models that translate peptide sequences into expected mass spectrometry behaviour, including fragment ion intensities, retention time, and ion mobility. Tools such as MS²PIP, DeepLC, and IM2Deep make these predicted signals available for practical analysis workflows. This work supports spectral library generation, targeted method design, and identification rescoring, but its broader aim is more fundamental: to make peptide behaviour computationally explicit, testable, and reusable across instruments, datasets, and experimental designs.

+

Proteomics becomes more powerful when we can predict what a peptide should look like before it is measured. We build machine learning models that translate a peptide sequence into its expected behaviour in a mass spectrometer: fragment ion intensities, retention time, and ion mobility. Tools such as MS²PIP, DeepLC, and IM2Deep make these predictions available for everyday analysis workflows, supporting spectral library generation, targeted method design, and identification rescoring. The underlying aim is to make peptide behaviour something we can calculate and test directly, rather than only observe after the fact.

- 02 +

Identification

-

Identification

-

Peptide and protein identification is not only a database search problem; it is an ambiguity problem. A first-pass search engine proposes candidate matches, but much of the information in the data remains underused. We develop post-processing and data-driven rescoring approaches that combine search engine scores with predicted peptide behaviour, spectrum evidence, retention time, and ion mobility information. Through tools such as MS²Rescore/TIMS²Rescore combined with SearchGUI & PeptideShaker, we aim to increase confident identifications in DDA and DIA workflows while keeping false discovery control central. Our goal is to recover reliable signal without compromising statistical confidence.

+

Peptide and protein identification is usually treated as a database search problem, but much of the real difficulty is ambiguity. A first-pass search engine proposes candidate matches, yet a lot of the information already present in the data goes unused. We develop post-processing and data-driven rescoring methods that combine search engine scores with predicted peptide behaviour, spectrum evidence, retention time, and ion mobility. Tools such as MS²Rescore/TIMS²Rescore, used together with SearchGUI and PeptideShaker, increase the number of confident identifications in DDA and DIA workflows without loosening false discovery control. The point is to recover signal that is already there, not to relax the statistics.

- 03 +

Metaproteomics

-

Metaproteomics

-

Metaproteomics asks which organisms are present in a microbial community, what they are doing, and how they are doing it and importantly how confidently this can be inferred from peptide evidence. This is difficult because many peptides are shared across related taxa, while many functions are distributed across complex and unevenly characterized microbial proteomes. We develop methods for taxonomic and functional interpretation that explicitly account for this ambiguity rather than hiding it. Tools such as Unipept and peptonizer 2000 help translate peptide-level evidence into interpretable community profiles. We want to make metaproteomics scalable, transparent, and statistically grounded, from small microbiome studies to analyses spanning thousands of species.

+

Metaproteomics asks which organisms are present in a microbial community and what they are doing, and, just as important, how confidently any of that can be inferred from peptide evidence. That last part is hard: many peptides are shared across related taxa, and many functions are spread across microbial proteomes that are only partly characterized. We build methods for taxonomic and functional interpretation that account for this ambiguity instead of glossing over it. Tools such as Unipept and Peptonizer2000 turn peptide-level evidence into community profiles that are actually interpretable. The goal is to keep metaproteomics statistically grounded at any scale, from a single microbiome study to analyses covering thousands of species.

-
+
- 04 +

FAIR & AI-ready data

-

FAIR data principles

-

Public proteomics data only becomes scientifically reusable when it is described in a way that both people and machines can understand. We therefore work on metadata annotation, data standards, and community-facing tools that make proteomics data findable, accessible, interoperable, and reusable. Resources such as lesSDRF and annotation workflows around public repositories help turn deposited datasets into structured research objects that can be searched, compared, reprocessed, and used for machine learning. We want to move proteomics from data availability to data usability, where public datasets can support new questions beyond the study for which they were originally generated.

+

Public proteomics data only becomes reusable, by people or by machines, when it is well described. We work on metadata annotation, data standards, and community tools that make proteomics data findable, accessible, interoperable, and reusable, and increasingly, ready to train AI models directly. This is a community effort rather than something we do alone. Through PSI-AI we help shape metadata standards for AI use. ProteomicsML gives us a place to curate machine-learning-ready benchmark datasets and teach others how to apply AI to proteomics, and projects such as mzPeak and rusteomics give us fast, open tooling that makes parsing and reusing mass spectrometry data less painful. Resources such as lesSDRF and annotation workflows around public repositories turn deposited datasets into structured objects that can be searched, compared, reprocessed, and used to train models. The underlying goal is to move proteomics data from merely available to actually usable, for new scientific questions and new AI models, beyond the study that originally produced it.

- 05 +

Reprocessing

-

Reprocessing

-

Reprocessing brings our research lines together: peptide-property prediction improves how we model analyte behaviour, identification and rescoring software recover confident evidence from complex spectra, and FAIR annotation makes public datasets comparable at scale. We combine these developments to revisit existing proteomics data with new computational questions, extracting biological information that was not accessible in the original analysis. This includes large-scale tissue profiling, biomarker discovery, and the systematic recovery of previously missed post-translational modifications, as illustrated by Scop3PTM. Our aim is to make public proteomics data scientifically active beyond deposition, turning the vast amount of data that already exists into a continuing source of new biological insight.

+

Reprocessing pulls our other research lines together. Peptide-property prediction improves how we model analyte behaviour, identification and rescoring software recovers confident evidence from complex spectra, and FAIR/AI-ready annotation makes public datasets comparable at scale. We use these pieces together to revisit existing proteomics data with new computational questions and pull out biological information the original analysis did not capture. Recent examples include large-scale tissue profiling, biomarker discovery, and the systematic recovery of post-translational modifications that were missed the first time, as in Scop3PTM. The aim is to keep public proteomics data scientifically active after deposition, so that data already collected can keep producing new findings, not just the ones from its original study.

diff --git a/research/research.scss b/research/research.scss index 8036f80..dcfb4e2 100644 --- a/research/research.scss +++ b/research/research.scss @@ -32,8 +32,7 @@ // padding so intro + spectrum + the EXPLORE cue still fit above the fold @media (max-height: 860px) { padding-bottom: 3rem; - .research-spectrum { margin-top: 2.8rem; } - .research-spectrum svg { max-height: 340px; } + .research-spectrum { margin-top: 1.5rem; } } } @@ -106,21 +105,53 @@ // ── Signature: five research lines drawn as a five-channel mass spectrum ─────── .research-spectrum { - max-width: 68rem; // wider = larger (viewBox is short, so width governs size) - margin: 4.5rem auto 0; // always centered, nudged lower in the header + --spectrum-w: min(80vw, 700px); + width: var(--spectrum-w); + max-width: none; + margin: 3.0rem auto 0; // auto margins centre it (even when wider than column) padding: 0; svg { display: block; width: 100%; height: auto; - max-height: 440px; + aspect-ratio: 960 / 224; // fixes height to the width; never collapses overflow: visible; } .spec-base { stroke: $line; stroke-width: 1; } .spec-minor rect { fill: $line; } + // axes: intensity (y) vs m/z (x), so the motif reads as a mass spectrum + .spec-axis { stroke: $line; stroke-width: 1; } + .spec-axis-arrow { fill: $line; } + .spec-axis-label { + fill: $muted; + font-family: $font-family-monospace; + font-size: 12px; + font-weight: 600; + letter-spacing: .08em; + } + + // residue ladder annotation (difference arrows between successive b-ions) + .spec-annot { + line { stroke: $ink-soft; stroke-width: 1; } + polygon { fill: $ink-soft; } + } + .spec-annot-res { + fill: $ink; + font-family: $font-family-monospace; + font-size: 12px; + font-weight: 700; + text-anchor: middle; + } + .spec-annot-mz { + fill: $muted; + font-family: $font-family-monospace; + font-size: 9px; + text-anchor: middle; + } + // each accent peak grows up from the baseline on load, staggered by --i .spec-peak { rect { @@ -145,14 +176,19 @@ } } -// clickable line titles under each peak, aligned to the peaks via a 5-col grid +// clickable line titles, each pinned under its peak (peaks sit at b-ion m/z, so +// they are unevenly spaced — positioned via the inline `left` per label). On +// narrow screens this would crowd, so below 640px it falls back to an even grid. .research-spectrum-nav { - display: grid; - grid-template-columns: repeat(5, 1fr); - gap: .4rem; - margin-top: .55rem; + position: relative; + height: 3rem; + margin-top: .6rem; } .rs-line { + position: absolute; + top: 0; + transform: translateX(-50%); + white-space: nowrap; // keep each label on one line (e.g. "FAIR data principles") color: var(--accent); font-family: $font-family-sans-serif; font-size: clamp(.68rem, 1.5vw, .84rem); @@ -160,7 +196,6 @@ line-height: 1.2; text-align: center; text-decoration: none; - padding: 0 .2rem; opacity: 0; animation: research-peak-label .5s ease forwards; animation-delay: calc(.12s * var(--i) + .5s); @@ -170,6 +205,17 @@ &:focus-visible { text-decoration: underline; text-underline-offset: 3px; } } +@media (max-width: 640px) { + .research-spectrum-nav { + position: static; + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: .4rem; + height: auto; + } + .rs-line { position: static; transform: none; width: auto; } +} + @keyframes research-peak-rise { to { transform: scaleY(1); } } @keyframes research-peak-label { to { opacity: 1; } } @@ -193,12 +239,13 @@ @media (max-width: 620px) { padding: 2.5rem 0; } } -// accent peak + number: this section's mark on the spectrum, left-aligned +// accent peak + title on one line: the coloured bar marks the section, sitting +// just before the heading (no number) .research-section-top { display: flex; align-items: flex-end; gap: .7rem; - margin-bottom: 1.2rem; + margin-bottom: .9rem; color: var(--accent); } @@ -225,16 +272,6 @@ // peak draws up once the section scrolls into view (class added by inline JS) .research-section.is-revealed .peak-bar { transform: scaleY(1); } -.research-num { - font-family: $font-family-monospace; - font-size: 1rem; - font-weight: 700; - letter-spacing: .14em; - color: var(--accent); - line-height: 1; - padding-bottom: .1rem; -} - // respect reduced-motion: render peaks at full height, no animation @media (prefers-reduced-motion: reduce) { .research-spectrum .spec-peak rect, @@ -256,7 +293,7 @@ line-height: 1.12; letter-spacing: -0.02em; color: $ink; - margin: 0 0 .8rem; + margin: 0; padding: 0; border: none; } diff --git a/scripts/check-team-data.js b/scripts/check-team-data.js new file mode 100644 index 0000000..373bc5f --- /dev/null +++ b/scripts/check-team-data.js @@ -0,0 +1,91 @@ +// Quarto pre-render guard for the team page. +// +// The team cards are wired up by one big inline ``` diff --git a/team/network.qmd b/team/network.qmd index 83379f7..31601e5 100644 --- a/team/network.qmd +++ b/team/network.qmd @@ -84,6 +84,10 @@ toc: false Dr. Wim Vranken VUB, Belgium +
+ Ben Binke + UGent, Belgium +

Alumni & Former Colleagues

diff --git a/team/teams.scss b/team/teams.scss index e3a1a01..ec56d36 100644 --- a/team/teams.scss +++ b/team/teams.scss @@ -2,12 +2,298 @@ #title-block-header { display: none !important; } +// ── Team grid + cards + profile expander ───────────────────────────────────── +// All team-page card styling lives here (moved out of assets/compomics.scss) so +// the two stylesheets can't fight over the same selectors. .team-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 2.2rem 1.4rem; + margin: 2.5rem 0; + @media (min-width: 860px) { grid-template-columns: repeat(5, 1fr); } } +.team-card-wrap { display: contents; } + +.team-grid-selectors { margin-bottom: 1.75rem; } + +.team-card { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; + text-decoration: none; + color: inherit; + transition: transform 0.18s ease; + + appearance: none; + border: none; + background: transparent; + padding: 0; + cursor: pointer; + + &:hover { + transform: translateY(-5px); + text-decoration: none; + color: inherit; + + .team-photo { + filter: grayscale(0%); + border-color: $primary; + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18), 0 0 0 3px rgba(31, 95, 143, 0.12); + } + .team-name { color: $primary; } + } + + &.is-selected { + .team-photo { + filter: grayscale(0%); + border-color: $primary; + box-shadow: 0 0 0 4px rgba(31, 95, 143, 0.08); + } + .team-name { color: $primary; } + } +} + +.team-photo { + width: 150px; + height: 150px; + border-radius: 50%; + object-fit: cover; + object-position: center top; + border: 1px solid $line; + box-shadow: none; + margin-bottom: 0.75rem; + display: block; + transition: filter 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease; + filter: grayscale(12%); + + &:hover { filter: grayscale(0%); } +} + +.team-name { + font-family: $font-family-heading; + font-size: 1.02rem; + font-weight: 700; + color: $ink; + margin-bottom: 0.1rem; + line-height: 1.3; + height: calc(1.02rem * 1.3 * 2); + display: flex; + align-items: center; + justify-content: center; +} + +.team-role { + font-family: $font-family-sans-serif; + font-size: 0.74rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: $muted; + line-height: 1.35; +} + +.team-section-title { + font-family: $font-family-sans-serif; + font-size: 0.78rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.1em; + color: $muted; + margin: 3rem 0 0.5rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid $line; +} + +.team-shell-intro { + max-width: none; + margin-bottom: 1rem; + + p { + margin: 0.35rem 0 0; + color: $muted; + font-size: 0.94rem; + line-height: 1.7; + } +} + +// Shared dark panel look +.team-detail-panel, +.team-profile-expander { + position: relative; + margin-top: 2rem; + padding: clamp(1.6rem, 3.5vw, 2.8rem); + border-radius: 1rem; + overflow: hidden; + border: 1px solid rgba(90, 167, 218, 0.20); + background: linear-gradient(135deg, #0d1f38, #142d50); + box-shadow: 0 24px 70px rgba(0, 0, 0, 0.32), 0 0 0 1px rgba(90, 167, 218, 0.08); + + &[hidden] { display: none; } + + &::before { + content: ""; + position: absolute; + inset: 0; + background: + radial-gradient(circle at top right, rgba(90, 167, 218, 0.22), rgba(90, 167, 218, 0) 42%), + linear-gradient(135deg, rgba(10, 20, 40, 0.20), rgba(10, 20, 40, 0.55)); + pointer-events: none; + } +} + +// The expander spans the whole row so its width is identical for every member +// and the pointer notch can sit under any card in the row. Content fills the +// full width (justified) so there is no empty band of background on the right. +.team-profile-expander { + grid-column: 1 / -1; + margin-top: 0.5rem; + margin-bottom: 1rem; + display: grid; + gap: 1.15rem; + color: #f6f2ea; + + max-height: 0; + opacity: 0; + transition: max-height 0.45s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease; + + &::after { + content: ""; + position: absolute; + top: -8px; + left: var(--notch-x, 50%); + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid #0d1f38; + pointer-events: none; + z-index: 2; + } +} + +.team-detail-copy { + position: relative; + z-index: 1; + display: grid; + gap: 1.15rem; + color: #f6f2ea; +} + +.team-detail-header { + display: grid; + gap: 0.35rem; +} + +.team-detail-eyebrow { + font-family: $font-family-sans-serif; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.14em; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.72); +} + +.team-detail-header h3 { + margin: 0; + font-size: clamp(2rem, 4vw, 2.8rem); + color: #fff; + line-height: 1.08; +} + +.team-detail-role { + margin: 0; + color: rgba(255, 255, 255, 0.8); + font-size: 0.92rem; + letter-spacing: 0.03em; +} + +.team-detail-section { + padding-top: 0.35rem; + + h4 { + margin: 0 0 0.35rem; + color: rgba(255, 255, 255, 0.88); + font-family: $font-family-heading; + font-size: 0.9rem; + text-transform: none; + letter-spacing: -0.01em; + } + + p { + margin: 0; + color: rgba(255, 255, 255, 0.9); + line-height: 1.8; + font-size: 0.98rem; + text-align: justify; + hyphens: auto; + } +} + +.team-pub-list { + display: flex; + flex-direction: column; + gap: 0.45rem; +} + +.team-pub-item { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 0.25rem 0.6rem; + padding: 0.45rem 0.8rem; + border: 1px solid rgba(90, 167, 218, 0.28); + border-radius: 0.4rem; + background: rgba(255, 255, 255, 0.04); + text-decoration: none; + cursor: pointer; + transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; + + &::after { + content: "↗"; + font-size: 0.7rem; + color: rgba(90, 167, 218, 0.55); + align-self: center; + margin-left: auto; // push the arrow to the right edge of the full-width row + transition: color 0.15s ease, transform 0.15s ease; + display: inline-block; + } + + &:hover { + border-color: rgba(90, 167, 218, 0.65); + background: rgba(90, 167, 218, 0.12); + box-shadow: 0 0 12px rgba(90, 167, 218, 0.18); + text-decoration: none; + + &::after { + color: rgba(90, 167, 218, 0.95); + transform: translate(1px, -1px); + } + } +} + +.team-pub-title { + font-family: $font-family-heading; + font-size: 0.88rem; + font-weight: 600; + color: rgba(255, 255, 255, 0.95); + line-height: 1.3; +} + +.team-pub-venue { + font-family: $font-family-sans-serif; + font-size: 0.72rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.08em; + color: rgba(90, 167, 218, 0.85); + white-space: nowrap; +} + .page-hero-band { position: relative; left: 50%; @@ -36,9 +322,10 @@ background: linear-gradient(to bottom, rgba(6,8,12,.55) 0%, - rgba(6,8,12,.22) 55%, + rgba(6,8,12,.22) 30%, + rgba(6,8,12,.34) 65%, var(--bs-body-bg) 100%), - linear-gradient(135deg, rgba(31,95,143,.18), rgba(0,0,0,0) 60%); + linear-gradient(135deg, rgba(31,95,143,.18), rgba(0,0,0,0) 80%); } @@ -49,7 +336,8 @@ display: flex; flex-direction: column; justify-content: flex-end; - padding: 0 1.5rem clamp(1.8rem, 4.5vh, 3rem); + padding: 0 2.5rem clamp(1.8rem, 4.5vh, 3rem); + justify-content: center; } .page-hero-kicker { diff --git a/tools/index.qmd b/tools/index.qmd index fc0464d..599012e 100644 --- a/tools/index.qmd +++ b/tools/index.qmd @@ -93,6 +93,33 @@ toc: false }, devs: ['robbin', 'ralf'] }, + { + name: 'iDeepLC', cat: 'prediction', icon: 'bi-clock-history', logo: 'ideeplc.png', + desc: 'Retention-time prediction from peptide chemical structure (SMILES), generalising to modifications unseen during training.', + links: { + github: 'https://github.com/compomics/iDeepLC', + paper: 'https://doi.org/10.1021/acs.analchem.5c08017', + }, + devs: ['alireza', 'robbin'] + }, + { + name: 'CALLC', cat: 'prediction', icon: 'bi-clock-history', logo: 'callc.png', + desc: 'Generalized calibration that maps retention-time predictions between different liquid chromatography setups, avoiding setup-specific models.', + links: { + github: 'https://github.com/CompOmics/CALLC', + paper: 'https://doi.org/10.1021/acs.analchem.0c00233', + }, + devs: ['robbin'] + }, + { + name: 'peptide-GNN', cat: 'prediction', icon: 'bi-diagram-3', comingSoon: true, + desc: 'Graph neural network for interpretable peptide retention-time prediction.', + links: { + github: 'https://github.com/CompOmics/peptide-gnn', + paper: 'https://doi.org/10.64898/2026.05.18.725893', + }, + devs: ['robbin', 'alex'] + }, { name: 'IM2Deep', cat: 'prediction', icon: 'bi-wind', logo: 'im2deep.svg', desc: 'Predicts collisional cross-section (CCS) values for peptides, including modified, and multiple conformations.', @@ -194,6 +221,7 @@ toc: false desc: 'Comprehensive resource of human phosphosites mapped within their full structural context.', links: { github: 'https://github.com/compomics', + web: 'https://iomics.ugent.be/scop3p/', paper: 'https://doi.org/10.1021/acs.jproteome.0c00306', }, devs: ['pathmanaban', 'natalia'] @@ -201,7 +229,10 @@ toc: false { name: 'Scop3PTM', cat: 'biological', icon: 'bi-diagram-3-fill', logo: 'scop3ptm.png', desc: 'Maps post-translational modifications onto protein structures for contextual, structure-aware analysis.', - links: { github: 'https://github.com/compomics' }, + links: { + github: 'https://github.com/compomics', + web: 'https://iomics.ugent.be/scop3ptm', + }, devs: ['pathmanaban', 'natalia'] }, { @@ -209,6 +240,7 @@ toc: false desc: 'Machine-learning framework for tissue inference and biomarker discovery from proteomes.', links: { github: 'https://github.com/compomics', + web: 'https://mlmarker.streamlit.app/', paper: 'https://doi.org/10.1101/2025.06.10.658642', }, devs: ['tine'] @@ -219,9 +251,18 @@ toc: false links: { github: 'https://github.com/compomics' }, devs: ['enrico'] }, + { + name: 'PTMVision', cat: 'biological', icon: 'bi-eye', logo: 'ptmvision.png', + desc: 'Interactive web platform for exploratory visual analysis of post-translational modifications from mass spectrometry data.', + links: { + web: 'https://ptmvision-tuevis.cs.uni-tuebingen.de/', + paper: 'https://doi.org/10.1021/acs.jproteome.4c00679', + }, + devs: ['caro'] + }, { name: 'E. coli PeptideAtlas Build', cat: 'biological', icon: 'bi-virus', logo: 'bacterium.png', - desc:'Characterizing the observed Eschericia coli pan-proteome and its post-translational modifications.', + desc:'Characterizing the observed Escherichia coli pan-proteome and its post-translational modifications.', links: { web: 'https://peptideatlas.org/builds/ecoli/', paper: 'https://doi.org/10.1021/acs.jproteome.5c00902' @@ -292,6 +333,15 @@ toc: false paper: 'https://doi.org/10.1021/acs.jproteome.5c00435', }, devs: ['tim','ralf'] + }, + { + name: 'PSI-AI', cat: 'community', icon: 'bi-filetype-ai', + desc: 'Working group making proteomics data AI-ready and standardizing the use of AI in data analysis workflows.', + note: 'A HUPO-PSI community initiative.', + links: { + web: 'https://psi-ai.org/', + }, + devs: ['ralf', 'tine', 'hari'] } ]; @@ -370,12 +420,15 @@ toc: false } html += '
'; - // devs (own row, above the links) + // devs (own row, above the links) — each avatar links to that person's team entry if (tool.devs && tool.devs.length) { - html += '
'; + html += '
'; tool.devs.slice(0, 4).forEach(function (key) { - html += ''; + const devName = key.charAt(0).toUpperCase() + key.slice(1); + html += '' + + '' + esc(devName) + '' + + ''; }); html += '
'; } diff --git a/tools/tools.scss b/tools/tools.scss index 608dfb8..9a5fb38 100644 --- a/tools/tools.scss +++ b/tools/tools.scss @@ -362,7 +362,29 @@ $cat-community: #4f9d6b; // green (community projects) align-self: flex-start; // avatars hug the left, don't stretch } +.tool-tile-dev-link { + display: block; + line-height: 0; + border-radius: 50%; + transition: transform 0.15s ease; + + &:not(:first-child) { margin-left: -8px; } + + // lift above overlapping siblings on hover/focus so the whole avatar is visible + &:hover, + &:focus-visible { + transform: translateY(-3px); + z-index: 1; + } + + &:focus-visible { + outline: 2px solid $primary; + outline-offset: 2px; + } +} + .tool-tile-dev { + display: block; width: 26px; height: 26px; border-radius: 50%; @@ -371,8 +393,6 @@ $cat-community: #4f9d6b; // green (community projects) border: 2px solid $cream-2; background: $cream-3; - &:not(:first-child) { margin-left: -8px; } - .tool-tile:hover & { border-color: $surface-hover; } } diff --git a/tutorials/posts/2026-06-01-bioinformatics-for-proteomics.qmd b/tutorials/posts/2026-06-01-bioinformatics-for-proteomics.qmd new file mode 100644 index 0000000..937b33b --- /dev/null +++ b/tutorials/posts/2026-06-01-bioinformatics-for-proteomics.qmd @@ -0,0 +1,260 @@ +--- +title: "Bioinformatics for Proteomics" +date: 2026-06-01 +description: "The original hands-on CompOmics course on mass spectrometry-based proteomics data analysis: identification, functional analysis, data sharing, and quantification. Slides and exercise resources included. A modernised version is in preparation." +categories: [proteomics, course, identification, quantification, data-sharing, searchgui, peptideshaker] +--- + +```{=html} +
+ +

The classic Bioinformatics for Proteomics course: a hands-on walk through a full mass spectrometry data-analysis pipeline, from a raw spectrum file to a shared, quantified result. Work through the four modules in order, or jump to the step you need.

+ +
+ +
+

Archived materials. This page preserves the original course. Some tools, formats, and versions reflect the field as it was when the course was written and are now partly outdated (for example, PRIDE XML has been superseded by mzIdentML and mzTab). A modernised version is in preparation.

+

Shared under a CC BY-SA 4.0 licence. Please cite Vaudel et al. (2014).

+
+
+ +
+ Course-wide + +
+ + +
+
+ 1 +
+ Module +

Identification

+

The full path from a raw file to validated peptides and proteins: format conversion, spectrum processing, database preparation, peptide-spectrum matching, inference, validation, PTM analysis, and de novo sequencing.

+
+
+
    +
  1. + 1.1 +
    +

    Database generation

    + +
    +
  2. +
  3. + 1.2 +
    +

    Peak list generation

    + +
    +
  4. +
  5. + 1.3 +
    +

    Peptide to spectrum matching

    + +
    +
  6. +
  7. + 1.4 +
    +

    Browsing identification results

    + +
    +
  8. +
  9. + 1.5 +
    +

    Peptide and protein validation

    + +
    +
  10. +
  11. + 1.6 + +
  12. +
  13. + 1.7 +
    +

    De novo peptide identification

    + +
    +
  14. +
+
+ + +
+
+ 2 +
+ Module +

Functional analysis

+

Turning an identification list into biology: retrieving protein information, pathway analysis, 3D structure visualisation, and Gene Ontology annotation.

+
+
+ +
+ + +
+
+ 3 +
+ Module +

Data sharing

+

Submitting and reusing data through community repositories: converting results to standard formats, submitting to PRIDE and ProteomeXchange, browsing published datasets, and reprocessing.

+
+
+
+ +
+

These course notes use PRIDE XML, now deprecated. Current submissions use mzIdentML and mzTab; the submission workflow through PRIDE and ProteomeXchange is otherwise unchanged.

+
+
+
    +
  1. + 3.0 +
    +

    Introduction

    + +
    +
  2. +
  3. + 3.1 +
    +

    Submit

    + +
    +
  4. +
  5. + 3.2 +
    +

    Browse

    + +
    +
  6. +
  7. + 3.3 +
    +

    Reprocess

    + +
    +
  8. +
+ +
+ + +
+
+ 4 +
+ Module +

Quantification

+

Estimating protein abundance across several orders of magnitude, covering the main quantification strategies and their trade-offs.

+
+
+
    +
  1. + 4.0 +
    +

    Introduction

    + +
    +
  2. +
  3. + 4.1 +
    +

    Spectrum counting

    + +
    +
  4. +
  5. + 4.2 +
    +

    Reporter ions

    + +
    +
  6. +
  7. + 4.5 +
    +

    Statistical analysis

    + +
    +
  8. +
+
+ +
+``` diff --git a/tutorials/tutorials.scss b/tutorials/tutorials.scss index 731bdc7..670ebe6 100644 --- a/tutorials/tutorials.scss +++ b/tutorials/tutorials.scss @@ -41,3 +41,217 @@ max-width: 62ch; margin: 0; } + +// ── "Bioinformatics for Proteomics" course page ────────────────────────────── +// A numbered lab-manual layout: each module is a chapter, each step hangs off a +// left rail (the workflow is a real sequence, so the numbering carries meaning). +// Resources are type-coded chips — blue for materials, red for external tools. +// Scoped under .bfp so nothing leaks to other posts. +.bfp { + --bfp-rail: 3rem; // width of the number column + --bfp-gap: 1.4rem; // rail-to-content gap + max-width: 46rem; + + .bfp-lead { + font-family: $font-family-sans-serif; + font-size: 1.16rem; + line-height: 1.6; + color: $ink; + max-width: 40rem; + margin: 0.25rem 0 1.6rem; + } + + // ── Notes (archived banner + inline deprecation) ────────────────────────── + .bfp-note { + display: flex; + gap: 0.8rem; + padding: 0.9rem 1.1rem; + background: $cream-2; + border: 1px solid $line; + border-left: 3px solid $primary; + border-radius: 0 0.4rem 0.4rem 0; + margin: 1.5rem 0; + + > i { + flex-shrink: 0; + color: $primary; + font-size: 1.15rem; + margin-top: 0.1rem; + } + + p { + margin: 0; + font-family: $font-family-sans-serif; + font-size: 0.93rem; + line-height: 1.6; + color: $ink-soft; + } + p + p { margin-top: 0.4rem; } + strong { color: $ink; font-weight: 700; } + + .bfp-note-meta { color: $muted; font-size: 0.85rem; } + } + + .bfp-note--inline { + border-left-color: $secondary; + margin: 0 0 1.5rem; + > i { color: $secondary; } + } + + // ── Course-wide / related resource rows ─────────────────────────────────── + .bfp-general { margin: 1.5rem 0 2rem; } + .bfp-related { margin-top: 1.3rem; padding-left: calc(var(--bfp-rail) + var(--bfp-gap)); } + .bfp-loose { padding-left: calc(var(--bfp-rail) + var(--bfp-gap)); } + + .bfp-general-label, + .bfp-related-label { + display: block; + font-family: $font-family-monospace; + font-size: 0.68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.16em; + color: $muted; + margin-bottom: 0.55rem; + } + + // ── Module (chapter) ────────────────────────────────────────────────────── + .bfp-module { margin-top: 3.2rem; } + + .bfp-module-head { + display: grid; + grid-template-columns: var(--bfp-rail) 1fr; + column-gap: var(--bfp-gap); + align-items: start; + margin-bottom: 1.3rem; + } + + .bfp-module-num { + font-family: $font-family-heading; + font-weight: 800; + font-size: 2.3rem; + line-height: 1; + color: $primary; + text-align: right; + letter-spacing: -0.02em; + } + + .bfp-eyebrow { + display: block; + font-family: $font-family-monospace; + font-size: 0.68rem; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.16em; + color: $muted; + margin-bottom: 0.25rem; + } + + .bfp-module-title { + font-family: $font-family-heading; + font-size: 1.7rem; + font-weight: 800; + color: $ink; + line-height: 1.1; + margin: 0 0 0.4rem; + padding: 0; + border: none; + } + + .bfp-module-desc { + font-family: $font-family-sans-serif; + font-size: 0.96rem; + line-height: 1.6; + color: $ink-soft; + margin: 0; + max-width: 38rem; + } + + // ── Steps hanging off the rail ──────────────────────────────────────────── + .bfp-steps { + list-style: none; + margin: 0; + padding: 0; + } + + .bfp-step { + display: grid; + grid-template-columns: var(--bfp-rail) 1fr; + column-gap: var(--bfp-gap); + } + + .bfp-step-num { + font-family: $font-family-monospace; + font-size: 0.9rem; + font-weight: 700; + color: $primary; + text-align: right; + padding-top: 0.15rem; + } + + .bfp-step-body { + border-left: 2px solid darken($line, 22%); // stacked borders form the continuous rail + padding: 0 0 1.35rem var(--bfp-gap); + } + .bfp-step:last-child .bfp-step-body { padding-bottom: 0.35rem; } + + .bfp-step-title { + font-family: $font-family-heading; + font-size: 1.04rem; + font-weight: 700; + color: $ink; + line-height: 1.25; + margin: 0 0 0.5rem; + padding: 0; + border: none; + } + + // ── Resource chips ──────────────────────────────────────────────────────── + .bfp-links { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + } + + .bfp-link { + display: inline-flex; + align-items: center; + gap: 0.4rem; + padding: 0.3rem 0.7rem; + font-family: $font-family-sans-serif; + font-size: 0.8rem; + font-weight: 600; + line-height: 1; + color: $ink-soft; + background: $cream-2; + border: 1px solid $line; + border-radius: 0.4rem; + text-decoration: none; + transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease; + + i { font-size: 0.9rem; color: $primary; } + + &:hover { + border-color: $primary; + color: $primary; + background: $surface-hover; + text-decoration: none; + } + } + + // external software gets the red accent, so tools read differently from materials + .bfp-link--tool { + i { color: $secondary; } + &:hover { border-color: $secondary; color: $secondary; } + } + + // ── Narrow screens: shrink the rail, keep the spine ─────────────────────── + @media (max-width: 560px) { + --bfp-rail: 2.2rem; + --bfp-gap: 0.9rem; + + .bfp-module-num { font-size: 1.9rem; } + .bfp-module-title { font-size: 1.45rem; } + .bfp-step-num { font-size: 0.82rem; } + } +}