A copy-pasteable prompt for a landing page where the cursor acts as an X-ray torch — sweeping it across a dead, powered-down starship lights that part of the hull up with plasma conduits and lit engine bells. Two pixel-aligned 4K layers generated with Higgsfield, a CSS mask as the reveal, and a parallax debris field of keyed cutouts.
Overview
A 1.4-kilometre starship on pure black, and it looks dead. Cold grey
plating, dark engine bells, no lights anywhere. Then you move the cursor
over the hull and a soft circle of it wakes up — plasma light
running along every panel seam, orange-hot machinery visible through open
access sections, engine bells blazing cyan and magenta. Move away and it
goes cold again.
The trick is that there is no 3D model and no shader doing lighting. There
are two flat images of the same ship — one dormant, one fully powered —
stacked exactly on top of each other, and the cursor punches a hole in the
top one. That is the entire effect. It only works if the two images line
up to the pixel, which is the part everybody gets wrong.
Below is the whole prompt, plus why each clause is in it. Images generated
with Higgsfield
(gpt_image_2), keyed and composited locally with numpy.
What it produces: a full-viewport hull that bleeds past
the frame, a cursor torch that reveals the energised layer beneath, five
subsystem nodes that light only their own region and open a HUD readout,
and a parallax field of transparent asteroid and debris cutouts drifting
at different depths. Idle for a couple of seconds and the torch drifts
across the hull on its own so the effect stays discoverable.
Stack: one HTML file, one CSS file, one JS file — no
framework, no build step. Plus 11 generated images and a numpy/PIL pass
to key them. Page payload lands around 4MB.
The one idea that makes it work
Generate the dormant ship first. Then feed that image back in as a
reference and ask only for the power state to change, with the camera,
framing, scale and silhouette explicitly locked. You are not generating two
ships. You are generating one ship twice, and the second pass is forbidden
from moving it.
Ask for two ships independently and you get two different ships — the
camera drifts, the hull redesigns itself, and a circular reveal shows a
completely different vessel inside the circle. Nothing in CSS fixes that.
The prompt
Paste this into Claude Code (or any agent with Higgsfield access) in an
empty folder. It carries the exact generation prompts, the local keying
maths, and the traps.
Build me an interactive sci-fi landing page with a hover-reveal hull scanner and a
parallax debris field. Generate every image with Higgsfield, then key and composite
them locally. Work in a new `site/` folder.
SUBJECT: a huge deep-field survey starship called HELIOS.
(Swap this for anything with visible internals — a mech, a supercar, a turbine, a
sneaker. The whole technique survives the swap.)
## The effect I want
A giant ship on pure black. It looks dead and powered-down. Wherever my cursor goes,
a soft circular "scan" reveals that part of the hull FULLY ENERGISED — glowing plasma
seams, lit engine bells, orange internals — while everything outside the cursor stays
cold. Hovering a subsystem node lights only that region and shows a small HUD readout.
Separately, transparent cutout asteroids and debris float at different depths and
parallax with my cursor for an immersive effect.
## Step 1 — Higgsfield
Use the Higgsfield MCP tools if you have them; otherwise use the `higgsfield` CLI
(`higgsfield-generate` skill). Check `higgsfield account status` first and ask me to run
`higgsfield auth login` if the session is expired. Use model `gpt_image_2` throughout.
Pass `--wait` so each job blocks and prints its result URL. ~11 images total.
## Step 2 — The hero, in TWO PIXEL-ALIGNED LAYERS (this is the whole trick)
Generate the DORMANT ship first, 16:9, resolution 4k, quality high:
"Ultra-detailed hard science fiction heavy exploration starship, three-quarter front
view from slightly above, perfectly centered, entire ship visible with generous empty
margin on all sides. DORMANT POWERED-DOWN STATE: cold matte gunmetal and bone-white
ceramic hull plating, dense industrial greebling, visible panel seams and rivets,
armored plating, sensor masts, four large engine nozzles that are completely dark and
cold, all windows dark, absolutely no lights, no glow, no emissive surfaces anywhere.
Lighting: single hard cold rim light from upper left, deep black shadows, no fill
light. Background: pure flat solid black void, absolutely no stars, no nebula, no
planets, no fog, no gradient. Photorealistic CGI render, cinematic, razor sharp micro
detail, industrial hard-surface design. No text, no logos, no watermark, no user
interface elements."
Now generate the ENERGISED layer by feeding that image BACK IN as a reference
(`--image path/to/dormant.png`), same aspect ratio and resolution. Lock the geometry
explicitly — this is what makes a partial reveal read as one object:
"Take the reference starship image and change ONLY its power state. CRITICAL: keep the
exact same camera angle, exact same framing, exact same position in frame, exact same
scale, exact same silhouette and exact same hull geometry, pixel for pixel identical
composition. Do not move, rotate, rescale, re-pose or redesign the ship. Keep the pure
flat black background with no stars. The change: the ship is now FULLY ENERGIZED AND
POWERED UP. Every panel seam and recessed channel across the hull now glows with hot
cyan-white plasma light. Internal reactor conduits and orange-hot machinery are visible
glowing through open hull access sections along the spine. All four engine nozzles blaze
with intense cyan and magenta plasma light. Every window and cockpit strip is lit warm
amber from inside. Thin holographic amber schematic lines trace along the hull surface.
Keep all glow tight and contained within the hull footprint, no long exhaust plumes
extending beyond the ship, no lens flares. The hull plating itself stays the same colour
and material where it is not emissive."
VERIFY ALIGNMENT before building anything: threshold both images and compare silhouette
bounding boxes. They should agree within a handful of pixels across ~3800px. Also save a
red/cyan channel overlay (dormant in red, energised in cyan) and LOOK at it — hull edges,
masts and domes must not ghost or double. Do not trust IoU alone; the dormant hull is much
darker, so IoU reads low even on a perfect match. If the silhouettes genuinely differ,
regenerate the second layer, don't try to fix it in CSS.
## Step 3 — Debris objects on a chroma screen
Generate 9 objects, 1:1, quality high (4k for the three big ones, 2k for the rest):
a jagged asteroid with glowing cyan mineral veins; a cratered grey asteroid, no glow; a
shattered rock cluster with molten amber cracks; a black obsidian monolith with glowing
amber glyphs; a cyan crystal shard cluster; a broken satellite module with a torn solar
array; a small white scout drone with one glowing cyan eye; a gyroscopic artifact of three
nested metal rings around an amber core; a caged plasma reactor sphere.
End EVERY object prompt with this, so I get a clean key rather than guesswork:
"Isolated on a completely uniform flat chroma key green background (pure #00B140),
perfectly even, no gradient, no vignette, no shadow cast on the background, no ground
plane, no horizon. Object floats freely in frame, fully inside the frame with clear
margin on all sides. Photorealistic CGI render, dramatic hard rim lighting, razor sharp
detail. No text, no watermark, no UI."
Generate these in parallel (~5 at a time). Keep the untouched 4K originals in
`assets/raw/`; write web assets to `assets/out/`.
## Step 4 — Process locally with numpy/PIL (not a background-removal model)
HERO ALPHA: the background is pure black, so derive alpha from luminance. Build ONE mask
from the UNION (per-pixel max) of both layers' luminance, then apply that SAME mask to
both. Deriving alpha per layer gives two slightly different silhouettes and the reveal edge
will show it. Close gaps and fill enclosed holes so stars can't shine through dark hull
panels. Feather the edge ~1.5px. Export both as WebP ~2600px wide (an 8MB PNG becomes
~0.5MB).
OBJECT ALPHA: chroma key in numpy. Compute greenness `g = G - max(R, B)`; alpha is a
smoothstep over g (roughly 18→58). Despill by clamping G toward `max(R,B)` wherever g > 0.
Then trim to the alpha bounding box and export WebP.
CRITICAL: if you fill holes to rescue translucent interiors, SKIP any enclosed pixel that
is still strongly green (g > ~40). Otherwise you fill genuine see-through gaps — the
artifact's ring interiors and the reactor cage — with solid green. Verify by compositing
every cutout onto a harsh magenta checkerboard and looking at it.
## Step 5 — Build the page (plain HTML/CSS/JS, no build step, no framework)
Pure black `#000`. Cyan `#4fe3ff` + amber `#ffb14d` accents. Chakra Petch + IBM Plex Mono.
No nav, no header. Minimal text — one word of branding.
HERO: full viewport. Both hero layers absolutely stacked in ONE box that shares the images'
exact aspect ratio (so every layer stays registered). Energised layer underneath, dormant on
top. Ship sized `min(120vw, 1820px, 168vh)` — cap by viewport height too, or it crops
off-screen — anchored to the bottom edge and bleeding ~4% past it. The wordmark sits BEHIND
the hull so the masts cross the letters.
Three reveal mechanisms:
1. CURSOR TORCH — animate a `radial-gradient` `mask-image` on the dormant layer via CSS
custom properties (`--mx`, `--my`, `--r`), lerped in one shared rAF loop. Radius ~16% of
ship width. Add a faint scanline "lens" ring at the cursor with `mix-blend-mode: screen`.
2. SUBSYSTEM NODES — 5 small pinging ring buttons on real hull features. Each fades in a
copy of the energised layer masked to a SOFT elliptical `radial-gradient` (not
`clip-path` — a hard arc across the hull looks like a bug). Hover shows a mono label
chip; click locks it. A HUD readout panel fades in with code, name and three stats, and
is fully hidden when nothing is selected.
3. IDLE AUTOPILOT — after 2.4s of no pointer, drift the torch across the hull on a
lissajous path so the effect demos itself.
PARALLAX FIELD: place the 9 cutouts as ~13 fixed-position instances across depth bands.
Per frame, one `translate3d` each combining cursor offset × depth, an idle sine drift, slow
rotation and scroll offset. Blur the near-field ones for depth of field. Add a canvas
starfield with its own parallax, plus grain, scanlines and a vignette. One rAF loop drives
everything. Disable all motion under `prefers-reduced-motion`.
Below the fold, keep it visual and text-light: compact subsystem chips (code + name only),
a grid of the cutouts as specimen cards, four animated telemetry counters, a CTA, a footer.
## Step 6 — Verify in a real browser, don't assume
Add dev-only query params `?scan=x,y` (pins the torch at those hull percentages) and
`?zone=CODE` (forces one subsystem open), then screenshot with headless Chrome:
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless=new \
--disable-gpu --hide-scrollbars --virtual-time-budget=5000 --window-size=1600,1000 \
--screenshot=shot.png "file://$PWD/site/index.html?scan=58,42"
LOOK at the screenshots and fix what you see. Check 1600x1000 and a portrait size. On
portrait the height cap shrinks the hull to a third of the frame — centre it there and let
it bleed off both sides instead.
## Traps — please avoid these, I hit all of them
- Do NOT name a CSS custom property `--cy` on an element if `--cy` is also your cyan design
token. It shadows the colour inside that subtree, so `border: 1px solid var(--cy)` becomes
invalid and the whole declaration is silently dropped. My hotspot markers were invisible
and the DOM looked perfect. Use `--hx`/`--hy` for coordinates.
- Do NOT eyeball hotspot coordinates. Draw the ellipses onto the hero image with PIL, look at
the result, and correct them. My first pass put one node in empty space.
- Do NOT let absolutely-positioned panel content size a panel — it contributes no height and
spills past the border. Stack states in one CSS grid cell so the panel sizes to the tallest.
- Headless Chrome runs only a few rAF frames, so cursor/idle animation looks broken in
screenshots. That's the harness, not your code — that's what `?scan=` is for. It also
enforces a ~500px minimum viewport, so a 430px window renders 500px and *looks* clipped.
- If Python downloads fail with CERTIFICATE_VERIFY_FAILED, shell out to `curl` (or set
`SSL_CERT_FILE=$(python3 -m certifi)`). Generated jobs still complete server-side — recover
their URLs from `higgsfield generate list --json` instead of paying to regenerate.
Finish by telling me how to open it, and write a short README explaining the two-layer
registration trick and the union alpha mask.
Why each part is in there
“Pixel for pixel identical composition”
The second pass is an edit, not a generation, and it needs to be told that
six different ways: same camera angle, same framing, same position, same
scale, same silhouette, same hull geometry. Redundant phrasing genuinely
helps here. The measured result was bounding boxes agreeing within 6px
across 3840px of image.
Verify alignment with an overlay, not a number
The obvious check is intersection-over-union on the two silhouettes. It
lies. The dormant hull is dark, so thresholding drops most of it and IoU
came back at 0.66 on a pair that was actually registered perfectly — the
number was measuring brightness, not position.
Compare bounding boxes instead, and render a red/cyan channel overlay
(dormant in red, energised in cyan) and look at it. If masts and
panel edges ghost or double, the layers moved. If they sit on top of each
other and the only difference is glow, you are fine.
One alpha mask, built from both layers at once
Both images come back on pure black backgrounds, so alpha can be derived
from luminance instead of shipping a black rectangle. The catch: derive it
per-layer and you get two subtly different silhouettes, and the reveal edge
will show you exactly where they disagree.
So build one mask from the per-pixel maximum of both layers'
luminance and apply that same mask to both. Fill enclosed holes too, or
starfield will shine through dark hull panels like the ship is made of
mesh.
Chroma green beats asking for transparency
For the debris, generating on a flat #00B140 screen and keying
it yourself in numpy is better than any background-removal model. Greenness
is G - max(R, B), which is strongly positive on the screen and
negative on almost every real material, so a smoothstep over it gives clean
soft edges. Despill by pulling G back toward max(R,B). Measured
residual green on edge pixels came out around 2–5/255 — invisible.
One trap: if you fill holes to rescue translucent interiors, skip any
enclosed pixel that is still strongly green. Otherwise you fill the genuine
see-through gaps — the ring interiors of the gyroscope artifact, the gaps
between the reactor cage struts — with solid green paint. Composite every
cutout onto a magenta checkerboard and look before you trust it.
Soft elliptical masks, not clip-path
For the per-subsystem reveals, clip-path: ellipse() works but
cuts a hard arc straight across the hull, which reads as a rendering bug. A
radial-gradient mask with a feathered edge lets the energised
patch fade into the cold plating instead. Same registration, much better
result.
Cap the hull against viewport height, not just width
min(120vw, 1820px, 168vh) — the vh term is what
keeps a 120vw-wide ship from running off the top and bottom on a short
laptop screen. On portrait screens that same term inverts the problem and
shrinks the hull to a third of the frame, so portrait gets its own rule:
centre it and let it bleed off both sides.
What broke
-
Every subsystem marker was invisible. The coordinate
custom property was named
--cy, and so was the cyan design
token. Setting --cy: 25% on an element shadowed the colour
for that whole subtree, so border: 1px solid var(--cy)
became 1px solid 25% — invalid, so the entire declaration
was silently dropped. The DOM looked perfect. Name coordinates
--hx/--hy.
-
A hotspot sat in empty space. Eyeballed percentages
from a downscaled preview. Draw the ellipses onto the actual image with
PIL, look at the result, correct, repeat.
-
The HUD panel's stats spilled past its own border.
Absolutely-positioned content contributes no height to its parent. Stack
the panel states in one CSS grid cell so it sizes to the tallest.
-
The ship loaded below the fold, hiding the entire
interaction on arrival. Worth screenshotting before believing the layout.
-
The animation looked broken in every screenshot.
Headless Chrome runs only a handful of
requestAnimationFrame
callbacks, so the torch lerp never ramps. That is the harness, not the
code — which is why the prompt asks for a ?scan=x,y param
that pins the torch deterministically. Headless also enforces a ~500px
minimum viewport, so a 430px window renders at 500 and looks
clipped when nothing is wrong.
-
Every image download failed with
CERTIFICATE_VERIFY_FAILED. Python had no usable CA
bundle. The jobs had all completed server-side, so the fix was to
curl them and recover the URLs from
higgsfield generate list --json rather than pay to
regenerate nine 4K images.
Recap
-
One ship generated twice, with the second pass forbidden from moving it.
Not two ships.
-
Check registration with a channel overlay you actually look at. IoU will
tell you a perfect pair is broken.
-
One alpha mask from the union of both layers, or the reveal edge shows
you where they disagree.
-
Key chroma green yourself. It beats a background-removal model and it is
faster.
-
Never shadow a design token with a coordinate variable of the same name.
-
Screenshot it. Layout and visibility bugs do not show up in the DOM.
If you want more prompts in this shape, there is
a fluid ink-reveal homepage with a Higgsfield-generated wordmark
video,
a frosted-glass refraction cube in raw WebGL, and
a single-file sticky-notes app.