# Ceiling Fan Wipe — `ceiling-fan-wipe@1.0.0`

The overhead ceiling fan transition from TikTok: a slowly turning fan right under the camera, and every time a blade sweeps across, the picture below has changed.

The ceiling fan trend, rebuilt as a transition you can reuse. The camera looks straight down past a ceiling fan; each time a blade passes over the subject, the look underneath changes, and the cut is always hidden under the blade. The fan is drawn entirely in code: wood-grain or painted blades on metal blade irons, a brass, nickel, black or white motor cap, real motion blur, a soft focus because the blades are close to the lens, and a soft shadow on the floor. Choose the number of blades, the finish, how often the look changes, which way it turns and whether the new look follows the blade (sweep) or appears at once (cut). The demo wipes between four floors under window light; in your project the looks can be anything you can draw: outfits, products, photos, video frames or other ingredients.

- Kind: effect; status: published; digest sha256:963098383927f554ed6a9e3c64e0d25aef104bed4b6484490e1814f4655ab17a
- Role: Full-frame transition (Canvas 2D): switches between looks you draw, hidden behind a moving ceiling fan in the foreground.
- Implementation: canvas2d; entry `src/ceiling-fan-wipe.js`
- Files: https://aipixelwizard.com/registry/ceiling-fan-wipe/1.0.0/<path> (`LICENSE`, `asset.json`, `demo.js`, `index.html`, `src/ceiling-fan-wipe.js`)
- Manifest JSON: https://aipixelwizard.com/api/v1/visuals/ceiling-fan-wipe/versions/1.0.0
- Runnable demo: https://aipixelwizard.com/registry/ceiling-fan-wipe/1.0.0/index.html (open over http; it imports sibling packages by relative path)
- Dependencies (exact): `apw-runtime@1.0.0` (demo) — Demo harness and seeded random numbers for the floors. src/ceiling-fan-wipe.js has no dependencies.

## Exports
- `createCeilingFanWipe({ blades?, hub?, hubSize?, reach?, bladeWidth?, finish?, metal?, passes?, direction?, shutter?, samples?, focusBlur?, shadow?, shadowOffset?, lightAngle?, subject?, mode?, seed? }) => { draw(ctx, info, width, height, drawLook), drawFan(ctx, info, width, height), angleAt(time, duration, width?, height?), lookAt(time, duration), passes, blades }` — Canvas 2D transition. draw() calls drawLook(ctx, index, info, width, height) for the looks it needs (the current one and, while a blade is crossing, its neighbours, clipped along the blade), then draws the fan shadow, blurred blades and motor cap on top. lookAt() tells you which look is at the subject, for syncing sound or captions.

## Parameters
- `finish` (select one of oak | walnut | black | white, default "oak") — Blade finish
- `metal` (select one of brass | nickel | black | white, default "brass") — Motor and arms
- `blades` (integer 3–6, default 5) — Blades
- `passes` (integer 4–24, default 8) — Changes per loop: How many times a blade passes and the look changes in the 8-second loop. 8 is one change a second.
- `hub` (select one of corner | centre, default "corner") — Fan position: Corner: the hub sits in the top-left corner and the blades sweep diagonally across. Middle: the fan hangs over the centre and the whole picture cuts as a blade crosses the subject.
- `wipe` (select one of sweep | cut, default "sweep") — Change style: Sweep: the new look follows the blade across the frame. Cut: the whole picture changes the moment a blade covers the subject. With the hub in the middle it always cuts.
- `direction` (select one of clockwise | anticlockwise, default "clockwise") — Turning
- `motionBlur` (number 0–1, default 0.5) — Motion blur: Blur along the turn, as a fraction of a frame. 0 is razor sharp.
- `softness` (number 0–12, default 3) — Blade softness: Out-of-focus blur on the fan, because it is close to the lens (pixels at 1080).
- `shadow` (number 0–0.8, default 0.35) — Shadow on the floor
- `captions` (boolean, default true) — Captions: Number and name each look in the corner, lookbook style.
- `seed` (integer 1–9999, default 3) — Variation: Changes the wood grain and the floor details.

