Skip to content

fix: stale Astro cache deploys old CSS; TV intro overlay flash#55

Merged
jaypatrick merged 3 commits intomainfrom
copilot/fix-stale-build-cache-and-tv-intro-flash
May 7, 2026
Merged

fix: stale Astro cache deploys old CSS; TV intro overlay flash#55
jaypatrick merged 3 commits intomainfrom
copilot/fix-stale-build-cache-and-tv-intro-flash

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 7, 2026

Two independent production bugs: partial Astro cache hits could restore stale compiled CSS, and site chrome was visible for ~50ms before the TV intro black overlay hydrated.

Cache (.github/workflows/deploy.yml)

Drop restore-keys from the Astro cache step. A partial key match on astro-Linux-node24-* was restoring old .astro/ output, causing stale CSS to ship. Now only an exact hash match restores — anything else builds clean.

TV intro flash (BaseLayout.astro, global.css, TVIntro.svelte)

The ~50ms gap existed because Svelte hydration is async; the black overlay didn't exist in the DOM yet when the browser first painted.

Fix: run a synchronous inline script in <body> — before <TVIntro client:load /> — that stamps html.tv-intro-active during HTML parse if the intro should play:

(function() {
  try {
    var seen = sessionStorage.getItem('tv-intro-seen');
    var rm = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
    if (!seen && !rm) { document.documentElement.classList.add('tv-intro-active'); }
  } catch(e) {}
})();

Paired CSS holds the viewport black and scroll-locked until the overlay is ready:

html.tv-intro-active,
html.tv-intro-active body {
  overflow: hidden;
  background: #000;
}

TVIntro.svelte removes the class in both notifyDone (normal completion) and finalizeImmediately (reduced-motion / already-seen skip path).

Original prompt

Fix two issues: stale build cache causing old CSS to deploy, and TV intro flash.

FIX 1: .github/workflows/deploy.yml — remove the restore-keys fallback from the Astro cache step. Change:

      - name: Cache Astro build
        uses: actions/cache@v4
        with:
          path: .astro/
          key: astro-${{ runner.os }}-node${{ env.NODE_VERSION }}-${{ hashFiles('src/**', 'astro.config.*', 'tsconfig.json', 'package-lock.json') }}
          restore-keys: |
            astro-${{ runner.os }}-node${{ env.NODE_VERSION }}-

To:

      - name: Cache Astro build
        uses: actions/cache@v4
        with:
          path: .astro/
          key: astro-${{ runner.os }}-node${{ env.NODE_VERSION }}-${{ hashFiles('src/**', 'astro.config.*', 'tsconfig.json', 'package-lock.json') }}

FIX 2: TV intro flash — site chrome is visible for ~50ms before the black overlay mounts.

In src/layouts/BaseLayout.astro, replace the line {shouldRenderTvIntro && <TVIntro client:load />} with:

{shouldRenderTvIntro && <script is:inline>
  (function() {
    try {
      var seen = sessionStorage.getItem('tv-intro-seen');
      var rm = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
      if (!seen && !rm) { document.documentElement.classList.add('tv-intro-active'); }
    } catch(e) {}
  })();
</script>}
{shouldRenderTvIntro && <TVIntro client:load />}

In src/styles/global.css, add after the existing root/body variable block:

/* Phosphor — suppress site flash before TV intro overlay mounts */
html.tv-intro-active,
html.tv-intro-active body {
  overflow: hidden;
  background: #000;
}

In src/components/TVIntro.svelte, update the notifyDone function to remove the class:

function notifyDone() {
  if (introState.done) return;
  introState.done = true;
  document.documentElement.classList.remove('tv-intro-active');
  document.dispatchEvent(new CustomEvent('tv-intro-done'));
}

And update finalizeImmediately to also remove the class:

const finalizeImmediately = () => {
  phase = 'done';
  document.body.style.overflow = originalOverflow;
  document.documentElement.classList.remove('tv-intro-active');
  notifyDone();
};

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: @copilot Accepted Confirmation: Confirm agent session

Assistant: ````list type="task"
data:
- title: 'fix: status text legibility, grid flash before intro, Calendly modal with CRT power-on effect'
repository: jaypatrick/jk.com
url: https://github.com/copilot/tasks/pull/PR_kwDOSHNyYs7ZARvz?session_id=16822cd6-b9d6-444b-8196-4a1b8ba52d36
state: queued


Three things in this one, here's the thinking behind each:

**Status text legibility** — `color-text-ghost` (`#475569`) was the culprit, essentially invisible against the dark background. Bumped to `color-text-dim` (`#94a3b8`) for the body text, and the `ONLINE` token gets its own class with full `color-cyan` + slight weight so it reads as the "active" signal it is. The pulsing dot will now have visible company.

