Skip to content

Comments

feat(launch): implement Xiuper launch animation with design system#497

Merged
phodal merged 5 commits intomasterfrom
feature/xiuper-launch-animation
Dec 7, 2025
Merged

feat(launch): implement Xiuper launch animation with design system#497
phodal merged 5 commits intomasterfrom
feature/xiuper-launch-animation

Conversation

@phodal
Copy link
Owner

@phodal phodal commented Dec 7, 2025

Summary

Implement the Xiuper launch animation for Desktop app based on the design system specification (xuiper-ds.md).

Changes

New Files

  • AutoDevAnimation.kt: Animation curves and timing constants

    • EaseXiu: cubic-bezier(0.16, 1, 0.3, 1) - ultra-fast response
    • EaseStream: linear - for AI code streaming
    • SpringTactile: bounce effect for micro-interactions
    • Duration constants for Launch animation phases
  • XiuperLaunchScreen.kt: Complete launch animation component

    • 6-phase animation state machine
    • Multi-layer glow effects (AI purple + Xiu cyan)
    • Speed lines for forward momentum visual
    • Breathing pulse animation
    • Reduced-motion accessibility support

Modified Files

  • Platform.kt (all platforms): Added prefersReducedMotion() function

    • JVM: macOS/Windows/Linux system settings detection
    • Android: Settings.Global accessibility check
    • JS: prefers-reduced-motion media query
    • iOS: UIAccessibility.isReduceMotionEnabled
    • WASM: Returns false (no system access)
  • Main.kt: Integrated launch screen with splash state management

    • --skip-splash command line argument support
    • ThemeManager.ThemeMode.DARK for launch screen

Animation Timeline (2.2s total)

[0-100ms]     Initial delay - 'gathering power' (静如处子)
[100-500ms]   Glow expansion - energy gathering
[500-1000ms]  Logo scale up with ease-xiu curve (动如脱兔)
[1000-1300ms] Text slide in from below
[1300-1900ms] Brand display + breathing glow
[1900-2200ms] Fade out to main interface

Design System Alignment

