feat: 自动创建API文档目录

This commit is contained in:
unanmed 2025-03-26 22:06:06 +08:00
parent 1294c5f1ca
commit 3581e2604b
10 changed files with 1483 additions and 313 deletions

97
docs/.vitepress/api.ts Normal file
View File

@ -0,0 +1,97 @@
import fs from 'fs-extra';
import path from 'path';
import chokidar from 'chokidar';
import { DefaultTheme } from 'vitepress';
const apiDir = path.resolve('./docs/api');
const sidebarConfigPath = path.resolve('./docs/.vitepress/apiSidebar.ts');
const weight: Record<string, number> = {
主页: 10,
函数: 5
};
function generateSidebar(): void {
const sidebar: DefaultTheme.SidebarItem[] = [
{ text: '目录', link: '/api/' }
];
// 遍历 api 目录,查找 package 目录
const packages = fs
.readdirSync(apiDir)
.filter(pkg => fs.statSync(path.join(apiDir, pkg)).isDirectory());
packages.forEach(pkg => {
const pkgPath = path.join(apiDir, pkg);
const files = fs
.readdirSync(pkgPath)
.filter(file => file.endsWith('.md'));
const items: DefaultTheme.SidebarItem[] = files.map(file => {
const filePath = `api/${pkg}/${file}`;
const fileName = path.basename(file, '.md');
return {
text:
fileName === 'index'
? '主页'
: fileName === 'functions'
? '函数'
: fileName,
link: `/${filePath.replace(/\\/g, '/')}` // 兼容 Windows 路径
};
});
items.sort((a, b) => {
const titleA = a.text ?? '';
const titleB = b.text ?? '';
return (weight[titleA] ?? 0) - (weight[titleB] ?? 0);
});
sidebar.push({
text: pkg,
collapsed: true,
items
});
});
// 生成 sidebar.ts
const sidebarContent = `import { DefaultTheme } from 'vitepress';
export default ${JSON.stringify(
sidebar,
null,
4
)} as DefaultTheme.SidebarItem[];`;
fs.writeFileSync(sidebarConfigPath, sidebarContent);
console.log('✅ Sidebar 配置已更新');
}
// 初次运行
generateSidebar();
// 监听文件变动
chokidar
.watch(apiDir, { ignoreInitial: true })
.on('add', filePath => {
console.log(`📄 文件新增: ${filePath}`);
generateSidebar();
})
.on('unlink', filePath => {
console.log(`❌ 文件删除: ${filePath}`);
generateSidebar();
})
.on('addDir', dirPath => {
console.log(`📁 目录新增: ${dirPath}`);
generateSidebar();
})
.on('unlinkDir', dirPath => {
console.log(`📁 目录删除: ${dirPath}`);
generateSidebar();
})
.on('raw', (event, path, details) => {
if (event === 'rename') {
console.log(`🔄 文件或文件夹重命名: ${path}`);
generateSidebar();
}
});

View File

