# Tag Cloud: Archimedean Spiral Layout ## Context The existing tag cloud partial uses centered flex-wrap with continuous font scaling (weight → size/opacity). Tags appear as a flat weighted list. The goal is a visually striking cloud: big tags centered, smaller tags scattered organically around the outside — deterministic per tag, not random per load. ## Approach: Archimedean Spiral + CSS Fallback Two layers: - **Hugo partial** (existing) renders tags in DOM with added `data-weight` attribute - **Vanilla JS module** reads weights, sorts tags, places them via Archimedean spiral CSS fallback (no JS / narrow viewport): existing centered flex layout unchanged. ## Components ### 1. `tag-cloud.html` partial (modify) - Add `data-weight="{{ $ratio }}"` to each `.tag-cloud-link` element - Add `data-tag-cloud` attribute to the `.tag-cloud` container div - No other changes to markup or existing CSS classes ### 2. `assets/js/tag-cloud-spiral.js` (new, ~60 lines) **Algorithm:** 1. Find all `[data-tag-cloud]` containers on page 2. For each container: collect tags, sort descending by `data-weight` 3. Per tag: derive deterministic angle seed from tag text hash 4. Place along Archimedean spiral `r = a * θ` stepping `θ` until AABB collision-free 5. Set container `position: relative`, tags `position: absolute` with computed `left/top` 6. Set container explicit height = bounding box of all placed tags + 2rem padding 7. Remove flex layout class from container after placement **Determinism:** simple string hash (sum of charCodes) → starting `θ` offset. Same tag text always seeds same angle. **Collision detection:** AABB check against array of already-placed rects. O(n²) — fine for ≤50 tags. **Responsive guard:** if container `offsetWidth < 400px`, skip spiral entirely, leave flex layout intact. ### 3. Script loading Inline ` ``` Or inline if small enough. Loaded only when partial is rendered. ## A11y Compliance (WCAG 2.1 AA) - **DOM order** = weight order (biggest first) — logical reading sequence - **Tab order** = DOM order — keyboard navigation follows prominence, acceptable - **No animation** — `prefers-reduced-motion` not affected - **Container:** `overflow: visible` to prevent clipping at zoom levels - **Existing** `aria-label` on links preserved unchanged ## CSS Changes - Container: add `overflow: visible` and `min-height` guard (set by JS, not CSS) - No color/spacing changes — theming via CSS variables unaffected ## Fallback Behavior | Condition | Behavior | |-----------|----------| | JS disabled | Centered flex wrap (current layout) | | Container < 400px | Centered flex wrap (JS skips spiral) | | JS enabled, container ≥ 400px | Archimedean spiral | ## Verification 1. `npm run build` — CSS compiles clean 2. `hugo serve` — tag cloud renders on homepage, sidebar, 404 3. JS enabled wide viewport: spiral layout, big tags centered 4. JS enabled narrow viewport (< 400px): flex fallback 5. JS disabled (devtools): flex fallback 6. Keyboard Tab through tags: logical order, all focusable 7. Dark/light mode toggle: colors correct (CSS vars) 8. Screen reader (or axe DevTools): no new violations