Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ This is the living history of Chimera's evolution. Each entry represents a day o

---

### Day 64: 2026-05-03
**Feature/Change**: Frontend Polish — Back-to-Top Button & Animated Progress Bars
**Description**: Two focused, high-impact visual improvements. **(1) Back-to-top floating button**: A polished fixed-position button appears with a spring animation (`ease-bounce`) after the user scrolls more than 400 px, making navigation effortless on the long single-page app. The button uses the brand gradient (`--color-accent → --color-accent-secondary`), has a soft accent glow (`--shadow-accent`) and a satisfying hover-lift/scale effect. Clicking it smoothly scrolls back to the top. The button is fully accessible (ARIA label, focus-visible ring) and is suppressed for users who prefer reduced motion. It adapts cleanly to both dark and light themes and scales down on mobile. **(2) Animated category progress bars**: The "Evolution Categories" breakdown bars previously snapped to their final width immediately because the inline `style.width` was set before the browser had painted, making the CSS `transition: width 1s` a no-op. The dashboard now sets each bar's target width as a `--bar-target-width` CSS custom property and starts the bar at `0%`, then triggers the fill via a CSS `@keyframes bar-fill` animation on the next paint using `requestAnimationFrame`. The result is a smooth, sequenced bar-fill on every page load — giving the statistics section a living, premium feel. The animation is suppressed for `prefers-reduced-motion`. All 2,653 tests continue to pass and the TypeScript/Vite build succeeds.
**Files Modified**: src/style.css, src/main.ts, src/dashboard.ts, README.md, public/README.md

---

### Day 63: 2026-04-19

**Feature/Change**: Frontend Polish - Hero Surface, Heading Rhythm & Timeline Card Refinement
Expand Down
7 changes: 7 additions & 0 deletions public/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ This is the living history of Chimera's evolution. Each entry represents a day o

---

### Day 64: 2026-05-03
**Feature/Change**: Frontend Polish — Back-to-Top Button & Animated Progress Bars
**Description**: Two focused, high-impact visual improvements. **(1) Back-to-top floating button**: A polished fixed-position button appears with a spring animation (`ease-bounce`) after the user scrolls more than 400 px, making navigation effortless on the long single-page app. The button uses the brand gradient (`--color-accent → --color-accent-secondary`), has a soft accent glow (`--shadow-accent`) and a satisfying hover-lift/scale effect. Clicking it smoothly scrolls back to the top. The button is fully accessible (ARIA label, focus-visible ring) and is suppressed for users who prefer reduced motion. It adapts cleanly to both dark and light themes and scales down on mobile. **(2) Animated category progress bars**: The "Evolution Categories" breakdown bars previously snapped to their final width immediately because the inline `style.width` was set before the browser had painted, making the CSS `transition: width 1s` a no-op. The dashboard now sets each bar's target width as a `--bar-target-width` CSS custom property and starts the bar at `0%`, then triggers the fill via a CSS `@keyframes bar-fill` animation on the next paint using `requestAnimationFrame`. The result is a smooth, sequenced bar-fill on every page load — giving the statistics section a living, premium feel. The animation is suppressed for `prefers-reduced-motion`. All 2,653 tests continue to pass and the TypeScript/Vite build succeeds.
**Files Modified**: src/style.css, src/main.ts, src/dashboard.ts, README.md, public/README.md

---

### Day 63: 2026-04-19

**Feature/Change**: Frontend Polish - Hero Surface, Heading Rhythm & Timeline Card Refinement
Expand Down
9 changes: 8 additions & 1 deletion src/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,14 @@ function createCategoryItem(name: string, count: number, maxCount: number): HTML
bar.className = 'category-bar';
// Safety check to prevent division by zero
const percentage = maxCount > 0 ? (count / maxCount) * 100 : 0;
bar.style.width = `${percentage}%`;
// Store the target width as a CSS custom property for the CSS animation,
// and start the bar at 0 width so it can animate in.
bar.style.setProperty('--bar-target-width', `${percentage}%`);
bar.style.width = '0%';
// Trigger the fill animation on the next paint so the CSS transition fires
requestAnimationFrame(() => {
bar.classList.add('animate');
});

