130

Jack-o'-Lantern Light

£10 or the whole Vault, £99

A photographic jack-o'-lantern with real 3D form that is the light source for your page: its candle flickers across real content, nearer elements glow brighter and every card casts a soft shadow away from the flame. Carry it and it swings from its stem while the light follows; press it to blow the candle out.

advanced
8 more details
webgl-shaderpointer-effectspointer-dragtouch-dragkeyboard-navigationviewport-aware-tickerblend-modeambient

This demo reads better at your own screen size than in the frame below:

Released

About this effect

A seasonal effect where the light comes from inside the page. A real photograph of a carved pumpkin, given true 3D form, sits among your content with a candle burning inside it, and that candle is the only light there is. Everything around it is in low moonlight until the flame reaches it: the nearest cards come up in warm, slightly overexposed candle colour, the light reddens and fades as it travels, and the far side of the layout stays in the dark.

Read the full effect overview

Every element you mark casts a soft shadow pointing away from the flame. Elements close to the lantern throw short, firm shadows; elements further away throw longer, softer ones. The flame never sits still, so neither does anything it lights: the light breathes and gutters on a noise-driven flicker, now and then caught by a draught, and the shadows tremble with it.

The pumpkin is never quite still. It turns a little to look at the pointer, and when you pick it up it hangs from its stem and swings as you carry it, trailing its direction of travel, while the glow in its carving shimmers and leans against the motion. The light and every shadow follow it live, and when you let go it sets down with a small bounce and rocks to a stop. Bring the pointer close and the candle flares: the carving runs hot, a halo blooms around it and the light reaches further. Press it and the candle gutters out, a curl of smoke rises and the page drops to moonlight; press again and a match-strike flare relights it.

Jack-o'-Lantern Light - GSAP animation effect preview

What's included

14 items
  • A real photograph of a lit jack-o'-lantern with true 3D form: three.js lays it over a depth relief, so it turns, tilts and swings like an object, and straight on at rest it is the untouched photograph
  • The carving is alive: its glow pulses with the candle's flicker, shimmers like heat over a flame, runs hot with a growing halo on hover, goes black when blown out and flashes on the match strike
  • The lantern is the page's light source: a colour-dodge light map lifts moonlit content back to full, warm candle colour, strongest at the flame and reddening with distance
  • Projected shadows for every [data-lantern-lit] element, pointing away from the flame, longer and softer with distance, with per-element height
  • One noise-driven candle flicker with occasional draughts, shared by the carving glow, the page light and the shadows so everything trembles together
  • Carry it with mouse or touch: it hangs from its stem and swings with your movement, the light and shadows follow live, and it bounces and rocks to a stop when set down
  • Turns gently to face the pointer, with a barely-there idle sway
  • Blow it out and relight it: a last gutter of flicker and a curl of smoke into moonlight with the carving gone black, then a match-strike flare back to a steady flame
  • Opens in moonlight and strikes the candle on load, or starts lit with one attribute
  • Graceful fallback: without WebGL, without three.js or with reduced motion, the same photograph is shown flat with the same light, drag, keyboard and candle
  • Small canvas, pixel ratio capped, idle redraws throttled; turning shades the side that faces away and catches a moonlit rim, without changing the photograph at rest
  • Sleeps entirely off screen, in hidden tabs and while the candle is out
  • Keyboard: the lantern is a real toggle button; arrow keys move it, Enter or Space blows the candle out or relights it
  • Small API: moveTo, setLit, on and revert, plus data attributes for flicker, colour, shadow strength, reach and 3D form

Perfect for

5 use cases
  • Halloween and autumn landing pages, product grids and sale pages
  • Event listings for late openings, ghost walks and seasonal nights
  • Restaurant, bar and café menus for October
  • Seasonal campaign pages for homeware, candle and gift shops
  • Portfolio and studio sites that want one playful, physical moment in October

How it works

4 sections

The page is darkened to moonlight by one multiply layer. Above it, a radial colour-dodge map is centred on the flame: dodge undoes the moonlight in proportion to how strongly the candle reaches each spot, so near the lantern the content is restored to its own colours and a little past them, and far away it stays dark. The map is drawn once at a small size and only ever moved and scaled with a transform, so the flicker never repaints it.

Each marked element gets a shadow plate under it, softened once when it is created. A flat element raised above the page under a point light projects to itself scaled about the light, so a single translate and scale per element per frame is the whole shadow model; the firm plate fades into a wider soft one as distance grows.

