From a459b643e80021f5da849dfd3c8015c701fdf575 Mon Sep 17 00:00:00 2001 From: michael Date: Wed, 6 May 2026 21:38:42 -0700 Subject: [PATCH] feat(web): dt-scale-in invisible-via-opacity during delay so children can self-measure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prior keyframes held descendants at transform: scale(0) during the animation-delay phase (with fill-mode: both). Any DTStaggerContainer child performing getBoundingClientRect()-based self-measurement on mount — most notably R3F's , but also chart libs, video players, and virtualized lists — read a near-zero rect at the transform-multiplied size and never recovered, because transform changes don't fire ResizeObserver when they end. New keyframes: 0% opacity 0, transform none (during delay: invisible but full layout size, no transform — children measure correctly) 0.001% opacity 0, transform scale(0) (snap to scaled-down at start) 100% opacity 1, transform scale(1) (animate scale + fade in) Behavior change for consumers: entrance gains a subtle fade-in alongside the scale-in. Functionally equivalent for the existing DTStaggerContainer use cases. Fixes the SuggestedPlacements 3D viewer "blank teal block until scroll" bug on the Hydrogen storefront product pages. Bumps @dangerousthings/web to 0.5.0 (MINOR — visual behavior change). To revert: git revert Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/web/CHANGELOG.md | 6 ++++++ packages/web/package.json | 2 +- packages/web/src/components/animations.css | 12 ++++++++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index e19e3de..40b0878 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,11 @@ # @dangerousthings/web +## 0.5.0 + +### Minor Changes + +- `dt-scale-in` keyframes now hold `transform: none, opacity: 0` during `animation-delay` (the period when `animation-fill-mode: both` shows the first keyframe), then snap to `scale(0)` at animation start before scaling/fading to 1. Visual difference vs prior is a subtle fade-in alongside the scale-in. **Why:** prior keyframes held descendants at `transform: scale(0)` during the delay, which caused any child performing `getBoundingClientRect()`-based self-measurement on mount (R3F ``, ResizeObserver-driven charts, virtualized lists, etc.) to read a near-zero rect and never recover — `transform` changes don't fire `ResizeObserver` when they end. Fixes the SuggestedPlacements 3D viewer "blank teal block until scroll" bug on the Hydrogen storefront product pages. + ## 0.4.1 ### Patch Changes diff --git a/packages/web/package.json b/packages/web/package.json index f59f4c7..2033cce 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,6 +1,6 @@ { "name": "@dangerousthings/web", - "version": "0.4.1", + "version": "0.5.0", "description": "Web CSS theme for the Dangerous Things design system — bevels, glows, form styles", "license": "MIT", "author": { diff --git a/packages/web/src/components/animations.css b/packages/web/src/components/animations.css index a6caf52..72f60f0 100644 --- a/packages/web/src/components/animations.css +++ b/packages/web/src/components/animations.css @@ -7,8 +7,16 @@ ============================================================================ */ @keyframes dt-scale-in { - from { transform: scale(0); } - to { transform: scale(1); } + /* During animation-delay (with fill-mode: both), this 0% keyframe holds. + transform: none lets descendants self-measure correctly on mount — + critical for ResizeObserver-based components (R3F Canvas, charts, + virtualized lists) whose initial getBoundingClientRect() would + otherwise be transform-multiplied to ~0 inside a scale(0) ancestor. */ + 0% { opacity: 0; transform: none; } + /* Snap to scale(0) at animation start so the entrance is still a + visible scale-in (with a brief fade-in alongside). */ + 0.001% { opacity: 0; transform: scale(0); } + 100% { opacity: 1; transform: scale(1); } } @keyframes dt-fade-in {