diff --git a/README.md b/README.md
index 0ea3256..99abc61 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
纯 Android + Jetpack Compose 日历应用,支持农历/节气/节日、个人班次排期,提供月/周/年三种视图。
-

+
## 特性
diff --git a/app/src/main/assets/AGENTS.md b/app/src/main/assets/AGENTS.md
index d23a126..438ef21 100644
--- a/app/src/main/assets/AGENTS.md
+++ b/app/src/main/assets/AGENTS.md
@@ -1,25 +1,25 @@
-
+
# assets
## Purpose
-原始资产文件目录,存放不需要 Android 资源系统处理的二进制文件。当前包含 GIF 动画资源。
+`:app` 模块原始资产文件目录。当前为空(2026-06 清理后)。
## Key Files
-无顶层文件
+无
## Subdirectories
-| Directory | Purpose |
-|-----------|---------|
-| `gifs/` | GIF 动画资源(见 `gifs/AGENTS.md`) |
+无(原 `gifs/` 子目录的镜像说明已删除 —— 实际 UI/WebP 资源只在 `:core`)
## For AI Agents
### Working In This Directory
-- 新增原始资源文件直接放入此目录或其子目录
-- 通过 `AssetManager` 在运行时访问
+- 历史上此目录曾放 `app_icon.png`/`app_icon_original.png` 作图标源,因无代码引用已于 2026-06 删除
+- 应用内图标用 `core/src/main/assets/app_icon.webp`(`Platform.kt`)
+- 启动器图标用 `app/src/main/res/mipmap-*/`(含 Adaptive Icon)
+- **不要再把图标源 PNG 放这里**:会被打进 APK。原图 `app_icon_original.png` (2048px) 保留在 git 历史(commit `a36f6c4`),重新生成 foreground 时用 `git show a36f6c4:app/src/main/assets/app_icon_original.png` 恢复,生成脚本见 `docs/superpowers/plans/2026-06-15-image-management-optimization.md` Task 5
diff --git a/app/src/main/assets/app_icon.png b/app/src/main/assets/app_icon.png
deleted file mode 100644
index 00ff673..0000000
Binary files a/app/src/main/assets/app_icon.png and /dev/null differ
diff --git a/app/src/main/assets/app_icon_original.png b/app/src/main/assets/app_icon_original.png
deleted file mode 100644
index 6639e39..0000000
Binary files a/app/src/main/assets/app_icon_original.png and /dev/null differ
diff --git a/app/src/main/assets/gifs/AGENTS.md b/app/src/main/assets/gifs/AGENTS.md
deleted file mode 100644
index 8659a6f..0000000
--- a/app/src/main/assets/gifs/AGENTS.md
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-# gifs
-
-## Purpose
-GIF 动画资源目录,存放应用使用的动画 GIF 文件(001.gif ~ 152.gif),由 `AnimatedGif` Composable 组件通过 `sketch` 库加载显示。
-
-## Key Files
-
-| File | Description |
-|------|-------------|
-| `001.gif` ~ `152.gif` | 应用动画 GIF 资源 |
-
-## Subdirectories
-无
-
-## For AI Agents
-
-### Working In This Directory
-- 替换或新增 GIF 时保持连续编号
-- GIF 文件较大,注意 APK 体积影响
-- `AnimatedGif` 组件使用 `sketch` 库异步加载和播放
-
-## Dependencies
-
-### Internal
-- `core/src/main/kotlin/plus/rua/project/ui/AnimatedGif.kt` — GIF 显示组件
-
-### External
-- `sketch` 4.4.0(GIF 解码和播放)
-
-
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..782052f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..b0c9de2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..1d66005
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..40f2872
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..a6ad9d0
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..6c37040
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 0000000..be55a6d
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index aa3b9d9..fd3c00b 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -12,6 +12,21 @@ android {
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
consumerProguardFiles("proguard-rules.pro")
+
+ // 构建期扫描 assets/animations/ 生成 WebP 文件列表,避免运行期硬编码 (1..152)
+ // 与 assets/ 目录耦合却不校验,导致增删文件后隐性 bug
+ val webpFiles = layout.projectDirectory
+ .dir("src/main/assets/animations")
+ .asFile
+ .listFiles { f -> f.extension.equals("webp", ignoreCase = true) }
+ ?.map { it.name }
+ ?.sorted()
+ ?: emptyList()
+ require(webpFiles.isNotEmpty()) { "assets/animations/ 不应为空,请检查目录" }
+ // 拼成 Java 数组字面量: new String[]{"001.webp","002.webp",...}
+ val quoted = webpFiles.joinToString(",") { name -> "\"$name\"" }
+ val arrayLiteral = "new String[]{$quoted}"
+ buildConfigField("String[]", "WEBP_FILES", arrayLiteral)
}
buildTypes {
diff --git a/core/src/main/assets/AGENTS.md b/core/src/main/assets/AGENTS.md
index df256ae..2d87b65 100644
--- a/core/src/main/assets/AGENTS.md
+++ b/core/src/main/assets/AGENTS.md
@@ -1,25 +1,28 @@
-
+
# assets
## Purpose
-核心模块原始资产文件目录,与 `app/src/main/assets/` 镜像,包含 GIF 动画资源供 `AnimatedGif` Composable 组件加载。
+核心模块原始资产文件目录,通过 `AssetManager` 在运行时访问。包含应用内图标和动画 WebP 资源。
## Key Files
-无顶层文件
+| File | Description |
+|------|-------------|
+| `app_icon.webp` | 应用内展示用的图标(`Platform.kt` 的 `getAppIconUri()` 引用) |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
-| `gifs/` | GIF 动画资源(见 `gifs/AGENTS.md`) |
+| `animations/` | 动画 WebP 资源(见 `animations/AGENTS.md`) |
## For AI Agents
### Working In This Directory
-- 此目录与 `app/src/main/assets/` 内容同步
-- 通过 `AssetManager` 在运行时访问
+- 新增原始资源文件直接放入此目录或其子目录
+- **不与 `app/src/main/assets/` 镜像**:启动器图标在 `:app`,UI/WebP 资源在 `:core`
+- 通过 `file:///android_asset/` URI 在运行时访问
diff --git a/core/src/main/assets/gifs/001.webp b/core/src/main/assets/animations/001.webp
similarity index 100%
rename from core/src/main/assets/gifs/001.webp
rename to core/src/main/assets/animations/001.webp
diff --git a/core/src/main/assets/gifs/002.webp b/core/src/main/assets/animations/002.webp
similarity index 100%
rename from core/src/main/assets/gifs/002.webp
rename to core/src/main/assets/animations/002.webp
diff --git a/core/src/main/assets/gifs/003.webp b/core/src/main/assets/animations/003.webp
similarity index 100%
rename from core/src/main/assets/gifs/003.webp
rename to core/src/main/assets/animations/003.webp
diff --git a/core/src/main/assets/gifs/004.webp b/core/src/main/assets/animations/004.webp
similarity index 100%
rename from core/src/main/assets/gifs/004.webp
rename to core/src/main/assets/animations/004.webp
diff --git a/core/src/main/assets/gifs/005.webp b/core/src/main/assets/animations/005.webp
similarity index 100%
rename from core/src/main/assets/gifs/005.webp
rename to core/src/main/assets/animations/005.webp
diff --git a/core/src/main/assets/gifs/006.webp b/core/src/main/assets/animations/006.webp
similarity index 100%
rename from core/src/main/assets/gifs/006.webp
rename to core/src/main/assets/animations/006.webp
diff --git a/core/src/main/assets/gifs/007.webp b/core/src/main/assets/animations/007.webp
similarity index 100%
rename from core/src/main/assets/gifs/007.webp
rename to core/src/main/assets/animations/007.webp
diff --git a/core/src/main/assets/gifs/008.webp b/core/src/main/assets/animations/008.webp
similarity index 100%
rename from core/src/main/assets/gifs/008.webp
rename to core/src/main/assets/animations/008.webp
diff --git a/core/src/main/assets/gifs/009.webp b/core/src/main/assets/animations/009.webp
similarity index 100%
rename from core/src/main/assets/gifs/009.webp
rename to core/src/main/assets/animations/009.webp
diff --git a/core/src/main/assets/gifs/010.webp b/core/src/main/assets/animations/010.webp
similarity index 100%
rename from core/src/main/assets/gifs/010.webp
rename to core/src/main/assets/animations/010.webp
diff --git a/core/src/main/assets/gifs/011.webp b/core/src/main/assets/animations/011.webp
similarity index 100%
rename from core/src/main/assets/gifs/011.webp
rename to core/src/main/assets/animations/011.webp
diff --git a/core/src/main/assets/gifs/012.webp b/core/src/main/assets/animations/012.webp
similarity index 100%
rename from core/src/main/assets/gifs/012.webp
rename to core/src/main/assets/animations/012.webp
diff --git a/core/src/main/assets/gifs/013.webp b/core/src/main/assets/animations/013.webp
similarity index 100%
rename from core/src/main/assets/gifs/013.webp
rename to core/src/main/assets/animations/013.webp
diff --git a/core/src/main/assets/gifs/014.webp b/core/src/main/assets/animations/014.webp
similarity index 100%
rename from core/src/main/assets/gifs/014.webp
rename to core/src/main/assets/animations/014.webp
diff --git a/core/src/main/assets/gifs/015.webp b/core/src/main/assets/animations/015.webp
similarity index 100%
rename from core/src/main/assets/gifs/015.webp
rename to core/src/main/assets/animations/015.webp
diff --git a/core/src/main/assets/gifs/016.webp b/core/src/main/assets/animations/016.webp
similarity index 100%
rename from core/src/main/assets/gifs/016.webp
rename to core/src/main/assets/animations/016.webp
diff --git a/core/src/main/assets/gifs/017.webp b/core/src/main/assets/animations/017.webp
similarity index 100%
rename from core/src/main/assets/gifs/017.webp
rename to core/src/main/assets/animations/017.webp
diff --git a/core/src/main/assets/gifs/018.webp b/core/src/main/assets/animations/018.webp
similarity index 100%
rename from core/src/main/assets/gifs/018.webp
rename to core/src/main/assets/animations/018.webp
diff --git a/core/src/main/assets/gifs/019.webp b/core/src/main/assets/animations/019.webp
similarity index 100%
rename from core/src/main/assets/gifs/019.webp
rename to core/src/main/assets/animations/019.webp
diff --git a/core/src/main/assets/gifs/020.webp b/core/src/main/assets/animations/020.webp
similarity index 100%
rename from core/src/main/assets/gifs/020.webp
rename to core/src/main/assets/animations/020.webp
diff --git a/core/src/main/assets/gifs/021.webp b/core/src/main/assets/animations/021.webp
similarity index 100%
rename from core/src/main/assets/gifs/021.webp
rename to core/src/main/assets/animations/021.webp
diff --git a/core/src/main/assets/gifs/022.webp b/core/src/main/assets/animations/022.webp
similarity index 100%
rename from core/src/main/assets/gifs/022.webp
rename to core/src/main/assets/animations/022.webp
diff --git a/core/src/main/assets/gifs/023.webp b/core/src/main/assets/animations/023.webp
similarity index 100%
rename from core/src/main/assets/gifs/023.webp
rename to core/src/main/assets/animations/023.webp
diff --git a/core/src/main/assets/gifs/024.webp b/core/src/main/assets/animations/024.webp
similarity index 100%
rename from core/src/main/assets/gifs/024.webp
rename to core/src/main/assets/animations/024.webp
diff --git a/core/src/main/assets/gifs/025.webp b/core/src/main/assets/animations/025.webp
similarity index 100%
rename from core/src/main/assets/gifs/025.webp
rename to core/src/main/assets/animations/025.webp
diff --git a/core/src/main/assets/gifs/026.webp b/core/src/main/assets/animations/026.webp
similarity index 100%
rename from core/src/main/assets/gifs/026.webp
rename to core/src/main/assets/animations/026.webp
diff --git a/core/src/main/assets/gifs/027.webp b/core/src/main/assets/animations/027.webp
similarity index 100%
rename from core/src/main/assets/gifs/027.webp
rename to core/src/main/assets/animations/027.webp
diff --git a/core/src/main/assets/gifs/028.webp b/core/src/main/assets/animations/028.webp
similarity index 100%
rename from core/src/main/assets/gifs/028.webp
rename to core/src/main/assets/animations/028.webp
diff --git a/core/src/main/assets/gifs/029.webp b/core/src/main/assets/animations/029.webp
similarity index 100%
rename from core/src/main/assets/gifs/029.webp
rename to core/src/main/assets/animations/029.webp
diff --git a/core/src/main/assets/gifs/030.webp b/core/src/main/assets/animations/030.webp
similarity index 100%
rename from core/src/main/assets/gifs/030.webp
rename to core/src/main/assets/animations/030.webp
diff --git a/core/src/main/assets/gifs/031.webp b/core/src/main/assets/animations/031.webp
similarity index 100%
rename from core/src/main/assets/gifs/031.webp
rename to core/src/main/assets/animations/031.webp
diff --git a/core/src/main/assets/gifs/032.webp b/core/src/main/assets/animations/032.webp
similarity index 100%
rename from core/src/main/assets/gifs/032.webp
rename to core/src/main/assets/animations/032.webp
diff --git a/core/src/main/assets/gifs/033.webp b/core/src/main/assets/animations/033.webp
similarity index 100%
rename from core/src/main/assets/gifs/033.webp
rename to core/src/main/assets/animations/033.webp
diff --git a/core/src/main/assets/gifs/034.webp b/core/src/main/assets/animations/034.webp
similarity index 100%
rename from core/src/main/assets/gifs/034.webp
rename to core/src/main/assets/animations/034.webp
diff --git a/core/src/main/assets/gifs/035.webp b/core/src/main/assets/animations/035.webp
similarity index 100%
rename from core/src/main/assets/gifs/035.webp
rename to core/src/main/assets/animations/035.webp
diff --git a/core/src/main/assets/gifs/036.webp b/core/src/main/assets/animations/036.webp
similarity index 100%
rename from core/src/main/assets/gifs/036.webp
rename to core/src/main/assets/animations/036.webp
diff --git a/core/src/main/assets/gifs/037.webp b/core/src/main/assets/animations/037.webp
similarity index 100%
rename from core/src/main/assets/gifs/037.webp
rename to core/src/main/assets/animations/037.webp
diff --git a/core/src/main/assets/gifs/038.webp b/core/src/main/assets/animations/038.webp
similarity index 100%
rename from core/src/main/assets/gifs/038.webp
rename to core/src/main/assets/animations/038.webp
diff --git a/core/src/main/assets/gifs/039.webp b/core/src/main/assets/animations/039.webp
similarity index 100%
rename from core/src/main/assets/gifs/039.webp
rename to core/src/main/assets/animations/039.webp
diff --git a/core/src/main/assets/gifs/040.webp b/core/src/main/assets/animations/040.webp
similarity index 100%
rename from core/src/main/assets/gifs/040.webp
rename to core/src/main/assets/animations/040.webp
diff --git a/core/src/main/assets/gifs/041.webp b/core/src/main/assets/animations/041.webp
similarity index 100%
rename from core/src/main/assets/gifs/041.webp
rename to core/src/main/assets/animations/041.webp
diff --git a/core/src/main/assets/gifs/042.webp b/core/src/main/assets/animations/042.webp
similarity index 100%
rename from core/src/main/assets/gifs/042.webp
rename to core/src/main/assets/animations/042.webp
diff --git a/core/src/main/assets/gifs/043.webp b/core/src/main/assets/animations/043.webp
similarity index 100%
rename from core/src/main/assets/gifs/043.webp
rename to core/src/main/assets/animations/043.webp
diff --git a/core/src/main/assets/gifs/044.webp b/core/src/main/assets/animations/044.webp
similarity index 100%
rename from core/src/main/assets/gifs/044.webp
rename to core/src/main/assets/animations/044.webp
diff --git a/core/src/main/assets/gifs/045.webp b/core/src/main/assets/animations/045.webp
similarity index 100%
rename from core/src/main/assets/gifs/045.webp
rename to core/src/main/assets/animations/045.webp
diff --git a/core/src/main/assets/gifs/046.webp b/core/src/main/assets/animations/046.webp
similarity index 100%
rename from core/src/main/assets/gifs/046.webp
rename to core/src/main/assets/animations/046.webp
diff --git a/core/src/main/assets/gifs/047.webp b/core/src/main/assets/animations/047.webp
similarity index 100%
rename from core/src/main/assets/gifs/047.webp
rename to core/src/main/assets/animations/047.webp
diff --git a/core/src/main/assets/gifs/048.webp b/core/src/main/assets/animations/048.webp
similarity index 100%
rename from core/src/main/assets/gifs/048.webp
rename to core/src/main/assets/animations/048.webp
diff --git a/core/src/main/assets/gifs/049.webp b/core/src/main/assets/animations/049.webp
similarity index 100%
rename from core/src/main/assets/gifs/049.webp
rename to core/src/main/assets/animations/049.webp
diff --git a/core/src/main/assets/gifs/050.webp b/core/src/main/assets/animations/050.webp
similarity index 100%
rename from core/src/main/assets/gifs/050.webp
rename to core/src/main/assets/animations/050.webp
diff --git a/core/src/main/assets/gifs/051.webp b/core/src/main/assets/animations/051.webp
similarity index 100%
rename from core/src/main/assets/gifs/051.webp
rename to core/src/main/assets/animations/051.webp
diff --git a/core/src/main/assets/gifs/052.webp b/core/src/main/assets/animations/052.webp
similarity index 100%
rename from core/src/main/assets/gifs/052.webp
rename to core/src/main/assets/animations/052.webp
diff --git a/core/src/main/assets/gifs/053.webp b/core/src/main/assets/animations/053.webp
similarity index 100%
rename from core/src/main/assets/gifs/053.webp
rename to core/src/main/assets/animations/053.webp
diff --git a/core/src/main/assets/gifs/054.webp b/core/src/main/assets/animations/054.webp
similarity index 100%
rename from core/src/main/assets/gifs/054.webp
rename to core/src/main/assets/animations/054.webp
diff --git a/core/src/main/assets/gifs/055.webp b/core/src/main/assets/animations/055.webp
similarity index 100%
rename from core/src/main/assets/gifs/055.webp
rename to core/src/main/assets/animations/055.webp
diff --git a/core/src/main/assets/gifs/056.webp b/core/src/main/assets/animations/056.webp
similarity index 100%
rename from core/src/main/assets/gifs/056.webp
rename to core/src/main/assets/animations/056.webp
diff --git a/core/src/main/assets/gifs/057.webp b/core/src/main/assets/animations/057.webp
similarity index 100%
rename from core/src/main/assets/gifs/057.webp
rename to core/src/main/assets/animations/057.webp
diff --git a/core/src/main/assets/gifs/058.webp b/core/src/main/assets/animations/058.webp
similarity index 100%
rename from core/src/main/assets/gifs/058.webp
rename to core/src/main/assets/animations/058.webp
diff --git a/core/src/main/assets/gifs/059.webp b/core/src/main/assets/animations/059.webp
similarity index 100%
rename from core/src/main/assets/gifs/059.webp
rename to core/src/main/assets/animations/059.webp
diff --git a/core/src/main/assets/gifs/060.webp b/core/src/main/assets/animations/060.webp
similarity index 100%
rename from core/src/main/assets/gifs/060.webp
rename to core/src/main/assets/animations/060.webp
diff --git a/core/src/main/assets/gifs/061.webp b/core/src/main/assets/animations/061.webp
similarity index 100%
rename from core/src/main/assets/gifs/061.webp
rename to core/src/main/assets/animations/061.webp
diff --git a/core/src/main/assets/gifs/062.webp b/core/src/main/assets/animations/062.webp
similarity index 100%
rename from core/src/main/assets/gifs/062.webp
rename to core/src/main/assets/animations/062.webp
diff --git a/core/src/main/assets/gifs/063.webp b/core/src/main/assets/animations/063.webp
similarity index 100%
rename from core/src/main/assets/gifs/063.webp
rename to core/src/main/assets/animations/063.webp
diff --git a/core/src/main/assets/gifs/064.webp b/core/src/main/assets/animations/064.webp
similarity index 100%
rename from core/src/main/assets/gifs/064.webp
rename to core/src/main/assets/animations/064.webp
diff --git a/core/src/main/assets/gifs/065.webp b/core/src/main/assets/animations/065.webp
similarity index 100%
rename from core/src/main/assets/gifs/065.webp
rename to core/src/main/assets/animations/065.webp
diff --git a/core/src/main/assets/gifs/066.webp b/core/src/main/assets/animations/066.webp
similarity index 100%
rename from core/src/main/assets/gifs/066.webp
rename to core/src/main/assets/animations/066.webp
diff --git a/core/src/main/assets/gifs/067.webp b/core/src/main/assets/animations/067.webp
similarity index 100%
rename from core/src/main/assets/gifs/067.webp
rename to core/src/main/assets/animations/067.webp
diff --git a/core/src/main/assets/gifs/068.webp b/core/src/main/assets/animations/068.webp
similarity index 100%
rename from core/src/main/assets/gifs/068.webp
rename to core/src/main/assets/animations/068.webp
diff --git a/core/src/main/assets/gifs/069.webp b/core/src/main/assets/animations/069.webp
similarity index 100%
rename from core/src/main/assets/gifs/069.webp
rename to core/src/main/assets/animations/069.webp
diff --git a/core/src/main/assets/gifs/070.webp b/core/src/main/assets/animations/070.webp
similarity index 100%
rename from core/src/main/assets/gifs/070.webp
rename to core/src/main/assets/animations/070.webp
diff --git a/core/src/main/assets/gifs/071.webp b/core/src/main/assets/animations/071.webp
similarity index 100%
rename from core/src/main/assets/gifs/071.webp
rename to core/src/main/assets/animations/071.webp
diff --git a/core/src/main/assets/gifs/072.webp b/core/src/main/assets/animations/072.webp
similarity index 100%
rename from core/src/main/assets/gifs/072.webp
rename to core/src/main/assets/animations/072.webp
diff --git a/core/src/main/assets/gifs/073.webp b/core/src/main/assets/animations/073.webp
similarity index 100%
rename from core/src/main/assets/gifs/073.webp
rename to core/src/main/assets/animations/073.webp
diff --git a/core/src/main/assets/gifs/074.webp b/core/src/main/assets/animations/074.webp
similarity index 100%
rename from core/src/main/assets/gifs/074.webp
rename to core/src/main/assets/animations/074.webp
diff --git a/core/src/main/assets/gifs/075.webp b/core/src/main/assets/animations/075.webp
similarity index 100%
rename from core/src/main/assets/gifs/075.webp
rename to core/src/main/assets/animations/075.webp
diff --git a/core/src/main/assets/gifs/076.webp b/core/src/main/assets/animations/076.webp
similarity index 100%
rename from core/src/main/assets/gifs/076.webp
rename to core/src/main/assets/animations/076.webp
diff --git a/core/src/main/assets/gifs/077.webp b/core/src/main/assets/animations/077.webp
similarity index 100%
rename from core/src/main/assets/gifs/077.webp
rename to core/src/main/assets/animations/077.webp
diff --git a/core/src/main/assets/gifs/078.webp b/core/src/main/assets/animations/078.webp
similarity index 100%
rename from core/src/main/assets/gifs/078.webp
rename to core/src/main/assets/animations/078.webp
diff --git a/core/src/main/assets/gifs/079.webp b/core/src/main/assets/animations/079.webp
similarity index 100%
rename from core/src/main/assets/gifs/079.webp
rename to core/src/main/assets/animations/079.webp
diff --git a/core/src/main/assets/gifs/080.webp b/core/src/main/assets/animations/080.webp
similarity index 100%
rename from core/src/main/assets/gifs/080.webp
rename to core/src/main/assets/animations/080.webp
diff --git a/core/src/main/assets/gifs/081.webp b/core/src/main/assets/animations/081.webp
similarity index 100%
rename from core/src/main/assets/gifs/081.webp
rename to core/src/main/assets/animations/081.webp
diff --git a/core/src/main/assets/gifs/082.webp b/core/src/main/assets/animations/082.webp
similarity index 100%
rename from core/src/main/assets/gifs/082.webp
rename to core/src/main/assets/animations/082.webp
diff --git a/core/src/main/assets/gifs/083.webp b/core/src/main/assets/animations/083.webp
similarity index 100%
rename from core/src/main/assets/gifs/083.webp
rename to core/src/main/assets/animations/083.webp
diff --git a/core/src/main/assets/gifs/084.webp b/core/src/main/assets/animations/084.webp
similarity index 100%
rename from core/src/main/assets/gifs/084.webp
rename to core/src/main/assets/animations/084.webp
diff --git a/core/src/main/assets/gifs/085.webp b/core/src/main/assets/animations/085.webp
similarity index 100%
rename from core/src/main/assets/gifs/085.webp
rename to core/src/main/assets/animations/085.webp
diff --git a/core/src/main/assets/gifs/086.webp b/core/src/main/assets/animations/086.webp
similarity index 100%
rename from core/src/main/assets/gifs/086.webp
rename to core/src/main/assets/animations/086.webp
diff --git a/core/src/main/assets/gifs/087.webp b/core/src/main/assets/animations/087.webp
similarity index 100%
rename from core/src/main/assets/gifs/087.webp
rename to core/src/main/assets/animations/087.webp
diff --git a/core/src/main/assets/gifs/088.webp b/core/src/main/assets/animations/088.webp
similarity index 100%
rename from core/src/main/assets/gifs/088.webp
rename to core/src/main/assets/animations/088.webp
diff --git a/core/src/main/assets/gifs/089.webp b/core/src/main/assets/animations/089.webp
similarity index 100%
rename from core/src/main/assets/gifs/089.webp
rename to core/src/main/assets/animations/089.webp
diff --git a/core/src/main/assets/gifs/090.webp b/core/src/main/assets/animations/090.webp
similarity index 100%
rename from core/src/main/assets/gifs/090.webp
rename to core/src/main/assets/animations/090.webp
diff --git a/core/src/main/assets/gifs/091.webp b/core/src/main/assets/animations/091.webp
similarity index 100%
rename from core/src/main/assets/gifs/091.webp
rename to core/src/main/assets/animations/091.webp
diff --git a/core/src/main/assets/gifs/092.webp b/core/src/main/assets/animations/092.webp
similarity index 100%
rename from core/src/main/assets/gifs/092.webp
rename to core/src/main/assets/animations/092.webp
diff --git a/core/src/main/assets/gifs/093.webp b/core/src/main/assets/animations/093.webp
similarity index 100%
rename from core/src/main/assets/gifs/093.webp
rename to core/src/main/assets/animations/093.webp
diff --git a/core/src/main/assets/gifs/094.webp b/core/src/main/assets/animations/094.webp
similarity index 100%
rename from core/src/main/assets/gifs/094.webp
rename to core/src/main/assets/animations/094.webp
diff --git a/core/src/main/assets/gifs/095.webp b/core/src/main/assets/animations/095.webp
similarity index 100%
rename from core/src/main/assets/gifs/095.webp
rename to core/src/main/assets/animations/095.webp
diff --git a/core/src/main/assets/gifs/096.webp b/core/src/main/assets/animations/096.webp
similarity index 100%
rename from core/src/main/assets/gifs/096.webp
rename to core/src/main/assets/animations/096.webp
diff --git a/core/src/main/assets/gifs/097.webp b/core/src/main/assets/animations/097.webp
similarity index 100%
rename from core/src/main/assets/gifs/097.webp
rename to core/src/main/assets/animations/097.webp
diff --git a/core/src/main/assets/gifs/098.webp b/core/src/main/assets/animations/098.webp
similarity index 100%
rename from core/src/main/assets/gifs/098.webp
rename to core/src/main/assets/animations/098.webp
diff --git a/core/src/main/assets/gifs/099.webp b/core/src/main/assets/animations/099.webp
similarity index 100%
rename from core/src/main/assets/gifs/099.webp
rename to core/src/main/assets/animations/099.webp
diff --git a/core/src/main/assets/gifs/100.webp b/core/src/main/assets/animations/100.webp
similarity index 100%
rename from core/src/main/assets/gifs/100.webp
rename to core/src/main/assets/animations/100.webp
diff --git a/core/src/main/assets/gifs/101.webp b/core/src/main/assets/animations/101.webp
similarity index 100%
rename from core/src/main/assets/gifs/101.webp
rename to core/src/main/assets/animations/101.webp
diff --git a/core/src/main/assets/gifs/102.webp b/core/src/main/assets/animations/102.webp
similarity index 100%
rename from core/src/main/assets/gifs/102.webp
rename to core/src/main/assets/animations/102.webp
diff --git a/core/src/main/assets/gifs/103.webp b/core/src/main/assets/animations/103.webp
similarity index 100%
rename from core/src/main/assets/gifs/103.webp
rename to core/src/main/assets/animations/103.webp
diff --git a/core/src/main/assets/gifs/104.webp b/core/src/main/assets/animations/104.webp
similarity index 100%
rename from core/src/main/assets/gifs/104.webp
rename to core/src/main/assets/animations/104.webp
diff --git a/core/src/main/assets/gifs/105.webp b/core/src/main/assets/animations/105.webp
similarity index 100%
rename from core/src/main/assets/gifs/105.webp
rename to core/src/main/assets/animations/105.webp
diff --git a/core/src/main/assets/gifs/106.webp b/core/src/main/assets/animations/106.webp
similarity index 100%
rename from core/src/main/assets/gifs/106.webp
rename to core/src/main/assets/animations/106.webp
diff --git a/core/src/main/assets/gifs/107.webp b/core/src/main/assets/animations/107.webp
similarity index 100%
rename from core/src/main/assets/gifs/107.webp
rename to core/src/main/assets/animations/107.webp
diff --git a/core/src/main/assets/gifs/108.webp b/core/src/main/assets/animations/108.webp
similarity index 100%
rename from core/src/main/assets/gifs/108.webp
rename to core/src/main/assets/animations/108.webp
diff --git a/core/src/main/assets/gifs/109.webp b/core/src/main/assets/animations/109.webp
similarity index 100%
rename from core/src/main/assets/gifs/109.webp
rename to core/src/main/assets/animations/109.webp
diff --git a/core/src/main/assets/gifs/110.webp b/core/src/main/assets/animations/110.webp
similarity index 100%
rename from core/src/main/assets/gifs/110.webp
rename to core/src/main/assets/animations/110.webp
diff --git a/core/src/main/assets/gifs/111.webp b/core/src/main/assets/animations/111.webp
similarity index 100%
rename from core/src/main/assets/gifs/111.webp
rename to core/src/main/assets/animations/111.webp
diff --git a/core/src/main/assets/gifs/112.webp b/core/src/main/assets/animations/112.webp
similarity index 100%
rename from core/src/main/assets/gifs/112.webp
rename to core/src/main/assets/animations/112.webp
diff --git a/core/src/main/assets/gifs/113.webp b/core/src/main/assets/animations/113.webp
similarity index 100%
rename from core/src/main/assets/gifs/113.webp
rename to core/src/main/assets/animations/113.webp
diff --git a/core/src/main/assets/gifs/114.webp b/core/src/main/assets/animations/114.webp
similarity index 100%
rename from core/src/main/assets/gifs/114.webp
rename to core/src/main/assets/animations/114.webp
diff --git a/core/src/main/assets/gifs/115.webp b/core/src/main/assets/animations/115.webp
similarity index 100%
rename from core/src/main/assets/gifs/115.webp
rename to core/src/main/assets/animations/115.webp
diff --git a/core/src/main/assets/gifs/116.webp b/core/src/main/assets/animations/116.webp
similarity index 100%
rename from core/src/main/assets/gifs/116.webp
rename to core/src/main/assets/animations/116.webp
diff --git a/core/src/main/assets/gifs/117.webp b/core/src/main/assets/animations/117.webp
similarity index 100%
rename from core/src/main/assets/gifs/117.webp
rename to core/src/main/assets/animations/117.webp
diff --git a/core/src/main/assets/gifs/118.webp b/core/src/main/assets/animations/118.webp
similarity index 100%
rename from core/src/main/assets/gifs/118.webp
rename to core/src/main/assets/animations/118.webp
diff --git a/core/src/main/assets/gifs/119.webp b/core/src/main/assets/animations/119.webp
similarity index 100%
rename from core/src/main/assets/gifs/119.webp
rename to core/src/main/assets/animations/119.webp
diff --git a/core/src/main/assets/gifs/120.webp b/core/src/main/assets/animations/120.webp
similarity index 100%
rename from core/src/main/assets/gifs/120.webp
rename to core/src/main/assets/animations/120.webp
diff --git a/core/src/main/assets/gifs/121.webp b/core/src/main/assets/animations/121.webp
similarity index 100%
rename from core/src/main/assets/gifs/121.webp
rename to core/src/main/assets/animations/121.webp
diff --git a/core/src/main/assets/gifs/122.webp b/core/src/main/assets/animations/122.webp
similarity index 100%
rename from core/src/main/assets/gifs/122.webp
rename to core/src/main/assets/animations/122.webp
diff --git a/core/src/main/assets/gifs/123.webp b/core/src/main/assets/animations/123.webp
similarity index 100%
rename from core/src/main/assets/gifs/123.webp
rename to core/src/main/assets/animations/123.webp
diff --git a/core/src/main/assets/gifs/124.webp b/core/src/main/assets/animations/124.webp
similarity index 100%
rename from core/src/main/assets/gifs/124.webp
rename to core/src/main/assets/animations/124.webp
diff --git a/core/src/main/assets/gifs/125.webp b/core/src/main/assets/animations/125.webp
similarity index 100%
rename from core/src/main/assets/gifs/125.webp
rename to core/src/main/assets/animations/125.webp
diff --git a/core/src/main/assets/gifs/126.webp b/core/src/main/assets/animations/126.webp
similarity index 100%
rename from core/src/main/assets/gifs/126.webp
rename to core/src/main/assets/animations/126.webp
diff --git a/core/src/main/assets/gifs/127.webp b/core/src/main/assets/animations/127.webp
similarity index 100%
rename from core/src/main/assets/gifs/127.webp
rename to core/src/main/assets/animations/127.webp
diff --git a/core/src/main/assets/gifs/128.webp b/core/src/main/assets/animations/128.webp
similarity index 100%
rename from core/src/main/assets/gifs/128.webp
rename to core/src/main/assets/animations/128.webp
diff --git a/core/src/main/assets/gifs/129.webp b/core/src/main/assets/animations/129.webp
similarity index 100%
rename from core/src/main/assets/gifs/129.webp
rename to core/src/main/assets/animations/129.webp
diff --git a/core/src/main/assets/gifs/130.webp b/core/src/main/assets/animations/130.webp
similarity index 100%
rename from core/src/main/assets/gifs/130.webp
rename to core/src/main/assets/animations/130.webp
diff --git a/core/src/main/assets/gifs/131.webp b/core/src/main/assets/animations/131.webp
similarity index 100%
rename from core/src/main/assets/gifs/131.webp
rename to core/src/main/assets/animations/131.webp
diff --git a/core/src/main/assets/gifs/132.webp b/core/src/main/assets/animations/132.webp
similarity index 100%
rename from core/src/main/assets/gifs/132.webp
rename to core/src/main/assets/animations/132.webp
diff --git a/core/src/main/assets/gifs/133.webp b/core/src/main/assets/animations/133.webp
similarity index 100%
rename from core/src/main/assets/gifs/133.webp
rename to core/src/main/assets/animations/133.webp
diff --git a/core/src/main/assets/gifs/134.webp b/core/src/main/assets/animations/134.webp
similarity index 100%
rename from core/src/main/assets/gifs/134.webp
rename to core/src/main/assets/animations/134.webp
diff --git a/core/src/main/assets/gifs/135.webp b/core/src/main/assets/animations/135.webp
similarity index 100%
rename from core/src/main/assets/gifs/135.webp
rename to core/src/main/assets/animations/135.webp
diff --git a/core/src/main/assets/gifs/136.webp b/core/src/main/assets/animations/136.webp
similarity index 100%
rename from core/src/main/assets/gifs/136.webp
rename to core/src/main/assets/animations/136.webp
diff --git a/core/src/main/assets/gifs/137.webp b/core/src/main/assets/animations/137.webp
similarity index 100%
rename from core/src/main/assets/gifs/137.webp
rename to core/src/main/assets/animations/137.webp
diff --git a/core/src/main/assets/gifs/138.webp b/core/src/main/assets/animations/138.webp
similarity index 100%
rename from core/src/main/assets/gifs/138.webp
rename to core/src/main/assets/animations/138.webp
diff --git a/core/src/main/assets/gifs/139.webp b/core/src/main/assets/animations/139.webp
similarity index 100%
rename from core/src/main/assets/gifs/139.webp
rename to core/src/main/assets/animations/139.webp
diff --git a/core/src/main/assets/gifs/140.webp b/core/src/main/assets/animations/140.webp
similarity index 100%
rename from core/src/main/assets/gifs/140.webp
rename to core/src/main/assets/animations/140.webp
diff --git a/core/src/main/assets/gifs/141.webp b/core/src/main/assets/animations/141.webp
similarity index 100%
rename from core/src/main/assets/gifs/141.webp
rename to core/src/main/assets/animations/141.webp
diff --git a/core/src/main/assets/gifs/142.webp b/core/src/main/assets/animations/142.webp
similarity index 100%
rename from core/src/main/assets/gifs/142.webp
rename to core/src/main/assets/animations/142.webp
diff --git a/core/src/main/assets/gifs/143.webp b/core/src/main/assets/animations/143.webp
similarity index 100%
rename from core/src/main/assets/gifs/143.webp
rename to core/src/main/assets/animations/143.webp
diff --git a/core/src/main/assets/gifs/144.webp b/core/src/main/assets/animations/144.webp
similarity index 100%
rename from core/src/main/assets/gifs/144.webp
rename to core/src/main/assets/animations/144.webp
diff --git a/core/src/main/assets/gifs/145.webp b/core/src/main/assets/animations/145.webp
similarity index 100%
rename from core/src/main/assets/gifs/145.webp
rename to core/src/main/assets/animations/145.webp
diff --git a/core/src/main/assets/gifs/146.webp b/core/src/main/assets/animations/146.webp
similarity index 100%
rename from core/src/main/assets/gifs/146.webp
rename to core/src/main/assets/animations/146.webp
diff --git a/core/src/main/assets/gifs/147.webp b/core/src/main/assets/animations/147.webp
similarity index 100%
rename from core/src/main/assets/gifs/147.webp
rename to core/src/main/assets/animations/147.webp
diff --git a/core/src/main/assets/gifs/148.webp b/core/src/main/assets/animations/148.webp
similarity index 100%
rename from core/src/main/assets/gifs/148.webp
rename to core/src/main/assets/animations/148.webp
diff --git a/core/src/main/assets/gifs/149.webp b/core/src/main/assets/animations/149.webp
similarity index 100%
rename from core/src/main/assets/gifs/149.webp
rename to core/src/main/assets/animations/149.webp
diff --git a/core/src/main/assets/gifs/150.webp b/core/src/main/assets/animations/150.webp
similarity index 100%
rename from core/src/main/assets/gifs/150.webp
rename to core/src/main/assets/animations/150.webp
diff --git a/core/src/main/assets/gifs/151.webp b/core/src/main/assets/animations/151.webp
similarity index 100%
rename from core/src/main/assets/gifs/151.webp
rename to core/src/main/assets/animations/151.webp
diff --git a/core/src/main/assets/gifs/152.webp b/core/src/main/assets/animations/152.webp
similarity index 100%
rename from core/src/main/assets/gifs/152.webp
rename to core/src/main/assets/animations/152.webp
diff --git a/core/src/main/assets/animations/AGENTS.md b/core/src/main/assets/animations/AGENTS.md
new file mode 100644
index 0000000..c02985d
--- /dev/null
+++ b/core/src/main/assets/animations/AGENTS.md
@@ -0,0 +1,37 @@
+
+
+
+# animations
+
+## Purpose
+动画 WebP 资源目录,存放应用日历切换时随机展示的动画(文件名 `001.webp` ~ `NNN.webp`,由构建期扫描生成)。由 `AnimatedWebp` Composable 通过 `sketch` 库加载。
+
+> 历史命名曾为 `gifs/`(2026-06 前),实际格式一直是 WebP 动画,现已正名。
+
+## Key Files
+
+| File | Description |
+|------|-------------|
+| `001.webp` ~ `NNN.webp` | 动画 WebP 资源,编号零填充三位 |
+
+## Subdirectories
+无
+
+## For AI Agents
+
+### Working In This Directory
+- 替换或新增 WebP 时保持连续三位编号(如 `153.webp`)
+- **无需手动更新列表**:`core/build.gradle.kts` 在构建期扫描本目录生成 `BuildConfig.WEBP_FILES`
+- 由 `AnimatedWebpFilesTest` 守卫目录与列表一致
+- WebP 文件较大,注意 APK 体积
+
+## Dependencies
+
+### Internal
+- `core/src/main/kotlin/plus/rua/project/ui/AnimatedWebp.kt` — WebP 显示组件
+- `core/build.gradle.kts` — 构建期扫描注入 `BuildConfig.WEBP_FILES`
+
+### External
+- `sketch` 4.4.0(`sketch-animated-webp`,动画 WebP 解码播放)
+
+
diff --git a/core/src/main/assets/gifs/AGENTS.md b/core/src/main/assets/gifs/AGENTS.md
deleted file mode 100644
index 8659a6f..0000000
--- a/core/src/main/assets/gifs/AGENTS.md
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-# gifs
-
-## Purpose
-GIF 动画资源目录,存放应用使用的动画 GIF 文件(001.gif ~ 152.gif),由 `AnimatedGif` Composable 组件通过 `sketch` 库加载显示。
-
-## Key Files
-
-| File | Description |
-|------|-------------|
-| `001.gif` ~ `152.gif` | 应用动画 GIF 资源 |
-
-## Subdirectories
-无
-
-## For AI Agents
-
-### Working In This Directory
-- 替换或新增 GIF 时保持连续编号
-- GIF 文件较大,注意 APK 体积影响
-- `AnimatedGif` 组件使用 `sketch` 库异步加载和播放
-
-## Dependencies
-
-### Internal
-- `core/src/main/kotlin/plus/rua/project/ui/AnimatedGif.kt` — GIF 显示组件
-
-### External
-- `sketch` 4.4.0(GIF 解码和播放)
-
-
diff --git a/core/src/main/baseline-prof.txt b/core/src/main/baseline-prof.txt
index 8654ea2..5624a71 100644
--- a/core/src/main/baseline-prof.txt
+++ b/core/src/main/baseline-prof.txt
@@ -24042,25 +24042,25 @@ PLplus/rua/project/ui/AboutScreenKt$$ExternalSyntheticLambda1;->(Lkotlin/j
PLplus/rua/project/ui/AboutScreenKt$$ExternalSyntheticLambda1;->invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
PLplus/rua/project/ui/AboutScreenKt$$ExternalSyntheticLambda3;->(Lkotlin/jvm/functions/Function0;)V
PLplus/rua/project/ui/AboutScreenKt$$ExternalSyntheticLambda3;->invoke(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
-Lplus/rua/project/ui/AnimatedGifKt;
-SPLplus/rua/project/ui/AnimatedGifKt;->$r8$lambda$9BZMU2k1IVE0mP-Qo_-iEdny3Pc(Landroidx/compose/animation/core/Animatable;Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/Unit;
-SPLplus/rua/project/ui/AnimatedGifKt;->$r8$lambda$eedbksBryfiyumw--DGGjkjuU4A(Lcom/github/panpf/sketch/request/ImageOptions$Builder;)Lkotlin/Unit;
-SPLplus/rua/project/ui/AnimatedGifKt;->()V
-SPLplus/rua/project/ui/AnimatedGifKt;->AnimatedGif$lambda$4$0(Lcom/github/panpf/sketch/request/ImageOptions$Builder;)Lkotlin/Unit;
-SPLplus/rua/project/ui/AnimatedGifKt;->AnimatedGif$lambda$5$0(Landroidx/compose/animation/core/Animatable;Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/Unit;
-SPLplus/rua/project/ui/AnimatedGifKt;->AnimatedGif(Landroidx/compose/ui/Modifier;Ljava/lang/String;Ljava/lang/Object;Landroidx/compose/runtime/Composer;II)V
-Lplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda0;
-SPLplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda0;->()V
-SPLplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda0;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
-Lplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda1;
-SPLplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda1;->(Landroidx/compose/animation/core/Animatable;)V
-SPLplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
-Lplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda2;
-SPLplus/rua/project/ui/AnimatedGifKt$$ExternalSyntheticLambda2;->(Landroidx/compose/ui/Modifier;Ljava/lang/String;Ljava/lang/Object;II)V
-Lplus/rua/project/ui/AnimatedGifKt$AnimatedGif$1$1;
-SPLplus/rua/project/ui/AnimatedGifKt$AnimatedGif$1$1;->(Landroidx/compose/animation/core/Animatable;Lkotlin/coroutines/Continuation;)V
-SPLplus/rua/project/ui/AnimatedGifKt$AnimatedGif$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
-SPLplus/rua/project/ui/AnimatedGifKt$AnimatedGif$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
+Lplus/rua/project/ui/AnimatedWebpKt;
+SPLplus/rua/project/ui/AnimatedWebpKt;->$r8$lambda$9BZMU2k1IVE0mP-Qo_-iEdny3Pc(Landroidx/compose/animation/core/Animatable;Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/Unit;
+SPLplus/rua/project/ui/AnimatedWebpKt;->$r8$lambda$eedbksBryfiyumw--DGGjkjuU4A(Lcom/github/panpf/sketch/request/ImageOptions$Builder;)Lkotlin/Unit;
+SPLplus/rua/project/ui/AnimatedWebpKt;->()V
+SPLplus/rua/project/ui/AnimatedWebpKt;->AnimatedWebp$lambda$4$0(Lcom/github/panpf/sketch/request/ImageOptions$Builder;)Lkotlin/Unit;
+SPLplus/rua/project/ui/AnimatedWebpKt;->AnimatedWebp$lambda$5$0(Landroidx/compose/animation/core/Animatable;Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/Unit;
+SPLplus/rua/project/ui/AnimatedWebpKt;->AnimatedWebp(Landroidx/compose/ui/Modifier;Ljava/lang/String;Ljava/lang/Object;Landroidx/compose/runtime/Composer;II)V
+Lplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda0;
+SPLplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda0;->()V
+SPLplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda0;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+Lplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda1;
+SPLplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda1;->(Landroidx/compose/animation/core/Animatable;)V
+SPLplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda1;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
+Lplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda2;
+SPLplus/rua/project/ui/AnimatedWebpKt$$ExternalSyntheticLambda2;->(Landroidx/compose/ui/Modifier;Ljava/lang/String;Ljava/lang/Object;II)V
+Lplus/rua/project/ui/AnimatedWebpKt$AnimatedWebp$1$1;
+SPLplus/rua/project/ui/AnimatedWebpKt$AnimatedWebp$1$1;->(Landroidx/compose/animation/core/Animatable;Lkotlin/coroutines/Continuation;)V
+SPLplus/rua/project/ui/AnimatedWebpKt$AnimatedWebp$1$1;->create(Ljava/lang/Object;Lkotlin/coroutines/Continuation;)Lkotlin/coroutines/Continuation;
+SPLplus/rua/project/ui/AnimatedWebpKt$AnimatedWebp$1$1;->invokeSuspend(Ljava/lang/Object;)Ljava/lang/Object;
Lplus/rua/project/ui/BottomCardKt;
SPLplus/rua/project/ui/BottomCardKt;->$r8$lambda$MmxJZOraXJqgtb59adckNnYY5bg(Landroidx/compose/ui/semantics/SemanticsPropertyReceiver;)Lkotlin/Unit;
SPLplus/rua/project/ui/BottomCardKt;->$r8$lambda$T_UOYYXhKodAWp_8kVjxIHHBmW0(Ljava/lang/String;Lkotlinx/datetime/LocalDate;Ljava/lang/String;Ljava/lang/String;Landroidx/compose/runtime/State;Landroidx/compose/runtime/Composer;I)Lkotlin/Unit;
diff --git a/core/src/main/kotlin/plus/rua/project/Platform.kt b/core/src/main/kotlin/plus/rua/project/Platform.kt
index 8608d19..1e0626d 100644
--- a/core/src/main/kotlin/plus/rua/project/Platform.kt
+++ b/core/src/main/kotlin/plus/rua/project/Platform.kt
@@ -10,7 +10,7 @@ import androidx.compose.ui.platform.LocalContext
* @param webpFile WebP 文件名(如 "001.webp")
* @return 平台特定的资源 URI
*/
-fun getWebpUri(webpFile: String): String = "file:///android_asset/gifs/$webpFile"
+fun getWebpUri(webpFile: String): String = "file:///android_asset/animations/$webpFile"
fun getAppIconUri(): String = "file:///android_asset/app_icon.webp?v=2"
diff --git a/core/src/main/kotlin/plus/rua/project/ui/AnimatedGif.kt b/core/src/main/kotlin/plus/rua/project/ui/AnimatedWebp.kt
similarity index 84%
rename from core/src/main/kotlin/plus/rua/project/ui/AnimatedGif.kt
rename to core/src/main/kotlin/plus/rua/project/ui/AnimatedWebp.kt
index 9a6bb4f..b641955 100644
--- a/core/src/main/kotlin/plus/rua/project/ui/AnimatedGif.kt
+++ b/core/src/main/kotlin/plus/rua/project/ui/AnimatedWebp.kt
@@ -15,11 +15,15 @@ import com.github.panpf.sketch.rememberAsyncImageState
import com.github.panpf.sketch.request.ImageOptions
import com.github.panpf.sketch.request.repeatCount
import plus.rua.project.getWebpUri
+import plus.rua.project.shared.BuildConfig
/**
- * WebP 动画文件名列表(001.webp ~ 152.webp)。
+ * WebP 动画文件名列表,由构建期 `BuildConfig.WEBP_FILES` 注入
+ * (见 `core/build.gradle.kts` 扫描 `assets/animations/` 的 `buildConfigField`)。
+ *
+ * `internal` 让同模块测试可直接访问(见 `AnimatedWebpFilesTest`)。
*/
-private val WEBP_FILES = (1..152).map { "${it.toString().padStart(3, '0')}.webp" }
+internal val WEBP_FILES: List = BuildConfig.WEBP_FILES.toList()
/**
* 显示动画 WebP 图片,切换日期时随机选择一个。
@@ -31,7 +35,7 @@ private val WEBP_FILES = (1..152).map { "${it.toString().padStart(3, '0')}.webp"
* @param seed 用于控制重新随机时机的 key,变化时重新选择 WebP
*/
@Composable
-fun AnimatedGif(
+fun AnimatedWebp(
modifier: Modifier = Modifier,
contentDescription: String? = null,
seed: Any? = null,
diff --git a/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt b/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt
index 75e5d0a..27df096 100644
--- a/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt
+++ b/core/src/main/kotlin/plus/rua/project/ui/BottomCard.kt
@@ -172,7 +172,7 @@ fun BottomCard(
)
}
Spacer(modifier = Modifier.height(12.dp))
- AnimatedGif(
+ AnimatedWebp(
modifier = Modifier
.fillMaxWidth()
.height(140.dp)
diff --git a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt
index 153f5fc..0285dfe 100644
--- a/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt
+++ b/core/src/main/kotlin/plus/rua/project/ui/CalendarMonthView.kt
@@ -580,7 +580,7 @@ private fun BottomCardArea(
slideAnim.animateTo(if (isYearView) 1f else 0f, tween(200))
}
val slideProgress = slideAnim.value
- // 延迟一帧显示 BottomCard,避免 AnimatedGif 和 lunar 计算阻塞首帧
+ // 延迟一帧显示 BottomCard,避免 AnimatedWebp 和 lunar 计算阻塞首帧
var hasLoaded by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
delay(32)
diff --git a/core/src/test/kotlin/plus/rua/project/ui/AnimatedWebpFilesTest.kt b/core/src/test/kotlin/plus/rua/project/ui/AnimatedWebpFilesTest.kt
new file mode 100644
index 0000000..2766739
--- /dev/null
+++ b/core/src/test/kotlin/plus/rua/project/ui/AnimatedWebpFilesTest.kt
@@ -0,0 +1,49 @@
+package plus.rua.project.ui
+
+import java.io.File
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+import org.junit.Test
+
+/**
+ * 守卫:运行期使用的 WebP 文件列表必须与 assets/animations/ 目录实际内容一致。
+ *
+ * 防止两类回归:
+ * 1. 有人把 BuildConfig 方案回退成硬编码 (1..152),与目录脱钩后增删文件即隐性 bug
+ * 2. assets/animations/ 在 CI / 打包流程中意外丢失或被 Git LFS 过滤掉
+ *
+ * 注:当前实现里 WEBP_FILES 与目录都来自同一次构建期扫描,二者天然一致;
+ * 本测试的核心价值是锁定「两者一致」这个不变量,使上述回归一旦发生即立即失败。
+ */
+class AnimatedWebpFilesTest {
+
+ private val animationsDir = File("src/main/assets/animations")
+
+ @Test
+ fun webpFilesMatchDirectoryContents() {
+ assertTrue(animationsDir.exists(), "assets/animations 目录应存在: ${animationsDir.absolutePath}")
+
+ val onDisk = animationsDir.listFiles { f -> f.extension.equals("webp", ignoreCase = true) }
+ ?.map { it.name }
+ ?.sorted()
+ ?: emptyList()
+ assertTrue(onDisk.isNotEmpty(), "assets/animations 不应为空(若失败请检查 Git LFS / checkout 完整性)")
+
+ // WEBP_FILES 由构建期 BuildConfig 注入(见 core/build.gradle.kts 的 buildConfigField)
+ val inCode = WEBP_FILES.sorted()
+
+ assertEquals(onDisk, inCode, "WEBP_FILES 必须与 assets/animations/ 实际 webp 文件一一对应")
+ }
+
+ @Test
+ fun webpFilesUseZeroPaddedThreeDigitNames() {
+ // 锁定命名约定:NNN.webp(三位零填充),防止有人误改成 1.webp / 01.webp 等
+ val expected = Regex("""^\d{3}\.webp$""")
+ WEBP_FILES.forEach { name ->
+ assertTrue(
+ expected.matches(name),
+ "文件名 $name 不符合 NNN.webp 约定,getWebpUri 与 AnimatedWebp 依赖此格式",
+ )
+ }
+ }
+}
diff --git a/scripts/profile.sh b/scripts/profile.sh
index 8e3d403..036f7e8 100755
--- a/scripts/profile.sh
+++ b/scripts/profile.sh
@@ -225,7 +225,7 @@ run_scenario() {
date_select)
SCENARIO_NAME="点击日期选择"
- SCENARIO_DESC="依次点击日历中不同位置的日期,测试 DayCell 重组和 AnimatedGif 动画性能"
+ SCENARIO_DESC="依次点击日历中不同位置的日期,测试 DayCell 重组和 AnimatedWebp 动画性能"
echo ""
echo "[场景] ${SCENARIO_NAME}"
echo " ${SCENARIO_DESC}"
@@ -1100,7 +1100,7 @@ EOF
cat >> "${REPORT_FILE}" <