greenlanternwatch.com. Your Sector for All Things Green Lantern. An unofficial fan site, not affiliated with or endorsed by DC.
Next.js (App Router) + Tailwind CSS v4 + Sanity + Vercel. Sanity Studio is embedded at /studio.
-
Create a Sanity project and dataset (from this folder):
npx sanity login npx sanity init --env --create-project "Green Lantern Watch" --dataset productionIf
inittries to scaffold files, decline. You only need the project ID. -
Create
.env.localfrom.env.exampleand fill in the project ID. -
Run it:
npm install npm run dev
Site: http://localhost:3000, Studio: http://localhost:3000/studio
-
In https://www.sanity.io/manage, open the project, go to API, CORS origins, and add
http://localhost:3000with credentials allowed. -
Create five categories in the Studio with these exact slugs:
comics,movies-tv,characters,features,reviews. The nav and home page link to them.
While NEXT_PUBLIC_SANITY_PROJECT_ID is empty, npm run dev fills every page with clearly labelled placeholder content so you can check the layout. A banner says so. Production builds never show demo content, only empty states.
- Import the repo in Vercel. The framework preset is detected automatically.
- Add the environment variables from
.env.exampleunder Project Settings, Environment Variables. - Add
greenlanternwatch.comunder Project Settings, Domains, and point DNS at Vercel as it instructs. Add the www variant and redirect one to the other. - Add
https://greenlanternwatch.com(and the www variant) as CORS origins in Sanity with credentials allowed, so/studioworks in production.
Content updates go live through a Sanity webhook. Pages are cached for a day otherwise, because short ISR timers re-render pages on nearly every visit and burn through Vercel's CPU allowance.
This is already set up (October 2026). To recreate it:
- Generate a secret (
openssl rand -base64 32) and add it in Vercel asSANITY_REVALIDATE_SECRET(Production). - In sanity.io/manage, under API, Webhooks, create a webhook: URL
https://www.greenlanternwatch.com/api/revalidate(thewwwhost, since Sanity won't follow a redirect on POST), datasetproduction, trigger on create, update and delete, filter!(_type in ["sanity.imageAsset", "sanity.fileAsset"]), projection{_type}, HTTP method POST, drafts off, and the same secret.
Any publish clears the whole site's cache, and each page re-renders the next time someone visits it. If the webhook fails, content still refreshes within a day.
| Route | What it is |
|---|---|
/ |
Hero carousel, latest news, featured articles, latest comics, recent features, sidebar |
/news, /news/[slug] |
All articles, article page |
/category/[slug] |
Articles by category (Movies & TV, Features, Reviews, and so on) |
/comics |
The Book of Oa: reading orders, story arcs, key issues, new-comic coverage |
/comics/reading-orders/[slug], /comics/arcs/[slug] |
Reading order and story arc hubs |
/characters, /characters/[slug] |
The character database |
/corps, /corps/[slug] |
The emotional spectrum and each Corps |
/search |
Search across articles, characters, arcs, reading orders and Corps |
article: title, slug, excerpt, category, author, publishedAt, featured, mainImage (alt, caption, credit), body, tags, and an optionalcomicReleasegroup that feeds Latest Comicscategory,authorreadingOrder: audience (new reader, era, character), sections ofreadingEntryitemsstoryArc: kind (event, run, storyline), creators, years, summary, reading list, characters, CorpskeyIssue: kind (first appearance, origin, villain debut, historic ring, milestone), why it matters, characterscharacter: section (Earth, alien, other), Corps, bio, abilities, construct style, portrayals, key storylines, reading recommendationscorps: spectrum color, emotion, tagline, key figures, description
Most reference content is written as code in scripts/ and imported into Sanity, so it can be reviewed in diffs and rebuilt from scratch. ComicVine fills in the facts.
- Seed scripts (
characters.mjs,corps.mjs,story-arcs.mjs,explainers.mjsand the reading order scripts) write NDJSON forsanity dataset import. Document IDs are fixed, so re-running an import replaces documents in place. Reading orders use a shorthand (GL (2005) #29-35 @secret-origin | note) thatreading-order-build.mjsexpands. - ComicVine (
scripts/comicvine/): the CBL reading lists inscripts/data/record a ComicVine ID for every issue.fetch.mjscaches covers, release dates and creator credits, pacing itself under ComicVine's rate limit and picking up where it left off.sync.mjswrites those fields into Sanity without touching editorial notes and uploads each cover once.key-issues.mjsandlatest.mjsdo the same for key issues and for the newest issues of every current Lantern series.
Each script's header comment has its exact commands. The ComicVine scripts read comicvine_api_key from .env.local.
- Not built yet: community and forums, the Corps quiz, the Sector map, polls, a light theme, and the newsletter back end. The signup box appears only when
NEXT_PUBLIC_NEWSLETTER_ACTIONis set to your email provider's form URL. Social links appear only for the handles you set. - This is an unofficial fan site. Do not upload official logos, studio stills or scanned comic pages you do not have rights to. Every image field has a credit field for this reason. The footer disclaimer is in
src/components/SiteFooter.tsx. - Types in
src/sanity/types.tsare written by hand. Sanity TypeGen is a good next step once the schema settles.
