← Learn · Prompt · 4 August 2026 · 13 min

The Prompt I Used to Build a Hover-Reveal Spaceship Scanner, with Higgsfield-Generated Hull Layers

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.