chore(agent): track .agent/ planning tree in git
Remove the blanket .agent/ gitignore so the phase roadmap, user stories, reports, and PLAN.md are versioned with the code. Only runtime artifacts (.agent/phase-sessions/, .agent/pipeline.log) remain ignored. Update AGENTS.md git protocol rule to match.
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
# Phase 25 — Background: No Motion, Only Fading Light
|
||||
|
||||
**Source:** Owner report (2026-08-25, chat): the background "jitters down
|
||||
and to the right every second and it slowly blinks brighter and darker. It
|
||||
should be smooth, fluxuating, dimming and brightening, but not moving.
|
||||
Different bright spots should slowly fade in and out."
|
||||
**Story:** `.agent/user_stories/background-no-motion.md` (created by task 02)
|
||||
**Context:** `frontend/assets/styles.css` — the background block:
|
||||
`body::before` (44px grid, 1px lines at 60% `--line` alpha, widened radial
|
||||
mask, `animation: bg-grid-drift 60s linear infinite` → `0 0` →
|
||||
`44px 44px` ≈ 0.73px/s down-right) and `body::after` (indigo + cyan radial
|
||||
glows, `animation: bg-glow-breathe 14s ease-in-out infinite alternate` →
|
||||
opacity 0.85↔1 + scale 1↔1.05). Both are
|
||||
`position: fixed; inset: 0; z-index: -1; pointer-events: none`; `<html>`
|
||||
owns the `var(--bg)` canvas, `<body>` stays transparent (no-occlusion
|
||||
contract). Pins to adapt: `tests/unit/test_background_animation.py`,
|
||||
`tests/e2e/test_background_animation.py`,
|
||||
`tests/e2e/test_dark_tech_theme.py` (`test_animated_background` pins
|
||||
60s/14s; `test_reduced_motion_honored` pins the two body pseudo-layers).
|
||||
|
||||
## Objective
|
||||
Stop the background from moving entirely, and replace the uniform
|
||||
whole-layer "blink" with **different bright spots that slowly fade in and
|
||||
out**: the grid becomes a static texture, and three soft glow spots
|
||||
(phase-08 colors/positions, plus a third spot) each run their own
|
||||
slow, **opacity-only** fade cycle at a different period, so the
|
||||
background's brightness fluxuates smoothly and irregularly — no blink, no
|
||||
jitter, no motion.
|
||||
|
||||
## Root cause (found from the code, 2026-08-25)
|
||||
1. **"Jitters down and to the right every second"** = `bg-grid-drift`:
|
||||
44px/60s (≈0.73px/s) in the diagonal `44px 44px` direction (exactly
|
||||
down-right). A 1px grid line translated sub-pixel-by-sub-pixel is
|
||||
rasterized with per-frame stepping/shimmer — perceived as a once-per-
|
||||
second jitter, not smooth drift. Phase 22 made the drift *visible*;
|
||||
that is precisely why it now reads as jitter.
|
||||
2. **"Slowly blinks brighter and darker"** = `bg-glow-breathe`: a uniform
|
||||
whole-layer opacity swing 0.85↔1 over 14s (alternate) plus
|
||||
`scale(1)↔scale(1.05)` — the entire background pulses in unison (the
|
||||
scale adds a faint zoom). One synchronized pulse reads as a blink; the
|
||||
owner wants independent spots instead.
|
||||
|
||||
Phase 22 served the phase-08 design intent (grid drift + whole-layer
|
||||
breathe). The owner now supersedes that design intent — this is an
|
||||
owner revision of a **design comment**, not of any LOCKED anchor: A1–A17
|
||||
are untouched, and the phase-08 anchors this phase must still honor are
|
||||
pure CSS / zero JS / no CDN / no new assets / no `filter: blur` (A11 +
|
||||
the block's perf note).
|
||||
|
||||
## Owner direction (2026-08-25, verbatim)
|
||||
> "It should be smooth, fluxuating, dimming and brightening, but not
|
||||
> moving. Different bright spots should slowly fade in and out."
|
||||
|
||||
1. **No movement** — no grid drift, no `scale`/`transform`, no
|
||||
`background-position` animation, anywhere in the background.
|
||||
2. **Fluxuating brightness** — overall page brightness varies smoothly and
|
||||
irregularly (not one synchronized pulse).
|
||||
3. **Different bright spots** — multiple glow spots, each fading in and
|
||||
out on its own slow cycle.
|
||||
4. **The static grid stays** — the owner rejected the grid's *motion*, not
|
||||
the grid; it remains as a still texture. (If the owner later wants the
|
||||
grid gone, that is a follow-up, not this phase.)
|
||||
|
||||
## Design (pure CSS, zero JS — A11 anchor)
|
||||
- `body::before` — grid: **remove** the `animation`; **delete**
|
||||
`@keyframes bg-grid-drift`. Keep the 44px cells, 60% `--line` alpha
|
||||
lines, and widened radial mask (the static texture).
|
||||
- Three glow-spot layers, one soft radial gradient each, **opacity-only**
|
||||
keyframes (`0%,100%` low → `50%` 1, `ease-in-out`, `infinite`), with
|
||||
different durations + negative delays so the cycles are out of phase
|
||||
(periods 26/34/42s → LCM 4641s, the composite pattern effectively never
|
||||
repeats within a viewing session):
|
||||
|
||||
| layer | spot (gradient) | keyframes | cycle |
|
||||
|---|---|---|---|
|
||||
| `body::after` | indigo `rgb(109 120 242 / 0.14)`, circle 56rem at 12% 8% (phase-08) | `bg-glow-a` | 26s, low opacity 0.25 |
|
||||
| `html::before` | cyan `rgb(34 211 238 / 0.10)`, circle 60rem at 88% 92% (phase-08) | `bg-glow-b` | 34s, delay −12s, low 0.20 |
|
||||
| `html::after` | indigo `rgb(109 120 242 / 0.09)`, circle 52rem at 14% 86% | `bg-glow-c` | 42s, delay −23s, low 0.15 |
|
||||
|
||||
- `html::before` / `html::after` join `body::after` as background layers:
|
||||
`<html>` is the root stacking context — its `z-index: -1`
|
||||
pseudo-elements paint **above** the `var(--bg)` canvas and **below**
|
||||
the transparent, non-stacking `<body>`'s content, so the no-occlusion
|
||||
contract holds unchanged (verify in the E2E, not just assume).
|
||||
- All four layers keep: `content: ""; position: fixed; inset: 0;
|
||||
z-index: -1; pointer-events: none;`
|
||||
- `prefers-reduced-motion: reduce` stills **all four** layers
|
||||
(`animation: none`).
|
||||
- No `filter` (phase-08 no-blur perf anchor), no JS, no new assets; the
|
||||
WCAG palette and every text contrast pair are untouched (the layers
|
||||
carry no text). Opacity-only keyframes stay compositor-friendly.
|
||||
|
||||
## Dependencies
|
||||
- `08_story_dark_tech_theme` (complete) — the layers, the palette, the
|
||||
pure-CSS / no-blur / no-CDN anchors, and the 60s/14s pins in
|
||||
`tests/e2e/test_dark_tech_theme.py` this phase adapts.
|
||||
- `22_background_animation` (complete) — the current implementation and
|
||||
the unit/E2E pins this phase supersedes.
|
||||
- `07_story_responsive_polish` (complete) — the 360px overflow pin (the
|
||||
layers are `fixed; inset: 0` — they must add no width).
|
||||
|
||||
## Tasks
|
||||
1. `01_still_background_css.md` — the CSS redesign (static grid + three
|
||||
opacity-only glow fades) + unit source pins (new
|
||||
`tests/unit/test_background_no_motion.py`; the phase-22 pins in
|
||||
`tests/unit/test_background_animation.py` adapted).
|
||||
2. `02_e2e_story_suite_commit.md` — `tests/e2e/test_background_no_motion.py`
|
||||
(the story gate, isolated), the regression suites adapted
|
||||
(`test_background_animation.py`, `test_dark_tech_theme.py`), the story
|
||||
file, the phase report + screenshots, final validation, the single
|
||||
atomic commit, phase move to `complete/`.
|
||||
|
||||
## Locked decisions
|
||||
- **A11 untouched** — vanilla HTML/CSS/JS in git, no CDN, zero JS, system
|
||||
fonts; the whole change is CSS. **No `filter`/`blur`** (phase-08 perf
|
||||
anchor). No new assets. **No anchor changed** — the superseded spec is
|
||||
the phase-08 *design intent* (grid drift + whole-layer breathe), not a
|
||||
LOCKED decision; the owner's 2026-08-25 direction is recorded above as
|
||||
the revision. **A16 honored** — one new story E2E suite + adapted
|
||||
regressions. **A17 honored** — one atomic `--no-gpg-sign` commit.
|
||||
|
||||
## Testing & Quality
|
||||
- **Unit (source-level, repo source-pin pattern):**
|
||||
- New `tests/unit/test_background_no_motion.py` — pins the full new
|
||||
contract (task 01, step 6).
|
||||
- Adapted `tests/unit/test_background_animation.py` — the phase-22
|
||||
drift/breathe pins flip to the new contract; the generic
|
||||
layer-plumbing and no-blur/no-JS sections stay (task 01, step 7).
|
||||
- **Integration:** none (no `app/` changes).
|
||||
- **Coverage:** frontend-only; the >90% `app/` gate is unaffected (TOTAL
|
||||
must stay ≥ the pre-change number).
|
||||
- **E2E:** `tests/e2e/test_background_no_motion.py` (task 02), green
|
||||
**in isolation** (prereq `podman compose up -d db`); regressions green
|
||||
in isolation after adaptation: `test_background_animation.py`,
|
||||
`test_dark_tech_theme.py`, `test_responsive_polish.py`.
|
||||
- **Lint/types:** `uv run ruff check . && uv run pyright` clean.
|
||||
|
||||
## Completion Criteria
|
||||
- [ ] No movement: the grid is static (`bg-grid-drift` gone, no
|
||||
`animation` on `body::before`) and **no `bg-*` keyframe animates
|
||||
anything but `opacity`** — audited in a real Chromium via
|
||||
`document.styleSheets` (E2E test 3).
|
||||
- [ ] Three distinct bright spots (`body::after`, `html::before`,
|
||||
`html::after`) run distinct slow opacity fades (26s/34s/42s,
|
||||
out of phase); the timelines advance; the layer opacity and a
|
||||
clipped screenshot of the glow region measurably change within a
|
||||
few seconds (E2E tests 2, 4, 5).
|
||||
- [ ] Contracts hold: all four layers `fixed; inset: 0; z-index: -1;
|
||||
pointer-events: none`; `<html>` keeps the `var(--bg)` canvas and
|
||||
`<body>` stays transparent (no occlusion); `prefers-reduced-motion`
|
||||
stills all four; no horizontal overflow at 360px (E2E tests 6–8).
|
||||
- [ ] `.agent/reports/25_background_no_motion/` documents the two root
|
||||
causes with before/after screenshot pairs
|
||||
(`.agent/screenshots/25_background_no_motion/`).
|
||||
- [ ] `uv run pytest` green; `uv run pytest --cov=app
|
||||
--cov-report=term-missing` TOTAL ≥ pre-change number (gate >90%).
|
||||
- [ ] `uv run pytest tests/e2e/test_background_no_motion.py -v --no-cov`
|
||||
green in isolation; `test_background_animation.py`,
|
||||
`test_dark_tech_theme.py`, `test_responsive_polish.py` green in
|
||||
isolation after adaptation.
|
||||
- [ ] `uv run ruff check . && uv run pyright` clean.
|
||||
- [ ] UI Structure Check (AGENTS.md rule 5): layers stay behind content,
|
||||
no text/contrast impact, no 360px overflow.
|
||||
- [ ] `.agent/user_stories/background-no-motion.md` exists; the old
|
||||
`background-animation.md` story carries a supersession note.
|
||||
- [ ] One `--no-gpg-sign` commit staging **only this phase's files** (the
|
||||
unrelated dirty `TODO.md` must NOT be staged);
|
||||
`.agent/phases/todo/25_background_no_motion/` moved to
|
||||
`.agent/phases/complete/`.
|
||||
|
||||
## Commit
|
||||
```bash
|
||||
git add -f .agent/phases/complete/25_background_no_motion \
|
||||
.agent/user_stories/background-no-motion.md \
|
||||
.agent/user_stories/background-animation.md \
|
||||
.agent/reports/25_background_no_motion \
|
||||
.agent/screenshots/25_background_no_motion
|
||||
git add frontend/assets/styles.css tests/unit tests/e2e
|
||||
git commit --no-gpg-sign -m "fix(ui): background no longer moves — static grid, three glow spots fading in and out on their own slow cycles (owner 2026-08-25)"
|
||||
```
|
||||
Reference in New Issue
Block a user