NOIRKIT · the floor

The floor

Theme, effects, components, and the roll. Hover a frame. It lifts. Press roll and the picture goes black, then the next screen comes up on the same tape.

Effects

Grain
Grainstepped, not a blur
Flicker
Flickerthe lamp, not a glitch
Falloff
Vignettethe corners fall off
Case Closed
Stampone red stamp

Hover

Hover a frame. It lifts. Nothing glows.

Stopthe cap button, on the page
Filed
Stampthe only red
Exhibit 07
Markerthe box on the footage
No. 1
Sony
$500
Suspectthe photo lifts
08Sony WH-1000XM6$500
Case file linename and price turn paper-white

Transition

One strip. The frame leaves, a soft black tail, then the next picture. Sprocket holes ride with it.

Reel 1
Live
The walk
The Usual
Suspects
Reel 2
Picture, black, picture.
NOIRKIT

Start here

This page uses the real noir.css and noir.js. The numbers come off the stylesheet. If it looks right here, it looks right on the dashboard.

  1. Link noir.css and copy the fonts/ folder next to it.
  2. Copy the markup from demo.html (everything above the demo driver) into the Flask template. Swap the demo canvas for <img id="frame" class="feed-img" alt=""> and the fake QR for the server's QR image.
  3. Add <script src="noir.js"></script><script>Noir.connect('/state.json')</script>. That's the whole integration.
  4. Build the three backend routes in BUILD-GUIDE.md §4.2: a clean /frame.jpg, /state.json, /crop/<n>.jpg.

If the kit doesn't cover it, ask one question. Would this exist in a 1950s police station, or on 1950s film? If not, it doesn't ship. The reasons are in README.md.

Conditional motion rehearsal: loading, slow responses, camera loss, reconnection, new observations, debriefs, and confirmed/failed actions. Simulated data only; no rig commands.

02

The screens

Previews of demo.html, jumped to each state. Open it and press ? to run the real sequence.

Title cardidle

Job: the whole idea in five seconds, with nobody talking.

Live walk/

Job: footage, the take, the ledger, the header. That's the screen.

Reveal/reveal

Job: five suspects, one total, one stamp.

Footage lostcamera_ok: false
Line deadrig unreachable
Case file/manifest

Job: a page you can scan, read on a phone, or print.

On a phone

03

Color

Black and white, plus one red. The red is only a rubber stamp. Never on text, chrome, or a button. Contrast is measured live. Ink for the screen, paper for the document.

04

Type

Four faces. League Gothic is the headline (Alternate Gothic, 1903). Special Elite is typed onto the form. Courier Prime is the form. Caveat is one pencil note per screen. Sizes are computed at this window.

Cut-paper lettering

Add class="cut" and noir.js tilts each letter, up to 2.5°, with a fixed baseline shift. It doesn't shimmer. Titles only. Numbers and names stay straight.

Plain.t-view
The Usual Suspects
Cut.t-view.cut
The Usual Suspects
05

Scale & space

Every size is a multiple of --u. 1px up to a 1440px screen, then it grows (1.8px at 2592). 1440 is the reference. A 4K projector gets the same layout, larger. Right now --u is .

TokenValueUse
--r-frame 2px · --r-stamp 3px0 to 3px, nothing rounderFeed frame and QR mat 2px, stamps 3px, everything else square. Cut paper and card stock.
--rule1pxEvery hairline. smoke by default, bone where it must read at a distance.
--z-*Title card under the curtain, the curtain under the film texture. Grain and flicker always sit on top: it's still the same film.
06

Motion

Cuts, dissolves, freeze-frames. Nothing slides. Numbers don't bounce. Loops run on twos, about 12fps, with steps(). Change a duration token and the CSS and noir.js both follow.

AnimationWhat changesDurationEasingTrigger
Stage Afeed
Stage Bledger & counter
Stage Cstamp & lineup

From the button press: the feed settles () while the curtain is already dissolving (). The lineup fades up (). The next suspect starts before the previous one has landed (every , rank 5 to rank 1). The total rolls as the last photo settles. The stamp lands while that roll is finishing. Reduced motion turns the texture off and finishes every animation at once. The content still shows.

07

Components

Every component, every state. Markup is the HTML. The log, the counter, and the lineup are filled by noir.js.

Chrome

Headerrig answering
Case NO. 1138 · The Appraisal Job
FR 00:14:32:08  ·  ● REC○ LINE DEAD
Headerbody.offline
Case NO. 1138 · The Appraisal Job
FR 00:14:32:08  ·  ● REC○ LINE DEAD

Feed

Footagewith markers
Exhibit 01"VINTAGE ROLEX" · $4,200
Exhibit 02"LEICA M3" · $1,850
Footage lost.feed.lost
Footage Lost
Roll A · Cam 01 · reconnecting...
Line deadNoir.setOffline(true)
Line Dead
Rig unreachable · redialing...

Evidence marker

Default.marker
Exhibit 07"WATCH, WRIST" · $4,200
Top 5 callout.marker.hot (800ms pulse)
Exhibit 07"WATCH, WRIST" · $4,200
Long name, estimatetruncates at 38ch
Exhibit 06"DIAMOND RIVIÈRE NECKLACE, 18K WHITE GOLD, APPRAISER'S CASE" · $1,275,000 est.

