init with react+axum+spacetimedb
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-26 18:06:23 +08:00
commit cbc27bad4a
20199 changed files with 883714 additions and 0 deletions

178
UI_CODING_STANDARD.md Normal file
View File

@@ -0,0 +1,178 @@
# UI Coding Standard
> **会话交接 / 改动总览**:见 `docs/experience/AGENT_UI_CHANGELOG.md`文件映射、9-slice 架构、已知坑、未收尾项)。
## Goal
This project should treat `public/UI` and `public/Icons` as the single source of truth for fantasy UI chrome and item icon semantics. New UI code should match asset naming first, then map product meaning onto those assets through a small semantic layer in code.
## Asset Folders
- `public/UI`: UI chrome, tabs, buttons, frames, arrows, HUD, equipment-slot markers, map controls.
- `public/Icons`: item and ability icons. Most files are semantic item glyphs with numeric prefixes.
## Naming Rules Observed
### `public/UI`
- `1_*`: base interaction assets and compact function glyphs.
- `11_*`: directional arrows and small action markers.
- `_s`: small size.
- `_xs`: extra-small size.
- `_pick` / `_picked`: selected, active, or pressed state.
- `_d`: disabled, dimmed, or inactive state.
- `_on` / `_off`: explicit toggle state.
- `Hud_icon_*`: HUD/tab-friendly icons.
- `Icon_Eq_*`: equipment-slot semantics.
- `Map_*`: map-only controls or chrome.
- `Frame_*`, `Popup_*`, `Dialogue_*`, `Inventory_*`, `Quest_*`, `Skill_*`: domain-specific container assets.
### `public/Icons`
- Pattern is usually `NN_name.png`.
- The numeric prefix is an atlas/catalog index, not UI meaning.
- Semantic matching should be based on the name segment, not the number.
- Prefer item-like meanings such as `sword`, `magic`, `potion`, `relic`, `treasure`, `crystal`, `shield`.
## Required Coding Pattern
- Do not hardcode random asset filenames directly in feature components.
- Put semantic mappings in `src/uiAssets.ts`.
- Render pixel UI assets through `src/components/PixelIcon.tsx`.
- Pick icons by UI meaning, not by whichever file "looks close enough" in one screen.
- If a state exists in art, wire both active and inactive assets instead of tinting one image in CSS.
- Major UI chrome should use authored textures from `public/UI`, not only plain Tailwind borders.
- Do not mix `background` shorthand with `backgroundImage` / `backgroundRepeat` / `backgroundPosition` / `backgroundSize` in the same inline `style` object; use longhand fields consistently to avoid React rerender warnings and stale paint bugs.
## Layout Rules For Icon UI
- Navigation/tab icons should be visually larger than body text.
- Preferred structure is `icon above + label below`, centered, instead of inline icon-text rows for compact nav.
- Tab labels should stay readable on mobile with `clamp()`-based sizing.
- Touch targets should remain comfortable on phones; do not ship tiny icon buttons.
## Responsive Rules For UI Images
- Do not stretch framed pixel UI with `background-size: 100% 100%`.
- Framed buttons, panels, tabs, modal shells, and title plates must use 9-slice scaling.
- Corners stay fixed, edges only stretch or repeat on one axis, and the center fills independently.
- Use `clamp()` for padding, min-height, icon size, and text size when the same control appears on desktop and mobile.
- Avoid fixed pixel-only widths for primary panels and buttons unless the element is purely decorative.
- For modal or framed panels, allow internal scrolling on small screens instead of overflowing the viewport.
- Decorative UI should never block content readability; add a dark tint layer when needed.
- Avoid non-integer `scale()` hover effects on pixel-framed controls; prefer `translateY`, brightness, or shadow shifts.
## Pixel Rendering Rules
- Pixel icons must use point-sampled rendering such as `image-rendering: pixelated`.
- Pixel-framed UI should keep consistent slice thickness on both axes; never uniformly squash the whole frame texture.
- Any large information plate inside a popup must also be skinned with UI art, not a plain dark rectangle.
## Semantic Mapping Used Now
### Tabs
- `character` -> `1_armor` / `1_armor_d`
- `adventure` -> `1_weapon` / `1_weapon_d`
- `inventory` -> `Hud_icon_inventory` / `Hud_icon_inventory_d`
### World Select
- `wuxia` -> `38_sword`
- `xianxia` -> `72_magic`
### Shared Chrome
- option arrow -> `11_right_arrow`
- map header -> `Map_icon_action`
- close action -> `1_exit_s`
### UI Shell / Panels
- app shell -> `Background_fill`
- world selection buttons -> `1_orange_button`, `1_violet_button`(极扁条形图,切片须符合尺寸约束,见「已知问题」)
- character selection card -> `pick_hero_frame` + `pick_hero_bg`
- tab shell -> `Shop_tab`, `Shop_tab_picked`
- section panel -> `Frame_bg_big_2`
- story panel -> `Dialogue_frame`
- inventory panel -> `Inventory_bg`
- stats panel -> `Stats_bar`
- choice button -> `Options_bar`
- modal shell -> `Popup_window`
- map info plate -> `Dialogue_frame`
- map node cells -> `Map_frame`
- map diagram canvas -> `Frame_bg_big_2`
- scene title -> `Title_frame_m`
- app / root chrome -> `Background_fill` + light tint避免整块纯深蓝底
### Equipment / Inventory
- `武器` -> `Icon_Eq_Weapon`
- `护甲` -> `Icon_Eq_Chest`
- `饰品` -> `Icon_Eq_ring`
- `消耗品` -> `12_potion`
- `稀有品` -> `68_relic`
- `专属品` -> `47_treasure`
- `材料` -> `45_crystal`
## State Handling
- Selected tab/button: prefer `_pick` or `_picked`.
- Disabled/unavailable action: prefer `_d`.
- Toggle widgets: prefer `_on` / `_off`.
- Size changes must use authored sizes like `_s` / `_xs`; avoid CSS-downscaling a large ornamental asset when a small authored version exists.
## Assets To Avoid By Default
These names are ambiguous and should not be used as standards until art is confirmed:
- `* copy`
- `Avatar_ref`
- `map_ref`
- `special_button`
- `Skill_bar_long_nopt`
- `Skill_bar_noColbs`
- `Options_button_save_p`
- `11_Q_d`
## Review Checklist For New UI
- Does the component use `src/uiAssets.ts` instead of ad-hoc file paths?
- Does the chosen icon name match the feature meaning?
- If the control has selected/disabled states, are those states backed by asset variants?
- Is the asset from `UI` for chrome and `Icons` for item semantics?
- Is pixel rendering preserved?
## Example
```tsx
import { PixelIcon } from './components/PixelIcon';
import { TAB_ICONS } from './uiAssets';
<PixelIcon
src={active ? TAB_ICONS.inventory.active : TAB_ICONS.inventory.inactive}
className="h-4 w-4"
/>
```
## Known issues / 已知问题
### 开局「武侠 / 仙侠」按钮中部发空 / 像透明
**现象**:世界选择页上,`1_orange_button` / `1_violet_button` 套 9-slice 后,中间区域异常,像没画上或透出背景。
**正确原因(切片几何,而非文字冲突)**
1. **图源尺寸**`1_orange_button.png` / `1_violet_button.png` 实际为 **125×28** 的横向条(可用设计工具或脚本读 IHDR 确认)。
2. **非法切片**:若 `border-image-slice` 在竖直方向取 `top + bottom >= 高度(28)`,则图源里用于「中间横条」的像素行数为 **0**。此时 `fill` 没有可拉伸的中间带,浏览器无法正确铺满内容区,中间会发空或表现异常。
3. **错误补救**:用 `baseColor` 铺底虽能盖住背景,但**与素材本身的渐变/内描边不一致**,且中间没有原画的边框层次,视觉上「只有一块平色 + 外框」,不符合预期。
**不是**`PixelIcon``pixel-world-button__label` 抢层级或颜色把中间「挡住」;二者在内容区内,不会导致 9-slice 中间带消失。
**正确修改方式**
- **先按像素量体裁衣**:保证 `slice.top + slice.bottom < 图高``slice.left + slice.right < 图宽`。对 28px 高的条,上下 slice 宜各约 **810px**(需与素材圆角/浮雕厚度对齐),留出 **约 812px** 高的中间行供纵向拉伸。
- 横条在 UI 里被拉得很高时,中间带主要靠 **纵向 stretch**`border-image-repeat` 对边可用 `stretch`(条形成品常见),按观感在 `round` / `stretch` 间微调。
- 仅在确认图源中心 **确实透明**RGBA且引擎式叠色才是需求时再考虑 `baseColor` 或换一张中心有底的按钮图。
**维护提醒**:新增 9-slice 配置前,先读 **宽高**,再填 slice避免 `top+bottom``left+right` 把中间切片挤没。