# CCTV Night Cam (Security Camera Footage) — `cctv-night-cam@1.0.0`

Makes any animation look like a security camera recording at night: wide-lens bulge, choppy frame rate, grain, blocky compression, a running timestamp, REC and a motion-detection box.

The look behind the AI 'caught on camera' and found-footage horror clips that fill feeds every October. Whatever you draw goes through a cheap night-time security camera: the wide lens bulges the middle of the picture, the picture turns black-and-white infrared (or green night vision, or washed-out colour), fine detail goes soft but edges get the camera's over-sharpened halos, grain climbs as the auto-gain fights the dark, shadows break into blotchy compression blocks and lights bloom. The camera runs at a choppy 8–15 frames a second and now and then stalls on a frame. On top, the recorder's display stays crisp: date and a ticking clock, a blinking REC, the camera number and its name, and a motion box that blinks when something appears. The demo watches an empty corridor from a camera high in the corner at 3 a.m.; the lights cut out twice, and each time they come back a tall figure stands closer. Choose the place (Backrooms, office, hospital ward), the look, the date, time, camera name and how cheap the camera is.

- Kind: effect; status: published; digest sha256:d306e71094d774d74f3f0bc16c5bcc221d7ee61b149e4688514e99807aa59aa8
- Role: Full-frame finishing effect (Canvas 2D) plus a recorder display, a motion-detection box and a camera frame-rate helper.
- Implementation: three; entry `src/cctv-night-cam.js`
- Files: https://aipixelwizard.com/registry/cctv-night-cam/1.0.0/<path> (`LICENSE`, `asset.json`, `demo.js`, `index.html`, `src/cctv-night-cam.js`)
- Manifest JSON: https://aipixelwizard.com/api/v1/visuals/cctv-night-cam/versions/1.0.0
- Runnable demo: https://aipixelwizard.com/registry/cctv-night-cam/1.0.0/index.html (open over http; it imports sibling packages by relative path)
- Dependencies (exact): `liminal-corridor@1.0.0` (demo) — The demo films this corridor from a fixed corner camera. src/cctv-night-cam.js has no dependencies and works on any 2D canvas.; `three@0.185.1` (demo) — Renders the demo's corridor.; `apw-runtime@1.0.0` (demo) — Demo harness.