barContainer.appendChild(bar);

Expand Down
26 changes: 26 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,32 @@ document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
const themeToggle = createThemeToggle()
document.body.appendChild(themeToggle)

// Add back-to-top button
const backToTopBtn = document.createElement('button')
backToTopBtn.className = 'back-to-top'
backToTopBtn.setAttribute('aria-label', 'Back to top')
backToTopBtn.innerHTML = '&#8679;'
document.body.appendChild(backToTopBtn)

let scrollTicking = false
window.addEventListener('scroll', () => {
if (!scrollTicking) {
requestAnimationFrame(() => {
if (window.scrollY > 400) {
backToTopBtn.classList.add('is-visible')
} else {
backToTopBtn.classList.remove('is-visible')
}
scrollTicking = false
})
scrollTicking = true
}
}, { passive: true })

backToTopBtn.addEventListener('click', () => {
window.scrollTo({ top: 0, behavior: 'smooth' })
})

// Add tutorial launcher button to the page
const tutorialLauncher = createTutorialLauncher()
document.body.appendChild(tutorialLauncher)
Expand Down
117 changes: 117 additions & 0 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -14445,3 +14445,120 @@ textarea:focus::placeholder {
transform: translateY(-2px);
}
}

/* ================================
Day 64: Frontend Polish — Back-to-Top Button & Animated Progress Bars
================================ */

/* ── 1. Back-to-top floating button ── */

/*
* --back-to-top-clearance: vertical gap above the theme-toggle button (56px
* button + 8px gap = 64px; align to spacing grid → 72px desktop, 68px mobile).
*/
:root {
--back-to-top-clearance: 72px;
}

@media (max-width: 600px) {
:root {
--back-to-top-clearance: 68px;
}
}

.back-to-top {
position: fixed;
bottom: calc(var(--space-lg) + var(--back-to-top-clearance));
right: var(--space-lg);
width: 48px;
height: 48px;
border-radius: 50%;
background: linear-gradient(135deg, var(--color-accent) 0%, var(--color-accent-secondary) 100%);
border: 2px solid rgba(255, 255, 255, 0.15);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 1.3rem;
font-weight: 700;
line-height: 1;
box-shadow: var(--shadow-accent);
z-index: 999;

/* Hidden by default */
opacity: 0;
transform: translateY(16px) scale(0.85);
pointer-events: none;
transition:
opacity 0.3s var(--ease-out),
transform 0.3s var(--ease-bounce),
box-shadow 0.2s var(--ease-out);
}

.back-to-top.is-visible {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: auto;
}

.back-to-top:hover {
transform: translateY(-4px) scale(1.1);
box-shadow: var(--shadow-accent-hover);
}

.back-to-top:active {
transform: translateY(-1px) scale(0.96);
transition-duration: 80ms;
}

.back-to-top:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 4px;
}

[data-theme="light"] .back-to-top {
border-color: rgba(124, 58, 237, 0.2);
color: #fff;
}

@media (max-width: 600px) {
.back-to-top {
bottom: calc(var(--space-md) + var(--back-to-top-clearance));
right: var(--space-md);
width: 44px;
height: 44px;
font-size: 1.15rem;
}
}

@media (prefers-reduced-motion: reduce) {
.back-to-top {
transition: opacity 0.15s ease;
transform: none !important;
}
.back-to-top.is-visible {
transform: none;
}
}

/* ── 2. Category bar entrance animation ── */
/*
Bars start at width 0 and expand to their data-target-width value
via a CSS animation triggered by the .animate class added in JS.
*/
@keyframes bar-fill {
from { width: 0; }
to { width: var(--bar-target-width, 100%); }
}

.category-bar.animate {
animation: bar-fill 1s var(--ease-out) forwards;
}

@media (prefers-reduced-motion: reduce) {
.category-bar.animate {
animation: none;
width: var(--bar-target-width, 100%);
}
}