# Animal Crossing Theme Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Add an "animal-crossing" design theme (warm cream light / deep forest dark) to the hyyzhome IoT portal. **Architecture:** Four small, independent file edits. No new files created. The theme slug is registered in `theme.js`, a dropdown option added in `index.html`, CSS variables + component overrides added in `style.css`, and display labels added in `i18n.js`. Changes are order-independent but committing theme.js + index.html first lets you visually verify the option appears before styling is complete. **Tech Stack:** Vanilla JS, Vite, CSS custom properties. No framework. No test suite — verification is manual in the dev server (`npm start`). --- ## Files Modified | File | Change | |---|---| | `theme.js:1` | Add `"animal-crossing"` to `DESIGN_THEMES` array | | `index.html:45` | Add `
  • ` after the Nord option | | `i18n.js:136–213` | Add `"animal-crossing"` key to every language in `DESIGN_THEME_LABELS` | | `style.css` | Append light + dark variable blocks and component overrides at end of file | --- ## Task 1: Register the theme slug **Files:** - Modify: `theme.js:1` - Modify: `index.html:45` - [ ] **Step 1: Add slug to DESIGN_THEMES** In `theme.js`, change line 1 from: ```js const DESIGN_THEMES = ["fluent", "material-you", "terminal", "cyberpunk", "nord"] ``` to: ```js const DESIGN_THEMES = ["fluent", "material-you", "terminal", "cyberpunk", "nord", "animal-crossing"] ``` - [ ] **Step 2: Add dropdown option in index.html** In `index.html`, after the Nord `
  • ` (currently line 45): ```html
  • Nord
  • ``` add immediately after: ```html
  • 动森
  • ``` - [ ] **Step 3: Start dev server and verify option appears** ```bash npm start ``` Open the app in a browser. Click the design theme dropdown — "动森" should appear as a new option. Selecting it will show unstyled (inherits Fluent variables) — that's expected at this stage. - [ ] **Step 4: Commit** ```bash git add theme.js index.html git commit -m "feat: register animal-crossing theme slug" ``` --- ## Task 2: Add i18n labels **Files:** - Modify: `i18n.js:136–213` - [ ] **Step 1: Add label to every language in DESIGN_THEME_LABELS** In `i18n.js`, add `"animal-crossing"` to each language object inside `DESIGN_THEME_LABELS`. The full updated constant (lines 136–214) should be: ```js export const DESIGN_THEME_LABELS = { "zh-Hans": { fluent: "Fluent", "material-you": "Material You", terminal: "终端", cyberpunk: "赛博朋克", nord: "Nord", "animal-crossing": "动森", }, "zh-Hant": { fluent: "Fluent", "material-you": "Material You", terminal: "終端", cyberpunk: "賽博龐克", nord: "Nord", "animal-crossing": "動森", }, en: { fluent: "Fluent", "material-you": "Material You", terminal: "Terminal", cyberpunk: "Cyberpunk", nord: "Nord", "animal-crossing": "Animal Crossing", }, ja: { fluent: "Fluent", "material-you": "Material You", terminal: "ターミナル", cyberpunk: "サイバーパンク", nord: "Nord", "animal-crossing": "どうぶつの森", }, ko: { fluent: "Fluent", "material-you": "Material You", terminal: "터미널", cyberpunk: "사이버펑크", nord: "Nord", "animal-crossing": "동물의 숲", }, wenyan: { fluent: "流光", "material-you": "物材", terminal: "终端", cyberpunk: "赛博", nord: "清寒", "animal-crossing": "森友", }, mars: { fluent: "流↗光", "material-you": "材↘質", terminal: "終↗★端", cyberpunk: "賽↘!博", nord: "清↗寒★", "animal-crossing": "动↗森★", }, garbled: { fluent: "◼è▦", "material-you": "拷▤屯ä锟◽", terminal: "¥¬▤▨¿¿", cyberpunk: "◼çæ¥烫¥", nord: "æ◽屯¿", "animal-crossing": "ä◼▤è", }, bin: { fluent: "0101", "material-you": "010101", terminal: "01010101", cyberpunk: "0101010101", nord: "0101010", "animal-crossing": "01010101", }, meow: { fluent: "喵喵", "material-you": "喵喵喵", terminal: "喵喵", cyberpunk: "喵喵喵喵", nord: "喵喵喵", "animal-crossing": "喵喵喵喵", }, emoji: { fluent: "💧", "material-you": "🧱", terminal: "⌨️", cyberpunk: "⚡", nord: "❄️", "animal-crossing": "🌿", }, } ``` - [ ] **Step 2: Verify labels in browser** With the dev server still running, switch language to English — the dropdown option should now read "Animal Crossing" instead of "动森". Switch to Japanese — should read "どうぶつの森". Switch to emoji — should read "🌿". - [ ] **Step 3: Commit** ```bash git add i18n.js git commit -m "feat: add animal-crossing labels for all 11 languages" ``` --- ## Task 3: Add CSS — light mode **Files:** - Modify: `style.css` (append after the Nord section, before the `@media (max-width: 600px)` block) - [ ] **Step 1: Append light-mode CSS block** At the end of the Nord section in `style.css` (before the `@media (max-width: 600px)` rule), append: ```css /* ─── Animal Crossing — Sunny Meadow ───────────────────────── */ html[data-design-theme="animal-crossing"] { color-scheme: light; --accent: #6dbc7e; --accent-rgb: 109, 188, 126; --accent-2: #5aad6d; --accent-3: #4a9e5d; --accent-secondary-rgb: 244, 200, 66; --page-gradient: linear-gradient( 135deg, #fdf6e3 0%, #f5f0d8 25%, #fdf6e3 50%, #f8f2e0 75%, #fdf6e3 100% ); --page-texture: radial-gradient( circle at 20% 50%, rgba(109, 188, 126, 0.08) 0%, transparent 50% ), radial-gradient( circle at 80% 80%, rgba(244, 200, 66, 0.06) 0%, transparent 50% ); --title-gradient: linear-gradient( 135deg, #6dbc7e 0%, #5aad6d 40%, #f4c842 100% ); --control-bg: rgba(255, 252, 240, 0.82); --control-border: rgba(109, 188, 126, 0.35); --control-inset: rgba(255, 255, 255, 0.85); --control-fg: #5c4824; } html[data-design-theme="animal-crossing"] body { color: #5c4824; } html[data-design-theme="animal-crossing"] .design-theme-button, html[data-design-theme="animal-crossing"] .theme-toggle { border-radius: 14px; } html[data-design-theme="animal-crossing"] .card { background: rgba(255, 252, 240, 0.85); border: 1px solid rgba(109, 188, 126, 0.25); border-radius: 16px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.03), inset 0 1px 0 rgba(255, 255, 255, 0.9); } html[data-design-theme="animal-crossing"] .card::before { display: none; } html[data-design-theme="animal-crossing"] .card.pin { background: rgba(245, 242, 228, 0.88); } html[data-design-theme="animal-crossing"] .card h2 { color: #5c4824; } html[data-design-theme="animal-crossing"] .card p { color: #7a6040; } html[data-design-theme="animal-crossing"] .card:hover, html[data-design-theme="animal-crossing"] .card:focus { color: var(--accent); transform: translateY(-2px); border-color: rgba(109, 188, 126, 0.45); box-shadow: 0 8px 24px rgba(109, 188, 126, 0.2), 0 4px 8px rgba(0, 0, 0, 0.08), inset 0 1px 0 rgba(255, 255, 255, 0.95); } html[data-design-theme="animal-crossing"] .card:hover h2, html[data-design-theme="animal-crossing"] .card:focus h2 { color: var(--accent); } html[data-design-theme="animal-crossing"] .card:hover p, html[data-design-theme="animal-crossing"] .card:focus p { color: #5c4824; } html[data-design-theme="animal-crossing"] .beian a { color: #7a6040; } html[data-design-theme="animal-crossing"] .beian a:hover { color: var(--accent); } ``` - [ ] **Step 2: Verify light mode in browser** Select "Animal Crossing" / "动森" in the dropdown with light mode active. Verify: - Background is warm cream (not white/dark) - Title has green-to-yellow gradient - Cards are creamy with rounded corners (16px) - Card hover shows green glow and lifts up - Control buttons have 14px border radius - [ ] **Step 3: Commit** ```bash git add style.css git commit -m "feat: add animal-crossing light mode CSS" ``` --- ## Task 4: Add CSS — dark mode **Files:** - Modify: `style.css` (append immediately after the light-mode block from Task 3) - [ ] **Step 1: Append dark-mode CSS block** Immediately after the light-mode block (still before `@media (max-width: 600px)`), append: ```css html[data-theme="dark"][data-design-theme="animal-crossing"] { color-scheme: dark; --accent: #9ed98a; --accent-rgb: 158, 217, 138; --accent-2: #86cb72; --accent-3: #6dbc5e; --accent-secondary-rgb: 245, 210, 90; --page-gradient: #1e2d1e; --page-texture: radial-gradient( circle at 20% 50%, rgba(158, 217, 138, 0.06) 0%, transparent 50% ), radial-gradient( circle at 80% 80%, rgba(245, 210, 90, 0.04) 0%, transparent 50% ); --title-gradient: linear-gradient( 135deg, #9ed98a 0%, #86cb72 40%, #f5d25a 100% ); --control-bg: rgba(25, 40, 25, 0.82); --control-border: rgba(158, 217, 138, 0.25); --control-inset: rgba(255, 255, 255, 0.04); --control-fg: #e8f4d8; } html[data-theme="dark"][data-design-theme="animal-crossing"] body { color: #e8f4d8; } html[data-theme="dark"][data-design-theme="animal-crossing"] .card { background: rgba(30, 48, 30, 0.82); border: 1px solid rgba(158, 217, 138, 0.18); border-radius: 16px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.04); } html[data-theme="dark"][data-design-theme="animal-crossing"] .card::before { display: none; } html[data-theme="dark"][data-design-theme="animal-crossing"] .card.pin { background: rgba(38, 58, 38, 0.88); } html[data-theme="dark"][data-design-theme="animal-crossing"] .card h2 { color: #e8f4d8; } html[data-theme="dark"][data-design-theme="animal-crossing"] .card p { color: #b0c8a0; } html[data-theme="dark"][data-design-theme="animal-crossing"] .card:hover, html[data-theme="dark"][data-design-theme="animal-crossing"] .card:focus { border-color: rgba(158, 217, 138, 0.45); box-shadow: 0 8px 24px rgba(158, 217, 138, 0.2), 0 4px 8px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.05); } html[data-theme="dark"][data-design-theme="animal-crossing"] .card:hover h2, html[data-theme="dark"][data-design-theme="animal-crossing"] .card:focus h2 { color: var(--accent); } html[data-theme="dark"][data-design-theme="animal-crossing"] .card:hover p, html[data-theme="dark"][data-design-theme="animal-crossing"] .card:focus p { color: #c8deb8; } html[data-theme="dark"][data-design-theme="animal-crossing"] .design-theme-list { background: rgba(22, 36, 22, 0.9); box-shadow: 0 12px 30px rgba(0, 0, 0, 0.55), 0 6px 12px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.04); } html[data-theme="dark"][data-design-theme="animal-crossing"] .beian a { color: #b0c8a0; } html[data-theme="dark"][data-design-theme="animal-crossing"] .beian a:hover { color: var(--accent); } @media (prefers-reduced-motion: reduce) { html[data-design-theme="animal-crossing"] .card, html[data-design-theme="animal-crossing"] .design-theme-button, html[data-design-theme="animal-crossing"] .theme-toggle { transition-duration: 0.01ms !important; transform: none !important; } } ``` - [ ] **Step 2: Verify dark mode in browser** Toggle to dark mode while "Animal Crossing" theme is active. Verify: - Background is deep forest green `#1e2d1e` (not generic dark grey) - Title has soft lime-to-yellow gradient - Cards are dark forest green with subtle lime border - Card hover shows lime glow - Toggling back to light mode restores the cream palette - [ ] **Step 3: Commit** ```bash git add style.css git commit -m "feat: add animal-crossing dark mode CSS" ``` --- ## Task 5: Final verification - [ ] **Step 1: Check theme persists across reload** Select "Animal Crossing" in dark mode. Reload the page. Theme and dark/light preference should both be restored from `localStorage`. - [ ] **Step 2: Check theme switching is clean** Cycle through all 6 themes (Fluent → Material You → Terminal → Cyberpunk → Nord → Animal Crossing → Fluent). No visual artifacts or broken styles should appear at any step. - [ ] **Step 3: Check forced-dark themes restore correctly** While on Animal Crossing (light mode), switch to Terminal (forces dark). Then switch back to Animal Crossing — it should restore the light mode you had before. - [ ] **Step 4: Run formatter** ```bash npm run fmt ``` Confirm no diff beyond whitespace normalisation. Commit if formatter changed anything: ```bash git add -p git commit -m "style: run prettier after animal-crossing theme" ```