Repository navigation
feat(motion): lean animation path for scroll jank and reduced motion (spike 659) - #581
Closed
ExcelDsigN-tech wants to merge 25 commits into
Closed
ExcelDsigN-tech wants to merge 25 commits into
ExcelDsigN-tech wants to merge 25 commits into
Conversation
PhaseFeatureFlag lost phase-146..153, phase-editions and phase-timed-drops, and SecurityCounterName lost ~50 counters used by merged spikes. Restoring them clears 96 of the 120 tsc errors on main. Also registers phase-159, phase-161, phase-162 and phase-163 for spikes 659, 661, 662 and 663.
…chamber modules 0d14b9a ("fixed") re-encoded several files as cp1252-decoded UTF-8 and prepended a BOM plus // @ts-nocheck. User-facing strings in the chamber (e.g. "Transacción", "…") shipped corrupted, and a few glyphs (●, ”) were lost outright. Files with no later commits are restored from 0d14b9a^; files edited since get only their mojibake comments repaired. 60001c5 (PHASE-STELLAR#33 refactor) moved ChamberLogStream, ChamberCatalogThumb, PhaserLiqTokenLink and the chamber chrome classes out of fusion-chamber into components/chamber/* but never committed those files, and left five one-word "placeholder" files behind. The four modules are recreated verbatim from the code it deleted; the unused placeholder imports and files are removed.
- offers accept route: spike 674 collab-split fan-out (3e4b562), with the splits binding hoisted so the response can actually read it - IpfsDisplayImg: `fallback` prop destructure (b89c4f2) - wash-screening: washScreenReasonForEdition (3e4b562) - viewer-signature: viewerSignatureShort (f9a08b6; removed by 7cc03e4 while three components still import it) - sqlite-db: exhibitions, price_suggestions, moderation_queue and quest_arcs tables (b89c4f2). Their absence failed 27 tests.
Real bugs the type errors were hiding: - nft-index subscribe: validateWebhookUrl accepted https://127.0.0.1 and every 172.16/12, 100.64/10 and 0/8 literal (SSRF). Now a proper IPv4 range check. - lib/stellar.ts settle verification read meta v1/v3 only and called ContractEventV0.contractId(), which no longer exists, so every settle check fell through to SETTLE_EVENT_NOT_FOUND. It now reads meta v4 (protocol 23) and v3 and takes the emitter from ContractEvent. Still fails closed on any mismatch. - artist-attestation passed a string where an ScAddress is required and decoded an already-decoded retval, so attestation never read true. Also: winback route called a nonexistent addNotification (now createNotification with a winback_reactivation type), wallet-provider declared `controller` twice, duplicate `ok` keys in ve-lock, and Buffer/Uint8Array typing in the ipfs and avatar routes. wallet-provider and stellar.ts are also restored from the 0d14b9a encoding damage.
- artist-profile-client imported describe/it from node:test, so vitest
found no suite
- world-roles-rbac seeded worldRoles.json while the store reads
world-roles.json (serverDataJsonPath("worldRoles"))
- avatar-provenance hashed a string through the bytes-only sha256Hex;
encoding first gives the same digest
- forge-pipeline imported bun:test; the APIs it uses are identical in vitest
- viewer-authorization: Buffer typing for Keypair.sign
eslint.config.mjs imports eslint-config-next, which was never installed, so npm run lint failed outright. dotenv is imported by scripts that the root test suite loads (scripts/reset-phase.ts).
- ethnum 1.5.2 -> 1.5.3 in both lockfiles: 1.5.2 fails to compile on rustc 1.97 (E0512 transmute), which broke cargo test for both crates - mock-token test called an associated fn as a method outside a contract context; it now goes through the generated MockTokenClient phase-protocol still does not compile: see the baseline notes. Three merged spikes each claimed PhaseError discriminants from 18 upward.
tsc is at 0 errors and vitest is green on this branch, so both can gate PRs now. docs/investigations/main-baseline-2026-10-17.md records what was fixed and what is blocked (phase-protocol discriminant collision).
…lient) lib/stellar-wallet-kit.ts is loaded by the wallet provider on every route and imported randomUUID from node:crypto. The client polyfill has no randomUUID, so hydration threw and nothing interactive rendered. The nonce path is browser-only, so it now uses globalThis.crypto.randomUUID().
…STELLAR#522) The root layout stamps data-phase-motion="lean" on <html> when NEXT_PUBLIC_FEATURE_PHASE_159 is set. Every CSS override is scoped to that attribute and every JS branch reads the same value, so flag off runs the legacy paths unchanged. - Lenis only on "/" in lean mode, never under reduced motion - fix ticker teardown: the anonymous rAF callback was never removed - hero fade on a CSS scroll timeline, gsap scrub kept as fallback - ScrollTrigger.batch reveals with will-change only while tweening - server-rendered H1 with a textContent scramble and a WAAPI settle flip - compositor-only loops, no permanent box-shadow/filter will-change - reduced motion honored by ticker, skeletons, flap and smooth scroll - clear lint errors in the touched files Tests: lib/__tests__/motion-performance.test.ts, including a CSS guard that lean rules are attribute-scoped and compositor-only.
…659) - scripts/proof-motion-659.ts (npm run proof:659): median-of-N Lighthouse (mobile, simulated throttling) for / and /explore, refuses a build whose data-phase-motion attribute does not match --label, and prints an off/on comparison table - spike doc rewritten against the real issue: browser-verified behavior table (normal vs reduced motion), Lighthouse/trace/reduced-motion checklist with placeholders, follow-up - docs/spikes/PR_659.md
The ticker's inline <style> contains html[data-phase-motion="lean"] in every build, so the mislabel guard rejected the flag-off build.
…ion builds Two passes, median of 5 runs each, flag off vs on. On /, main-thread work is down 24-27% and Speed Index down 13-25%, LCP flat. /explore LCP is bimodal noise in both builds. A headless Chromium check confirms reduced motion stops Lenis, the hero fade and the ticker only with the flag on. The device trace is still pending.
SEP-53 wallets sign SHA256("Stellar Signed Message:\n" + message). Signals,
world roles, avatar ownership and gated-preview viewer auth verified the
raw prefixed bytes instead, so every real Freighter signature was rejected
with "Invalid signature: payload not signed by this wallet". The unit
tests passed only because they signed the same raw bytes.
- lib/viewer-signature.ts: sep53SignedBytes + verifySep53Signature, used
by verifySignalSignature, verifyWorldRoleSignature and the avatar route
- lib/viewer-authorization.ts: viewerSignatureBytes is now the SHA-256
digest the wallet's key actually signs
- tests sign like a wallet; the official SEP-53 spec vectors are a
regression test; tests/viewer-authorization.test.ts used an address
unrelated to its seed and could never pass
Resolve lib/feature-flags.ts: keep the restored phase-146..153, editions and timed-drops members alongside upstream phase-158..161. The spike flags move to their own branches.
Upstream PHASE-STELLAR#573 assigned phase-159 to the batched owner-key loader.
…animation-scroll-jank-purge Keep both flag rows in the docs; feature-flags.ts takes the baseline and adds phase-164.
Resolves conflicts in the wallet provider, fusion chamber, security counters, wallet kit, flags and copy. Registers phase-170..173, types the new copy blocks, restores the legal data paths and QR scanner imports, and drops the re-added @ts-nocheck and mojibake.
Upstream assigned phase-164 to age bands. A named flag cannot collide with later numbering.
…k-purge # Conflicts: # PROJECT_ARCHITECTURE.md # app/layout.tsx # lib/feature-flags.ts
|
@ExcelDsigN-tech Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a lean motion path behind
phase-motion(default off). Smooth scroll only runs where it's needed, the hero fades on a CSS scroll timeline, ScrollTriggers are batched, the H1 renders on the server and flips with WAAPI, infinite loops animate onlytransform/opacity,will-changelives only while something animates, andprefers-reduced-motionis honored by the ticker, skeletons, flap text and smooth scroll. It also fixes a gsap ticker leak on every route change (always on).The flag is the named
phase-motion. It wasphase-159, thenphase-164, and upstream took both numbers for other spikes, so it now has a name that cannot collide. The lab runs below setNEXT_PUBLIC_FEATURE_PHASE_159; only the name changed since.Changes
app/layout.tsx: stampsdata-phase-motion="lean"when the build flag is set. Every CSS override is scoped to that attribute.components/smooth-scroll.tsx: Lenis only on/in lean mode, never under reduced motion; fixed teardown (the anonymous rAF callback was never removed).components/hero-section.tsx: CSS scroll-timeline fade with the gsap fallback.colophon,principles,signals,worksections,highlight-text:ScrollTrigger.batchreveals vialib/motion-reveal.ts,quickTocursor, no scrub parallax in lean mode.components/split-flap-text.tsx: server-rendered final glyphs,textContentscramble, WAAPI settle flip, audio only when unmuted and motion is allowed.app/tactical-command.css,app/globals.css,components/system-ticker.tsx: compositor-only loops,will-change: autounless interacting, reduced-motion freezes.lib/motion-performance.ts: pure helpers.scripts/proof-motion-659.ts(npm run proof:659): Lighthouse before/after runner.Files ruled out
draw-text.tsxandscramble-text.tsxhave no importers.app/explore/page.tsxis covered by route scoping and the scoped CSS.package.jsononly gains the proof script.Flag and rollback
NEXT_PUBLIC_FEATURE_PHASE_MOTION, build-time, default off. Rollback: unset, rebuild and redeploy. The scoped CSS goes inert and the legacy paths run. The ticker-leak fix stays on.Tests
lib/__tests__/motion-performance.test.ts(12), including a CSS guard that every lean rule is attribute-scoped and compositor-only.tsc --noEmit: 0 errors.vitest run: green with flags off.will-changeisauto, and reduced motion turns off Lenis, the hero animation and the ticker./exploreruns without Lenis. No page errors.Live proof
Lab run on production builds (Lighthouse mobile, median of 5, two passes): on
/, main-thread work is down 24–27% and Speed Index down 13–25%, with LCP and CLS flat. Reduced motion verified in headless Chromium: Lenis, the hero animation and the ticker all stop with the flag on, and the flag-off build keeps the legacy behavior. Full tables are in the spike doc under "Lab results".Still pending: a real low-end Android trace (checklist step 4). I will add it as a comment when captured.
Follow-up
Delete the dead text components, isolate the ticker clock, decide the CSP for the ticker's price and time APIs, and add production RUM.
Depends on
#574 (
chore/fix-main-baseline). Merge that first; until it merges, this diff also shows its commits.Closes #522