The pumpkin is the photograph laid over a finely divided relief, raised by a depth map baked from the cut-out: a rounded bulge from each point's distance to the silhouette, faint relief from the photo's own light, and the stem set back on the body. three.js draws it in a small transparent canvas on the lantern button with a camera that never turns, so at rest the relief projects onto exactly the photograph's pixels. Turning reveals the form, darkens the side turning away and catches a cool rim. The carving glow, the candle-out version and the halo are the same baked layers the page uses, mixed by the same candle values, so the 3D and flat versions always agree. Its swing, its turn toward the pointer and the shimmer's lean are simple spring physics in the script's own frame loop, and the page light follows the flame as it swings.

GSAP's ticker drives that loop and the flicker, and GSAP tweens carry the drag follow, the lift and squash, the hover flare, the guttering blow-out and the match-strike relight. GSAP's media queries switch to the flat photograph and a gentle breathing light under reduced motion.

Difficulty Advanced
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this effect's demo, from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Paid effect

Purchase to unlock the code.

Buying Jack-o'-Lantern Light opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£10 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £99, one payment.

Documentation

Quick Start

1. Add to your HTML <head>:

Code snippet omitted: it ships with the download.

2. Add before the closing </body> tag. three.js loads as an ES module through an import map; the small module script then loads the effect, and loads it anyway if three.js fails, so the light still runs with the photograph.

Code snippet omitted: it ships with the download.

Already using three.js as a module on your page? Assign it to window.THREE before script.js runs and drop the import map. Want only the photographic lantern? Leave three.js out entirely and load script.js with a plain <script> tag; or set data-three="false".

3. Wrap the content to be lit, and put the lantern inside it:

Code snippet omitted: it ships with the download.

The lantern can sit anywhere inside [data-lantern-light]: where it renders is where it rests. In the demo it sits in an empty grid cell among the products.

Using It With Your Own Design

What the effect needs from your markup:

  • [data-lantern-light]: the area that is lit. Everything inside it is in moonlight except where the candle reaches. The script adds its light and shadow layers inside this element.
  • [data-lantern]: the lantern, which should be a <button> so it is focusable and toggles with Enter and Space. Give it an aria-label and, ideally, an aria-describedby that explains it can be moved with the arrow keys.
  • [data-lantern-body]: a wrapper inside the button holding the images. It is what lifts, swings and squashes; the contact shadow and floor glow stay on the ground beneath it.
  • data-lantern-depthmap on the button: the depth map for the 3D lantern (assets/img/lantern-depth.webp, white is nearest). Without it the photograph stays flat. The script adds a .lantern-canvas inside the button, sized to the button plus room to swing, and uses the images below as its textures; they also give the button its size and are the fallback.
  • [data-lantern-img="lit"] is required. unlit (shown when the candle is out), glow (the carving running hot) and bloom (the halo) are optional; leave any out and that part simply does not happen.
  • data-lantern-origin="x y": where the flame is, as percentages of the lantern image. 55.6 63.2 is right for the bundled photograph; change it if you swap the image. The 3D lantern uses the same resting point and moves the light from there as the pumpkin swings.
  • [data-lantern-lit]: any raised element that should cast a shadow. Give one a different height with data-lantern-depth (pixels; 0 turns its shadow off). Unmarked content is still lit; it just casts no shadow.
  • [data-lantern-cue] (optional): a hint that fades out the first time the lantern is moved.

What is only the demo's styling: the whole shop: the grid, cards, type, palette, the intro copy and the product photographs. Replace it wholesale. The cue pill's look is demo styling too.

CSS the effect depends on (all under "Effect layers" in style.css):

  • [data-lantern-light] needs position: relative, isolation: isolate and overflow: hidden. Isolation keeps the light's blend modes inside the section; without it they would blend with the rest of your page.
  • The moonlight is the ::after of [data-lantern-light] under .has-js. Its colour is --lantern-moon (default rgb(66, 70, 88)): lighter is a brighter night, bluer is colder.
  • Lay the lit area out in mid-tones, not near-black. The light reveals what is there, so a black ground has nothing for it to reveal and nothing for shadows to fall on. The demo uses a warm mid-brown ground (--lit-page) and slightly lighter cards (--lit-surface) under .has-js, and keeps dark colours for the no-JavaScript page. Check text contrast against these mid-tones.
  • .lantern-map, .lantern-air, .lantern-shadows, .lantern-shadow*, .lantern-contact, .lantern-spill and .lantern-smoke style the generated layers. Keep their positioning, blend modes and will-change; the shadow plates' colours and softness can be tuned.
  • [data-lantern] needs a z-index above the light layers (it is the source, so it is never dimmed) and touch-action: none so a touch drag moves the lantern instead of scrolling the page. Size it with width.
  • .is-live [data-lantern-img] { visibility: hidden } hides the flat photograph once the 3D lantern has drawn, without collapsing the button. Both draw the same pixels at rest, so the swap is invisible. .lantern-canvas must stay position: absolute and pointer-events: none.
  • .has-js [data-lantern-img='lit'] { opacity: 0 } lets the page open in moonlight before the candle is struck. Without JavaScript the class is never added and the lit lantern shows.

