diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e6cad4db..cda053009 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -271,6 +271,13 @@ jobs: echo "LIME_WINDOWS_SIGNING_CERTIFICATE_FILE=$CERTIFICATE_PATH" >> "$GITHUB_ENV" echo "LIME_WINDOWS_SIGNING_CERTIFICATE_PASSWORD=$WINDOWS_SIGNING_CERTIFICATE_PASSWORD" >> "$GITHUB_ENV" + - name: Prepare sherpa-onnx runtime + shell: bash + run: | + set -euo pipefail + node scripts/prepare-sherpa-onnx-runtime.mjs \ + --target "${{ matrix.target }}" + - name: Build Electron app shell: bash env: diff --git a/RELEASE_NOTES.en.md b/RELEASE_NOTES.en.md index f8b001ae1..4485635db 100644 --- a/RELEASE_NOTES.en.md +++ b/RELEASE_NOTES.en.md @@ -16,6 +16,7 @@ - Fixed inconsistent loading, error, disconnect, close, and retry states in Settings and Browser Runtime, and removed the retired Chrome Relay guide path from the current product chain. - Fixed re-entry boundaries in Electron updater, App Server host, and Windows startup paths, with deterministic configuration for unsigned macOS development packaging. - Fixed a Windows Squirrel N-1 smoke navigation race that treated the preload-enabled startup page as the final renderer; packaged launches now also remove unsupported `NODE_OPTIONS` and the development-server URL. +- Fixed Electron Release workflow builds when the Rust cache omits sherpa-onnx prebuilt libraries; shared runtime libraries are now prepared explicitly for each target before packaging. ### Improvements and Refactors diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9ca7016fb..7726f8467 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -14,6 +14,7 @@ - 修复设置页和 Browser Runtime 在加载、错误、断开、关闭与重试状态下的文案和控件不一致问题,并移除已脱离 current 主链的旧 Chrome Relay guide 双轨。 - 修复 Electron updater、App Server host 和 Windows 启动路径的并发/重入边界,补齐 macOS 未签名开发打包的确定性配置。 - 修复 Windows Squirrel N-1 smoke 将带 preload 的临时启动页误判为最终 renderer 的导航竞态;打包启动环境同时移除不受支持的 `NODE_OPTIONS` 与开发服务器地址。 +- 修复 Electron Release workflow 在 Rust cache 未恢复 sherpa-onnx 预编译库时的构建失败;构建前会按目标平台显式准备共享运行库。 ### 优化与重构 diff --git a/internal/exec-plans/release-v1.107.0-plan.md b/internal/exec-plans/release-v1.107.0-plan.md index 376cfd5db..02169720c 100644 --- a/internal/exec-plans/release-v1.107.0-plan.md +++ b/internal/exec-plans/release-v1.107.0-plan.md @@ -1,6 +1,6 @@ # Lime v1.107.0 发布执行计划 -状态:validated-ready-to-cover-release +状态:validated-ready-to-rerun-release 日期:2026-07-18 目标版本:`1.107.0` 目标 tag:`v1.107.0` @@ -12,7 +12,7 @@ ## Release Candidate - 基线:`v1.106.0`;任务开始时 `main`、`origin/main` 与该 tag 指向同一提交,目标 tag 在本地不存在。 -- 初始候选盘点包含 213 个已跟踪改动和 72 个未跟踪文件,共 285 个候选路径;本轮追加 Windows Squirrel N-1 导航竞态修复、回归测试及首页皮肤资源,仍无排除项。 +- 初始候选盘点包含 213 个已跟踪改动和 72 个未跟踪文件,共 285 个候选路径;本轮追加 Windows Squirrel N-1 导航竞态修复、Release sherpa-onnx 预编译库预热、回归测试及首页皮肤资源,仍无排除项。 - `release metadata`:`package.json`、`packages/lime-cli-npm/package.json`、`lime-rs/Cargo.toml`、`lime-rs/Cargo.lock`、`RELEASE_NOTES.md`、`RELEASE_NOTES.en.md` 与本计划。 - `candidate changes`:当前工作树全部产品、测试、脚本、schema、资源、治理和文档改动,无排除项。 - `excluded changes`:无。 @@ -34,7 +34,8 @@ - Release candidate 已冻结,纳入当前全部候选路径,无排除项;用户已明确要求覆盖 `v1.107.0` 并递交全部当前改动。 - 版本事实源与双语 release notes 已更新,并补记 Windows startup-page navigation race hotfix。 -- 版本事实源、合同、Rust、Agent fixture、GUI smoke 与 Windows Squirrel 定向回归均已通过;Git staging、commit、tag 与 push 待执行。 +- 首轮覆盖提交 `7fb666415` 已完成并推送;Release workflow `29631194668` 因三平台构建时缺少 sherpa-onnx 预编译库失败,未进入 Windows N-1 smoke。 +- 已加入 Release 构建前按目标显式准备 sherpa-onnx 运行库的 workflow guard;本轮定向回归通过,待重新覆盖提交、tag 和 workflow。 ## 验证记录 @@ -46,8 +47,10 @@ - `npm run verify:gui-smoke`:通过;renderer、Desktop Host、preload、App Server sidecar、Workbench、Memory Settings 与 reload 主路径可用,报告 `appserver.v0 / 1.107.0`。 - `git diff --check`:通过。 - `npx vitest run scripts/electron/windows-squirrel-rc-smoke.test.mjs scripts/electron/release-workflow-guard.test.mjs scripts/electron/current-entrypoints.test.mjs`:通过,3 files / 52 tests。 +- 更新 workflow 后 `npx vitest run scripts/electron/release-workflow-guard.test.mjs scripts/electron/windows-squirrel-rc-smoke.test.mjs scripts/electron/current-entrypoints.test.mjs src/components/agent/chat/components/EmptyStateLayout.test.tsx src/components/agent/chat/components/homeSkinPresentation.test.ts`:通过,5 files / 62 tests。 - 两个 Windows Squirrel 修改脚本 `node --check`:通过。 -- 真实 Windows packaged L8/N-1 验证:待新的远端 Release workflow 执行;本机为 macOS,无法代替 Windows 证据。 +- 首轮远端 Release `29631194668`:失败于三平台 `app-server` 链接;Windows `sherpa-onnx-c-api.lib` 缺失,macOS `sherpa-onnx-c-api` 共享库目录缺失,未执行 N-1。 +- 真实 Windows packaged L8/N-1 验证:待修复后的远端 Release workflow 执行;本机为 macOS,无法代替 Windows 证据。 ## 架构确认 @@ -56,4 +59,4 @@ - 责任人:release owner(v1.107.0)。 - 日期:2026-07-18。 -当前完成度:`97%`。下一刀:`git add -A` 后复核 staged 摘要,创建覆盖提交,移动并强推 `v1.107.0`,再监控远端 Windows Release workflow 与资产。 +当前完成度:`94%`。下一刀:纳入提交后新增的首页皮肤改动与 sherpa workflow 修复,覆盖提交和 `v1.107.0`,再监控 Release workflow 至 Windows N-1 终态。 diff --git a/scripts/electron/release-workflow-guard.mjs b/scripts/electron/release-workflow-guard.mjs index 56457d6b6..05d8cfd8f 100644 --- a/scripts/electron/release-workflow-guard.mjs +++ b/scripts/electron/release-workflow-guard.mjs @@ -318,6 +318,14 @@ function assertBuildSteps(buildJob) { const buildStep = stepByName(steps, "Build Electron app"); const buildRun = buildStep?.run || ""; + const sherpaStep = stepByName(steps, "Prepare sherpa-onnx runtime"); + const sherpaRun = sherpaStep?.run || ""; + for (const required of [ + "scripts/prepare-sherpa-onnx-runtime.mjs", + '--target "${{ matrix.target }}"', + ]) { + assertIncludes(sherpaRun, required, "sherpa-onnx runtime preparation"); + } for (const required of [ "npm run electron:build", "npx electron-forge package", diff --git a/scripts/electron/release-workflow-guard.test.mjs b/scripts/electron/release-workflow-guard.test.mjs index 60433a9e1..f48ce90d1 100644 --- a/scripts/electron/release-workflow-guard.test.mjs +++ b/scripts/electron/release-workflow-guard.test.mjs @@ -132,6 +132,20 @@ describe("Electron release workflow guard", () => { ); }); + it("rejects release workflow without sherpa-onnx runtime preparation", () => { + const current = fs.readFileSync(".github/workflows/release.yml", "utf8"); + const workflowPath = tempWorkflowPath( + current.replace( + / - name: Prepare sherpa-onnx runtime[\s\S]*? --target "\$\{\{ matrix\.target \}\}"\n\n/, + "", + ), + ); + + expect(() => validateReleaseWorkflow({ workflowPath })).toThrow( + /sherpa-onnx runtime preparation.*scripts\/prepare-sherpa-onnx-runtime\.mjs/, + ); + }); + it("rejects missing macOS transient package retry in Forge package step", () => { const current = fs.readFileSync(".github/workflows/release.yml", "utf8"); const workflowPath = tempWorkflowPath( diff --git a/src/components/agent/chat/components/EmptyStateHero.tsx b/src/components/agent/chat/components/EmptyStateHero.tsx index 1f3f2deb6..76fc517e7 100644 --- a/src/components/agent/chat/components/EmptyStateHero.tsx +++ b/src/components/agent/chat/components/EmptyStateHero.tsx @@ -15,55 +15,209 @@ const heroReveal = keyframes` } `; -const foregroundFloat = keyframes` +const portraitBreathe = keyframes` 0%, 100% { - transform: translate3d(0, 0, 0) rotate(0deg); + transform: translate3d(0, 0, 0) scale(1); } 50% { - transform: translate3d(0, calc(var(--home-hero-motion-distance, 12px) * -1), 0) - rotate(var(--home-hero-motion-rotate, 0deg)); + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 8px) * -0.35), + 0 + ) + scale(var(--home-hero-motion-scale, 1.02)); } `; -const foregroundSway = keyframes` +const foliageSway = keyframes` 0%, 100% { - transform: translate3d(0, 0, 0) rotate(0deg); + transform: rotate(calc(var(--home-hero-motion-rotate, 2deg) * -0.35)); } 50% { - transform: translate3d(calc(var(--home-hero-motion-distance, 12px) * -1), 0, 0) - rotate(var(--home-hero-motion-rotate, 0deg)); + transform: translate3d( + calc(var(--home-hero-motion-distance, 8px) * -0.25), + 0, + 0 + ) + rotate(var(--home-hero-motion-rotate, 2deg)); } `; -const foregroundPulse = keyframes` +const cheerBob = keyframes` + 0%, + 100% { + transform: translate3d(0, 0, 0) scale(1); + } + 42% { + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 10px) * -1), + 0 + ) + scale(1.01, 0.985); + } + 54% { + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 10px) * -0.55), + 0 + ) + scale(0.995, var(--home-hero-motion-scale, 1.02)); + } +`; + +const powerPulse = keyframes` 0%, 100% { transform: scale(1); - opacity: 1; + filter: brightness(1) drop-shadow(0 0 0 transparent); } 50% { - transform: scale(var(--home-hero-motion-scale, 1.04)); - opacity: 0.94; + transform: scale(var(--home-hero-motion-scale, 1.035)); + filter: brightness(1.08) + drop-shadow( + var(--home-hero-motion-glow, 0 0 16px rgba(73, 222, 255, 0.42)) + ); } `; -const foregroundDrift = keyframes` +const silkDrift = keyframes` 0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg); } 50% { transform: translate3d( - calc(var(--home-hero-motion-distance, 12px) * -1), - calc(var(--home-hero-motion-distance, 12px) * -0.55), + calc(var(--home-hero-motion-distance, 10px) * -1), + calc(var(--home-hero-motion-distance, 10px) * -0.3), 0 ) rotate(var(--home-hero-motion-rotate, 0deg)); } `; +const stageBeat = keyframes` + 0%, + 58%, + 100% { + transform: translate3d(0, 0, 0) rotate(0deg); + } + 45% { + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 12px) * -1), + 0 + ) + rotate(calc(var(--home-hero-motion-rotate, 0.8deg) * -1)); + } + 52% { + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 12px) * -0.4), + 0 + ) + rotate(calc(var(--home-hero-motion-rotate, 0.8deg) * 0.35)); + } +`; + +const creativeTilt = keyframes` + 0%, + 100% { + transform: rotate(calc(var(--home-hero-motion-rotate, 1.4deg) * -0.3)); + } + 50% { + transform: translate3d( + calc(var(--home-hero-motion-distance, 9px) * -0.5), + calc(var(--home-hero-motion-distance, 9px) * -0.6), + 0 + ) + rotate(var(--home-hero-motion-rotate, 1.4deg)); + } +`; + +const streetBeat = keyframes` + 0%, + 100% { + transform: translate3d(0, 0, 0) rotate(0deg); + } + 32% { + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 11px) * -1), + 0 + ) + rotate(calc(var(--home-hero-motion-rotate, 1.8deg) * -0.8)); + } + 42% { + transform: translate3d( + 0, + calc(var(--home-hero-motion-distance, 11px) * -0.3), + 0 + ) + rotate(calc(var(--home-hero-motion-rotate, 1.8deg) * 0.35)); + } + 68% { + transform: translate3d( + calc(var(--home-hero-motion-distance, 11px) * -0.45), + calc(var(--home-hero-motion-distance, 11px) * -0.7), + 0 + ) + rotate(var(--home-hero-motion-rotate, 1.8deg)); + } +`; + +const spotlightBreathe = keyframes` + 0%, + 100% { + transform: scale(1); + filter: brightness(1) drop-shadow(0 0 0 transparent); + } + 50% { + transform: scale(var(--home-hero-motion-scale, 1.018)); + filter: brightness(1.06) + drop-shadow( + var(--home-hero-motion-glow, 0 0 14px rgba(255, 220, 176, 0.26)) + ); + } +`; + +const portalPulse = keyframes` + 0%, + 100% { + transform: scale(1); + filter: brightness(0.96) drop-shadow(0 0 0 transparent); + } + 50% { + transform: scale(var(--home-hero-motion-scale, 1.04)); + filter: brightness(1.16) + drop-shadow( + var(--home-hero-motion-glow, 0 0 20px rgba(146, 194, 255, 0.46)) + ); + } +`; + +const cityGlide = keyframes` + 0%, + 100% { + transform: translate3d(0, 0, 0) scale(1); + filter: brightness(1) drop-shadow(0 0 0 transparent); + } + 50% { + transform: translate3d( + calc(var(--home-hero-motion-distance, 14px) * -1), + 0, + 0 + ) + scale(var(--home-hero-motion-scale, 1.012)); + filter: brightness(1.06) + drop-shadow( + var(--home-hero-motion-glow, 0 0 16px rgba(229, 53, 69, 0.3)) + ); + } +`; + const HeroSection = styled.section` position: relative; display: flex; @@ -291,32 +445,69 @@ const ArtworkForeground = styled.div` width: var(--home-hero-foreground-width, 0); overflow: visible; pointer-events: none; - transform-origin: 70% 82%; - will-change: transform; + transform-origin: var(--home-hero-motion-origin, 50% 85%); + will-change: transform, filter; - &[data-home-hero-motion="float"] { - animation: ${foregroundFloat} var(--home-hero-motion-duration, 8s) - ease-in-out var(--home-hero-motion-delay, 0s) infinite; + &:not([data-home-hero-motion="none"]) { + animation-duration: var(--home-hero-motion-duration, 8s); + animation-timing-function: ease-in-out; + animation-delay: var(--home-hero-motion-delay, 0s); + animation-iteration-count: infinite; + animation-direction: var(--home-hero-motion-direction, normal); + animation-fill-mode: both; } - &[data-home-hero-motion="sway"] { - animation: ${foregroundSway} var(--home-hero-motion-duration, 8s) - ease-in-out var(--home-hero-motion-delay, 0s) infinite; + &[data-home-hero-motion="portrait-breathe"] { + animation-name: ${portraitBreathe}; } - &[data-home-hero-motion="pulse"] { - animation: ${foregroundPulse} var(--home-hero-motion-duration, 8s) - ease-in-out var(--home-hero-motion-delay, 0s) infinite; + &[data-home-hero-motion="foliage-sway"] { + animation-name: ${foliageSway}; } - &[data-home-hero-motion="drift"] { - animation: ${foregroundDrift} var(--home-hero-motion-duration, 8s) - ease-in-out var(--home-hero-motion-delay, 0s) infinite; + &[data-home-hero-motion="cheer-bob"] { + animation-name: ${cheerBob}; + animation-timing-function: cubic-bezier(0.34, 1.28, 0.64, 1); + } + + &[data-home-hero-motion="power-pulse"] { + animation-name: ${powerPulse}; + } + + &[data-home-hero-motion="silk-drift"] { + animation-name: ${silkDrift}; + } + + &[data-home-hero-motion="stage-beat"] { + animation-name: ${stageBeat}; + animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1); + } + + &[data-home-hero-motion="creative-tilt"] { + animation-name: ${creativeTilt}; + } + + &[data-home-hero-motion="street-beat"] { + animation-name: ${streetBeat}; + animation-timing-function: cubic-bezier(0.34, 1.12, 0.64, 1); + } + + &[data-home-hero-motion="spotlight-breathe"] { + animation-name: ${spotlightBreathe}; + } + + &[data-home-hero-motion="portal-pulse"] { + animation-name: ${portalPulse}; + } + + &[data-home-hero-motion="city-glide"] { + animation-name: ${cityGlide}; } @media (prefers-reduced-motion: reduce) { animation: none !important; will-change: auto; + filter: none; } img { @@ -552,6 +743,9 @@ export function EmptyStateHero({ "--home-hero-motion-distance": foregroundMotion?.distance ?? "12px", "--home-hero-motion-rotate": foregroundMotion?.rotate ?? "0deg", "--home-hero-motion-scale": foregroundMotion?.scale ?? "1.04", + "--home-hero-motion-origin": foregroundMotion?.origin ?? "50% 85%", + "--home-hero-motion-direction": foregroundMotion?.direction ?? "normal", + "--home-hero-motion-glow": foregroundMotion?.glow ?? "0 0 0 transparent", "--home-hero-breakout-space": presentation.breakoutSpace ?? "0", "--home-hero-breakout-space-mobile": presentation.breakoutSpaceMobile ?? "0", diff --git a/src/components/agent/chat/components/EmptyStateLayout.test.tsx b/src/components/agent/chat/components/EmptyStateLayout.test.tsx index 3d664d477..9266a87f0 100644 --- a/src/components/agent/chat/components/EmptyStateLayout.test.tsx +++ b/src/components/agent/chat/components/EmptyStateLayout.test.tsx @@ -100,7 +100,7 @@ describe("EmptyStateLayout", () => { artworkStage ?.querySelector('[data-testid="home-hero-foreground"]') ?.getAttribute("data-home-hero-motion"), - ).toBe("float"); + ).toBe("portrait-breathe"); expect( artworkStage?.style.getPropertyValue("--home-hero-motion-duration"), ).toBe("4.8s"); @@ -135,7 +135,7 @@ describe("EmptyStateLayout", () => { artworkStage ?.querySelector('[data-testid="home-hero-foreground"]') ?.getAttribute("data-home-hero-motion"), - ).toBe("pulse"); + ).toBe("power-pulse"); expect( artworkStage?.style.getPropertyValue("--home-hero-art-blend-width"), ).toBe("68%"); diff --git a/src/components/agent/chat/components/homeSkinPresentation.test.ts b/src/components/agent/chat/components/homeSkinPresentation.test.ts index 83e07e6d3..93131459f 100644 --- a/src/components/agent/chat/components/homeSkinPresentation.test.ts +++ b/src/components/agent/chat/components/homeSkinPresentation.test.ts @@ -24,7 +24,7 @@ describe("homeSkinPresentation", () => { expect(presentation.stageHeightWide).toBe("430px"); expect(presentation.foreground?.top).toBe("-56px"); expect(presentation.breakoutSpace).toBe("68px"); - expect(presentation.foreground?.motion?.kind).toBe("float"); + expect(presentation.foreground?.motion?.kind).toBe("portrait-breathe"); expect(presentation.foreground?.motion?.duration).toBe("4.8s"); }); @@ -42,6 +42,12 @@ describe("homeSkinPresentation", () => { "100% center", ); expect(getHomeSkinPresentation("lime-forest").artFit).toBe("contain"); + expect(getHomeSkinPresentation("lime-forest").foreground?.width).toBe( + "43%", + ); + expect(getHomeSkinPresentation("lime-forest").foreground?.bottom).toBe( + "-2px", + ); expect(getHomeSkinPresentation("lime-forest").artBlendWidth).toBe("68%"); expect(getHomeSkinPresentation("lime-luxury").artBlendWidth).toBe("68%"); expect(getHomeSkinPresentation("lime-ocean").image).toContain( @@ -83,6 +89,12 @@ describe("homeSkinPresentation", () => { expect(getHomeSkinPresentation("lime-luxury").image).toContain( "lime-luxury-hero.png", ); + expect(getHomeSkinPresentation("lime-luxury").foreground?.width).toBe( + "43%", + ); + expect(getHomeSkinPresentation("lime-luxury").foreground?.bottom).toBe( + "-1px", + ); }); it("每套皮肤都应使用独立 Hero 素材", () => { @@ -153,7 +165,7 @@ describe("homeSkinPresentation", () => { ).toBe(true); expect( new Set(foregrounds.map((foreground) => foreground?.motion?.kind)).size, - ).toBe(4); + ).toBe(11); }); it("hero 外框和阴影应跟随皮肤色调", () => { diff --git a/src/components/agent/chat/components/homeSkinPresentation.ts b/src/components/agent/chat/components/homeSkinPresentation.ts index c76a67175..87849f1be 100644 --- a/src/components/agent/chat/components/homeSkinPresentation.ts +++ b/src/components/agent/chat/components/homeSkinPresentation.ts @@ -61,7 +61,18 @@ export type HomeKeepsakeVariant = | "medallion" | "bookmark"; -export type HomeHeroMotionKind = "float" | "sway" | "pulse" | "drift"; +export type HomeHeroMotionKind = + | "portrait-breathe" + | "foliage-sway" + | "cheer-bob" + | "power-pulse" + | "silk-drift" + | "stage-beat" + | "creative-tilt" + | "street-beat" + | "spotlight-breathe" + | "portal-pulse" + | "city-glide"; export interface HomeHeroMotion { kind: HomeHeroMotionKind; @@ -70,6 +81,9 @@ export interface HomeHeroMotion { distance?: string; rotate?: string; scale?: string; + origin?: string; + direction?: "normal" | "reverse"; + glow?: string; } export interface HomeHeroForeground { @@ -177,11 +191,12 @@ const HOME_SKIN_PRESENTATIONS: Record< right: "4%", rightMobile: "1%", motion: { - kind: "float", + kind: "portrait-breathe", duration: "4.8s", delay: "-1.2s", - distance: "13px", - rotate: "1.2deg", + distance: "8px", + scale: "1.025", + origin: "65% 88%", }, }, heroDecorations: { @@ -225,10 +240,11 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "translate(2%, 2%) scale(0.94)", transformMobile: "translate(2%, 2%) scale(1.02)", motion: { - kind: "sway", - duration: "5.6s", - distance: "12px", - rotate: "2.2deg", + kind: "foliage-sway", + duration: "5.8s", + distance: "8px", + rotate: "2.4deg", + origin: "44% 100%", }, }, heroDecorations: { trailingIcon: "leaf" }, @@ -259,20 +275,23 @@ const HOME_SKIN_PRESENTATIONS: Record< image: limeForestHero, foreground: { image: limeForestForeground, - width: "39%", - widthMobile: "54%", - top: "-28px", - topMobile: "-14px", - right: "1%", - rightMobile: "-4%", - transform: "scale(1.08)", - transformMobile: "scale(1.16)", + width: "43%", + widthMobile: "58%", + top: "auto", + topMobile: "auto", + right: "-2%", + rightMobile: "-9%", + bottom: "-2px", + bottomMobile: "-1px", + transform: "scale(1.04)", + transformMobile: "scale(1.08)", motion: { - kind: "sway", - duration: "4.4s", + kind: "cheer-bob", + duration: "3.6s", delay: "-2.4s", - distance: "10px", - rotate: "1.3deg", + distance: "11px", + scale: "1.025", + origin: "55% 100%", }, }, heroDecorations: { trailingIcon: "coins" }, @@ -304,18 +323,22 @@ const HOME_SKIN_PRESENTATIONS: Record< image: limeOceanHero, foreground: { image: limeOceanForeground, - width: "34%", - widthMobile: "47%", - top: "-58px", - topMobile: "-32px", - right: "-1%", - rightMobile: "-6%", - transform: "translate(2%, 2%) scale(0.98)", - transformMobile: "translate(2%, 2%) scale(1.06)", + width: "40%", + widthMobile: "56%", + top: "auto", + topMobile: "auto", + right: "-3%", + rightMobile: "-10%", + bottom: "-2px", + bottomMobile: "-1px", + transform: "translate(2%, 0) scale(0.98)", + transformMobile: "translate(2%, 0) scale(1.02)", motion: { - kind: "pulse", - duration: "4.2s", - scale: "1.04", + kind: "power-pulse", + duration: "4.6s", + scale: "1.035", + origin: "50% 86%", + glow: "0 0 18px rgba(50, 238, 255, 0.48)", }, }, heroDecorations: { trailingIcon: "shield" }, @@ -356,11 +379,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "scale(1.04)", transformMobile: "scale(1.1)", motion: { - kind: "float", - duration: "5.6s", + kind: "silk-drift", + duration: "6.8s", delay: "-2.1s", - distance: "12px", - rotate: "1deg", + distance: "10px", + rotate: "0.7deg", + origin: "60% 92%", }, }, heroDecorations: { trailingIcon: "sun" }, @@ -401,11 +425,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "scale(1.05)", transformMobile: "scale(1.14)", motion: { - kind: "sway", - duration: "3.8s", + kind: "stage-beat", + duration: "3.2s", delay: "-0.8s", - distance: "15px", - rotate: "2deg", + distance: "13px", + rotate: "0.7deg", + origin: "50% 100%", }, }, heroDecorations: { trailingIcon: "music" }, @@ -446,11 +471,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "scale(1.04)", transformMobile: "scale(1.12)", motion: { - kind: "float", - duration: "4.2s", + kind: "creative-tilt", + duration: "4.6s", delay: "-1.7s", - distance: "14px", + distance: "9px", rotate: "1.5deg", + origin: "55% 95%", }, }, heroDecorations: { trailingIcon: "lightbulb" }, @@ -491,11 +517,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "scale(1.08)", transformMobile: "scale(1.14)", motion: { - kind: "drift", - duration: "5.2s", + kind: "spotlight-breathe", + duration: "6s", delay: "-3.1s", - distance: "10px", - rotate: "1.2deg", + scale: "1.018", + origin: "50% 90%", + glow: "0 0 16px rgba(232, 185, 116, 0.3)", }, }, heroDecorations: { trailingIcon: "mic" }, @@ -536,10 +563,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "translate(3%, 2%) scale(0.94)", transformMobile: "translate(3%, 2%) scale(1.04)", motion: { - kind: "pulse", - duration: "5.8s", + kind: "portal-pulse", + duration: "5.4s", delay: "-2.8s", - scale: "1.055", + scale: "1.04", + origin: "50% 58%", + glow: "0 0 20px rgba(146, 194, 255, 0.48)", }, }, heroDecorations: { trailingIcon: "circle" }, @@ -579,11 +608,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "scale(1.05)", transformMobile: "scale(1.14)", motion: { - kind: "sway", - duration: "4.2s", + kind: "street-beat", + duration: "3.7s", delay: "-1.5s", - distance: "14px", + distance: "11px", rotate: "1.8deg", + origin: "50% 100%", }, }, heroDecorations: { trailingIcon: "palette" }, @@ -624,11 +654,12 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "scale(1.06)", transformMobile: "scale(1.12)", motion: { - kind: "float", - duration: "6s", + kind: "portrait-breathe", + duration: "6.2s", delay: "-4s", - distance: "10px", - rotate: "0.8deg", + distance: "5px", + scale: "1.012", + origin: "55% 100%", }, }, heroDecorations: { trailingIcon: "book-open" }, @@ -660,20 +691,23 @@ const HOME_SKIN_PRESENTATIONS: Record< image: limeLuxuryHero, foreground: { image: limeLuxuryForeground, - width: "31%", - widthMobile: "46%", - top: "-36px", - topMobile: "-22px", - right: "2%", - rightMobile: "-6%", - transform: "translate(2%, 0) scale(1)", - transformMobile: "translate(2%, 0) scale(1.04)", + width: "43%", + widthMobile: "58%", + top: "auto", + topMobile: "auto", + right: "-2%", + rightMobile: "-10%", + bottom: "-1px", + bottomMobile: "-1px", + transform: "translate(1%, 0) scale(1)", + transformMobile: "translate(1%, 0) scale(1.02)", motion: { - kind: "drift", - duration: "6.2s", + kind: "spotlight-breathe", + duration: "6.6s", delay: "-2.6s", - distance: "9px", - rotate: "0.8deg", + scale: "1.02", + origin: "50% 100%", + glow: "0 0 18px rgba(131, 117, 255, 0.34)", }, }, heroDecorations: { trailingIcon: "gem" }, @@ -714,10 +748,13 @@ const HOME_SKIN_PRESENTATIONS: Record< transform: "translate(-1%, 3%) scale(0.92)", transformMobile: "translate(-1%, 3%) scale(1.02)", motion: { - kind: "pulse", - duration: "4.8s", + kind: "city-glide", + duration: "8s", delay: "-1.9s", - scale: "1.04", + distance: "14px", + scale: "1.012", + origin: "50% 80%", + glow: "0 0 16px rgba(229, 53, 69, 0.3)", }, }, heroDecorations: { trailingIcon: "orbit" },