Exhibit log

Every line state.log
EXHIBIT 01: "VINTAGE ROLEX"$4,200.00
EXHIBIT 02: "SILK SMOKING JACKET"$420.00est.
EXHIBIT ??: UNIDENTIFIEDNO APPRAISAL
EXHIBIT 03: "DIAMOND RIVIÈRE NECKLACE, 18K WHITE GOLD, APPRAISER'S CASE"$1,275,000.00est.
> LINE TO THE RIG IS DEAD. REDIALING...
EXHIBIT 04: "BRASS DESK LAMP"$180.00
> EXAMINING EXHIBIT 05...

Top to bottom: older lines (ash), estimate, unidentified, truncated long name, system line, newest line, pending with caret.

Emptybefore the first scan
> SCENE STABLE. AWAITING TARGETS...

Odometer

Running take.odo · Noir.makeOdo(el).set(n)
Huge takeshrinks via --odo-k, never overflows

Stamps

On screen--stamp-lit
Case Closed
Zero suspects--stamp-lit
Case Unsolved
On paper--stamp, multiply
"SILK SMOKING JACKET" ...... $420.00
Evidence
Filedsmall, on paper
Filed 09/26/2026

Lineup slot

Filled · estimate · long name · vacant.suspect, filled by Noir.runReveal()
Suspect NO. 4
First-ed. Hemingway
APPRAISED: $950
Suspect NO. 3
Silk Smoking Jacket
APPRAISED: $420 est.
Suspect NO. 2
Diamond Rivière Necklace, 18K White Gold, Appraiser's Case
APPRAISED: $1,275,000 est.
NO. 1 · Vacant
NO SUSPECT
Markup

Case file

Rowsnormal · estimate · long · total
"VINTAGE ROLEX"$4,200.00
"SILK SMOKING JACKET"$420.00est.
"DIAMOND RIVIÈRE NECKLACE, 18K WHITE GOLD, APPRAISER'S CASE"$1,275,000.00est.
TOTAL TAKE$1,279,620.00
Emptynothing recovered
NO EXHIBITS RECOVERED
TOTAL TAKE$0.00

Projection

These make the screen act like a reel in a 1950s projector. The leader is the Academy leader, 1930 to the mid-1960s: a number in a circle, one per foot of film, NINE and SIX spelled out. The sweep-hand countdown people picture is the 1965 SMPTE leader. That's a decade late, so the kit doesn't use it.

Leader frame.leader
8
Spelled out.leader-n.word
SIX
Picture start.reel-start
Picture
Start
Changeover cue.cue, 4 frames

Top right, as reel 1 ends. That's the button press.

The end.the-end, after every run
A RowdyHacks XII Picture
The End
Case No. 1138 · Closed

Small parts

File copyQR on its paper mat, always
Scan this. It's the file.
Marginalia.note · one per screen
the good stuff's never on the first shelf.
Labels.label · .meta
Estimated Take
Items: 07 · Room 3 · Exhibits wing
08

State matrix

Every state the app can hit, where it's handled, and the demo.html key. If the rig can produce it, it has a design.

StateWhat the room seesTriggered byDemo key
BootAcademy leader: PICTURE START, then 8 to 3, then the title cardPage load (Noir.connect() runs it)reload
IdleTitle card, cycling credits, blinking prompt15s with no new exhibit (--idle-after)T
ScanningLedger types > EXAMINING EXHIBIT 05... with a caretpending: trueL
New exhibitTyped line, then the marker, then the odometer ticksA new entry in itemsL
Top-5 exhibitMarker tag pulses once (with the speaker callout)The new item ranks in the top fiveL
Estimated priceest. after the amount, everywhereestimated: trueL (jacket)
No bboxLedger line only, no markerbbox missing or dropped by validation(automatic)
UnidentifiedEXHIBIT ??: UNIDENTIFIED, struck throughThe LLM returns nothing usableU
Long nameEllipsis in the ledger and marker, 2 lines in the lineup, wraps on paperVerbose LLM outputB
Huge takeOdometer shrinks to fit (--odo-k)7+ digit totalsB
Camera lostFOOTAGE LOST slate; ledger and take staycamera_ok: falseF
Rig unreachableLINE DEAD slate, ○ LINE DEAD in the header, a system line in the ledger3 failed polls in a row (about 1.5s)W
Reveal, 5 suspectsFreeze, dissolve, lineup, total, CASE CLOSEDrevealed: trueR
Reveal, 1 to 4Empty ranks stand VACANT; subtitle ONLY THREE SUSPECTS BROUGHT INFew items3
Reveal, noneNO SUSPECTS, $0, CASE UNSOLVEDZero items0
Run finishedTHE END card, then the title card; the case number advances (1138 to 1139)revealed goes back to falseL after R
Case filePaper document; scrolls on phones; prints clean/manifestM
Reduced motionNo texture, no animation, all content presentOS setting(OS)
Screen readerEach exhibit and the verdict announced once#log-sr, #reveal-sr(automatic)
09

Projector test card

Run this on the venue screen before the demo. Projectors crush dark greys. If ink and carbon merge, or the four near-black patches look the same, raise the black level until you can see every step. Then check the smallest line from the back of the table.