- Shipped
- August 20, 2026 at 2:28 AM UTC
- Author
- Kamo
- Commit
- 6a63737
"Reduce unused JavaScript" has named the same 35.4 KB chunk in every report, and it is Framer Motion. It is not an eager script on the homepage, which is why it survived earlier passes — it arrives because the footer links 27 routes and <Link> prefetches their chunks, and those routes' clients still imported it. Removing it from the homepage alone was never possible; the library had to go. Two thirds of the problem turned out to be code nobody calls. 86 files imported framer-motion and 62 of them are referenced by nothing but the markdown guides that proposed them — PhysicsField, LiquidWave, DataViz3D, Testimonials3DCarousel and 58 more. Those are deleted. Dead files never entered a chunk, so this is not where the bytes were; it is what made the remaining work tractable and what stops the library being reintroduced by someone reaching for one of them. The 24 live files are 130 motion elements, and they were all doing one of three things: an entrance, a hover, or a press. Those are `.reveal`, `.lift` and `.press`, which already exist in globals.css and cost nothing at runtime — `animation-timeline: view()` behind an @supports guard, so a browser without scroll-driven animations simply shows the content. AnimatePresence wrappers become fragments; their children were already conditionally rendered, and what is lost is the exit animation on elements that unmount. The confirmation page needed real work rather than a rewrite rule. Its checkmark was three useAnimation controls awaiting each other, so the flourish the page exists to show could not begin until the runtime had hydrated. The sequence has fixed offsets, so it is four keyframe tracks now, the second pair delayed 0.8s exactly as the awaited version was. Its `style={{ rotate: -90, originX }}` was Framer's own dialect, which plain React forwards to the DOM where `rotate` means something else and `originX` means nothing — that is now a real transform. framer-motion is uninstalled, so this cannot regress quietly: an import fails the build rather than silently putting 110 KB back on 27 routes. Verified: clean build, typecheck, and all three guards.