## Exports
- `createCCTV({ look?, fisheye?, softness?, sharpen?, noise?, compression?, bloom?, autoGain?, vignette?, seed? }) => { apply(ctx, width, height, info), lensPoint(x, y, width, height) }` — The camera. apply() reads the 2D canvas and replaces it with the recording: lens bulge, auto-gain, soft but over-sharpened picture, grain, compression blocks, bloom and the colour look. lensPoint() tells you where a scene point lands after the lens, for boxes and labels.
- `cameraTime(info, { fps?, hiccups?, seed? }) => { ...info, time, frame, fps, sourceFrame }` — The recorder's choppy frame rate with the odd stalled frame. Draw your scene at the returned time and pass the result to apply() and the overlay.
- `drawCCTVOverlay(ctx, width, height, info, { date?, clock?, camera?, label?, rec?, color?, recColor?, scale? })` — The recorder display: date and running clock top left, blinking REC top right, camera number bottom left, its name bottom right, in a blocky outlined recorder font.
- `drawMotionBox(ctx, { x, y, w, h }, info, { label?, color?, blink?, scale? })` — A motion-detection box: thin frame, heavy corner brackets and a label tag. Blinks while blink is true.
- `drawPixelText(ctx, text, x, y, { cell?, color?, outline?, tracking?, align? }) => width` — Any text in the built-in 5×7 recorder font (A–Z, 0–9, : - / . # ! ') with a dark outline.
- `measurePixelText(text, cell, tracking?) => width` — Width of text in the recorder font, for layout.

## Parameters
- `place` (select one of backrooms | office | hospital, default "backrooms") — Demo place: Which corridor the camera watches. Your own project can put anything through the camera.
- `look` (select one of ir | green | color, default "ir") — Camera look
- `figure` (boolean, default true) — Something in the hallway: The figure that appears after each power cut. Turn off for an empty corridor.
- `motionBox` (boolean, default true) — Motion box: The recorder's box around the figure, blinking when it first appears.
- `date` (text, default "2026-10-31") — Date: Shown top left. Letters, numbers, spaces and : - / . work.
- `clock` (text, default "03:14:07") — Start time: HH:MM:SS. The seconds tick on as the clip plays.
- `camera` (text, default "CAM 04") — Camera number
- `label` (text, default "HALLWAY B") — Camera name: Shown bottom right. Leave empty to hide it.
- `rec` (boolean, default true) — Blinking REC
- `cameraFps` (integer 5–30, default 12) — Camera frame rate: Security recorders store few frames a second; lower is choppier.
- `fisheye` (number 0–1, default 0.6) — Wide-lens bulge
- `noise` (number 0–1, default 0.5) — Grain: Sensor grain. It climbs on its own when the picture goes dark.
- `compression` (number 0–1, default 0.55) — Compression blocks: How blotchy and blocky the shadows get.
- `softness` (number 0–1.5, default 0.7) — Softness: How much fine detail the cheap camera loses.
- `bloom` (number 0–1.5, default 0.6) — Light glow
- `seed` (integer 1–9999, default 4) — Variation: Changes the grain, the stalled frames, the flicker of the faulty light and the corridor's details.

## Composition
- Inputs: Canvas 2D context, width, height and the frame info from cameraTime(). apply() takes whatever is already drawn on the canvas.
- Outputs: apply() replaces the frame with the recording (opaque). drawCCTVOverlay and drawMotionBox draw on top without clearing.
- Coordinates: Pixels. Effect sizes are tuned at 1080 wide and scale with the canvas. The display sits 5.5% in from the edges.
- Lighting: None of its own. Auto-gain brightens dark frames and their grain; bloom makes bright areas glow.
- Timing: Pure function of the camera frame from cameraTime(): grain changes every camera frame and is held on a stalled one; the clock ticks with time; REC blinks once a second.
- Works with: liminal-corridor, vhs-camcorder, rain-window, thunderstorm, glitch-text
- Draw your scene at cameraTime(info).time, not info.time, or the choppy frame rate is lost.
- Draw the display and motion box after apply() so they stay crisp, as a recorder adds them. Use lensPoint() to bend a box measured in your scene so it sits on the bulged picture.
- apply() reads pixels back, so the canvas must be same-origin. For three.js, render to its own canvas and drawImage it onto the 2D canvas first, as the demo does.
- The date and time are plain text you choose; nothing reads the real clock, so renders stay repeatable.

## Output and loop
- 1080×1080, 30 fps, 10 s, procedural
- Seamless loop: no — A ten-second story beat (two power cuts, a figure that comes closer); it does not loop.
- Verified 2026-10-10 in Chrome 154.0.8037.97 headless on Linux 7.0.0-38-generic (x64), Node 22.14.0 (WebGL 2 via SwiftShader (software)); deterministic: yes

## Use it
New project: Create the camera once with createCCTV(options). Each frame: const cam = cameraTime(info, { fps: 12 }); draw your scene at cam.time; cctv.apply(ctx, width, height, cam); drawCCTVOverlay(ctx, width, height, cam, { date, clock, camera, label }); optionally drawMotionBox around something moving.

Existing project: Copy src/cctv-night-cam.js. At the end of your 2D frame call cctv.apply(ctx, width, height, cameraTime(info)), then drawCCTVOverlay. For WebGL, render to its own canvas and drawImage it onto a 2D canvas each frame, then apply there.

Reuse ideas:
- Turn any AI 'caught on camera' clip into convincing security footage: draw each frame of the clip at cameraTime(info).time, apply(), add drawCCTVOverlay with your own date and camera name, and say in the caption that it is fiction.
- Watch Rain on a Window or Thunderstorm through the camera with look 'color' for a stormy-night doorbell-cam shot.
- A horror title card: draw Glitch Text or a plain title, apply() with look 'green', and set the camera name to your film's title.
- A four-camera DVR grid: render four scenes into quarters of the frame, call apply() on each quarter's canvas and give each its own CAM number.

## Limitations
- It degrades what it is given: it cannot make an AI clip's motion believable or fix impossible physics. The camera angle has to be right in the scene you feed it (high, fixed, wide).
- The demo's figure is a flat silhouette: it reads at corridor distance and through the camera, not in close-up.
- The recorder font covers capital letters, digits and a few symbols only; there are no accented letters.
- Footage this convincing can mislead. Label fictional clips as fiction, especially anything that looks like evidence of a real event.

## 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-09 by an automated agent (the daily trend routine), inspired by the AI security-camera and found-footage horror clips of the Halloween season (see content/trends/2026-10-09-cctv-night-cam.md). The list of tells to reproduce (timestamp and camera ID overlay, low resolution and 8–15 fps, grain, compression, lens distortion, high fixed corner angle, low light and fluorescent flicker) follows https://www.topmediai.com/video-tips/ai-cctv-footage/. Barrel distortion, unsharp masking, box blurs and block-wise quantisation are standard image-processing techniques; the code, the 5×7 recorder font and the figure were all written for this package. The demo's corridor is AI Pixel Wizard's own Liminal Corridor 1.0.0, imported unchanged. No code, images, fonts or shaders were copied.

