Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/observatory/llms.txt
Use this file to discover all available pages before exploring further.
CaseStudyReader presents long-form case studies using the metaphor of a photographic darkroom. A narrow film-strip sidebar on the left lists all available studies. Clicking an entry exposes the content in the right-hand darkroom panel — it emerges from a blurred, high-contrast, desaturated state to full clarity, as if a photograph is developing under a red safelight.
Visual appearance
The component renders a full-width flex container that stacks vertically on mobile and switches to a two-column layout onlg breakpoints.
Film-strip sidebar
The left panel is one-quarter of the total width on large screens. It has an “EXPOSURE INDEX” heading in monospace and a stack of film-strip entry buttons. Each button features:- A left-side strip of 6 sprocket holes (
w-1.5 h-2black rounded rectangles) at 20% opacity, simulating 35mm film - A date label in
aurora-tealmonospace (10px) - The case study title in display font — active entries are
aurora-turquoise; inactive entries areslate-300with a white hover state - An active border
aurora-tealwith a faint teal background tint; inactive entries have awhite/10border
Darkroom content panel
The right panel takes three-quarters of the width on large screens. It has a near-black#0a0a0a background with a white/5 border and a subtle red-tinted glow blob at the top center (red-900/10 blur-[100px]), evoking the warm red light of a darkroom.
A persistent film-grain noise overlay (opacity-[0.04] mix-blend-overlay) adds texture to the dark background at all times.
The active entry’s content is wrapped in AnimatePresence mode="wait" and rendered inside a m.div keyed to the entry id.
Content sections are parsed by splitting each string on ': '. The portion before the first colon is rendered as a monospace slate-500 label prefix; the remainder is rendered as plain slate-300 body text. Each section staggered by 0.5s with a 1s base delay, animating from opacity: 0, y: 10 to opacity: 1, y: 0 over 1.5s.
Development animation
When an entry is selected, them.div exits with opacity: 0, filter: blur(5px) and the incoming entry enters with a dramatic 2.5 second ease-out animation:
Content format
Each content section string uses the formatKEYWORD: body text. The component splits on ': ' and renders the keyword as a monospace prefix label:
Animations
| Effect | Implementation |
|---|---|
| Development reveal | m.div blur/contrast/grayscale filter animation, 2.5s easeOut |
| Section stagger | Per-section m.div opacity + y, base 1s delay + index × 0.5s |
| Panel exit | m.div exit opacity: 0, filter: blur(5px) |
| Entry transition | AnimatePresence mode="wait", keyed to entry.id |
Where it’s used
CaseStudyReader is the primary content component on the /case-studies route:
Data shape
The case studies array is defined incomponents/aurora/CaseStudyReader.js.
Unique identifier for the case study. Used as the React key and as the
AnimatePresence key to trigger the development animation.Case study title displayed in both the sidebar entry button and as the
h2 heading in the darkroom panel.Date label in “stardate” format (e.g.,
'Stardate 4592.1'). Displayed above the title in the darkroom header and as a small monospace label in the sidebar entry.Array of section strings. Each string should follow the
KEYWORD: body text format. The keyword becomes a monospace prefix label; the body text follows inline. Sections are animated in sequentially with a 0.5s stagger after a 1s base delay.How to customize
Layout tips
- Use 3–6 content sections per case study for the best reading rhythm. The stagger delay means very long studies take longer to fully reveal.
- The
KEYWORD:labels work best as single words or short phrases in uppercase:PROBLEM:,APPROACH:,OUTCOME:, etc. - The first entry in the array is selected by default on mount.