docs: establish approved Phase 1 design + Phase 2 spec as project foundation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
# ANIMATION_CONCEPTS.md
|
||||
Named animation concepts, each mapped to the question it answers. All obey MOTION_GUIDELINES tokens & reduced-motion variants.
|
||||
|
||||
---
|
||||
|
||||
## A1 · "Trace draw" — hero identity moment
|
||||
On first paint: a 1.5px accent line draws left→right under the role line (700ms `signature`), steps down 8px mid-way (PCB-trace corner), and terminates in a 4px status dot that blinks once, then stays lit next to `Open to work`.
|
||||
*Question answered:* "the page is ready — and he's available."
|
||||
Reduced motion: line + lit dot render complete, static. Repeat visits: draws once per session only.
|
||||
|
||||
## A2 · "Section arrive"
|
||||
Each homepage section reveals on 20% viewport entry: opacity 0→1 + 12px rise (400ms), heading first, content children staggered 60ms (max 3 groups). Fires once per page load.
|
||||
*Question:* "what's new in view?" — creates reading rhythm without withholding content (text is present for search/reader modes regardless).
|
||||
|
||||
## A3 · "Card focus"
|
||||
Project cards on hover/focus-visible: border → `border-strong`, screenshot shifts up 4px (240ms), title gains accent underline draw (160ms), `Read case study →` arrow nudges 4px right.
|
||||
*Question:* "is this clickable, and what happens?"
|
||||
|
||||
## A4 · "Chip pulse"
|
||||
The `ACTIVE` status dot pulses twice (scale 1→1.4 opacity fade) when its chip first enters viewport, then rests lit. Amber `IN DEVELOPMENT` dots never pulse (calm hierarchy: live > in-progress).
|
||||
*Question:* "which of these is running right now?"
|
||||
|
||||
## A5 · "Diagram flow" (case-study architecture, desktop only)
|
||||
Architecture diagrams are static SVGs; hovering a node highlights its connected edges in accent (160ms) and dims unrelated nodes to 60%. No autoplay, no looping data-packet animations.
|
||||
*Question:* "what talks to what?"
|
||||
Mobile/touch + reduced motion: full static diagram, always fully legible without interaction.
|
||||
|
||||
## A6 · "Theme morph"
|
||||
Sun⇄moon icon path-morph (160ms) + global 240ms token cross-fade. The hero trace re-tints without redrawing.
|
||||
|
||||
## A7 · "Language cross-fade"
|
||||
On EN⇄NO switch: text nodes fade out 80ms / in 160ms; layout containers keep dimensions during swap (pre-measured against longer NO strings) so nothing jumps. The switch control itself slides its active-segment thumb (160ms).
|
||||
*Question:* "same page, other language — nothing lost."
|
||||
|
||||
## A8 · "Timeline grow"
|
||||
Experience timeline's vertical hairline draws downward as the section enters (400ms); period dots fade in with their rows.
|
||||
*Question:* "read this top-down, newest first."
|
||||
|
||||
## A9 · "Form confirm"
|
||||
On successful submit, the form panel cross-fades to a confirmation card: accent check icon draws (240ms stroke), message + "I usually reply within a day" (`Jeg svarer vanligvis innen en dag`).
|
||||
*Question:* "did it actually send?" — the current site's broken-looking send feedback (raw � glyphs) is exactly what this replaces.
|
||||
|
||||
## A10 · "404 fray"
|
||||
The trace motif runs, stutters, and frays into dots at the break point; mono caption `route not found — no such page` / `fant ikke siden`. Static in reduced motion.
|
||||
*Purpose:* the one place allowed personality-forward motion — errors are where craft shows.
|
||||
|
||||
---
|
||||
|
||||
### Explicitly rejected concepts (documented so Phase 3 doesn't re-invent them)
|
||||
Typewriter hero text (junior tell) · particle backgrounds · 3D tilt cards · scroll-pinned storytelling · animated skill counters · magnetic buttons (see CURSOR_INTERACTIONS) · autoplaying screenshot carousels.
|
||||
@@ -0,0 +1,25 @@
|
||||
# CURSOR_INTERACTIONS.md
|
||||
|
||||
## Verdict: near-zero custom cursor work — by design
|
||||
|
||||
Custom cursors (dot followers, magnetic buttons, cursor-morphing) were evaluated and **rejected** for this site. Reasons, documented so the decision survives future redesign itch:
|
||||
|
||||
1. **Audience mismatch.** P1 recruiters on trackpads/mobile never see it; P2 engineering managers disproportionately *dislike* cursor gimmicks (input latency, hijacked expectations).
|
||||
2. **Brand mismatch.** "Kontrollrom" promises precision and restraint; a floating blob promises an agency reel.
|
||||
3. **Cost.** Pointer-following JS is the classic source of main-thread jank — the exact failure mode this site must never exhibit.
|
||||
|
||||
## What ships instead (native cursor semantics, used *correctly*)
|
||||
|
||||
| Context | Cursor | Note |
|
||||
|---|---|---|
|
||||
| Links, buttons, cards, TOC | `pointer` | Whole project card = pointer (it's one link) |
|
||||
| Fact chips (non-interactive) | `default` | Honest affordance — no fake clickability |
|
||||
| Text/prose | `text` | Never suppressed |
|
||||
| Screenshot in lightbox (zoomable) | `zoom-in` / `zoom-out` | The one "delight" allowed |
|
||||
| Click-to-copy e-mail | `copy` | Native, semantically perfect, zero JS cost |
|
||||
| Diagram nodes with hover-highlight | `default` + visual highlight | Hover is enhancement, not interaction — pointer would over-promise |
|
||||
| Disabled controls | `not-allowed` | |
|
||||
|
||||
## The single permitted flourish
|
||||
|
||||
On the hero, the status dot at the end of the trace shows a `crosshair`-style precision hover halo (pure CSS, 160ms) revealing a mono tooltip: `status: open to work` / `status: åpen for muligheter`. Desktop-only easter egg; invisible to touch, absent under reduced motion, no positional JS. If it ever measures as jank — cut it without debate.
|
||||
@@ -0,0 +1,54 @@
|
||||
# MICRO_INTERACTIONS.md
|
||||
Component-level interaction specs. Every interactive element defines: rest / hover / active / focus-visible / disabled, keyboard behaviour, and touch behaviour.
|
||||
|
||||
---
|
||||
|
||||
## Buttons
|
||||
- **Primary (accent fill):** hover → brightness +6% and 1px rise (transform); active → rise removed (press); focus-visible → 2px accent ring, 2px offset; disabled → surface-2 + ink-faint, no events.
|
||||
- **Secondary (outline):** hover → border-strong + surface-1 fill.
|
||||
- **Ghost (nav, footer):** hover → ink (from ink-muted) + accent underline draw.
|
||||
- Touch: no hover states persist; active state on touchstart (≤80ms feedback).
|
||||
|
||||
## Split CV button (header)
|
||||
- Primary zone downloads locale CV; label: `Download CV` / `Last ned CV`, mono-meta suffix shows size `· pdf 180 kB`.
|
||||
- Chevron zone (separate 44px hit area) opens a 2-item menu: `English (pdf)` / `Norsk (pdf)` with a subtle flag-free language tag (`EN`/`NO` mono chips — no flag icons anywhere; flags conflate language and nationality).
|
||||
- Keyboard: button reachable in tab order; chevron = separate stop; menu arrows + Esc. Download triggers a one-time toast-less confirmation: button icon swaps to check for 1.5s.
|
||||
|
||||
## Language switch (header, segmented control)
|
||||
- Two segments `EN | NO`, active segment has surface-1 thumb + ink text; inactive = ink-muted. Hover inactive → ink. Thumb slides 160ms on change (A7).
|
||||
- Keyboard: single tab stop, arrow keys toggle, Enter/Space activates. `aria` as a proper toggle group; screen reader announces "Norsk — bytt språk / English — switch language" (label in *target* language, the convention that works when you can't read the current one).
|
||||
- Mobile: inside menu overlay header, full-width segmented control, same behaviour.
|
||||
- Never a dropdown (two options), never flags, never auto-switching.
|
||||
|
||||
## Theme toggle
|
||||
- Icon-only button, morphing sun⇄moon; tooltip on hover-delay 600ms (`Switch to light mode` / `Bytt til lyst modus` — target-state phrasing).
|
||||
- First visit follows system; once touched, choice persists and system changes no longer override (standard expectation).
|
||||
|
||||
## Nav links
|
||||
- Rest: ink-muted → hover: ink + 2px accent underline drawing left→right (160ms). Current-page: ink + static accent underline + `aria-current`.
|
||||
- Scroll-spy on homepage: section currently in view marks its nav item (underline at 60% opacity) — subtle, no jumping.
|
||||
|
||||
## Chips
|
||||
- Fact chips: non-interactive, no hover (cursor default — honesty about affordance).
|
||||
- Stack chips on project cards: hover shows a 600ms-delay tooltip with one context line ("React 18 — SPA frontend"); tap on mobile: no-op (tooltip content lives in case-study text instead).
|
||||
|
||||
## Project cards
|
||||
- Whole card = one link (single tab stop); internal "Read case study →" is decorative affordance, not a second link. Hover per A3. Focus-visible: ring around entire card.
|
||||
- Screenshot inside frames: `alt` text written per language, meaningful ("JobTrack applications table with status filters", not "screenshot").
|
||||
|
||||
## Timeline items
|
||||
- Featured item expanded by default. Compact one-liners: entire row hover → surface-1 tint; they are *not* expandable (content lives in CV/experience page — avoid hidden-content traps for scanners).
|
||||
|
||||
## Form (contact)
|
||||
- Fields: 2px border; focus → accent border + ring; label always visible above (no placeholder-as-label). Error on blur-validate: danger border + icon + message under field (`Please enter a valid e-mail` / `Skriv inn en gyldig e-postadresse`); error summary focus-moved on failed submit.
|
||||
- Submit per A9. Honey-pot antispam invisible to AT (no CAPTCHA — friction kills recruiter conversion).
|
||||
- Beside the form, equal visual weight: direct e-mail (click-to-copy with `copied ✓ / kopiert ✓` mono feedback) and LinkedIn — many recruiters won't touch forms.
|
||||
|
||||
## Screenshot lightbox
|
||||
- Click/Enter opens; Esc, backdrop-click, or × closes; arrows navigate gallery; focus trapped; caption + `n/N` mono counter. Mobile: pinch-zoom enabled, swipe between captures.
|
||||
|
||||
## "On this page" mini-TOC (case studies, ≥1200px)
|
||||
- Items = ghost links with scroll-spy accent tick; click = smooth scroll (instant under reduced motion) with header-offset anchor.
|
||||
|
||||
## Copy affordances
|
||||
- E-mail and `git.cesnimda.uk` in footer/contact: click-to-copy with mono `copied ✓` swap (1.5s). Phone number: plain `tel:` link, no copy gimmick.
|
||||
@@ -0,0 +1,45 @@
|
||||
# SCROLL_EXPERIENCE.md
|
||||
|
||||
## 1. Governing rule
|
||||
|
||||
**The scrollbar is a contract.** Native scroll physics everywhere: no hijacking, no pinned scenes, no snap-scrolling on prose, no horizontal sections. Recruiters skim with momentum-flicks; anything that interferes reads as hostile.
|
||||
|
||||
## 2. Homepage scroll narrative (desktop)
|
||||
|
||||
| Scroll position | What happens | Why |
|
||||
|---|---|---|
|
||||
| 0 (load) | Hero static except trace draw (A1) | Decision facts readable instantly |
|
||||
| 0–120px | Header compresses 72→56px, gains blur backdrop + hairline bottom border (linear-mapped to scroll, not toggled — no pop) | Reclaims space, signals "we're moving" |
|
||||
| Each section at 20% entry | A2 section arrive, once | Reading rhythm |
|
||||
| Proof strip enter | Chip dots light in stagger (accent pulse A4) | Draws eye across the four facts |
|
||||
| Projects enter | Cards rise in 2-stagger; screenshots have 4px max parallax offset relative to card scroll | Depth without gimmick |
|
||||
| Experience enter | Timeline draw (A8) | Guides top-down reading |
|
||||
| Contact band enter | No animation — band is high-contrast already | Calm before conversion action |
|
||||
| Any position | Header CV button + nav always available | ≤1 interaction to CV rule |
|
||||
|
||||
Scroll-spy updates nav underline per section. No "back to top" button on homepage (header is sticky; document is ~5 viewports); case studies (longer) get one after 3 viewports, ghost-style, bottom-right.
|
||||
|
||||
## 3. Case-study scroll
|
||||
|
||||
- Mini-TOC (≥1200px) tracks reading position with an accent tick; no progress bars (this is a document, not an article funnel — but see next point).
|
||||
- Long-form sections use generous `space-9` rhythm; architecture diagram gets full-width breakout (max 1200px) beyond the 72ch prose measure.
|
||||
- Images lazy-load 1 viewport ahead with aspect-locked skeletons — **zero cumulative layout shift** is a hard requirement.
|
||||
- Section anchors offset by header height + 24px; anchor links in TL;DR jump correctly.
|
||||
|
||||
## 4. Mobile scroll
|
||||
|
||||
- No parallax, no scroll-linked header compression (fixed 56px slim header from the start); section reveals still fire (opacity-dominant).
|
||||
- Sticky elements budget: header only. No sticky CTAs covering content (thumb-reach conversion handled by the contact band + header CV icon-button).
|
||||
- Overscroll behaviour default; PWA-style rubber-banding untouched.
|
||||
- Gallery swipe is the only horizontal gesture, clearly contained inside the lightbox.
|
||||
|
||||
## 5. Deep-link & restoration behaviour
|
||||
|
||||
- Anchor navigation (nav click, TOC, TL;DR links): smooth scroll 400ms max — distance-capped so cross-page-length jumps don't take seconds; reduced motion → instant.
|
||||
- Back/forward restores scroll position (browser default — do not fight it).
|
||||
- Language switch preserves scroll ratio where section structure matches (A7); if the target page differs structurally, land at top of the equivalent section rather than a mismatched pixel offset.
|
||||
|
||||
## 6. Performance constraints on scroll effects
|
||||
|
||||
- All scroll-linked effects (header compression, spy, reveals) via passive observers/transforms — no scroll-handler layout reads (jank = instant credibility loss with P2).
|
||||
- Reveal thresholds via IntersectionObserver semantics (conceptually); everything degrades to "visible" when JS is absent — **content is never gated behind scroll animation.**
|
||||
Reference in New Issue
Block a user