@ -0,0 +1,338 @@
import { DefaultTheme } from 'vitepress';
export default [
{
"text": "目录",
"link": "/api/"
},
{
"text": "motajs-client",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-client/index.md"
}
]
},
{
"text": "motajs-client-base",
"collapsed": true,
"items": [
{
"text": "KeyCode",
"link": "/api/motajs-client-base/KeyCode.md"
},
{
"text": "主页",
"link": "/api/motajs-client-base/index.md"
}
]
},
{
"text": "motajs-common",
"collapsed": true,
"items": [
{
"text": "Logger",
"link": "/api/motajs-common/Logger.md"
},
{
"text": "函数",
"link": "/api/motajs-common/functions.md"
},
{
"text": "主页",
"link": "/api/motajs-common/index.md"
}
]
},
{
"text": "motajs-legacy-client",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-legacy-client/index.md"
}
]
},
{
"text": "motajs-legacy-common",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-legacy-common/index.md"
}
]
},
{
"text": "motajs-legacy-system",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-legacy-system/index.md"
}
]
},
{
"text": "motajs-legacy-ui",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-legacy-ui/index.md"
}
]
},
{
"text": "motajs-render",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-render/index.md"
}
]
},
{
"text": "motajs-render-core",
"collapsed": true,
"items": [
{
"text": "Container",
"link": "/api/motajs-render-core/Container.md"
},
{
"text": "ContainerCustom",
"link": "/api/motajs-render-core/ContainerCustom.md"
},
{
"text": "Event",
"link": "/api/motajs-render-core/Event.md"
},
{
"text": "GL2",
"link": "/api/motajs-render-core/GL2.md"
},
{
"text": "GL2Program",
"link": "/api/motajs-render-core/GL2Program.md"
},
{
"text": "MotaOffscreenCanvas2D",
"link": "/api/motajs-render-core/MotaOffscreenCanvas2D.md"
},
{
"text": "MotaRenderer",
"link": "/api/motajs-render-core/MotaRenderer.md"
},
{
"text": "RenderAdapter",
"link": "/api/motajs-render-core/RenderAdapter.md"
},
{
"text": "RenderItem",
"link": "/api/motajs-render-core/RenderItem.md"
},
{
"text": "Shader",
"link": "/api/motajs-render-core/Shader.md"
},
{
"text": "ShaderProgram",
"link": "/api/motajs-render-core/ShaderProgram.md"
},
{
"text": "Sprite",
"link": "/api/motajs-render-core/Sprite.md"
},
{
"text": "Transform",
"link": "/api/motajs-render-core/Transform.md"
},
{
"text": "函数",
"link": "/api/motajs-render-core/functions.md"
},
{
"text": "主页",
"link": "/api/motajs-render-core/index.md"
}
]
},
{
"text": "motajs-render-elements",
"collapsed": true,
"items": [
{
"text": "BlockCacher",
"link": "/api/motajs-render-elements/BlockCacher.md"
},
{
"text": "Camera",
"link": "/api/motajs-render-elements/Camera.md"
},
{
"text": "CameraAnimation",
"link": "/api/motajs-render-elements/CameraAnimation.md"
},
{
"text": "主页",
"link": "/api/motajs-render-elements/index.md"
}
]
},
{
"text": "motajs-render-style",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-render-style/index.md"
}
]
},
{
"text": "motajs-render-vue",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-render-vue/index.md"
}
]
},
{
"text": "motajs-system",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-system/index.md"
}
]
},
{
"text": "motajs-system-action",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-system-action/index.md"
}
]
},
{
"text": "motajs-system-ui",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-system-ui/index.md"
}
]
},
{
"text": "motajs-types",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/motajs-types/index.md"
}
]
},
{
"text": "user-client-modules",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-client-modules/index.md"
}
]
},
{
"text": "user-data-base",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-data-base/index.md"
}
]
},
{
"text": "user-data-fallback",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-data-fallback/index.md"
}
]
},
{
"text": "user-data-state",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-data-state/index.md"
}
]
},
{
"text": "user-data-utils",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-data-utils/index.md"
}
]
},
{
"text": "user-entry-client",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-entry-client/index.md"
}
]
},
{
"text": "user-entry-data",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-entry-data/index.md"
}
]
},
{
"text": "user-legacy-plugin-client",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-legacy-plugin-client/index.md"
}
]
},
{
"text": "user-legacy-plugin-data",
"collapsed": true,
"items": [
{
"text": "主页",
"link": "/api/user-legacy-plugin-data/index.md"
}
]
}
] as DefaultTheme.SidebarItem[];

View File

@ -1,5 +1,6 @@
import { defineConfig } from 'vitepress';
import { MermaidMarkdown, MermaidPlugin } from 'vitepress-plugin-mermaid';
import api from './apiSidebar';
// https://vitepress.dev/reference/site-config
export default defineConfig({
@ -69,306 +70,7 @@ export default defineConfig({
'/api/': [
{
text: 'API 列表',
items: [
{ text: '目录', link: '/api/' },
{
text: '@motajs/client',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-client/' }
]
},
{
text: '@motajs/client-base',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-client-base/'
},
{
text: 'KeyCode',
link: '/api/motajs-client-base/KeyCode'
}
]
},
{
text: '@motajs/common',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-common/' },
{
text: '函数',
link: '/api/motajs-common/functions'
},
{
text: 'Logger',
link: '/api/motajs-common/Logger'
}
]
},
{
text: '@motajs/legacy-client',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-legacy-client/'
}
]
},
{
text: '@motajs/legacy-common',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-legacy-common/'
}
]
},
{
text: '@motajs/legacy-system',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-legacy-system/'
}
]
},
{
text: '@motajs/legacy-ui',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-legacy-ui/' }
]
},
{
text: '@motajs/render',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-render/' }
]
},
{
text: '@motajs/render-core',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-render-core/'
},
{
text: '函数',
link: '/api/motajs-render-core/functions'
},
{
text: '交互事件',
link: '/api/motajs-render-core/Event'
},
{
text: 'MotaOffscreenCanvas2D',
link: '/api/motajs-render-core/MotaOffscreenCanvas2D'
},
{
text: 'Transform',
link: '/api/motajs-render-core/Transform'
},
{
text: 'RenderItem',
link: '/api/motajs-render-core/RenderItem'
},
{
text: 'Container',
link: '/api/motajs-render-core/Container'
},
{
text: 'ContainerCustom',
link: '/api/motajs-render-core/ContainerCustom'
},
{
text: 'Sprite',
link: '/api/motajs-render-core/Sprite'
},
{
text: 'MotaRenderer',
link: '/api/motajs-render-core/MotaRenderer'
},
{
text: 'GL2',
link: '/api/motajs-render-core/GL2'
},
{
text: 'GL2Program',
link: '/api/motajs-render-core/GL2Program'
},
{
text: 'RenderAdapter',
link: '/api/motajs-render-core/RenderAdapter'
},
{
text: 'Shader',
link: '/api/motajs-render-core/Shader'
},
{
text: 'ShaderProgram',
link: '/api/motajs-render-core/ShaderProgram'
}
]
},
{
text: '@motajs/render-elements',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-render-elements/'
}
]
},
{
text: '@motajs/render-style',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-render-style/'
}
]
},
{
text: '@motajs/render-vue',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-render-vue/'
}
]
},
{
text: '@motajs/system',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-system/' }
]
},
{
text: '@motajs/system-action',
collapsed: true,
items: [
{
text: '主页',
link: '/api/motajs-system-action/'
}
]
},
{
text: '@motajs/system-ui',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-system-ui/' }
]
},
{
text: '@motajs/types',
collapsed: true,
items: [
{ text: '主页', link: '/api/motajs-types/' }
]
},
{
text: '@user/client-modules',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-client-modules/'
}
]
},
{
text: '@user/data-base',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-data-base/'
}
]
},
{
text: '@user/data-fallback',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-data-fallback/'
}
]
},
{
text: '@user/data-state',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-data-state/'
}
]
},
{
text: '@user/data-utils',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-data-utils/'
}
]
},
{
text: '@user/entry-client',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-entry-client/'
}
]
},
{
text: '@user/entry-data',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-entry-data/'
}
]
},
{
text: '@user/legacy-plugin-client',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-legacy-plugin-client/'
}
]
},
{
text: '@user/legacy-plugin-data',
collapsed: true,
items: [
{
text: '主页',
link: '/api/user-legacy-plugin-data/'
}
]
}
]
items: api
}
]
},

