Skip to content
Merged
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
4 changes: 3 additions & 1 deletion components/AppShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ import { useRouter } from "next/navigation";
import ScoutForm from "@/components/ScoutForm";
import CardFan from "@/components/CardFan";
import LoadingScreen from "@/components/LoadingScreen";
import HowItWorksModal from "@/components/HowItWorksModal";
import dynamic from "next/dynamic";
import FooterCredit from "@/components/FooterCredit";
import BuyMeACoffee from "@/components/BuyMeACoffee";
import GithubStar from "@/components/GithubStar";
import { SAMPLE_CARDS } from "@/lib/github/samples";

const HowItWorksModal = dynamic(() => import("@/components/HowItWorksModal"), { ssr: false });

export default function AppShell({ stars, scoutCount }: { stars: number | null; scoutCount: number | null }) {
const router = useRouter();
const [isPending, startTransition] = useTransition();
Expand Down
42 changes: 19 additions & 23 deletions components/Background.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,35 @@ const NOISE = `url("data:image/svg+xml;utf8,${encodeURIComponent(noiseSvg)}")`;

// Faint GitHub-contribution-grid motif — a brand signature drawn into the
// backdrop. A few cells gently pulse green (see .gf-grid-cell in globals.css).
function ContribGrid() {
//
// The grid is fully deterministic, so we precompute it ONCE as a static SVG string and inject it via
// dangerouslySetInnerHTML. This serializes as a single node in the RSC flight instead of 210 separate
// <rect> flight nodes (each ~90B escaped), shrinking the inline hydration payload — while preserving the
// exact rects, rounded corners, and per-cell pulse animations (class + --gf-dur inlined into the string).
const CONTRIB_GRID_SVG = (() => {
const cols = 30;
const rows = 7;
const cells = [];
let rects = "";
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const seed = (r * 7 + c * 13) % 11;
const lit = seed < 3;
cells.push(
<rect
key={`${r}-${c}`}
x={c * 16}
y={r * 16}
width={12}
height={12}
rx={2.5}
fill={lit ? "#39d353" : "#1b2530"}
className={lit ? "gf-grid-cell" : undefined}
style={lit ? { ["--gf-dur" as string]: `${2.4 + seed * 0.4}s` } : undefined}
/>,
);
const attrs = lit
? ` fill="#39d353" class="gf-grid-cell" style="--gf-dur:${2.4 + seed * 0.4}s"`
: ` fill="#1b2530"`;
rects += `<rect x="${c * 16}" y="${r * 16}" width="12" height="12" rx="2.5"${attrs}/>`;
}
}
return `<svg width="${cols * 16}" height="${rows * 16}" viewBox="0 0 ${cols * 16} ${rows * 16}" style="width:100%;height:100%" aria-hidden="true">${rects}</svg>`;
})();

function ContribGrid() {
return (
<svg
width={cols * 16}
height={rows * 16}
viewBox={`0 0 ${cols * 16} ${rows * 16}`}
style={{ width: "100%", height: "100%" }}
<div
aria-hidden
>
{cells}
</svg>
style={{ width: "100%", height: "100%" }}
dangerouslySetInnerHTML={{ __html: CONTRIB_GRID_SVG }}
/>
);
}

Expand Down
4 changes: 3 additions & 1 deletion components/ResultView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ import Mascot from "./Mascot";
import FooterCredit from "./FooterCredit";
import BuyMeACoffee from "./BuyMeACoffee";
import GithubStar from "./GithubStar";
import HowItWorksModal from "./HowItWorksModal";
import dynamic from "next/dynamic";
import { AttributesPanel, MetricsPanel, ReportHeader } from "./ScoutReport";
import { resolveResultTheme } from "./finishTheme";
import { useReveal } from "@/hooks/useReveal";
import { burstConfetti } from "@/lib/confetti";

const HowItWorksModal = dynamic(() => import("./HowItWorksModal"), { ssr: false });

interface Props {
card: Card;
onBack: () => void;
Expand Down
8 changes: 8 additions & 0 deletions lib/capture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ export async function renderCardImage<T>(
);
await nextFrame();
await nextFrame();
// WebKit/Safari drops every raster layer (card art, avatar, flag, logo) from
// the FIRST html-to-image render unless a painted, blurred element is in the
// tree — the tier glow halo was incidentally that element. The transparent
// cut-out removes the glow (above), which re-exposes the bug: the export
// comes back as just the text overlay. A throwaway priming render fixes it
// (the documented html-to-image Safari workaround) — only paid on the
// transparent path (copy), since every other export keeps the glow.
if (opts.transparent) await capture(clone).catch(() => {});
return await capture(clone);
} finally {
holder.remove();
Expand Down
Loading