From 158a74342db4525fdfbd9dac0e23d7c66e9db8cf Mon Sep 17 00:00:00 2001 From: Harsh Singh Date: Thu, 27 Aug 2026 02:29:16 +0530 Subject: [PATCH] Put GitHub and sponsorship on the site, behind one shared footer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo and the sponsors page were never linked from the product, and seven pages each carried their own copy of a footer, so there was nowhere consistent for those links to live. - SiteFooter replaces all seven inline footers and adds four pages that had none (templates, privacy, terms, cookies), so every public page now carries both a GitHub and a sponsor link. - SponsorCard states the actual bargain — it is free because it is open source — and sits on the homepage and the pricing page. No live star count: that means an external fetch the page does not need and a number that is wrong when the request fails. - The navbar gains a GitHub link on desktop and both links in the mobile drawer. - The README's sponsor section no longer talks about model calls or paid plans, neither of which exists, and states plainly that sponsoring unlocks nothing. Also fixes a bug this work introduced: the premium template preview passed a fresh styleSpec object literal on every render, and SiteRenderer regenerates its frames whenever that changes identity — so once the ownership check gave the component a reason to re-render, the preview restarted generation forever and sat on "Rendering frames…". Found by rendering the page headlessly rather than by reading it. --- README.md | 9 ++- src/app/about/page.tsx | 10 +-- src/app/changelog/page.tsx | 12 +-- src/app/contact/page.tsx | 12 +-- src/app/cookies/page.tsx | 2 + src/app/launch/page.tsx | 11 +-- src/app/page.tsx | 52 ++---------- src/app/presets/page.tsx | 11 +-- src/app/pricing/page.tsx | 17 ++-- src/app/privacy/page.tsx | 2 + src/app/templates/[slug]/page.tsx | 18 ++++- src/app/templates/page.tsx | 2 + src/app/terms/page.tsx | 2 + src/components/GitHubMark.tsx | 8 ++ src/components/Navbar.tsx | 32 +++++++- src/components/SiteFooter.tsx | 130 ++++++++++++++++++++++++++++++ src/components/SponsorCard.tsx | 64 +++++++++++++++ src/lib/links.ts | 7 ++ 18 files changed, 295 insertions(+), 106 deletions(-) create mode 100644 src/components/GitHubMark.tsx create mode 100644 src/components/SiteFooter.tsx create mode 100644 src/components/SponsorCard.tsx create mode 100644 src/lib/links.ts diff --git a/README.md b/README.md index 97042f6..fb51795 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ **Ready-made cinematic scroll websites — no code, pure HTML.** Pick a template, change the words, and export a production‑ready HTML/CSS/JS ZIP you can -deploy anywhere. Every template is free on every plan. +deploy anywhere. The editor, publishing and ZIP export are free, along with 13 of the 21 +templates. The other 8 are bought once, outright. [Live demo](https://scrollcraft-gilt.vercel.app) · [Report a bug](https://github.com/singhharsh1708/scrollcraft/issues) · [Request a feature](https://github.com/singhharsh1708/scrollcraft/issues) @@ -250,10 +251,10 @@ coding standards, and how to pick up an issue. ## Sponsor ScrollCraft is free and open source, and the hosted version costs real money to run -(model calls, frame rendering, storage). If it saved you a studio invoice, you can +(frame rendering, blob storage, a database). If it saved you a studio invoice, you can [sponsor the project on GitHub](https://github.com/sponsors/singhharsh1708), one-off or -monthly. Sponsoring is separate from the paid plans: it funds the open source work, not an -account upgrade. +monthly. Sponsoring funds the open source work — it is not a purchase and unlocks +nothing, which is deliberate. Not in a position to pay? Starring the repo, filing a good bug report, or shipping a PR helps just as much. diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx index ab88895..573649b 100644 --- a/src/app/about/page.tsx +++ b/src/app/about/page.tsx @@ -6,6 +6,7 @@ import { Badge } from "@/components/ui/badge"; import { ArrowRight, Sparkles, Zap, Globe, Users } from "lucide-react"; import Navbar from "@/components/Navbar"; import { PRESETS } from "@/lib/presets"; +import SiteFooter from "@/components/SiteFooter"; const TEAM = [ { name: "Harsh Singh", role: "Founder & Engineer", avatar: "HS", bio: "Building the future of no-code web experiences." }, @@ -128,14 +129,7 @@ export default function AboutPage() { - + ); } diff --git a/src/app/changelog/page.tsx b/src/app/changelog/page.tsx index 208f439..9399c21 100644 --- a/src/app/changelog/page.tsx +++ b/src/app/changelog/page.tsx @@ -1,6 +1,7 @@ import { Badge } from "@/components/ui/badge"; -import { Sparkles } from "lucide-react"; +import { } from "lucide-react"; import Navbar from "@/components/Navbar"; +import SiteFooter from "@/components/SiteFooter"; const ENTRIES = [ { @@ -131,14 +132,7 @@ export default function ChangelogPage() { -
-
-
- -
- ScrollCraft — Built with Next.js -
-
+ ); } diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index 1bdbb43..48b343c 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -4,9 +4,10 @@ import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; -import { Sparkles, Mail, MessageSquare, Zap, CheckCircle2 } from "lucide-react"; +import { Mail, MessageSquare, Zap, CheckCircle2 } from "lucide-react"; import { toast } from "sonner"; import Navbar from "@/components/Navbar"; +import SiteFooter from "@/components/SiteFooter"; const TOPICS = ["General question", "Bug report", "Feature request", "Enterprise inquiry", "Billing", "Partnership"]; @@ -118,14 +119,7 @@ export default function ContactPage() { -
-
-
- -
- ScrollCraft — Built with Next.js & AI -
-
+ ); } diff --git a/src/app/cookies/page.tsx b/src/app/cookies/page.tsx index 42ddb8c..ece2641 100644 --- a/src/app/cookies/page.tsx +++ b/src/app/cookies/page.tsx @@ -1,5 +1,6 @@ import Link from "next/link"; import Navbar from "@/components/Navbar"; +import SiteFooter from "@/components/SiteFooter"; export const metadata = { title: "Cookie Policy" }; @@ -51,6 +52,7 @@ export default function CookiesPage() {

Contact

Questions? Email hello@scrollcraft.app. See also our Privacy Policy.

+ ); } diff --git a/src/app/launch/page.tsx b/src/app/launch/page.tsx index 3bab541..dcb8428 100644 --- a/src/app/launch/page.tsx +++ b/src/app/launch/page.tsx @@ -6,6 +6,7 @@ import { Badge } from "@/components/ui/badge"; import { ArrowRight, Check, Copy, Sparkles, Zap, Download, Play, ExternalLink } from "lucide-react"; import { toast } from "sonner"; import Navbar from "@/components/Navbar"; +import SiteFooter from "@/components/SiteFooter"; const PROMO_CODE = "PHHUNT"; const DISCOUNT = 30; @@ -205,15 +206,7 @@ export default function LaunchPage() { - {/* Footer */} -
-

© {new Date().getFullYear()} ScrollCraft. Made with ♥ for builders.

-
- Privacy - Terms - Contact -
-
+ ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 7e4c322..c910cf5 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -7,6 +7,8 @@ import { ArrowRight, Sparkles, Zap, Download, Play, Check } from "lucide-react"; import Navbar from "@/components/Navbar"; import StylePreview from "@/components/StylePreview"; import { findPreset, PRESETS } from "@/lib/presets"; +import SponsorCard from "@/components/SponsorCard"; +import SiteFooter from "@/components/SiteFooter"; const DEMO_COUNT = 60; const demoFrames = Array.from({ length: DEMO_COUNT }, (_, i) => `/api/demo-frame?i=${i}&total=${DEMO_COUNT}`); @@ -396,6 +398,11 @@ export default function Home() { + {/* Open source */} +
+ +
+ {/* Final CTA */}
@@ -423,50 +430,7 @@ export default function Home() {
- {/* Footer */} -
-
-
-
-
-
- -
- ScrollCraft -
-

Ready-made cinematic scroll templates with animated canvas backgrounds. Ship a site in minutes.

-
-
-

Product

-
- {[["Features", "/#features"], ["Presets", "/presets"], ["Pricing", "/pricing"], ["Builder", "/create"]].map(([label, href]) => ( - {label} - ))} -
-
-
-

Company

-
- {[["About", "/about"], ["Blog", "/changelog"], ["Changelog", "/changelog"], ["Contact", "/contact"]].map(([label, href]) => ( - {label} - ))} -
-
-
-

Legal

-
- {[["Privacy Policy", "/privacy"], ["Terms of Service", "/terms"], ["Cookie Policy", "/cookies"]].map(([label, href]) => ( - {label} - ))} -
-
-
-
-

© 2026 ScrollCraft. All rights reserved.

-

Built with Next.js

-
-
-
+ ); } diff --git a/src/app/presets/page.tsx b/src/app/presets/page.tsx index 671c539..fb0a014 100644 --- a/src/app/presets/page.tsx +++ b/src/app/presets/page.tsx @@ -9,6 +9,7 @@ import { ArrowRight, Search, Sparkles, Eye } from "lucide-react"; import Navbar from "@/components/Navbar"; import StylePreview from "@/components/StylePreview"; import { PRESETS } from "@/lib/presets"; +import SiteFooter from "@/components/SiteFooter"; const CATEGORIES = [ "All", "SaaS", "Agency", "E-commerce", "Mobile App", "Startup", @@ -172,15 +173,7 @@ export default function PresetsPage() { - {/* Footer */} -
-
-
- -
- ScrollCraft — Built with Next.js & AI -
-
+ ); } diff --git a/src/app/pricing/page.tsx b/src/app/pricing/page.tsx index f11c98a..2e1d6d0 100644 --- a/src/app/pricing/page.tsx +++ b/src/app/pricing/page.tsx @@ -8,6 +8,8 @@ import Navbar from "@/components/Navbar"; import { PLANS, siteAllowance } from "@/lib/plans"; import { TEMPLATES } from "@/lib/templates"; import { PRESETS } from "@/lib/presets"; +import SiteFooter from "@/components/SiteFooter"; +import SponsorCard from "@/components/SponsorCard"; // ScrollCraft is free. The subscription tiers this page used to sell are retired — see // the note in lib/plans.ts — so there is no billing toggle, no promo field and no @@ -186,6 +188,11 @@ export default function PricingPage() { + {/* Open source */} +
+ +
+ {/* FAQ */}

Questions

@@ -223,15 +230,7 @@ export default function PricingPage() {
- {/* Footer */} -
-
-
- -
- ScrollCraft — Built with Next.js -
-
+ ); } diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx index 9b5f61c..afaf15a 100644 --- a/src/app/privacy/page.tsx +++ b/src/app/privacy/page.tsx @@ -1,5 +1,6 @@ import Link from "next/link"; import Navbar from "@/components/Navbar"; +import SiteFooter from "@/components/SiteFooter"; export const metadata = { title: "Privacy Policy" }; @@ -37,6 +38,7 @@ export default function PrivacyPage() {

Contact

Questions? Email hello@scrollcraft.app.

+ ); } diff --git a/src/app/templates/[slug]/page.tsx b/src/app/templates/[slug]/page.tsx index af0064e..ef8c913 100644 --- a/src/app/templates/[slug]/page.tsx +++ b/src/app/templates/[slug]/page.tsx @@ -1,5 +1,5 @@ "use client"; -import { use, useCallback, useEffect, useState } from "react"; +import { use, useCallback, useEffect, useMemo, useState } from "react"; import { notFound } from "next/navigation"; import Link from "next/link"; import { Button } from "@/components/ui/button"; @@ -39,12 +39,21 @@ function Preview({ sections: Section[]; children: React.ReactNode; }) { + // SiteRenderer regenerates its frames whenever `styleSpec` changes identity, so this + // has to be a stable object. Passing a fresh literal restarted generation on every + // re-render, which left the premium preview stuck on "Rendering frames…" forever once + // the ownership check gave the component something to re-render for. + const styleSpec = useMemo( + () => ({ style: template.style, colors: template.colors }), + [template.style, template.colors] + ); + return (
@@ -158,8 +167,9 @@ function PremiumPreview({ template }: { template: Template }) { You're seeing the opening section

- {hidden} more {hidden === 1 ? "section is" : "sections are"} written and waiting. - Unlock once and it's yours to edit and export forever. + {hidden} more {hidden === 1 ? "section is" : "sections are"}{" "} + written and waiting. Unlock once and it's yours to edit and export + forever.

+ + + + +
+ ); + } + + return ( +
+
+
+
+ + Built in the open +
+

+ ScrollCraft is free because it is open source. The whole thing — the scroll + engine, the templates, the exporter — is on GitHub, and you can read it, fork + it, or file the bug you just hit. If it saved you a weekend, sponsoring keeps + it maintained. +

+
+ +
+ + + + + + +

+ Sponsorship goes to hosting and maintenance. +

+
+
+
+ ); +} diff --git a/src/lib/links.ts b/src/lib/links.ts new file mode 100644 index 0000000..2a390ab --- /dev/null +++ b/src/lib/links.ts @@ -0,0 +1,7 @@ +/** + * Outbound links that appear in more than one place. Kept here so the repo or the + * sponsors page can move without hunting through components. + */ +export const GITHUB_REPO_URL = "https://github.com/singhharsh1708/scrollcraft"; +export const GITHUB_SPONSORS_URL = "https://github.com/sponsors/singhharsh1708"; +export const CONTACT_EMAIL = "hello@scrollcraft.app";