View File

@ -0,0 +1,367 @@
# BlockCacher API 文档
本文档由 `DeepSeek R1` 模型生成并微调。
---
```mermaid
graph LR
BlockCacher --> EventEmitter
```
_继承自 `EventEmitter<BlockCacherEvent>`支持事件监听。_
---
## 属性说明
| 属性名 | 类型 | 描述 |
| ------------ | ---------------- | ------------------------------------------------------------------- |
| `width` | `number` | 区域总宽度(元素单位) |
| `height` | `number` | 区域总高度(元素单位) |
| `blockSize` | `number` | 单个分块的大小(元素单位) |
| `blockData` | `BlockData` | 分块计算结果(包含分块数量、最后一个块的尺寸等信息) |
| `cacheDepth` | `number` | 缓存深度(每个分块可存储多个缓存层) |
| `cache` | `Map<number, T>` | 缓存存储结构,键为精确索引(`(x + y * blockWidth) * depth + deep` |
---
## 构造方法
### `constructor`
```typescript
function constructor(
width: number,
height: number,
size: number,
depth?: number
): BlockCacher<T>;
```
创建分块缓存管理器并自动计算初始分块。
**示例:**
```typescript
const cacher = new BlockCacher<ICanvasCacheItem>(800, 600, 64); // 800x600区域64为分块大小
```
---
## 方法说明
### `size`
```typescript
function size(width: number, height: number): void;
```
重置区域尺寸并重新分块(触发 `split` 事件)。
**示例:**
```typescript
cacher.size(1024, 768); // 重置为1024x768区域
```
### `setBlockSize`
```typescript
function setBlockSize(size: number): void;
```
修改分块尺寸并重新分块(触发 `split` 事件)。
**示例:**
```typescript
cacher.setBlockSize(128); // 分块大小改为128
```
### `setCacheDepth`
```typescript
function setCacheDepth(depth: number): void;
```
调整缓存深度(最大 31自动迁移旧缓存。
**示例:**
```typescript
cacher.setCacheDepth(3); // 每个分块支持3层缓存
```
### `split`
```typescript
function split(): void;
```
重新计算分块数据并触发 `'split'` 事件。
**示例:**
```typescript
cacher.split(); // 手动触发分块计算(一般无需调用)
```
### `clearCache`
```typescript
function clearCache(index: number, deep: number): void;
```
清除指定分块索引的缓存(按二进制掩码清除深度)。
**示例:**
```typescript
cacher.clearCache(5, 0b101); // 清除分块5的第0层和第2层缓存
```
### `clearCacheByIndex`
```typescript
function clearCacheByIndex(index: number): void;
```
直接按精确索引清除单个缓存。
**示例:**
```typescript
cacher.clearCacheByIndex(42); // 清除精确索引42对应的缓存
```
### `clearAllCache`
```typescript
function clearAllCache(): void;
```
清空所有缓存并销毁关联资源。
**示例:**
```typescript
cacher.clearAllCache(); // 完全重置缓存
```
### `getIndex`
```typescript
function getIndex(x: number, y: number): number;
```
根据分块坐标获取分块索引(分块坐标 -> 分块索引)。
**示例:**
```typescript
const index = cacher.getIndex(2, 3); // 获取(2,3)分块的索引
```
### `getIndexByLoc`
```typescript
function getIndexByLoc(x: number, y: number): number;
```
根据元素坐标获取所属分块索引(元素坐标 -> 分块索引)。
**示例:**
```typescript
const index = cacher.getIndexByLoc(150, 200); // 元素坐标(150,200)所在分块索引
```
### `getBlockXYByIndex`
```typescript
function getBlockXYByIndex(index: number): [number, number];
```
根据分块索引获取分块坐标(分块索引 -> 分块坐标)。
**示例:**
```typescript
const [x, y] = cacher.getBlockXYByIndex(5); // 分块5的坐标
```
### `getBlockXY`
```typescript
function getBlockXY(x: number, y: number): [number, number];
```
获取一个元素位置所在的分块位置(即使它不在任何分块内)(元素索引 -> 分块坐标)。
**示例:**
```typescript
const [x, y] = cacher.getBlockXY(11, 24); // 指定位置所在分块位置
```
### `getPreciseIndex`
```typescript
function getPreciseIndex(x: number, y: number, deep: number): number;
```
根据分块坐标与 `deep` 获取一个分块的精确索引(分块坐标 -> 分块索引)。
**示例:**
```typescript
const index = cacher.getPreciseIndex(2, 1, 3); // 指定分块的索引
```
### `getPreciseIndexByLoc`
```typescript
function getPreciseIndexByLoc(x: number, y: number, deep: number): number;
```
根据元素坐标及 `deep` 获取元素所在块的精确索引(元素坐标 -> 分块索引)。
**示例:**
```typescript
const index = cacher.getPreciseIndexByLoc(22, 11, 3); // 指定元素所在分块的索引
```
### `updateElementArea`
```typescript
function updateElementArea(
x: number,
y: number,
width: number,
height: number,
deep: number = 2 ** 31 - 1
): Set<number>;
```
根据元素区域清除相关分块缓存(返回受影响的分块索引集合)(元素坐标->分块清空)。
**示例:**
```typescript
const blocks = cacher.updateElementArea(100, 100, 200, 200); // 清除200x200区域内的缓存
```
### `updateArea`
```typescript
function updateArea(
x: number,
y: number,
width: number,
height: number,
deep: number = 2 ** 31 - 1
): Set<number>;
```
更新指定分块区域内的缓存(注意坐标是分块坐标,而非元素坐标)(分块坐标->分块清空)。
**示例:**
```typescript
const blocks = cacher.updateArea(1, 1, 1, 1); // 清除指定分块区域内的缓存
```
### `getIndexOf`
```typescript
function getIndexOf(
x: number,
y: number,
width: number,
height: number
): Set<number>;
```
传入分块坐标与范围,获取该区域内包含的所有分块索引(分块坐标->分块索引集合)。
**示例:**
```typescript
const blocks = cacher.getIndexOf(1, 1, 1, 1); // 清除指定分块区域内的缓存
```
### `getIndexOfElement`
```typescript
function getIndexOfElement(
x: number,
y: number,
width: number,
height: number
): Set<number>;
```
传入元素坐标与范围,获取该区域内包含的所有分块索引(元素坐标->分块索引集合)。
**示例:**
```typescript
const blocks = cacher.getIndexOfElement(3, 5, 12, 23); // 清除指定元素区域内的缓存
```
### `getRectOfIndex`
```typescript
function getRectOfIndex(block: number): [number, number, number, number];
```
获取分块索引对应的元素坐标范围(分块索引 -> 元素矩形坐标)。
**示例:**
```typescript
const [x1, y1, x2, y2] = cacher.getRectOfIndex(5); // 分块5的坐标范围
```
### `getRectOfBlockXY`
```typescript
function getRectOfBlockXY(
x: number,
y: number
): [number, number, number, number];
```
根据分块坐标,获取这个分块所在区域的元素矩形范围(左上角横纵坐标及右下角横纵坐标)(分块坐标 -> 元素矩形坐标)。
**示例:**
```typescript
const [x1, y1, x2, y2] = cacher.getRectOfIndex(5); // 分块5的坐标范围
```
### `destroy`
```typescript
function destroy(): void;
```
摧毁这个块缓存。
---
## 事件说明
| 事件名 | 参数 | 描述 |
| ------- | ---- | ------------------ |
| `split` | 无 | 分块参数变更时触发 |
---
## 总使用示例
```typescript
// 创建缓存管理器
const cacheManager = new BlockCacher<ICanvasCacheItem>(1024, 768, 64);
// 监听分块变化
cacheManager.on('split', () => {
console.log('分块已重新计算');
});
// 添加测试缓存项
const blockIndex = cacheManager.getIndex(2, 3);
const preciseIndex = cacheManager.getPreciseIndex(2, 3, 0);
cacheManager.cache.set(
preciseIndex,
new CanvasCacheItem(new MotaOffscreenCanvas2D(), 1)
);
// 清除特定区域缓存
cacheManager.updateElementArea(150, 150, 100, 100);
// 销毁管理器
cacheManager.destroy();
```

View File

@ -0,0 +1,384 @@
# Camera API 文档
本文档由 `DeepSeek R1` 模型生成并微调。
---
```mermaid
graph LR
Camera --> EventEmitter
```
_继承自 `EventEmitter<CameraEvent>`支持事件监听。_
---
## 属性说明
| 属性名 | 类型 | 描述 |
| --------------------- | ------------------- | ------------------------------------------------ |
| `readonly binded` | `RenderItem` | 当前绑定的渲染元素 |
| `transform` | `Transform` | 目标变换矩阵,默认与 `binded.transform` 共享引用 |
| `protected operation` | `CameraOperation[]` | 当前应用的变换操作列表(平移/旋转/缩放) |
---
## 构造方法
### `Camera.for`
```typescript
function for(item: RenderItem): Camera
```
获取或创建与渲染元素关联的摄像机实例。
**示例:**
```typescript
const item = new RenderItem();
const camera = Camera.for(item); // 获取或创建摄像机
```
### `constructor`
```typescript
function constructor(item: RenderItem): Camera;
```
直接创建摄像机实例(不会自动注册到全局映射)。
**注意:** 推荐优先使用 `Camera.for()` 方法。
---
## 方法说明
### `disable`
```typescript
function disable(): void;
```
禁用摄像机变换效果。
**示例:**
```typescript
camera.disable(); // 暂停所有摄像机变换
```
### `enable`
```typescript
function enable(): void;
```
启用摄像机变换效果。
### `requestUpdate`
```typescript
function requestUpdate(): void;
```
请求在下一帧强制更新变换矩阵。
### `removeOperation`
```typescript
function removeOperation(operation: CameraOperation): void;
```
移除一个变换操作。
**参数说明**
- `operation`: 要移除的操作
**示例**
```ts
const operation = camera.addTranslate();
camera.removeOperation(operation);
```
### `clearOperation`
```ts
function clearOperation(): void;
```
清空变换操作列表。
### `addTranslate`
```typescript
function addTranslate(): ICameraTranslate;
```
添加平移操作并返回操作对象。
**示例:**
```typescript
const translateOp = camera.addTranslate();
translateOp.x = 100; // 设置横向偏移
camera.requestUpdate();
```
### `addRotate`
```typescript
function addRotate(): ICameraRotate;
```
添加旋转操作并返回操作对象。
**示例:**
```typescript
const rotateOp = camera.addRotate();
rotateOp.angle = Math.PI / 2; // 设置90度旋转
camera.requestUpdate();
```
### `addScale`
```typescript
function addScale(): ICameraScale;
```
添加缩放操作并返回操作对象。
**示例:**
```typescript
const scaleOp = camera.addScale();
scaleOp.x = 2; // 横向放大2倍
camera.requestUpdate();
```
### `applyAnimation`
```ts
function applyAnimation(time: number, update: () => void): void;
```
施加动画。
**参数说明**
- `time`: 动画时长。
- `update`: 每帧执行的更新函数。
### `applyTranslateAnimation`
```typescript
function applyTranslateAnimation(
operation: ICameraTranslate,
animate: Animation,
time: number
): void;
```
为平移操作绑定动画。
**参数说明:**
- `animate`: 预定义的动画实例
- `time`: 动画持续时间(毫秒)
### `applyRotateAnimation`
```typescript
function applyRotateAnimation(
operation: ICameraRotate,
animate: Animation,
time: number
): void;
```
为旋转操作绑定动画。
### `applyScaleAnimation`
```typescript
function applyScaleAnimation(
operation: ICameraScale,
animate: Animation,
time: number
): void;
```
为缩放操作绑定动画。
### `applyTranslateTransition`
```typescript
function applyTranslateTransition(
operation: ICameraTranslate,
animate: Transition,
time: number
): void;
```
为平移操作绑定渐变。
**参数说明:**
- `animate`: 预定义的渐变实例
- `time`: 渐变持续时间(毫秒)
### `applyRotateTransition`
```typescript
function applyRotateTransition(
operation: ICameraRotate,
animate: Transition,
time: number
): void;
```
为旋转操作绑定渐变。
### `applyScaleTransition`
```typescript
function applyScaleTransition(
operation: ICameraScale,
animate: Transition,
time: number
): void;
```
为缩放操作绑定渐变。
### `stopAllAnimates`
```ts
function stopAllAnimates(): void;
```
停止所有动画。
### `destroy`
```typescript
function destroy(): void;
```
销毁摄像机并释放所有资源。
**示例:**
```typescript
camera.destroy(); // 解除绑定并清理动画
```
---
## 事件说明
| 事件名 | 参数 | 描述 |
| --------- | ---- | ------------------ |
| `destroy` | 无 | 摄像机被销毁时触发 |
---
## 总使用示例
::: code-group
```typescript [动画]
import { Animation, linear } from 'mutate-animate';
// 获取摄像机实例
const item = new Sprite();
const camera = Camera.for(item);
// 添加平移和缩放操作
const translate = camera.addTranslate();
const scale = camera.addScale();
// 创建动画实例
const anim = new Animation()
.mode(linear())
.time(1000)
.move(100, 100)
.time(800)
.scale(1.5);
// 绑定动画
camera.applyTranslateAnimation(translate, anim, 1000);
camera.applyScaleAnimation(scale, anim, 800);
// 启用摄像机
camera.enable();
// 销毁(当不再需要时)
setTimeout(() => camera.destroy(), 2000);
```
```typescript [渐变]
import { Transition, hyper } from 'mutate-animate';
// 获取摄像机实例
const item = new Sprite();
const camera = Camera.for(item);
// 添加平移和缩放操作
const translate = camera.addTranslate();
const scale = camera.addScale();
// 创建渐变实例,使用双曲正弦速率曲线
const tran = new Transition().mode(hyper('sin', 'out')).time(1000);
// 初始化参数,这一步不会执行渐变
tran.value.x = 0;
tran.value.y = 0;
tran.value.size = 0;
// 对参数执行渐变,直接设置即可
tran.value.x = 100;
tran.value.y = 200;
tran.time(800); // 设置渐变时长为 800 毫秒
tran.value.size = 1.5;
// 绑定动画
camera.applyTranslateTransition(translate, tran, 1000);
camera.applyScaleTransition(scale, tran, 800);
// 启用摄像机
camera.enable();
// 销毁(当不再需要时)
setTimeout(() => camera.destroy(), 2000);
```
:::
---
## 接口说明
### `ICameraTranslate`
```typescript
interface ICameraTranslate {
readonly type: 'translate';
readonly from: RenderItem;
x: number; // 横向偏移量
y: number; // 纵向偏移量
}
```
### `ICameraRotate`
```typescript
interface ICameraRotate {
readonly type: 'rotate';
readonly from: RenderItem;
angle: number; // 旋转弧度值
}
```
### `ICameraScale`
```typescript
interface ICameraScale {
readonly type: 'scale';
readonly from: RenderItem;
x: number; // 横向缩放比
y: number; // 纵向缩放比
}
```

View File

@ -0,0 +1,199 @@
# CameraAnimation API 文档
本文档由 `DeepSeek R1` 模型生成并微调。
---
```mermaid
graph LR
CameraAnimation --> EventEmitter
```
_继承自 `EventEmitter<CameraAnimationEvent>`支持事件监听。_
---
## 属性说明
| 属性名 | 类型 | 描述 |
| -------- | -------- | ---------------- |
| `camera` | `Camera` | 关联的摄像机实例 |
---
## 构造方法
### `constructor`
```typescript
function constructor(camera: Camera): CameraAnimation;
```
创建摄像机动画管理器,需绑定到特定 `Camera` 实例。
**示例:**
```typescript
const camera = Camera.for(renderItem);
const animation = new CameraAnimation(camera);
```
---
## 方法说明
### `translate`
```typescript
function translate(
operation: ICameraTranslate,
x: number,
y: number,
time: number,
start: number,
timing: TimingFn
): void;
```
为平移操作添加动画。
**参数说明:**
- `x`, `y`: 目标偏移量(格子坐标,自动乘以 `32`,之后可能改动)
- `time`: 动画持续时间(毫秒)
- `start`: 动画开始时间(相对于总动画开始的延迟)
- `timing`: 缓动函数(输入时间完成度,输出动画完成度)
### `rotate`
```typescript
function rotate(
operation: ICameraRotate,
angle: number,
time: number,
start: number,
timing: TimingFn
): void;
```
为旋转操作添加动画。
**参数说明:**
- `angle`: 目标旋转弧度(如 `Math.PI` 表示 `180` 度)
- 其余参考[`rotate`](#rotate)
### `scale`
```typescript
function scale(
operation: ICameraScale,
scale: number,
time: number,
start: number,
timing: TimingFn
): void;
```
为缩放操作添加动画。
**参数说明:**
- `scale`: 目标缩放倍率(如 `1.5` 表示放大 `1.5` 倍)
- 其余参考[`rotate`](#rotate)
### `start`
```typescript
function start(): void;
```
启动所有已添加的动画,按时间顺序执行。
**注意:** 调用后动画将按 `start` 参数定义的顺序触发。
### `destroy`
```typescript
function destroy(): void;
```
销毁动画管理器并释放所有资源(停止未完成的动画)。
---
## 事件说明
| 事件名 | 参数 | 描述 |
| --------- | -------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `animate` | `operation: CameraOperation` <br> `execution: CameraAnimationExecution` <br> `item: CameraAnimationData` | 当某个动画片段开始执行时触发 |
---
## 总使用示例
```typescript
import { hyper, trigo } from 'mutate-animate';
// 创建渲染元素和摄像机
const renderItem = new Sprite();
const camera = Camera.for(renderItem);
// 添加平移和旋转操作
const translateOp = camera.addTranslate();
const rotateOp = camera.addRotate();
// 创建动画管理器
const animation = new CameraAnimation(camera);
// 添加平移动画1秒后开始持续2秒横向移动3格3*32像素
animation.translate(
translateOp,
3,
0, // x=3, y=0自动乘32
2000, // 动画时长2秒
1000, // 延迟1秒开始
hyper('sin', 'out') // 双曲正弦函数
);
// 添加旋转动画立即开始持续1.5秒旋转180度
animation.rotate(
rotateOp,
Math.PI, // 目标角度(弧度)
1500, // 动画时长1.5秒
0, // 无延迟
trigo('sin', 'out') // 正弦函数
);
// 启动动画
animation.start();
// 监听动画事件
animation.on('animate', (operation, execution, item) => {
console.log('动画片段开始:', item.type);
});
// 销毁(动画结束后)
setTimeout(() => {
animation.destroy();
camera.destroy();
}, 5000);
```
---
## 接口说明
### `CameraAnimationExecution`
```typescript
interface {
data: CameraAnimationData[]; // 动画片段列表
animation: Animation; // 关联的动画实例
}
```
### `CameraAnimationData`
```typescript
type CameraAnimationData =
| TranslateAnimation
| TranslateAsAnimation
| RotateAnimation
| ScaleAnimation;
```

View File

@ -14,7 +14,7 @@
"lines": "tsx script/lines.ts packages packages-user",
"build:packages": "vue-tsx --noEmit && tsx script/build-packages.ts",
"build:game": "vue-tsx --noEmit && tsx script/build-game.ts",
"docs:dev": "vitepress dev docs",
"docs:dev": "concurrently -k -n 'SIDEBAR,VITEPRESS' -c 'blue,green' \"tsx docs/.vitepress/api.ts\" \"vitepress dev docs\"",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
@ -59,6 +59,7 @@
"@vitejs/plugin-vue-jsx": "^4.1.2",
"chokidar": "^3.6.0",
"compressing": "^1.10.1",
"concurrently": "^9.1.2",
"eslint": "^9.22.0",
"eslint-plugin-prettier": "^5.2.3",
"eslint-plugin-vue": "^9.33.0",

View File

@ -137,7 +137,7 @@ export class BlockCacher<
}
/**
* {@link clearCache} ->void
* {@link clearCache} ->void
*/
clearCacheByIndex(index: number) {
const item = this.cache.get(index);
@ -303,10 +303,7 @@ export interface ICanvasCacheItem extends IBlockCacheable {
}
export class CanvasCacheItem implements ICanvasCacheItem {
constructor(
public canvas: MotaOffscreenCanvas2D,
public symbol: number
) {}
constructor(public canvas: MotaOffscreenCanvas2D, public symbol: number) {}
destroy(): void {
this.canvas.delete();

View File

@ -80,7 +80,7 @@ export class Camera extends EventEmitter<CameraEvent> {
});
const ca = Camera.cameraMap.get(item);
if (ca && !ca.enabled) {
if (ca && ca.enabled) {
logger.warn(22);
}
}
@ -371,40 +371,40 @@ interface CameraAnimationBase {
start: number;
}
interface TranslateAnimation extends CameraAnimationBase {
export interface TranslateAnimation extends CameraAnimationBase {
type: 'translate';
timing: TimingFn;
x: number;
y: number;
}
interface TranslateAsAnimation extends CameraAnimationBase {
export interface TranslateAsAnimation extends CameraAnimationBase {
type: 'translateAs';
timing: TimingFn<2>;
time: number;
}
interface RotateAnimation extends CameraAnimationBase {
export interface RotateAnimation extends CameraAnimationBase {
type: 'rotate';
timing: TimingFn;
angle: number;
time: number;
}
interface ScaleAnimation extends CameraAnimationBase {
export interface ScaleAnimation extends CameraAnimationBase {
type: 'scale';
timing: TimingFn;
scale: number;
time: number;
}
type CameraAnimationData =
export type CameraAnimationData =
| TranslateAnimation
| TranslateAsAnimation
| RotateAnimation
| ScaleAnimation;
interface CameraAnimationExecution {
export interface CameraAnimationExecution {
data: CameraAnimationData[];
animation: Animation;
}

View File

@ -123,6 +123,9 @@ importers:
compressing:
specifier: ^1.10.1
version: 1.10.1
concurrently:
specifier: ^9.1.2
version: 9.1.2
eslint:
specifier: ^9.22.0
version: 9.22.0
@ -2831,6 +2834,10 @@ packages:
resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==}
engines: {node: '>=6'}
cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'}
clone-buffer@1.0.0:
resolution: {integrity: sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==}
engines: {node: '>= 0.10'}
@ -2922,6 +2929,11 @@ packages:
resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
engines: {'0': node >= 6.0}
concurrently@9.1.2:
resolution: {integrity: sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==}
engines: {node: '>=18'}
hasBin: true
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
@ -3634,6 +3646,10 @@ packages:
resolution: {integrity: sha512-MtjsmYiCXcYDDrGqtNbeIYdAl85n+5mSv2r3FbzER/YV3ZILw4HNNIw34HuV5pyl0jzs6GFYU1VHVEefhgcNHQ==}
engines: {node: '>=18'}
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
@ -4920,6 +4936,10 @@ packages:
resolution: {integrity: sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==}
engines: {node: '>= 10'}
require-directory@2.1.1:
resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==}
engines: {node: '>=0.10.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
@ -4998,6 +5018,9 @@ packages:
rw@1.3.3:
resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==}
rxjs@7.8.2:
resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==}
safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
@ -5063,6 +5086,10 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
shell-quote@1.8.2:
resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==}
engines: {node: '>= 0.4'}
shiki@2.5.0:
resolution: {integrity: sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==}
@ -5291,6 +5318,10 @@ packages:
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
tree-kill@1.2.2:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
@ -5710,6 +5741,10 @@ packages:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
@ -5720,6 +5755,14 @@ packages:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
yargs@17.7.2:
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
engines: {node: '>=12'}
yazl@2.5.1:
resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==}
@ -8300,6 +8343,12 @@ snapshots:
cli-spinners@2.9.2: {}
cliui@8.0.1:
dependencies:
string-width: 4.2.3
strip-ansi: 6.0.1
wrap-ansi: 7.0.0
clone-buffer@1.0.0: {}
clone-stats@0.0.1: {}
@ -8377,6 +8426,16 @@ snapshots:
readable-stream: 3.6.2
typedarray: 0.0.6
concurrently@9.1.2:
dependencies:
chalk: 4.1.2
lodash: 4.17.21
rxjs: 7.8.2
shell-quote: 1.8.2
supports-color: 8.1.1
tree-kill: 1.2.2
yargs: 17.7.2
confbox@0.1.8: {}
confbox@0.2.1: {}
@ -9210,6 +9269,8 @@ snapshots:
ast-module-types: 6.0.1
node-source-walk: 7.0.1
get-caller-file@2.0.5: {}
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
@ -10620,6 +10681,8 @@ snapshots:
replace-ext@2.0.0: {}
require-directory@2.1.1: {}
require-from-string@2.0.2: {}
requirejs-config-file@4.0.0:
@ -10706,6 +10769,10 @@ snapshots:
rw@1.3.3: {}
rxjs@7.8.2:
dependencies:
tslib: 2.8.1
safe-buffer@5.1.2: {}
safe-buffer@5.2.1: {}
@ -10761,6 +10828,8 @@ snapshots:
shebang-regex@3.0.0: {}
shell-quote@1.8.2: {}
shiki@2.5.0:
dependencies:
'@shikijs/core': 2.5.0
@ -10998,6 +11067,8 @@ snapshots:
tr46@0.0.3: {}
tree-kill@1.2.2: {}
trim-lines@3.0.1: {}
trim-newlines@4.1.1: {}
@ -11441,12 +11512,26 @@ snapshots:
xtend@4.0.2: {}
y18n@5.0.8: {}
yallist@3.1.1: {}
yallist@4.0.0: {}
yargs-parser@20.2.9: {}
yargs-parser@21.1.1: {}
yargs@17.7.2:
dependencies:
cliui: 8.0.1
escalade: 3.2.0
get-caller-file: 2.0.5
require-directory: 2.1.1
string-width: 4.2.3
y18n: 5.0.8
yargs-parser: 21.1.1
yazl@2.5.1:
dependencies:
buffer-crc32: 0.2.13