diff --git a/README.md b/README.md index 6599f95..6affc30 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@

Open StatLab Watch the tour + Play the 20 second video

@@ -29,6 +30,11 @@ ## See it in action +

+ Poster of StatLab's 20-second launch video. Click to play it. +
▶️ Play the 20-second launch video (with sound), or watch the longer tour below. +

+

A one-minute tour of StatLab: the home page with a 14-day streak and 1300 points; a lesson where R runs in the page and draws a scree plot; an exercise where a wrong answer gets an explanation from the student's avatar and the right answer earns points and confetti; the least-squares simulation with a line being dragged; the model chooser recommending multiple regression in five clicks; and the avatar shop where a crown is bought with points.

@@ -78,6 +84,20 @@ The layout folds down for small screens, and progress can be exported and picked up on another device. + + +

🎯 "How many participants?"

+ A step-by-step sample size planner for two groups, repeated measures, 2 × 2 designs, regression and proportions, with the course model to fit, a power curve and R code that reproduces it. + + +

🧑‍🏫 "Where to?"

+ Type what you are looking for, "compare two groups" or "how many people do I need", and the avatar points to the right lesson or tool. + + +

♿ Built for everyone

+ Keyboard navigation, a skip link and screen reader labels, with every page scanned against WCAG 2.1 AA on each change. + + ## A look inside @@ -107,6 +127,14 @@ The R Workspace: RStudio's panes, with your own data. From research question to model in a few clicks. + + The sample size planner's result for a 2 × 2 pre-post design: recruit 144 participants to end with 128 complete cases, a table showing how many are needed if the true effect is smaller, and a power curve crossing 80% at 128 people. + The Where to? helper opened on a lesson page. The student typed how many people do I need, and it suggests the How many participants? planner and Lesson 8-4 on effect sizes and planning a study. + + + Plan a study: how many people, and what if the effect is smaller. + Lost? Ask the avatar where to go. + The least-squares simulation: a scatter of points, a line the student drags with intercept and slope sliders, and orange squares showing each squared residual. The Central Limit Theorem simulation: a strongly skewed population above, and below it 2000 sample means with n = 30 forming a near-normal histogram. @@ -193,6 +221,8 @@ on wellbeing). solution, alternate solution and known wrong answer through R and checks that the right ones pass and the wrong ones fail for the right reason. - **A real browser clicks through the site** before anything is published. +- **Accessible by default.** Every page is scanned with axe against WCAG 2.1 AA + on each change, and a failing scan blocks the release. - **It keeps itself up to date.** A weekly workflow checks for new versions of webR and the site's dependencies and only takes them after the full R check passes. diff --git a/docs/readme/launch.jpg b/docs/readme/launch.jpg new file mode 100644 index 0000000..5c5cb0b Binary files /dev/null and b/docs/readme/launch.jpg differ diff --git a/docs/readme/launch.mp4 b/docs/readme/launch.mp4 new file mode 100644 index 0000000..15f59d2 Binary files /dev/null and b/docs/readme/launch.mp4 differ diff --git a/docs/screenshots/helper.png b/docs/screenshots/helper.png new file mode 100644 index 0000000..7a39092 Binary files /dev/null and b/docs/screenshots/helper.png differ diff --git a/docs/screenshots/sample-size.png b/docs/screenshots/sample-size.png new file mode 100644 index 0000000..d8d8e4a Binary files /dev/null and b/docs/screenshots/sample-size.png differ diff --git a/src/components/Logo.tsx b/src/components/Logo.tsx index eb43678..7217630 100644 --- a/src/components/Logo.tsx +++ b/src/components/Logo.tsx @@ -1,23 +1,20 @@ import { useId } from 'react'; -/** Three bars of a histogram under a fitted curve: the course in one mark. */ +/** A bell curve on the brand gradient: the same mark as public/favicon.svg. */ export default function Logo({ size = 22 }: { size?: number }) { // Each instance needs its own gradient id: the first copy of a shared id can // sit in a hidden topbar, and a hidden gradient paints nothing. const gradient = `logo-gradient-${useId().replace(/:/g, '')}`; return ( - {lastVisitedLesson() ? 'Carry on' : 'Start here'}: Lesson {last.id} + {lastVisitedLesson() ? 'Carry on' : 'Start here'}: Lesson {last.id.replace(/^0/, '')} {last.title}

Or try:

diff --git a/src/content/guide.ts b/src/content/guide.ts index 2a2f77e..0678290 100644 --- a/src/content/guide.ts +++ b/src/content/guide.ts @@ -27,7 +27,7 @@ const ENTRIES: Entry[] = [ ...MODULES.flatMap((module) => module.lessons.map((lesson) => ({ to: `/lesson/${lesson.id}`, - title: `Lesson ${lesson.id}: ${lesson.title}`, + title: `Lesson ${lesson.id.replace(/^0/, '')}: ${lesson.title}`, detail: `Module ${module.number}: ${module.title}`, titleWords: new Set(words(lesson.title)), words: new Set(words(`${module.title} ${LESSON_KEYWORDS[lesson.id] ?? ''}`)), @@ -66,7 +66,7 @@ export function guide(text: string): GuideHit[] { const answer = best && allAnswers().find((entry) => entry.answer.id === best.id)?.answer; if (answer) { const lesson = answer.lessonId ? findLesson(answer.lessonId) : undefined; - const teaching: GuideHit[] = lesson ? [{ to: `/lesson/${lesson.id}`, title: `Lesson ${lesson.id}: ${lesson.title}`, detail: `Where the course teaches ${answer.model.toLowerCase()}` }] : []; + const teaching: GuideHit[] = lesson ? [{ to: `/lesson/${lesson.id}`, title: `Lesson ${lesson.id.replace(/^0/, '')}: ${lesson.title}`, detail: `Where the course teaches ${answer.model.toLowerCase()}` }] : []; const rest = hits.filter((hit) => !teaching.some((t) => t.to === hit.to)); return [{ to: `/which-model?model=${answer.id}`, title: `Likely analysis: ${answer.model}`, detail: 'Suggested from the words in your question. The model chooser explains it.' }, ...teaching, ...rest].slice(0, 4); }