Based on docs/design-system/xuiper-ds.md:

  • Neon-Noir aesthetic: Void background (#0B0E14)
  • Dual-color energy system: Xiu cyan (#00F3FF) + AI purple (#D946EF)
  • Speed Lines: Forward momentum visual (向右的动势)
  • Breathing glow: 'Never static' principle (永不静止)
  • Reduced Motion: Respects prefers-reduced-motion system setting

Screenshots

Launch animation with multi-layer glow effects and speed lines


Closes #493

Summary by CodeRabbit

  • New Features

    • Animated launch screen with rotating halos, glow and smooth text transitions.
    • Centralized animation presets and timing utilities for consistent motion.
    • Accessibility: cross-platform reduced-motion detection added (platforms without system access will default to animations).
    • Splash Screen Control: new --skip-splash flag to bypass the launch animation.
  • Tests

    • Minor test import added (no behavior changes).

✏️ Tip: You can customize this high-level summary in your review settings.

## Summary
Implement the Xiuper launch animation for Desktop app based on the
design system specification (xuiper-ds.md).

## Changes

### New Files
- AutoDevAnimation.kt: Animation curves and timing constants
  - EaseXiu: cubic-bezier(0.16, 1, 0.3, 1) - ultra-fast response
  - EaseStream: linear - for AI code streaming
  - SpringTactile: bounce effect for micro-interactions
  - Duration constants for Launch animation phases

- XiuperLaunchScreen.kt: Complete launch animation component
  - 6-phase animation state machine
  - Multi-layer glow effects (AI purple + Xiu cyan)
  - Speed lines for forward momentum visual
  - Breathing pulse animation
  - Reduced-motion accessibility support

### Modified Files
- Platform.kt (all platforms): Added prefersReducedMotion() function
  - JVM: macOS/Windows/Linux system settings detection
  - Android: Settings.Global accessibility check
  - JS: prefers-reduced-motion media query
  - iOS: UIAccessibility.isReduceMotionEnabled
  - WASM: Returns false (no system access)

- Main.kt: Integrated launch screen with splash state management
  - --skip-splash command line argument support
  - ThemeManager.ThemeMode.DARK for launch screen

## Animation Timeline (2.2s total)
- [0-100ms]    Initial delay - 'gathering power'
- [100-500ms]  Glow expansion - energy gathering
- [500-1000ms] Logo scale up with ease-xiu curve
- [1000-1300ms] Text slide in from below
- [1300-1900ms] Brand display + breathing glow
- [1900-2200ms] Fade out to main interface

## Design System Alignment
- Neon-Noir aesthetic with Void background (#0B0E14)
- Dual-color energy system (xiu cyan + ai purple)
- Speed lines for 'Forward Momentum'
- Breathing glow for 'never static' principle

Closes #493
Copilot AI review requested due to automatic review settings December 7, 2025 07:16
@coderabbitai
Copy link

coderabbitai bot commented Dec 7, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a cross-platform API Platform.prefersReducedMotion() and implements Xiuper launch animation primitives and composable. Platform implementations vary by target (Android stub, iOS/JS/JVM/WASM platform checks). Desktop JVM startup integrates the splash flow with a --skip-splash flag and reduced-motion consideration.

Changes

Cohort / File(s) Summary
Platform (common & targets)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt, mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt, mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt, mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt, mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt, mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt
Introduced prefersReducedMotion(): Boolean expect/actual across platforms. Common declares the API. Android currently returns false (stub/TODO). iOS uses UIAccessibilityIsReduceMotionEnabled. JS uses matchMedia when available; WASM returns false. JVM adds OS-specific checks (macOS defaults read, Windows default safe path, Linux GTK env), all guarded by try/catch.
Animation primitives
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt
New AutoDevAnimation object defining easing curves (EaseXiu, EaseStream, EaseStandard), spring presets (SpringTactile, SpringGentle), duration constants including Launch phase timings, and tween helper functions (tweenXiu, tweenStream, tweenStandard).
Launch screen composable
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt
New XiuperLaunchScreen(onFinished: () -> Unit, reducedMotion: Boolean = false) composable implementing a multi-phase launch animation (glow, logo scale/alpha, text slide/alpha, rotating halos, pulse). Driven by LaunchedEffect and AutoDevAnimation.Duration.Launch; honors reducedMotion to simplify/skip animations.
Desktop integration
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt
Adds --skip-splash flag and conditional startup flow: reads Platform.prefersReducedMotion() and shows XiuperLaunchScreen on startup (unless skipped), then transitions to DesktopWindowLayout after completion.
Test import only
mpp-idea/src/test/kotlin/cc/unitmesh/devins/idea/renderer/JewelRendererTest.kt
Added an import for TaskStatus — no behavioral changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas to focus:
    • JVM Platform: verify macOS defaults invocation, Windows fallback behavior, and Linux GTK env check for safety and portability.
    • Android stub: confirm plan for Context-aware initialization and ensure callers accept a default false.
    • XiuperLaunchScreen: validate phase sequencing, timing constants vs. animations, and reduced-motion bypass behavior.
    • AutoDevAnimation: confirm easing and duration constants align with design (Launch TOTAL and component timings).
    • JS/WASM: ensure matchMedia usage and error handling are correct for browser vs non-browser environments.

Poem

🐰
I hopped through code at break of day,
Drew neon halos that stretch and play,
I paused for those who like things slow,
A Xiuper wink — then off we go ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Out of Scope Changes check ❓ Inconclusive All changes are directly aligned with PR objectives: Platform.prefersReducedMotion() implementations support accessibility requirements, AutoDevAnimation.kt and XiuperLaunchScreen.kt implement the animation system, and Main.kt integrates it. One minor addition is the TaskStatus import in JewelRendererTest.kt, which appears unrelated to the animation PR scope. Clarify whether the TaskStatus import in JewelRendererTest.kt is intentional or an accidental inclusion, as it appears unrelated to the launch animation implementation.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main change: implementing a Xiuper launch animation with a design system, which accurately reflects the primary objectives.
Linked Issues check ✅ Passed All coding requirements from issue #493 are met: animation curves defined in AutoDevAnimation.kt, XiuperLaunchScreen.kt implements the launch animation, reduced-motion support added across platforms, and integration completed in Main.kt.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/xiuper-launch-animation

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6f7d8f and 2459882.

📒 Files selected for processing (1)
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build
  • GitHub Check: Test mpp-core (KMP)

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a comprehensive launch animation system for the Xiuper Desktop app, introducing a design system-aligned animation framework with multi-platform accessibility support. The implementation adds sophisticated visual effects (dual-color glows, speed lines, breathing pulse) while respecting user accessibility preferences across all platforms.

Key Changes:

  • Introduces AutoDevAnimation system with specialized easing curves (EaseXiu, EaseStream, SpringTactile) aligned with "唯快不破" design philosophy
  • Implements 6-phase launch animation (2.2s total) with reduced-motion fallback for accessibility
  • Adds Platform.prefersReducedMotion() with platform-specific implementations (macOS, Windows, Linux, Android, iOS, JS, WASM)

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt New animation system defining easing curves (EaseXiu, EaseStream, SpringTactile) and timing constants for the Xiuper design system
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt Complete launch screen with 6-phase animation, multi-layer glow effects, speed lines, and reduced-motion support
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt Integrates launch screen with splash state management and --skip-splash command line argument
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt Adds prefersReducedMotion() function to Platform interface for accessibility
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt Implements reduced motion detection for macOS, Windows, and Linux desktop platforms
mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt Android implementation for reduced motion detection (has implementation issue)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt iOS implementation using UIAccessibility.isReduceMotionEnabled
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt JavaScript implementation using prefers-reduced-motion media query
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt WebAssembly stub returning false (no system access)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 50 to 64
// Android: Check if animations are disabled in accessibility settings
// Note: This requires Context which we don't have here
// In a real implementation, this would check Settings.Global.ANIMATOR_DURATION_SCALE
// For now, return false as default
return try {
// Check if animator duration scale is 0 (animations disabled)
val animatorDurationScale = android.provider.Settings.Global.getFloat(
null, // ContentResolver - not available without Context
android.provider.Settings.Global.ANIMATOR_DURATION_SCALE,
1.0f
)
animatorDurationScale == 0f
} catch (e: Exception) {
false
}
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Android implementation will always fail because Settings.Global.getFloat() requires a non-null ContentResolver as the first parameter, but null is being passed. This will cause a NullPointerException at runtime.

Consider using a different approach for Android, such as:

  1. Pass a Context parameter through the Platform interface when needed for UI-related functions
  2. Return false as default for now and document this limitation
  3. For the Desktop app use case (JVM), this won't be an issue, but if Android support is planned, this needs to be addressed.
Suggested change
// Android: Check if animations are disabled in accessibility settings
// Note: This requires Context which we don't have here
// In a real implementation, this would check Settings.Global.ANIMATOR_DURATION_SCALE
// For now, return false as default
return try {
// Check if animator duration scale is 0 (animations disabled)
val animatorDurationScale = android.provider.Settings.Global.getFloat(
null, // ContentResolver - not available without Context
android.provider.Settings.Global.ANIMATOR_DURATION_SCALE,
1.0f
)
animatorDurationScale == 0f
} catch (e: Exception) {
false
}
// Android: Checking for reduced motion requires a Context to access ContentResolver.
// This implementation does not have access to Context, so we cannot check the setting.
// Always return false as default and document this limitation.
return false

Copilot uses AI. Check for mistakes.
Comment on lines 69 to 73
osName.contains("windows") -> {
// Windows: Check if animations are disabled via system property
// This is a simplified check; full implementation would use JNA/JNI
System.getProperty("swing.aatext", "false") == "false" &&
System.getProperty("awt.useSystemAAFontSettings", "") == "off"
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Windows accessibility check logic appears incorrect. The code checks if swing.aatext is "false" AND awt.useSystemAAFontSettings is "off" to determine if animations should be reduced. These properties are related to font anti-aliasing, not animation preferences.

For proper Windows reduced motion detection, you would need to check:

  • SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, ...) via JNA/JNI
  • Or check Windows registry: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\DisableAnimations

The current implementation will likely always return false regardless of the user's actual animation preferences on Windows.

Copilot uses AI. Check for mistakes.
*
* 特性:匀速,无加速减速
* 用途:AI 代码生成的打字机效果
* 原理:变与不确定的生成速度会让人感到卡顿,
Copy link

Copilot AI Dec 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor spelling issue: "原理:变与不确定的生成速度" should likely be "原理:可变与不确定的生成速度" (adding the character "可" for clarity, meaning "variable and uncertain generation speed").

Suggested change
* 原理:变与不确定的生成速度会让人感到卡顿
* 原理:可变与不确定的生成速度会让人感到卡顿

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (5)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt (1)

60-68: Add timeout to prevent indefinite blocking on macOS.

process.waitFor() can block indefinitely if the defaults command hangs. Consider adding a timeout to prevent potential UI freezes during startup.

                 osName.contains("mac") -> {
                     // Check macOS reduce motion setting via defaults command
                     val process = ProcessBuilder("defaults", "read", "com.apple.universalaccess", "reduceMotion")
                         .redirectErrorStream(true)
                         .start()
                     val result = process.inputStream.bufferedReader().readText().trim()
-                    process.waitFor()
+                    val completed = process.waitFor(1, java.util.concurrent.TimeUnit.SECONDS)
+                    if (!completed) {
+                        process.destroyForcibly()
+                        return false
+                    }
                     result == "1"
                 }
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (1)

69-69: Consider caching prefersReducedMotion() result.

On JVM/macOS, Platform.prefersReducedMotion() spawns an external process. While the splash only shows once, recomposition during animation could call this multiple times. Consider caching with remember:

+        val reducedMotion = remember { Platform.prefersReducedMotion() }
+
         // 显示启动动画或主界面
         if (showSplash) {
             AutoDevTheme(themeMode = ThemeManager.ThemeMode.DARK) {
                 XiuperLaunchScreen(
                     onFinished = {
                         showSplash = false
                         AutoDevLogger.info("AutoDevMain") { "✨ Launch animation completed" }
                     },
-                    reducedMotion = Platform.prefersReducedMotion()
+                    reducedMotion = reducedMotion
                 )
             }
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt (1)

147-158: Phase state access in coroutine loops may cause timing issues.

The while (phase < 5) loops in LaunchedEffect read phase which is a mutableStateOf var. While Compose state is thread-safe for reads, the coroutine may not immediately observe state changes, potentially causing extra loop iterations after phase transitions.

Consider using snapshotFlow or breaking out of the loop when phase changes:

     LaunchedEffect(phase) {
         if (phase >= 1 && phase < 5) {
             var time = 0f
-            while (phase < 5) {
+            while (true) {
+                if (phase >= 5) break
                 time += 0.03f
                 glowPulse = (sin(time * 2) * 0.25f + 0.75f)
                 delay(16)
             }
         }
     }
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt (2)

59-87: Consider adding explicit return types for SpringTactile.spec / SpringGentle.spec

Minor API clarity nit: giving these helpers an explicit return type (e.g., the spring spec type) would make their contract clearer at call sites and in IDE tooltips, without changing behavior.

-import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.SpringSpec
@@
-        fun <T> spec() = spring<T>(
+        fun <T> spec(): SpringSpec<T> = spring(
@@
-        fun <T> spec() = spring<T>(
+        fun <T> spec(): SpringSpec<T> = spring(

93-116: Derive Launch.TOTAL from its phase constants to avoid drift

Right now TOTAL is a hard-coded 2200ms that happens to match the sum of the phase durations. Deriving it from the components would prevent subtle bugs if any phase timing changes later.

         object Launch {
             const val INITIAL_DELAY = 100   // 初始延迟,营造"蓄力"感
             const val GLOW_EXPAND = 400     // 光晕扩散(先于 Logo)
             const val LOGO_SCALE = 500      // Logo 放大
             const val TEXT_SLIDE = 300      // 文字滑入
             const val GLOW_PULSE = 600      // 光晕呼吸停留(更长的品牌展示)
             const val FADE_OUT = 300        // 淡出(更优雅的过渡)
-            const val TOTAL = 2200          // 总时长(让用户看清品牌)
+            const val TOTAL =
+                INITIAL_DELAY +
+                GLOW_EXPAND +
+                LOGO_SCALE +
+                TEXT_SLIDE +
+                GLOW_PULSE +
+                FADE_OUT     // 总时长(让用户看清品牌)
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6466ad and a4501c2.

📒 Files selected for processing (9)
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt (1 hunks)
  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt (1 hunks)
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt (2 hunks)
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt (1 hunks)
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt (1 hunks)
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt (1 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt (1 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt (1 hunks)
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

**/*.kt: Use expect/actual for platform-specific code in Kotlin Multiplatform projects
For @JsExport in Kotlin, use concrete classes (not interfaces) and Promise (not Flow) for JavaScript interoperability
Avoid emoji and UTF-8 characters in WASM code

Files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt
🧠 Learnings (2)
📚 Learning: 2025-12-06T13:54:33.558Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T13:54:33.558Z
Learning: Applies to **/*.kt : Use `expect`/`actual` for platform-specific code in Kotlin Multiplatform projects

Applied to files:

  • mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt
  • mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt
📚 Learning: 2025-12-06T13:54:33.558Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T13:54:33.558Z
Learning: Applies to **/*Compose*.kt : For Compose UI design, use `AutoDevColors` or `MaterialTheme.colorScheme`

Applied to files:

  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt
🧬 Code graph analysis (1)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt (6)
mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt (1)
  • getOSName (15-17)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt (1)
  • getOSName (14-14)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt (1)
  • getOSName (19-21)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt (1)
  • getOSName (13-15)
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt (1)
  • getOSName (13-15)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/PlatformExports.kt (1)
  • getOSName (21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Agent
  • GitHub Check: Test mpp-core (KMP)
  • GitHub Check: Build
🔇 Additional comments (8)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt (1)

30-35: LGTM!

The expect declaration follows the established pattern and includes clear documentation explaining its accessibility purpose. This properly enables platform-specific implementations as per Kotlin Multiplatform conventions.

mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt (1)

48-51: LGTM!

The iOS implementation correctly uses UIAccessibility.isReduceMotionEnabled, which is the proper system API for detecting reduced motion preferences.

mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt (1)

67-81: LGTM!

The implementation correctly checks for browser environment before accessing window.matchMedia, uses the standard prefers-reduced-motion: reduce media query, and safely falls back to false for Node.js or on exceptions.

mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (1)

62-71: LGTM - Launch screen integration is well-structured.

The splash flow correctly:

  • Wraps in AutoDevTheme with dark mode for brand consistency
  • Passes reduced motion preference to XiuperLaunchScreen
  • Logs completion and transitions to main UI via state change
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt (2)

280-285: Verify brand name spelling: "Xuiper" vs "Xiuper".

The PR title and documentation reference "Xiuper" but the logo displays "Xuiper". Please confirm the intended spelling for brand consistency.


56-85: Well-implemented multi-phase animation with accessibility support.

The state machine cleanly orchestrates the 6-phase animation sequence:

  • Proper reduced motion support that bypasses animation entirely
  • Timing constants sourced from AutoDevAnimation.Duration.Launch
  • Clear phase transitions with appropriate delays

The implementation aligns well with the design system specification.

mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt (2)

9-54: Easing presets and documentation are coherent with the Xiuper spec

The three easing curves are well-chosen, documented, and match the described motion system; this should make reuse across the app straightforward.


122-138: Tween helpers nicely centralize motion semantics

The tweenXiu, tweenStream, and tweenStandard helpers give a clean, reusable surface for consistent motion across the app; defaults tied to your Duration presets are sensible.

@phodal
Copy link
Owner Author

phodal commented Dec 7, 2025

augment review

Use kotlin.math.PI for angle conversion to improve consistency.
Copy link

@augmentcode augmentcode bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 3 suggestions posted.

Comment augment review to trigger a new review at any time.

WindowPlacement.Maximized
}
}
reducedMotion = Platform.prefersReducedMotion()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling Platform.prefersReducedMotion() synchronously inside composition can block the UI thread (macOS branch spawns a ProcessBuilder and waits), risking startup jank or a freeze. Consider resolving this off the UI thread and caching the value before composition (also aligns with EDT best practices) (Guideline: edt_violations).

🤖 Was this useful? React with 👍 or 👎

.alpha(logoAlpha)
) {
Text(
text = "Xuiper",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User-facing brand string uses "Xuiper" while the PR/design system refer to "Xiuper"; this inconsistency can confuse users. Consider aligning the displayed text with the intended brand spelling (also applies to the other occurrence in the subtitle).

🤖 Was this useful? React with 👍 or 👎

letterSpacing = 4.sp, // 增加字间距,更有科技感
color = AutoDevColors.Text.secondary,
modifier = Modifier
.offset { IntOffset(0, textOffset.toInt()) }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifier.offset { IntOffset(...) } expects pixel units, but the comment and animation treat 30 as dp; mixing dp intent with px values will look off on high-DPI displays. Consider using a dp-based offset or converting dp to px via density to keep consistent spacing across densities.

🤖 Was this useful? React with 👍 or 👎

Refine platform-specific prefersReducedMotion implementations for better accuracy and performance. Also correct "Xuiper" to "Xiuper" in UI text.
Replace deprecated UIAccessibility.isReduceMotionEnabled with UIAccessibilityIsReduceMotionEnabled for prefersReducedMotion detection.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (1)

36-39: Consider moving prefersReducedMotion() call outside of composition.

While caching via remember prevents repeated calls, the initial call still occurs during composition on the UI thread. On macOS, this spawns a ProcessBuilder with a 1-second timeout, which could cause startup jank.

Consider initializing this before application {}:

+    // Cache reduced motion preference before composition to avoid blocking UI thread
+    val reducedMotion = Platform.prefersReducedMotion()
+
     application {
         val trayState = rememberTrayState()
         var isWindowVisible by remember { mutableStateOf(true) }
         var triggerFileChooser by remember { mutableStateOf(false) }
         // 启动动画状态
         var showSplash by remember { mutableStateOf(!skipSplash) }
-        // Cache prefersReducedMotion result to avoid repeated system calls
-        val reducedMotion = remember { Platform.prefersReducedMotion() }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4501c2 and f6f7d8f.

📒 Files selected for processing (8)
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt (1 hunks)
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt (2 hunks)
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt (1 hunks)
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt (1 hunks)
  • mpp-idea/src/test/kotlin/cc/unitmesh/devins/idea/renderer/JewelRendererTest.kt (1 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt (1 hunks)
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt (1 hunks)
  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • mpp-idea/src/test/kotlin/cc/unitmesh/devins/idea/renderer/JewelRendererTest.kt
🚧 Files skipped from review as they are similar to previous changes (1)
  • mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt
🧰 Additional context used
📓 Path-based instructions (1)
**/*.kt

📄 CodeRabbit inference engine (AGENTS.md)

**/*.kt: Use expect/actual for platform-specific code in Kotlin Multiplatform projects
For @JsExport in Kotlin, use concrete classes (not interfaces) and Promise (not Flow) for JavaScript interoperability
Avoid emoji and UTF-8 characters in WASM code

Files:

  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt
  • mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt
  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt
🧠 Learnings (2)
📚 Learning: 2025-12-06T13:54:33.558Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T13:54:33.558Z
Learning: Applies to **/*Compose*.kt : For Compose UI design, use `AutoDevColors` or `MaterialTheme.colorScheme`

Applied to files:

  • mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt
  • mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt
📚 Learning: 2025-12-06T13:54:33.558Z
Learnt from: CR
Repo: phodal/auto-dev PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T13:54:33.558Z
Learning: Applies to **/*.kt : Use `expect`/`actual` for platform-specific code in Kotlin Multiplatform projects

Applied to files:

  • mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt
  • mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt
🧬 Code graph analysis (2)
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (4)
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevTheme.kt (2)
  • AutoDevTheme (114-141)
  • AutoDevTheme (146-159)
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt (1)
  • XiuperLaunchScreen (56-301)
mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/desktop/DesktopWindowLayout.kt (1)
  • DesktopWindowLayout (24-46)
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/AutoDevApp.kt (1)
  • AutoDevApp (34-68)
mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt (6)
mpp-core/src/iosMain/kotlin/cc/unitmesh/agent/Platform.ios.kt (1)
  • getOSName (19-21)
mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt (1)
  • getOSName (15-17)
mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt (1)
  • getOSName (13-15)
mpp-core/src/commonMain/kotlin/cc/unitmesh/agent/Platform.kt (1)
  • getOSName (14-14)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/Platform.js.kt (1)
  • getOSName (13-15)
mpp-core/src/jsMain/kotlin/cc/unitmesh/agent/PlatformExports.kt (1)
  • getOSName (21-21)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test mpp-core (KMP)
  • GitHub Check: Build
🔇 Additional comments (13)
mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/theme/AutoDevAnimation.kt (4)

1-53: LGTM! Well-structured animation system.

The animation curves are correctly defined and align with the design system requirements. The EaseXiu curve (cubic-bezier(0.16, 1, 0.3, 1)) matches the specification for ultra-fast response, and the organization with clear documentation is excellent.


66-87: LGTM!

Spring animation specs are well-defined with appropriate damping ratios and stiffness values for tactile feedback and gentle transitions.


93-116: LGTM!

Duration constants are well-organized. The Launch sequence timings correctly sum to the declared TOTAL of 2200ms, matching the PR objectives.


122-139: LGTM!

Preset animation spec functions provide a clean API for common animation patterns.

mpp-core/src/wasmJsMain/kotlin/cc/unitmesh/agent/Platform.wasmJs.kt (1)

45-58: LGTM!

The WASM implementation correctly uses browser interop to query the prefers-reduced-motion media query, with appropriate browser environment detection and error handling.

mpp-core/src/androidMain/kotlin/cc/unitmesh/agent/Platform.kt (1)

49-54: Acknowledged limitation with proper documentation.

The stub implementation returning false is appropriate given the architectural constraint that Platform is a static object without Context access. The TODO comment clearly documents the path forward for future improvement.

mpp-ui/src/jvmMain/kotlin/cc/unitmesh/devins/ui/Main.kt (2)

63-73: LGTM!

The splash screen integration is clean with proper dark theme application and completion callback handling.


74-140: LGTM!

The main UI structure is well-organized with proper state management and callback wiring.

mpp-ui/src/commonMain/kotlin/cc/unitmesh/devins/ui/compose/launch/XiuperLaunchScreen.kt (4)

56-85: LGTM! Well-implemented animation state machine.

The phase-based animation sequence with proper reduced-motion support is well-designed. The reduced-motion path correctly bypasses the full animation with a brief brand display.


147-170: LGTM!

The animation loops are correctly implemented with proper termination conditions and frame timing.


178-270: LGTM!

Canvas rendering for the multi-layer glow effects is well-implemented with proper use of design system colors and phase-based visibility.


273-299: LGTM!

The logo and text section is correctly implemented. The brand spelling is consistent ("Xiuper"), and the offset animation properly uses dp units via textOffset.dp.

mpp-core/src/jvmMain/kotlin/cc/unitmesh/agent/Platform.jvm.kt (1)

52-89: LGTM with noted limitations.

The implementation correctly handles each OS:

  • macOS: Properly reads the reduceMotion setting with a 1-second timeout
  • Windows: Documented as requiring JNA/JNI for proper implementation, safely returns false
  • Linux: Checks GTK_ENABLE_ANIMATIONS environment variable

The blocking nature on macOS is a trade-off for functionality. This is cached once at startup via remember { Platform.prefersReducedMotion() } in Main.kt (line 39), avoiding repeated system calls during runtime.

Simplifies reduced motion detection for WASM by always returning false due to media query limitations.
@phodal phodal merged commit 888f8ad into master Dec 7, 2025
6 of 7 checks passed
@phodal phodal deleted the feature/xiuper-launch-animation branch December 8, 2025 23:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Animation] 实现 Xiuper 动效系统与 Launch 启动动画

1 participant