# Firecrawl motion audit — 2026-10-20

Primary page: https://www.firecrawl.dev/ . Read-only Chromium inspection at 1440×1000. Evidence: hero-t0.png and hero-t2.png (2 seconds apart), per-scroll screenshots + JSON, full.png, reduced.json, dom.html, sources.json (exact deployed chunk URLs). No application files edited.

## Verified inventory

1. **Hero ambient grid / random tiny glyphs.** A transparent 1314×506 canvas around the title is a Pixi renderer with an explicit `preference:"webgl"`, not a CSS noise texture. Runtime instrumentation captured WebGL/WebGL2 context requests. Module 110335 in source-41.js builds 101px cells, flickers cell opacity via short animations, and triggers random glyphs through timeouts. source-38.js only mounts this background for `min-width:996px`. Generic renderer source-45.js sets maxFPS=60 and uses IntersectionObserver to stop/start its ticker when the canvas leaves/reenters the viewport. It tests WebGL support; failure leaves the canvas transparent. The component has `smartStop:false` (so it does not stop merely because the animation task count reaches zero). No reduced-motion branch appears in this component or renderer. **Dealyo proposal:** sparse gray cells with one orange #FE4A23 glyph activation, square geometry. Low/medium complexity as DOM/CSS or Canvas 2D; high if retaining Pixi solely for this decoration. Do not copy the renderer dependency simply to flash a few squares.

2. **ASCII flame / ambient fields behind headings and hero input.** Actual Canvas 2D frame playback. `setupAsciiCanvas` scales for devicePixelRatio; `renderAsciiFrame` calls clearRect, sets Roboto Mono, and draws individual lines with fillText. Hero side flames: source-16.js module 713492, `loadHeroFlameFrames`, interval 85ms, mirrored right canvas. Core heading backdrop uses `loadCoreFlameFrames`, 80ms; other decorations 60–90ms. `useLazyFlameFrames` waits for IntersectionObserver with rootMargin 200px and caches fetched frames. `setFlameIntervalOnVisible` checks `prefers-reduced-motion:reduce`; it stops interval on change, uses `pauseWhenHidden:true`, and its shared helper suspends offscreen/hidden intervals. First frame is drawn before scheduling, so reduced motion retains a static image. **Dealyo proposal:** quiet abstract ASCII data flowing behind a section title or analysis output, orange only for active data. Medium complexity; preserve low contrast and separate text layout, but do not make essential information part of the canvas. Observed static decoration wrappers use pointer-events:none and select-none; these are not universal proof of aria-hidden on every canvas.

3. **Hero product demonstration: moving scan box.** DOM-based rectangle over a browser mockup; source-6.css `.hero-scraping-highlight:before` has a 1s linear infinite border/opacity keyframe. Runtime t0→t2 shows target box moving from left:971/top:89/width:80 to left:184/top:174/width:308; a separate 300ms ease-out animation drives rectangle transforms/layout. This is not WebGL. **Dealyo proposal:** an orange square-corner scan outlines a client website issue and then reveals the relevant result. Medium complexity. Observed caution: this scan and its infinite border blink remain running after `emulateMedia({reducedMotion:'reduce'})`; add an explicit static reduced-motion state.

4. **Pixel icons beside Search/Scrape/Map/Crawl.** 20px and 28px Canvas 2D icons, drawing small fillRect grids with alpha transitions, not image sprites. source-37.js has activate/deactivate handlers for mouseenter/mouseleave; selected/active icons can activate at IntersectionObserver threshold .5. Several routines deliberately execute a bounded 2–3 cycle sequence. Loading icon in source-29.js uses a 16-cell 20×20 canvas plus rAF and short opacity changes. **Dealyo proposal:** own square 4×4 symbols, #FE4A23 on active state, brief activation on hover/focus. Low complexity in SVG/CSS (canvas unnecessary at this scale). Not all icon routines contain an explicit reduced-motion check; do not generalize the flame helper behavior to these icons.

5. **Live web data / cache-to-web routing.** DOM/SVG diagram. Outer cache/web wrapper CSS rotation lasts 32s; child icons counterrotate with the same duration to remain upright. Runtime lists `animate-spin`, `animate-spin-reverse`, transitions for translate/width/height/opacity/filter, plus a 500ms Firecrawl node animation. **Dealyo proposal:** square nodes explaining input → analysis → action, orange pulse moving along a connector. Medium complexity. At hero scroll position these far-below-fold CSS animations already report running; they remain running in reduced.json. Add viewport pausing and reduced-motion static paths.

6. **Alexandria knowledge-library scene.** DOM `<pre>` layers, not canvas or WebGL. source-37.js module uses far/near text frames, updates at 220ms with setIntervalOnVisible, checks document.hidden, and reverses frame direction at ends. Fine-pointer parallax transforms near/far layers, up to approximately 10px horizontal / 5px vertical, with the far layer at .35 of near. CSS source-7.css adds a 7s alternate illumination opacity animation (.55→.95) to the far layer. Reduced-motion branch renders frame 0; pointer move handler exits for reduced motion; CSS turns the far-layer animation off. Runtime reduced.json no longer includes its 7s illumination animation. Wrapper has aria-hidden=true. **Dealyo proposal:** restrained typographic/ASCII process landscape beside a large claim, square orange active block. Medium/high complexity; screen-reader-hidden decoration and static reduced frame are good patterns to retain.

7. **Testimonial marquee / continuous proof strip.** Runtime records two 45s linear infinite DOM translate animations on testimonial rows; source-29.js duplicates children and animates the track. Mouseenter interpolates playbackRate toward 0 over .4s; mouseleave restores 1. Offscreen tracks are still reported running at the initial hero position. They also remain running under reduced motion. **Dealyo proposal:** static 2–3 client proof cards or one restrained row with a pause control; low complexity. Avoid copying continuous motion without a readable stationary state.

## Limits and evidence quality

- Tested desktop Chromium, not touch/mobile or multiple browsers. Desktop-only conditions verified from JS/CSS; no claim of a complete mobile audit.
- Reduced motion was toggled at runtime after loading and scrolling; this verifies change handling, not every possible initial-load branch.
- getAnimations reports animation states, not CPU/GPU usage. No performance trace or benchmark was run. Several decorative CSS animations stayed running while offscreen; shared Canvas ASCII intervals explicitly pause.
- Captured a React hydration error #418 during initial load. Page content and effects rendered; it could affect minor initial states.
- Browser source chunks are deployment-specific (`dpl_2B1YYmsKFkGJzkbk44qpNDUukqZr`). See sources.json for exact URLs and saved code.