Options

Set these on [data-lantern-light].

Attribute Values Default Description
data-flicker 0 to 2 1 Flicker strength. 0 is a steady flame; 2 is a draughty room
data-color Hex colour #ffae5c Candle colour. It sets how the light warms as it falls off: channels low in the colour fade first
data-shadow-strength 0 to 2 1 Shadow opacity. 0 turns shadows off
data-reach 0.4 to 2.5 1 How far the light carries before the page falls to moonlight
data-depth Pixels 16 Default height of [data-lantern-lit] elements above the page. Higher throws longer shadows
data-toggle true, false true Whether pressing the lantern blows the candle out and relights it
data-intro true, false true Open in moonlight and strike the candle on load
data-three true, false true Give the pumpkin 3D form when three.js and WebGL are available. false keeps it flat

On [data-lantern-lit]: data-lantern-depth overrides the default height for that element.

Accessibility

  • Keyboard: the lantern is a real <button> with aria-pressed reflecting whether the candle is lit. Arrow keys move it (Shift for bigger steps), Enter or Space blows the candle out or relights it. Focusing it gives a gentle flare so the focused state is visible beyond the focus ring.
  • Touch: drag the lantern with a finger; a tap toggles the candle. Only the lantern captures touch, so the rest of the page scrolls normally.
  • Reduced motion: the pumpkin stays a flat photograph, the flicker becomes a slow, gentle breath, the lantern moves without swing or squash, and the candle fades out and back in without the gutter, smoke or flare. The light and shadows still follow the lantern.
  • Readable content: the light and shadows are visual layers only. Text stays in the DOM, and even the furthest content stays legible in the moonlight. The demo's colours meet contrast against the page's own surfaces.
  • No JavaScript: the moonlight is never applied, the content shows at full brightness and the lit photographic pumpkin sits in its place.
  • No WebGL or no three.js: the flat photograph is used, with the same light, shadows, drag, keyboard and candle.

Performance

  • Per frame the script writes only transforms and opacities, on layers that were drawn once. The light map is drawn small and scaled up, and the shadow plates are softened once when they are created, so the flicker never re-rasterises a blur.
  • The 3D canvas is only the lantern's box plus room to swing, with the pixel ratio capped at 1.5. While nothing moves it redraws the flicker at about 30 fps; while the pumpkin turns, swings or is carried it draws every frame. The page's light layers update at up to 60 fps when idle.
  • Measured in headless Chrome on an Apple M1 Pro GPU at 1440×900, DPR 2 (main-thread time per 5 seconds): lit and idle about 0.18 s (0.16 s with data-three="false"), dragging continuously about 0.55 s, candle out 0 to 0.02 s, off screen about 0.02 s.
  • Everything stops when the section is off screen, when the tab is hidden and while the candle is out and nothing is moving.
  • The first lever to lower: data-three="false" (photographic lantern, no WebGL at all), then data-flicker="0".

Browser Support

The 3D form needs WebGL and ES module support (every current browser). The script probes WebGL before creating a renderer, and handles a lost context by falling back to the photograph until the context is restored.

Images

The pumpkin is a photograph by Mátyás Varga on Pexels (Illuminated Carved Pumpkin), used under the Pexels licence. The bundled files in assets/img/ are cut-out, art-directed derivatives: the lit pumpkin, a candle-out version, the carving on its own, its halo, and a depth map hand-built from the cut-out (an ellipsoid bulge from the distance to its edge, faint relief from the photo's own light, and the stem set on the body).

The product photographs (pendant lamps, stoneware bowls, lounge chair, candle table and cane chair) are Pexels photographs baked to graded WebP derivatives. They are demo content; replace them with your own.

To use your own lantern, cut it out on a transparent background, export the lit version, and set data-lantern-origin to the flame's position. The unlit, glow and bloom layers are optional extras. For 3D form, supply a greyscale depth map of the same framing (white nearest, black at the silhouette, softly rounded); a depth estimation model's output works, or a blurred, rounded version of the cut-out's alpha. Keep it smooth: sharp steps tear the photo when it turns.

Dependencies

Library Role
GSAP 3.12+ (demo: 3.15.0), core only The ticker that runs the flicker and drives every frame, the tweens for the drag follow, lift and squash, the hover flare, the blow-out and the match strike, and the reduced-motion switch
three.js r180 (demo: 0.180.0), optional Draws the photograph on its depth relief, with the carving glow, heat shimmer, halo and turn shading. The swing, the turn toward the pointer and the shimmer's lean are computed in the script's own frame loop, not by GSAP

No GSAP plugins.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.