1264 words7 min read

Redesigning My Site Theme in One Evening with Kiro IDE, Astro 7, and AWS Amplify

A build-in-public walkthrough of a full theme redesign — from colour exploration to production deployment — including the deployment issues I hit and how they were solved.

The following is a build-in-public walkthrough of a full theme redesign. From colour exploration to production deployment, including the deployment issues I hit and how they were solved.

The Setup

My site (mikefromnz.com) runs on Astro, deployed to AWS Amplify, styled with Tailwind CSS.

It had a dark theme — the typical near-black background (#0a0a0a), cyan accent (#22d3ee), Inter font at 16px. Functional, but generic.

Every dark-mode dev blog looks like this. (mine still has a way to go)

I wanted something warmer and more distinctive. I use Kiro IDE as my development environment, so the whole process happened as a conversation — describe what I want, iterate on options, apply changes, deploy.

The Design Process — BEFORE

Finding Colours

I went looking for colour palettes and landed on the work of Sanzo Wada, who founded the Japan Standard Color Association in 1927. His six-volume Haishoku Soukan documents over a thousand colour combinations. I browsed them at colors.elwyn.co and pulled out two palettes to explore:

Palette 1: Pomegranate Purple, Cobalt Green, Green Blue, Deep Slate Green

Palette 2: Spectrum Red, Ivory Buff, Rainette Green, Aconite Violet

Generating Mockups

Rather than guessing how colours would look applied to my actual layout, Kiro generated standalone HTML mockups — no dependencies, just open in a browser. Each mockup showed three side-by-side previews of my real site layout (nav, hero, blog cards, footer) with different colour mappings.

I explored three “patterns” for how to assign the colours:

  • Option A/B: Single bold accent colour
  • Option C: Calm primary accent with a contrasting “pop” colour on hover/active states

Option C won — the dual-accent approach gives the site personality without overwhelming the reader.

Picking a Font

I like Century Gothic for its clean geometric forms, but it’s a proprietary Monotype font — can’t load it from Google Fonts. Kiro suggested alternatives and mocked up three:

  • Outfit — modern, slightly condensed
  • Nunito — soft rounded terminals, warm (closest to Century Gothic)
  • Poppins — geometric, crisp, widely used

Nunito won. Then I compared 18px vs 20px base size — 20px gave an editorial feel that suits long-form technical content.

The Final Theme

Role Value
Background #1c2219 (dark mossy green)
Surface #272e23
Text #ebd3a2 (Ivory Buff)
Muted text #8fa071 (Rainette Green)
Accent #ebd3a2 (Ivory Buff)
Hover pop #a36aa5 (Aconite Violet)
Font Nunito, 20px base
Dot-field Faint Spectrum Red at 12% opacity

The actual code change? Two files:

  • tailwind.config.mjs — colour tokens and font family
  • src/layouts/BaseLayout.astro — Google Fonts link, base font-size, dot colour

The Deployment Issues

This is where the “build in public” part gets bumpy, but not impossible to fix. Three problems were hit on the way to production:

Problem 1: Astro 7 + astro-aws-amplify Peer Dependency Conflict

I upgraded from Astro 6 to 7.2.2 at the same time as the theme change. The astro-aws-amplify adapter (v0.4.1) declares peer astro@"^6.0.0", so npm ci in the Amplify build pipeline refused to install.

Fix: Added a .npmrc file to the repo:

legacy-peer-deps=true

The adapter works fine at runtime with Astro 7 — it’s just the peer dep declaration that’s outdated. My solution unblocked the install until the adapter publishes a v7-compatible release.

Problem 2: Build Output Exceeded Amplify’s 220MB Limit

The Amplify build completed successfully, but deployment failed:

CustomerError: The size of the build output (243093783) exceeds
the max allowed size of 230686720 bytes.

DOH!

Astro 7’s dependency tree is heavier than v6. The build moves node_modules into .amplify-hosting/compute/default/ for the SSR runtime, and it was 243MB — 23MB over the limit. DOUBLE DOH!

Fix: Added cleanup commands to amplify.yml after npm prune --production:

- find node_modules \( -name '*.ts' ! -name '*.d.ts' -o -name '*.map' -o -name 'CHANGELOG*' -o -name '*.test.*' -o -name '*.spec.*' \) -delete 2>/dev/null || true
- find node_modules -type d \( -name '__tests__' -o -name 'test' -o -name 'tests' -o -name 'docs' \) -exec rm -rf {} + 2>/dev/null || true
- find node_modules -name '*.md' ! -name 'LICENSE*' -delete 2>/dev/null || true

This strips TypeScript source files, source maps, changelogs, test directories, and documentation from production node_modules. Shaved enough to get under the limit.

Lesson: If you’re on Amplify with SSR (server output mode), watch your node_modules size after major framework upgrades. The 220MB limit is for the entire compute artifact including your bundled app AND node_modules.

Problem 3: New Routes 404ing Despite Successful Build

The /learn page (and all nested course pages) returned 404 on staging, even though:

  • The build log showed them prerendering successfully.
  • The static HTML existed at index.html.
  • Directly accessing index.html worked fine.

Root cause: Amplify’s deploy manifest routes extensionless paths (/learn) to the Compute (SSR) handler.

For prerendered pages to be served at clean URLs, they need app-level custom rewrite rules that map /learnindex.html.

These rules are pushed via the Amplify API in the postBuild step. But:

  1. The existing generate-amplify-rules.mjs script only handled single-depth routes (/about, /cv) and single-level wildcards (/blog/<slug>).
  2. The multi-level /learn/aws-aif-c01/aif-exam-overview/exam-format paths were never covered.
  3. The rule-push was restricted to the main branch, so staging deploys never updated the rules.

Fix: Rewrote the script to emit an explicit rewrite for every prerendered index.html regardless of nesting depth, and allowed staging to push rules too:

function toRules(paths) {
  const rules = [{ source: '/', target: '/index.html', status: '200' }];
  for (const p of paths) {
    rules.push({ source: `/${p}`, target: `/${p}/index.html`, status: '200' });
    rules.push({ source: `/${p}/`, target: `/${p}/index.html`, status: '200' });
  }
  return rules;
}

Lesson: If you’re using Astro in hybrid mode (some pages prerendered, some SSR) on Amplify, you need rewrite rules for every prerendered clean URL. The astro-aws-amplify adapter’s deploy manifest sends all extensionless paths to compute by default. Without explicit rewrites, prerendered pages at nested paths will 404.

What Worked Well

Kiro IDE kept the full conversation context — and alongside my Obsidian vault, it read my existing Tailwind config, understood the component structure, generated mockups using my actual layout, and applied changes to the right files without touching unrelated code.

Astro prerendered 80+ pages in under a second. The hybrid mode (SSR for admin, static for everything else) is exactly right for a content site with a lightweight CMS.

AWS Amplify gave me staging and production branches with automatic deploys from git push. The staging preview URL meant I could check the theme visually before going live.

The combination meant the feedback loop was measured in minutes: change colours → build → see it on staging → adjust → push to prod.

The ADR

I documented the decision formally as ADR-001 in the repo — captures the context, options considered, final decision, and consequences.

ALWAYS worth doing even for personal projects when you know you’ll forget why you picked that specific shade of green in six months.

Final Thoughts

The whole redesign — from “I want new colours” to live on production — took one evening session and half an hour the next morning to fix deployment issues.

The colour exploration alone (two palettes, six options, three fonts, two sizes) would have taken me days of indecision without the instant visual comparison that the mockup approach gave me.

Sometimes the best part of building in public is showing the problems, not just the polished result.


Colours by Sanzo Wada (via colors.elwyn.co).