Skip to content

Commit bca569c

Browse files
ewelsclaude
andcommitted
Docs site: theme refresh, custom homepage, sun/moon theme toggle
- Custom design tokens applied site-wide via Starlight CSS variables. Light mode is bone paper with prussian-blue ink (cyanotype-inverted), dark mode is deep navy with parchment text. Body has a graph-paper grid background. Display headings use Archivo Narrow, body text uses Inter, code uses JetBrains Mono. - New homepage with mascot hero, two benchmark figures, six-feature grid, install snippet with monospace buttons, and a STAR-vs-rustar comparison table. Wiggle dividers between sections animate as a slow water-surface morph via CSS path() keyframes (respects prefers-reduced-motion). - Replaced Starlight's three-option theme dropdown with a minimal sun/moon ThemeToggle component. First load follows OS preference; click flips and persists to localStorage under Starlight's key. - Restored a top border on framed code blocks since the title-bar header is now hidden, using EC's own --ec-brdWd/--ec-brdCol tokens. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c046162 commit bca569c

5 files changed

Lines changed: 878 additions & 87 deletions

File tree

docs/astro.config.mjs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ export default defineConfig({
1212
src: './src/assets/rustar-icon.svg',
1313
},
1414
favicon: '/favicon.svg',
15+
head: [
16+
{ tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.googleapis.com' } },
17+
{ tag: 'link', attrs: { rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' } },
18+
{
19+
tag: 'link',
20+
attrs: {
21+
rel: 'stylesheet',
22+
href: 'https://fonts.googleapis.com/css2?family=Archivo+Narrow:wght@400;500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;700&display=swap',
23+
},
24+
},
25+
],
1526
components: {
1627
Header: './src/components/Header.astro',
1728
},

docs/src/components/Header.astro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import LanguageSelect from 'virtual:starlight/components/LanguageSelect';
44
import Search from 'virtual:starlight/components/Search';
55
import SiteTitle from 'virtual:starlight/components/SiteTitle';
66
import SocialIcons from 'virtual:starlight/components/SocialIcons';
7-
import ThemeSelect from 'virtual:starlight/components/ThemeSelect';
7+
import ThemeToggle from './ThemeToggle.astro';
88
99
const shouldRenderSearch =
1010
config.pagefind || config.components.Search !== '@astrojs/starlight/components/Search.astro';
@@ -60,7 +60,7 @@ const { label: versionLabel, url: versionUrl } = await g.__rustarRelease;
6060
<div class="sl-flex social-icons">
6161
<SocialIcons />
6262
</div>
63-
<ThemeSelect />
63+
<ThemeToggle />
6464
<LanguageSelect />
6565
</div>
6666
</div>
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
---
2+
// Minimal sun/moon theme toggle.
3+
// - First load (no stored preference): follows OS via Starlight's existing
4+
// inline init script in <head>, which sets data-theme on <html>.
5+
// - Click: flips to the opposite of the current effective theme and persists
6+
// under Starlight's key ('starlight-theme') so the choice survives reload.
7+
---
8+
9+
<button
10+
type="button"
11+
class="rustar-theme-toggle"
12+
aria-label="Toggle light or dark theme"
13+
data-rustar-theme-toggle
14+
>
15+
<svg class="icon-sun" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
16+
<circle cx="12" cy="12" r="4"/>
17+
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
18+
</svg>
19+
<svg class="icon-moon" aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
20+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
21+
</svg>
22+
</button>
23+
24+
<style>
25+
.rustar-theme-toggle {
26+
background: transparent;
27+
border: none;
28+
padding: 6px;
29+
cursor: pointer;
30+
color: var(--sl-color-gray-2);
31+
display: inline-flex;
32+
align-items: center;
33+
justify-content: center;
34+
line-height: 0;
35+
transition: color 150ms ease;
36+
}
37+
.rustar-theme-toggle:hover,
38+
.rustar-theme-toggle:focus-visible {
39+
color: var(--sl-color-text-accent);
40+
outline: none;
41+
}
42+
.rustar-theme-toggle svg { width: 18px; height: 18px; }
43+
.rustar-theme-toggle .icon-sun,
44+
.rustar-theme-toggle .icon-moon { display: none; }
45+
:global(:root[data-theme='dark']) .rustar-theme-toggle .icon-sun { display: block; }
46+
:global(:root[data-theme='light']) .rustar-theme-toggle .icon-moon { display: block; }
47+
</style>
48+
49+
<script is:inline>
50+
(() => {
51+
const KEY = 'starlight-theme';
52+
const btn = document.querySelector('[data-rustar-theme-toggle]');
53+
if (!btn) return;
54+
const root = document.documentElement;
55+
const effective = () => {
56+
const stored = localStorage.getItem(KEY);
57+
if (stored === 'light' || stored === 'dark') return stored;
58+
return matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
59+
};
60+
btn.addEventListener('click', () => {
61+
const next = effective() === 'dark' ? 'light' : 'dark';
62+
root.dataset.theme = next;
63+
localStorage.setItem(KEY, next);
64+
});
65+
})();
66+
</script>

docs/src/content/docs/index.mdx

Lines changed: 162 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,166 @@
11
---
22
title: rustar-aligner
3-
description: A Rust reimplementation of STAR — the widely-used RNA-seq aligner — built for behavioural parity with the original.
4-
hero:
5-
title: A Rust port of STAR
6-
tagline: Faithful, byte-compatible RNA-seq alignment in modern Rust. Same index format, same <code>--camelCase</code> flags, same SAM/BAM output.
7-
image:
8-
file: ../../assets/rustar-logo.svg
9-
actions:
10-
- text: Quick start
11-
link: /rustar-aligner/getting-started/quick-start/
12-
icon: right-arrow
13-
variant: primary
14-
- text: View on GitHub
15-
link: https://github.com/Psy-Fer/rustar-aligner
16-
icon: external
17-
variant: minimal
3+
description: A faithful Rust reimplementation of STAR, the canonical RNA-seq aligner.
184
---
195

20-
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
21-
22-
<CardGrid stagger>
23-
<Card title="Drop-in compatible" icon="approve-check">
24-
Same genome index format, same `--camelCase` parameters, same SAM/BAM output as STAR. Existing pipelines work without changes.
25-
</Card>
26-
<Card title="99.88% byte-identical" icon="seti:rust">
27-
Tie-adjusted faithfulness vs STAR on yeast benchmark: 99.815% single-end, 99.883% paired-end. The suffix array is byte-for-byte identical.
28-
</Card>
29-
<Card title="Full feature set" icon="puzzle">
30-
Single-end, paired-end, two-pass, chimeric detection (4-tier), gene quantification, transcriptome SAM, GTF junctions, multi-threaded.
31-
</Card>
32-
<Card title="Built in Rust" icon="rocket">
33-
Modern toolchain, memory-safe, no manual memory management. 396 tests, zero clippy warnings, runs on Linux, macOS, and Windows.
34-
</Card>
35-
</CardGrid>
36-
37-
## Get going
38-
39-
<CardGrid>
40-
<LinkCard
41-
title="Migrating from STAR"
42-
href="/rustar-aligner/guides/migrating-from-star/"
43-
description="Already using STAR? See what's identical, what differs, and how to swap one for the other."
44-
/>
45-
<LinkCard
46-
title="CLI parameters"
47-
href="/rustar-aligner/reference/cli-parameters/"
48-
description="Every flag rustar-aligner accepts, grouped by category and matching STAR's naming."
49-
/>
50-
<LinkCard
51-
title="STAR compatibility"
52-
href="/rustar-aligner/reference/star-compatibility/"
53-
description="A detailed scoreboard of how identical the outputs are vs STAR, with the known edge cases listed."
54-
/>
55-
<LinkCard
56-
title="Quick start"
57-
href="/rustar-aligner/getting-started/quick-start/"
58-
description="Index a genome, align some reads, look at the output. Five commands."
59-
/>
60-
</CardGrid>
6+
import { Image } from 'astro:assets';
7+
import rustarIcon from '../../assets/rustar-icon.svg';
8+
9+
export const installCode = `<span class="comment"># Step 1 · install</span>
10+
<span class="prompt">$</span> cargo install <span class="flag">--git</span> https://github.com/Psy-Fer/rustar-aligner
11+
12+
<span class="comment"># Step 2 · align</span>
13+
<span class="prompt">$</span> rustar-aligner \\
14+
<span class="flag">--genomeDir</span> <span class="str">./yeast_index</span> \\
15+
<span class="flag">--readFilesIn</span> <span class="str">r1.fq r2.fq</span> \\
16+
<span class="flag">--outSAMtype</span> BAM SortedByCoordinate \\
17+
<span class="flag">--runThreadN</span> 8 \\
18+
<span class="flag">--outFileNamePrefix</span> <span class="str">./out_</span>`;
19+
20+
<div class="rustar-home">
21+
22+
<section class="rustar-hero">
23+
<div>
24+
<h1>rustar-aligner</h1>
25+
<p class="lead">A faithful Rust reimplementation of <em>STAR</em>, the canonical RNA-seq aligner originally written in C++ by Alexander Dobin.</p>
26+
<p class="lead-2">Same <code>{'--camelCase'}</code> CLI. Same SAM/BAM output formats. 99.883% mate-pair faithfulness on a 10,000-pair yeast benchmark, with zero MAPQ inflations.</p>
27+
<div class="rustar-btns rustar-hero-btns">
28+
<a href="/rustar-aligner/getting-started/introduction/" class="primary">Documentation</a>
29+
<a href="https://github.com/Psy-Fer/rustar-aligner">GitHub ↗</a>
30+
</div>
31+
</div>
32+
<Image src={rustarIcon} alt="rustar-aligner mascot: a red crab cradling a golden starfish" class="rustar-mascot" loading="eager" />
33+
</section>
34+
35+
<svg class="rustar-topo" viewBox="0 0 1200 50" preserveAspectRatio="none" aria-hidden="true">
36+
<path d="M0,28 Q200,14 400,28 T800,28 Q1000,16 1200,28" fill="none" stroke="currentColor" stroke-width="0.6" />
37+
<path d="M0,18 Q300,5 600,18 T1200,18" fill="none" stroke="currentColor" stroke-width="0.6" />
38+
<path d="M0,38 Q400,24 800,38 T1200,38" fill="none" stroke="currentColor" stroke-width="0.6" />
39+
</svg>
40+
41+
<section class="rustar-section">
42+
<h2>Where rustar agrees with the original.</h2>
43+
<p class="lede">10,000 yeast RNA-seq read pairs, ERR12389696, 150 bp paired-end. Same genome index, same CLI parameters as STAR 2.7.x. Compared mate by mate.</p>
44+
<div class="rustar-stats">
45+
<div class="rustar-stat">
46+
<div class="num">99.883%</div>
47+
<div class="lbl">PE Faithfulness</div>
48+
<div class="sub">tie-adjusted; 16,284 of 16,306 mate alignments byte-for-byte identical to STAR.</div>
49+
</div>
50+
<div class="rustar-stat">
51+
<div class="num">0</div>
52+
<div class="lbl">MAPQ Inflations</div>
53+
<div class="sub">zero deflations, zero NH-tag diffs, zero proper-pair classification differences.</div>
54+
</div>
55+
</div>
56+
</section>
57+
58+
<svg class="rustar-topo" viewBox="0 0 1200 50" preserveAspectRatio="none" aria-hidden="true">
59+
<path d="M0,28 Q200,14 400,28 T800,28 Q1000,16 1200,28" fill="none" stroke="currentColor" stroke-width="0.6" />
60+
<path d="M0,18 Q300,5 600,18 T1200,18" fill="none" stroke="currentColor" stroke-width="0.6" />
61+
<path d="M0,38 Q400,24 800,38 T1200,38" fill="none" stroke="currentColor" stroke-width="0.6" />
62+
</svg>
63+
64+
<section class="rustar-section">
65+
<h2>What it does.</h2>
66+
<div class="rustar-feats">
67+
<div class="rustar-feat">
68+
<div class="n">01</div>
69+
<div>
70+
<h3>Drop-in CLI</h3>
71+
<p>Same <code>{'--camelCase'}</code> parameter names as STAR. Existing wrapper scripts work without modification.</p>
72+
</div>
73+
</div>
74+
<div class="rustar-feat">
75+
<div class="n">02</div>
76+
<div>
77+
<h3>Same output formats</h3>
78+
<p>SAM, unsorted BAM, coordinate-sorted BAM, SJ.out.tab, ReadsPerGene.out.tab, Chimeric.out.junction.</p>
79+
</div>
80+
</div>
81+
<div class="rustar-feat">
82+
<div class="n">03</div>
83+
<div>
84+
<h3>Splice + chimeric + two-pass</h3>
85+
<p>Full splice-junction detection, two-pass mode, multi-junction chimeric (Tier 3) detection.</p>
86+
</div>
87+
</div>
88+
<div class="rustar-feat">
89+
<div class="n">04</div>
90+
<div>
91+
<h3>Deterministic tie-breaking</h3>
92+
<p><code>{'--runRNGseed'}</code> mirrors STAR. Identical seed produces identical primary tie-break within rustar runs.</p>
93+
</div>
94+
</div>
95+
<div class="rustar-feat">
96+
<div class="n">05</div>
97+
<div>
98+
<h3>Single-binary install</h3>
99+
<p>~14 MB stripped binary. No dynamic-library deps beyond <code>libc</code>. Builds with stable Rust 1.80+.</p>
100+
</div>
101+
</div>
102+
<div class="rustar-feat">
103+
<div class="n">06</div>
104+
<div>
105+
<h3>Multi-threaded</h3>
106+
<p>Rayon-based parallelism. Scales linearly across logical CPUs for the alignment phase.</p>
107+
</div>
108+
</div>
109+
</div>
110+
</section>
111+
112+
<svg class="rustar-topo" viewBox="0 0 1200 50" preserveAspectRatio="none" aria-hidden="true">
113+
<path d="M0,28 Q200,14 400,28 T800,28 Q1000,16 1200,28" fill="none" stroke="currentColor" stroke-width="0.6" />
114+
<path d="M0,18 Q300,5 600,18 T1200,18" fill="none" stroke="currentColor" stroke-width="0.6" />
115+
<path d="M0,38 Q400,24 800,38 T1200,38" fill="none" stroke="currentColor" stroke-width="0.6" />
116+
</svg>
117+
118+
<section class="rustar-section rustar-install-section">
119+
<h2>Two commands, one alignment.</h2>
120+
<div class="rustar-install">
121+
<div>
122+
<h3>Install &amp; run</h3>
123+
<p>Cargo will fetch the source, resolve dependencies, compile in release mode, and place the binary on your <code>$PATH</code>. About 90 to 180 seconds on recent hardware.</p>
124+
<p>Then run a paired-end alignment against a pre-built genome index.</p>
125+
<div class="rustar-btns">
126+
<a href="/rustar-aligner/getting-started/installation/" class="primary">install</a>
127+
<a href="/rustar-aligner/getting-started/quick-start/">quick start</a>
128+
<a href="/rustar-aligner/guides/migrating-from-star/">migrating from STAR</a>
129+
</div>
130+
</div>
131+
<pre class="rustar-code" set:html={installCode}></pre>
132+
</div>
133+
</section>
134+
135+
<svg class="rustar-topo" viewBox="0 0 1200 50" preserveAspectRatio="none" aria-hidden="true">
136+
<path d="M0,28 Q200,14 400,28 T800,28 Q1000,16 1200,28" fill="none" stroke="currentColor" stroke-width="0.6" />
137+
<path d="M0,18 Q300,5 600,18 T1200,18" fill="none" stroke="currentColor" stroke-width="0.6" />
138+
<path d="M0,38 Q400,24 800,38 T1200,38" fill="none" stroke="currentColor" stroke-width="0.6" />
139+
</svg>
140+
141+
<section class="rustar-section">
142+
<h2>Side by side with the original.</h2>
143+
<p class="lede">Selected metrics from the standard 10k-pair yeast benchmark. See the <a href="/rustar-aligner/reference/star-compatibility/">full compatibility scoreboard</a> for the rest.</p>
144+
<table class="rustar-compare">
145+
<thead>
146+
<tr>
147+
<th>Metric</th>
148+
<th style="text-align:right">rustar</th>
149+
<th style="text-align:right">STAR</th>
150+
<th style="text-align:right">Δ</th>
151+
</tr>
152+
</thead>
153+
<tbody>
154+
<tr><td class="metric">Both mates mapped</td><td class="num">8,390</td><td class="num">8,390</td><td class="match">match</td></tr>
155+
<tr><td class="metric">Half-mapped pairs</td><td class="num">0</td><td class="num">0</td><td class="match">match</td></tr>
156+
<tr><td class="metric">Position agreement (SE)</td><td class="num">99.815%</td><td class="num">—</td><td class="match">tie-adj.</td></tr>
157+
<tr><td class="metric">PE faithfulness</td><td class="num">99.883%</td><td class="num">—</td><td class="match">tie-adj.</td></tr>
158+
<tr><td class="metric">MAPQ inflations</td><td class="num">0</td><td class="num">—</td><td class="match">none</td></tr>
159+
<tr><td class="metric">NH-tag diffs</td><td class="num">0</td><td class="num">—</td><td class="match">none</td></tr>
160+
<tr><td class="metric">Proper-pair diffs</td><td class="num">0</td><td class="num">—</td><td class="match">none</td></tr>
161+
<tr><td class="metric">Tests passing</td><td class="num">396</td><td class="num">—</td><td class="match">all green</td></tr>
162+
</tbody>
163+
</table>
164+
</section>
165+
166+
</div>

0 commit comments

Comments
 (0)