**Grid flash before intro** — this is a classic SSR/hydration timing problem. The grid CSS renders at first paint, but `TVIntro` only mounts after JS hydrates. The fix is a tiny inline `<script>` in `<head>` that runs *synchronously before first paint* and stamps `data-phosphor-intro="active"` on `<html>` when the intro conditions are met (homepage + not seen + no reduced motion). A CSS rule then suppresses `background-image` on `body` and `.grid-overlay` for that attribute. `TVIntro` removes it the moment the intro completes or skips. Clean, zero-flash.

**Calendly modal** — the inline widget is gone. In its place: a `[ SCHEDULE_SESSION ]` button that opens a `position: fixed` modal with a backdrop blur. The modal panel itself starts at `scaleY(0.015)` — that thin-line CRT power-on effect — and expands to full height over 300ms when it opens. Corner brackets, the `SCHEDULE_SESSION` mono header with a pulsing dot, and a `[ CLOSE ]` button complete the Phosphor treatment. The Calendly iframe only initializes when the modal actually opens, which is also a nice performance win — no widget loading until the user explicitly asks for it.

User: A couple more tweaks to the theme: The chips in the tiles under Work That Ships need to be themed similar to the chips we redid under the hero. Also, remove the emoji...no offense but it's a dead giveaway that AI generated some of the content. And, the This. Is. JK.com fades in twice: the order is correct, but there's an extra this is jk.com that shows up while the static is still on. The static shouldn't have anything that fades in while it's on, only once it transitions from static to the This. Is. JK.com fades in on its own, then the rest of the site appears, and then the typewriter fires.

Assistant: Now I have a clear picture of all three issues. Let me dispatch the fix.

Assistant: Looks...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

@jaypatrick jaypatrick added the bug Something isn't working label May 7, 2026
@jaypatrick jaypatrick added this to the launch milestone May 7, 2026
Agent-Logs-Url: https://github.com/jaypatrick/jk.com/sessions/b5644dae-50d4-4993-a920-43138aea8316

Co-authored-by: jaypatrick <1800595+jaypatrick@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix stale build cache and TV intro flash issues fix: stale Astro cache deploys old CSS; TV intro overlay flash May 7, 2026
Copilot AI requested a review from jaypatrick May 7, 2026 16:28
@jaypatrick jaypatrick marked this pull request as ready for review May 7, 2026 16:29
Copilot AI review requested due to automatic review settings May 7, 2026 16:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses two production issues in JK.com: preventing stale CSS from being deployed due to partial Astro cache restores in GitHub Actions, and reducing/avoiding a brief “TV intro” flash where page chrome becomes visible before the intro overlay takes effect.

Changes:

  • Updates the deploy workflow to only restore the Astro build cache on exact key matches (no restore-key fallbacks).
  • Adds a synchronous inline script + CSS gating to apply an early tv-intro-active state while the TV intro should run.
  • Ensures TVIntro clears the tv-intro-active state both on normal completion and on the immediate-skip path.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
.github/workflows/deploy.yml Removes restore-keys to avoid restoring stale .astro/ output from partial cache hits.
src/layouts/BaseLayout.astro Adds an inline script (body) to stamp html.tv-intro-active before the TVIntro island hydrates.
src/styles/global.css Adds tv-intro-active CSS to force black background + scroll lock during the intro gate.
src/components/TVIntro.svelte Removes the tv-intro-active class in both completion and skip/finalize paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/styles/global.css
Comment thread src/layouts/BaseLayout.astro Outdated
Comment thread src/components/TVIntro.svelte
Comment thread src/components/TVIntro.svelte
Comment thread src/layouts/BaseLayout.astro Outdated
@jaypatrick
Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

Agent-Logs-Url: https://github.com/jaypatrick/jk.com/sessions/2419212a-52ee-4d94-8351-54a140b93770

Co-authored-by: jaypatrick <1800595+jaypatrick@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 7, 2026

@copilot apply changes based on the comments in this thread

Applied all five review comments in commit 6f02cc4:

  • Merged body script into head scripttv-intro-active is now stamped in the single existing <head> inline script alongside data-phosphor-intro. This runs earlier (during <head> parse, before any body content), eliminates the duplicate sessionStorage/matchMedia logic, and fixes the catch(e)catch (_) style inconsistency. The body-level script has been removed entirely.

  • Added body > * visibility suppressionglobal.css now includes html.tv-intro-active body > *:not(.tv-intro-overlay):not(.crt-power-line) { visibility: hidden } so pre-rendered Header/main/Footer markup is invisible until the overlay takes over, fully preventing any text or chrome from painting.

  • Added two new tests to TVIntro.test.ts:

    • removes the tv-intro-active class from document root on normal completion — asserts classList.remove('tv-intro-active') is present in the source
    • removes the tv-intro-active class in the immediate skip path (seen or reduced-motion) — asserts the removal appears at least twice (once in notifyDone, once in finalizeImmediately), ensuring neither path leaves the page scroll-locked

@jaypatrick jaypatrick merged commit 0c825fc into main May 7, 2026
4 checks passed
@jaypatrick jaypatrick deleted the copilot/fix-stale-build-cache-and-tv-intro-flash branch May 7, 2026 16:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants