You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Add plan for fixing entrance FOUC mechanism
* Fix format
* Change fouc prevention mechanism and add fill backwards to entrance
* Format and cleanup
* Fixed PR comments
* Fix phrasing of fill in viewenter rules
* Update packages/interact-validate/src/semantic/recommendedPatterns.ts
Co-authored-by: Ameer Abu-Fraiha <ameerf@wix.com>
* Simplified recommendation for fill on entrance
* Fix tests
---------
Co-authored-by: Ameer Abu-Fraiha <ameerf@wix.com>
overview: Prevent delayed entrance flashes without changing IntersectionObserver geometry by making the transient neutral styles author-important, using real zero delays, and giving entrance effects backwards fill by default. Align validation, documentation, and Interactor guidance with the runtime behavior.
4
+
todos:
5
+
- id: important-initial-css
6
+
content: Emit author-important transient FOUC declarations and preserve true zero animation delays
7
+
status: completed
8
+
- id: entrance-fill-defaults
9
+
content: Default every entrance preset descriptor to backwards fill while preserving explicit overrides
10
+
status: completed
11
+
- id: validation-guidance
12
+
content: Add backwards-fill validation guidance and align Interact docs, rules, and Interactor skill
13
+
status: completed
14
+
- id: regression-tests
15
+
content: Cover CSS serialization, timing, all entrance presets, validator behavior, and run targeted verification
16
+
status: completed
17
+
isProject: false
18
+
---
19
+
20
+
# Fix Delayed Entrance FOUC
21
+
22
+
## Implementation
23
+
24
+
- Extend the internal declaration shape in [`packages/interact/src/types/css.ts`](packages/interact/src/types/css.ts) with an `important` flag and serialize it in [`packages/interact/src/core/cssUtils.ts`](packages/interact/src/core/cssUtils.ts). Mark every [`DEFAULT_INITIAL`](packages/interact/src/core/css.ts) declaration important so `visibility: hidden` and neutral transform properties override pre-trigger animation values, while retaining the existing `:not([data-interact-enter])` lifecycle.
25
+
- In [`packages/motion/src/api/cssAnimations.ts`](packages/motion/src/api/cssAnimations.ts), replace the synthetic `delay || 1` fallback with `delay ?? 0`. Do not add the proposed `0.1ms` initial override, because it would alter computed sequence timing and could move a playing animation back from its active phase into its delay phase.
26
+
- Add a small `getEntranceFill()` helper in [`packages/motion-presets/src/utils.ts`](packages/motion-presets/src/utils.ts), returning `options.fill ?? 'backwards'`. Apply it after `...options` to every animation descriptor in all 19 modules under [`packages/motion-presets/src/library/entrance/`](packages/motion-presets/src/library/entrance/) so both CSS and WAAPI paths default to backwards fill while explicit `none`, `forwards`, or `both` values remain authoritative.
27
+
28
+
## Validation and guidance
29
+
30
+
- Add an informational `RECOMMENDED_FILL_BACKWARDS` semantic check in [`packages/interact-validate/src/semantic/recommendedPatterns.ts`](packages/interact-validate/src/semantic/recommendedPatterns.ts), wire it through [`collectSemanticWarnings.ts`](packages/interact-validate/src/semantic/collectSemanticWarnings.ts) and [`errors.ts`](packages/interact-validate/src/errors.ts), and recommend explicit `backwards` or `both` for effective `viewEnter`/`once` animation effects, including nested sequence effects. Keep this advisory so preset defaults remain a safety net rather than a schema requirement.
31
+
- Update the authoritative entrance/FOUC guidance and generated CSS examples in [`packages/interact/rules/viewenter.md`](packages/interact/rules/viewenter.md), [`packages/interact/rules/full-lean.md`](packages/interact/rules/full-lean.md), [`packages/interact/docs/api/functions.md`](packages/interact/docs/api/functions.md), and [`packages/interact/docs/examples/entrance-animations.md`](packages/interact/docs/examples/entrance-animations.md): explain the important neutral pre-trigger rule, use `fill: 'backwards'` for `once`, and reserve `both` for effects that must retain their final keyframe.
32
+
- Update the repository Interactor source in [`skills/interactor/SKILL.md`](skills/interactor/SKILL.md) plus its `config-schema`, `triggers`, `integration-recipes`, and `validate` references. Make explicit backwards fill an invariant in generated `viewEnter`/`once` configs and update the relevant eval expectation; do not manually edit external installed skill snapshots.
33
+
34
+
## Regression coverage
35
+
36
+
- Update [`packages/interact/test/css.spec.ts`](packages/interact/test/css.spec.ts) and [`cssUtils.spec.ts`](packages/interact/test/cssUtils.spec.ts) to verify important initial declarations are emitted only for eligible same-element `viewEnter`/`once` effects and disappear from the post-start selector.
37
+
- Update [`packages/motion/test/motion.spec.ts`](packages/motion/test/motion.spec.ts) to assert omitted/zero delay produces `0ms`, while positive delays remain unchanged.
38
+
- Add centralized entrance-preset tests covering all 19 exports: every generated descriptor defaults to `backwards`, and an explicit fill value is preserved. Retain existing per-preset behavior tests and add coverage for the currently untested `ExpandIn` export through this matrix.
39
+
- Add validator tests for direct effects, referenced registry effects, sequence effects, implicit `once`, accepted `backwards`/`both`, and informational severity/category overrides.
40
+
41
+
## Verification
42
+
43
+
- Run `nvm use`, then targeted tests and type checks for `@wix/motion`, `@wix/motion-presets`, `@wix/interact`, and `@wix/interact-validate`; finish with repository lint/format checks for touched files.
Copy file name to clipboardExpand all lines: packages/interact-validate/README.md
+20-19Lines changed: 20 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -194,25 +194,26 @@ The single source of truth for every code the validator emits. The agent-facing
194
194
195
195
These encode statically-detectable authoring pitfalls from the trigger rule files. Each belongs to a [rule category](#severity-model), so set the category to `'off'` to silence it or `'error'` to make it fail `valid`.
|`UNUSED_EFFECT`| A `config.effects` entry is never referenced. |`UNUSED_DEFINITION`|
200
-
|`UNUSED_SEQUENCE`| A `config.sequences` entry is never referenced. |`UNUSED_DEFINITION`|
201
-
|`UNUSED_CONDITION`| A `config.conditions` entry is never referenced. |`UNUSED_DEFINITION`|
202
-
|`DUPLICATE_KEYFRAME_NAME`| A `keyframeEffect.name` is reused across effects. |`UNIQUE_DEFINITION_IDS`|
203
-
|`SAME_ELEMENT_RETRIGGER`|`viewEnter` with a non-`once``triggerType` on the same source+target element. |`SAME_ELEMENT_RETRIGGER`|
204
-
|`HIT_AREA_SHIFT`|`hover`/`pointerMove``keyframeEffect` with a `translate`/`scale`/`matrix` transform on the same source+target element. |`HIT_AREA_SHIFT`|
205
-
|`SCROLL_PRESET_MISSING_RANGE`| A `*Scroll``namedEffect` on `viewProgress` omits `range`. |`SCROLL_RANGE`|
206
-
|`SCROLL_PRESET_BAD_RANGE`| A scroll preset `range` is not `'in'`/`'out'`/`'continuous'`. |`SCROLL_RANGE`|
207
-
|`ANIMATION_END_SELF_REFERENCE`| An `animationEnd` interaction waits on an effect it also produces (never starts). |`ANIMATION_END_GRAPH`|
208
-
|`LIST_ITEM_SELECTOR_WITHOUT_CONTAINER`|`listItemSelector` present without `listContainer` (inert). |`ELEMENT_SELECTION`|
209
-
|`REDUNDANT_SELECTOR_WITH_LIST_ITEM`|`selector` ignored when `listContainer` + `listItemSelector` are both present. |`ELEMENT_SELECTION`|
210
-
|`EMPTY_STYLE_PROPERTIES`| A state effect's `transition.styleProperties` / `transitionProperties` is `[]` (toggles nothing). |`STATE_EFFECT`|
211
-
|`STATE_REMOVE_WITHOUT_EFFECT_ID`|`stateAction: 'remove'` with no `effectId` to pair with a matching `'add'`. |`STATE_EFFECT`|
212
-
|`RECOMMENDED_FILL_BOTH`| A scrubbed (`viewProgress`/`pointerMove`) or toggling (`alternate`/`repeat`/`state`) effect omits `fill: 'both'`. |`RECOMMENDED_FILL`|
213
-
|`POINTER_AXIS_IGNORED`|`pointerMove``params.axis` set on a `namedEffect`/`customEffect` (axis only applies to `keyframeEffect`). |`POINTER_AXIS`|
214
-
|`KEYFRAME_PROP_NOT_CAMEL_CASE`| A `keyframeEffect` property name is kebab-case (not WAAPI camelCase). |`KEYFRAME_STYLE`|
215
-
|`INVALID_INSET`|`viewEnter``params.inset` is not 1–4 CSS lengths/percentages. |`VIEW_INSET`|
|`UNUSED_EFFECT`| A `config.effects` entry is never referenced. |`UNUSED_DEFINITION`|
200
+
|`UNUSED_SEQUENCE`| A `config.sequences` entry is never referenced. |`UNUSED_DEFINITION`|
201
+
|`UNUSED_CONDITION`| A `config.conditions` entry is never referenced. |`UNUSED_DEFINITION`|
202
+
|`DUPLICATE_KEYFRAME_NAME`| A `keyframeEffect.name` is reused across effects. |`UNIQUE_DEFINITION_IDS`|
203
+
|`SAME_ELEMENT_RETRIGGER`|`viewEnter` with a non-`once``triggerType` on the same source+target element. |`SAME_ELEMENT_RETRIGGER`|
204
+
|`HIT_AREA_SHIFT`|`hover`/`pointerMove``keyframeEffect` with a `translate`/`scale`/`matrix` transform on the same source+target element. |`HIT_AREA_SHIFT`|
205
+
|`SCROLL_PRESET_MISSING_RANGE`| A `*Scroll``namedEffect` on `viewProgress` omits `range`. |`SCROLL_RANGE`|
206
+
|`SCROLL_PRESET_BAD_RANGE`| A scroll preset `range` is not `'in'`/`'out'`/`'continuous'`. |`SCROLL_RANGE`|
207
+
|`ANIMATION_END_SELF_REFERENCE`| An `animationEnd` interaction waits on an effect it also produces (never starts). |`ANIMATION_END_GRAPH`|
208
+
|`LIST_ITEM_SELECTOR_WITHOUT_CONTAINER`|`listItemSelector` present without `listContainer` (inert). |`ELEMENT_SELECTION`|
209
+
|`REDUNDANT_SELECTOR_WITH_LIST_ITEM`|`selector` ignored when `listContainer` + `listItemSelector` are both present. |`ELEMENT_SELECTION`|
210
+
|`EMPTY_STYLE_PROPERTIES`| A state effect's `transition.styleProperties` / `transitionProperties` is `[]` (toggles nothing). |`STATE_EFFECT`|
211
+
|`STATE_REMOVE_WITHOUT_EFFECT_ID`|`stateAction: 'remove'` with no `effectId` to pair with a matching `'add'`. |`STATE_EFFECT`|
212
+
|`RECOMMENDED_FILL_BOTH`| A scrubbed (`viewProgress`/`pointerMove`) or toggling (`alternate`/`repeat`/`state`) effect omits `fill: 'both'`. |`RECOMMENDED_FILL`|
213
+
|`RECOMMENDED_FILL_BACKWARDS`| A `viewEnter` + `once` named/keyframe effect targeting another element or using a same-element delay omits `fill: 'backwards'` or `'both'`. |`RECOMMENDED_FILL`|
214
+
|`POINTER_AXIS_IGNORED`|`pointerMove``params.axis` set on a `namedEffect`/`customEffect` (axis only applies to `keyframeEffect`). |`POINTER_AXIS`|
215
+
|`KEYFRAME_PROP_NOT_CAMEL_CASE`| A `keyframeEffect` property name is kebab-case (not WAAPI camelCase). |`KEYFRAME_STYLE`|
216
+
|`INVALID_INSET`|`viewEnter``params.inset` is not 1–4 CSS lengths/percentages. |`VIEW_INSET`|
message: `Include \`fill: 'both'\` for ${reason}so the effect stays applied and is not garbage-collected.`,
45
+
message: `Include \`fill: 'backwards'\` (or \`'both'\` when the final keyframe must persist) so the starting keyframe applies before the animation starts on a target without FOUC hiding rules.`,
0 commit comments