@rainlotus97/ui
v1.0.0
Published
仙侠风游戏 UI 组件库
Readme
Xianxia UI 仙侠风游戏组件库
基于 Atlas Sprite Sheet + 运行时裁图 + 9-slice 渲染 的 Vue3 组件库,专为仙侠风游戏 UI 设计。
核心特性
✅ 运行时从 Atlas 裁子图 — 主题仍然只维护一张 atlas,组件加载时用 canvas 裁出目标资产
✅ 自动去背 — 裁出的子图会把品红背景 key 掉,生成透明 PNG data URL
✅ 9-slice 自适应 — 容器类组件任意拉伸不变形
✅ 主题切换 — 换一张 atlas 图 + 配置即可切换整套主题
✅ 标准化项目结构 — Vite + Vue3 + TypeScript
✅ 零依赖运行时 — 纯 CSS 实现,无需额外库
✅ 线条游戏组件 — 不依赖固定尺寸的装饰图,可直接用于移动端活动入口、任务条目、头像与操作界面
线条组件
以下组件以 CSS 边线、角花和内嵌 SVG 图标构成,tone 均支持 jade、gold、rose、stone。它们默认适配窄屏;容器宽度由父级控制,不会把素材拉伸变形。
<script setup lang="ts">
import { XActivityPanel, XAvatarFrame, XCultivationPanel, XPlayerHud, XTabBar, XTaskEntry } from '@rainlotus97/ui'
</script>
<template>
<XActivityPanel
title="问鼎九霄"
description="踏入云海秘境,争夺登仙榜首。"
time-left="余 6日12时"
reward="首通:灵石 x 300"
icon="crown"
tone="gold"
@click="openActivity"
/>
<XTaskEntry
title="宗门悬赏"
description="完成一次灵脉巡查"
:progress="2"
:progress-max="3"
icon="mission"
@click="openTask"
/>
<XAvatarFrame src="/avatars/hero.webp" alt="云岫" level="42" tone="jade" />
<XPlayerHud
player-name="云岫"
realm="炼气后期"
level="42"
:items="[
{ label: '修为', value: '12.35万', suffix: '+', icon: 'cultivation' },
{ label: '灵石', value: 2568, suffix: '枚', icon: 'spirit-stone', tone: 'gold' }
]"
/>
<XCultivationPanel
title="修炼"
realm="炼气后期"
current="1230"
max="2345"
:progress="52"
progress-label="练气六层"
timer="00:12:34"
efficiency="36/5秒"
next-breakthrough="筑基期"
:metrics="[
{ label: '修炼增益', value: '+18%', icon: 'spark' },
{ label: '渡劫概率', value: '72%', icon: 'crown', tone: 'gold' },
{ label: '服药', value: '回春丹', icon: 'pill', tone: 'rose' },
{ label: '武器法宝', value: '青锋剑', icon: 'sword', tone: 'stone' }
]"
@action="enterCultivation"
/>
<XTabBar
v-model="activeTab"
:items="[
{ value: 'map', label: '云游', icon: 'map' },
{ value: 'cultivation', label: '修炼', icon: 'cultivation' },
{ value: 'sect', label: '宗门', icon: 'sect' },
{ value: 'backpack', label: '背包', icon: 'backpack' },
{ value: 'settings', label: '设置', icon: 'settings' }
]"
/>
</template>| 组件 | 用途 | 关键 Props |
| --- | --- | --- |
| XActivityPanel | 活动入口或运营卡片 | title、description、timeLeft、reward、icon、tone |
| XTaskEntry | 日常、主线、奖励领取 | state (active/ready/done/locked)、progress、progressMax、tag |
| XAvatarFrame | 玩家、同道、NPC 头像框 | src、alt、level、status、shape、size |
| XPlayerHud | 人物信息与资源顶部栏 | playerName、realm、level、items,支持 avatar 插槽 |
| XCultivationPanel | 修炼、增益、渡劫与装备状态面板 | current、max、progress、metrics、timer |
| XTabBar | 移动端底部导航入口 | modelValue、items,支持 select 事件 |
XActivityPanel 提供 background 与 icon 插槽;当另一个项目已有角色或活动原图时,直接放入插槽即可。组件本身不生成或绑定背景图片。
XAvatarFrame 默认采用圆形边框,等级角标为圆形,关系/在线状态角标为胶囊形;只有需要装备栏、图鉴格位时再传入 shape="square"。
XTabBar 会按 items 数量自动分栏,适合固定在移动端底部;组件只负责线条容器与交互状态,入口内容由项目传入。
XCultivationPanel 使用 CSS/SVG 绘制 270° 进度环,进度从左下向右下缓动推进,环线使用玉青到鎏金的渐变;metrics 可传入修炼增益、渡劫概率、服药、武器法宝等项目数据。中心人物支持 figure 插槽替换为项目自己的透明线稿或角色素材。
<XCultivationPanel ...>
<template #figure>
<img src="/line-assets/cultivation-figure-line-crop.png" alt="" aria-hidden="true" />
</template>
</XCultivationPanel>角色与物品面板
新增的 XInventoryPanel、XEquipmentPanel、XUpgradePanel 和 XItemArt 用于组合背包、人物穿戴替换与法器升级流程。物品图不复用类型图标:每个物品都拥有独立的 id、assetKey、assetPath 和 artPrompt。
当前内置 60 件故事物品目录,分为武器、防具、饰品、丹药、药草和材料六类,位于 src/assets/items/item-catalog.ts。图像生成规范位于 ITEM_SHEET_PROMPTS.md:每张 sprite sheet 固定 5×2 个物品格,每格 256×256,总尺寸 1280×512;生成完成后可直接通过 iconSheet 与 iconFrame 接入,或切成独立 PNG。
正式物品图要求使用实体材质渲染,不使用线条图或 emoji 占位。图像尚未接入时,组件会显示语义占位字形,方便先验证布局和交互。
项目结构
xianxia-ui/
├── src/
│ ├── components/ # 组件
│ │ ├── XButton.vue
│ │ ├── XCard.vue
│ │ └── XPanel.vue
│ ├── composables/ # 组合式 API
│ │ ├── useTheme.ts # 主题管理
│ │ └── useAtlasSprite.ts # Atlas 样式生成
│ ├── types/ # 类型定义
│ │ └── index.ts
│ ├── assets/ # 资产文件
│ │ └── themes/
│ │ └── default/
│ │ └── theme.json # 主题配置(组件在 atlas 中的坐标)
│ ├── styles/
│ │ └── global.css
│ └── index.ts # 入口
├── examples/ # 演示应用
│ ├── App.vue
│ └── main.ts
├── public/
│ └── atlas-full-atlas-components-v1.png # Atlas 图集
├── vite.config.ts
├── tsconfig.json
└── package.json快速开始
安装依赖
pnpm install启动开发服务器
pnpm dev访问 http://localhost:5173/ 查看演示页面。
构建组件库
pnpm build发布
构建会先生成 dist 中的 ESM、CommonJS、CSS 和 TypeScript 声明文件,prepack 会自动执行构建:
pnpm pack --dry-run
npm publish --access public发布账号需要对 @xianxia scope 有权限。应用生产环境使用 semver 安装;组件库修改期间,应用可使用 pnpm dev:ui 直接读取兄弟目录源码进行 HMR。
License
MIT License,详见 LICENSE。
组件使用
1. 初始化主题
<script setup>
import { onMounted } from 'vue'
import { useTheme } from '@rainlotus97/ui'
const { loadTheme } = useTheme()
onMounted(async () => {
await loadTheme('default')
})
</script>2. 使用组件
<template>
<!-- 按钮 -->
<XButton token="button.primary" @click="handleClick">
开始修仙
</XButton>
<!-- 自定义尺寸 -->
<XButton token="button.primary" size="20rem">
大按钮
</XButton>
<!-- 卡片 -->
<XCard token="card.feature" size="28rem">
<template #title>历练</template>
<template #content>游历四方<br>获取资源</template>
</XCard>
<!-- 面板 -->
<XPanel token="panel.announcement" size="36rem">
<div>自定义内容</div>
</XPanel>
</template>
<script setup>
import { XButton, XCard, XPanel } from '@rainlotus97/ui'
const handleClick = () => {
console.log('按钮被点击')
}
</script>主题配置说明
主题配置文件 src/assets/themes/default/theme.json 定义了每个组件在 atlas 中的位置:
{
"name": "default",
"version": "1.0.0",
"atlasPath": "/atlas-full-atlas-components-v1.png",
"atlasSize": {
"width": 1024,
"height": 1024
},
"assets": {
"button.primary": {
"type": "9slice",
"sprite": {
"x": 20, // 在 atlas 中的 x 坐标
"y": 20, // 在 atlas 中的 y 坐标
"width": 680, // 组件宽度
"height": 180 // 组件高度
},
"slice": {
"top": 60, // 9-slice 上边距(边角装饰区域)
"right": 120,
"bottom": 60,
"left": 120
},
"defaultSize": "16rem",
"category": "button"
}
}
}调整组件位置和 9-slice 边距
如果组件显示不正确(边角被拉伸、位置偏移),只需编辑 theme.json:
- 调整坐标 — 修改
sprite.x/y定位到正确位置 - 调整尺寸 — 修改
sprite.width/height裁切正确区域 - 调整 9-slice — 修改
slice值,增大/减小边角装饰区域
刷新页面即可看到效果,无需重新生成图片。
切换主题
创建新主题:
- 准备新的 atlas 图集(保持组件布局一致)
- 复制
src/assets/themes/default/为src/assets/themes/dark/ - 替换
atlasPath指向新图集 - 调整各组件的坐标(如果布局变化)
加载新主题:
await loadTheme('dark')技术原理
为什么运行时裁子图?
- 浏览器原生
border-image不能从 atlas 子区域取图:它只能接收整张图片作为 source。 - 主题仍然是一张图:组件通过
theme.json的坐标裁出子图,不需要手工导出多张 PNG。 - 9-slice 作用在裁出的透明子图上:这样四角固定、边和中心可伸缩,和验证 01 的结论一致。
9-slice 原理
组件先用 canvas 从 atlas 裁出某个区域并去掉品红背景,再把裁出的透明 PNG 作为 border-image-source:
border-image-source: url(cropped-transparent-sprite.png);
border-image-slice: 60 120 60 120; /* 定义边角区域 */
border-image-width: 60px 120px 60px 120px;组件拉伸时,四个边角固定,四条边单向拉伸,中心区域双向拉伸。
当前组件
- ✅ XButton — 按钮(横向胶囊 + 小方形)
- ✅ XCard — 功能卡片
- ✅ XPanel — 面板容器(公告横幅 + 方形面板)
- ⏸️ 装饰元素 — 鹤装饰(已生成,未封装组件)
下一步
- [ ] 完善演示页面(展示更多尺寸变化、交互状态)
- [ ] 添加更多组件(对话框、进度条、角色卡)
- [ ] 优化 9-slice 配置(可视化调整工具)
- [ ] 生成更多风格的 atlas(暗黑主题、节日主题)
- [ ] 响应式适配方案(rem 基准计算)
许可
ISC