## Composition
- Inputs: Canvas 2D context, width, height, info from the harness, and a drawLook(ctx, index, info, width, height) callback that fills the frame with look number index (it may be negative or past your count; wrap it).
- Outputs: Opaque frame: the looks underneath, the fan shadow, then the blades and motor cap.
- Coordinates: hub and subject are fractions of width and height from the top left; sizes are fractions of the shorter side. Angles in radians, clockwise on screen.
- Lighting: The fan carries its own light: a sheen on the blades that brightens as they turn toward the light direction (lightAngle), lit blade edges, a metal cap with a glint, and a soft floor shadow offset by shadowOffset. Match lightAngle and shadowOffset to the light in your looks.
- Timing: Pure function of info.time and info.duration. The look index changes exactly when a blade centre line crosses the subject; lookAt(time, duration) returns it, starting at 0.
- Works with: gradient-background, kinetic-title, dither-animation, stop-motion-feel, particle-tunnel
- Sweep needs the hub near a corner or edge, so only one blade crosses the frame at a time. With the hub in the middle use mode cut.
- drawLook may be called up to three times a frame while a blade crosses; pre-render static looks to canvases like the demo does.
- Motion blur draws the blades once per sample (8 by default) into an internal layer; lower samples for a faster live preview.

## Output and loop
- 1080×1080, 30 fps, 8 s, procedural
- Seamless loop: yes — The fan turns a whole number of blade spacings per loop (Changes per loop) and every blade is identical, so the last frame meets the first. Changes per loop is always a multiple of 4, the number of demo looks, so the loop also ends on the look it started with.
- Verified 2026-10-03 in Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0 (Canvas 2D); deterministic: yes; loop check: Frame 0 vs end state (progress 1): mean |Δ| 0.0000, max |Δ| 0 of 255.

## Use it
New project: Create the transition once with createCeilingFanWipe(options). Each frame call fan.draw(ctx, info, width, height, drawLook), where drawLook fills the frame with your look number index.

Existing project: Copy src/ceiling-fan-wipe.js. Move your current frame drawing into drawLook, branching on the index, and call fan.draw(...) instead; or draw your scene as usual and call fan.drawFan(ctx, info, width, height) at the end for the fan without the wipe. info needs time, duration and fps.

Reuse ideas:
- Lookbook reel: make drawLook draw photo or video frame number index of your outfits, set passes to the number of outfits (or a multiple of it) and use lookAt to put the right caption on each.
- Colourway reveal: draw the same product shot from above in four colours, or four presets of Soft Moving Gradient with Kinetic Title Reveal on top, and let the fan wipe between them.
- Use drawFan alone over any scene for the overhead fan as a foreground layer, then run Dither Animation's applyToCanvas over the result for a lo-fi version of the trend.

## Limitations
- It is the transition and the fan, not the person: the outfits, products or photos underneath are yours to supply (the trend itself uses AI to restyle one photo).
- Seen only from straight under the ceiling; there is no tilted or perspective camera.
- Sweep assumes the hub sits near a corner or an edge; with the hub in the middle use cut, as real edits do.
- Blur uses the canvas filter property; browsers without it (Safari before 18) show sharp blades and a hard shadow.

## License
MIT. Copyright (c) 2026 AI Pixel Wizard. Released under the MIT License. See LICENSE in this folder.

Provenance: Original code written for AI Pixel Wizard on 2026-10-03 by an automated agent (the daily trend routine), inspired by the AI ceiling fan transition trend on TikTok and Reels (see content/trends/2026-10-03-ceiling-fan-wipe.md). The blade-as-wipe idea is the trend itself, as described by The Tab (https://thetab.com/2026/09/28/how-to-do-the-vibey-ai-ceiling-fan-trend-from-tiktok-where-your-outfit-changes) and Pixazo (https://www.pixazo.ai/trending/fan-transition-trend); the fan, wood grain, motion blur, wipe geometry and floors are generated by this code. No code, images, fonts or shaders were copied.

