feat: launch ArborFlow behavior tree studio

This commit is contained in:
TuxMonkey
2026-07-21 20:09:00 +08:00
commit cb6ca3d24b
32 changed files with 9869 additions and 0 deletions

41
src/lib/project.ts Normal file
View File

@@ -0,0 +1,41 @@
import type { BehaviorTreeDocument } from '../types'
export function serializeProject(document: BehaviorTreeDocument) {
return JSON.stringify(document, null, 2) + '\n'
}
export function parseProject(content: string): BehaviorTreeDocument {
const value: unknown = JSON.parse(content)
if (!value || typeof value !== 'object') throw new Error('工程文件内容无效')
const candidate = value as Partial<BehaviorTreeDocument>
if (candidate.format !== 'arborflow/project' || candidate.version !== 1) {
throw new Error('不是受支持的 ArborFlow 工程文件')
}
if (!Array.isArray(candidate.nodes) || !Array.isArray(candidate.edges)) {
throw new Error('工程文件缺少节点或连接数据')
}
return candidate as BehaviorTreeDocument
}
export function downloadText(filename: string, content: string, type = 'text/plain') {
const blob = new Blob([content], { type })
const url = URL.createObjectURL(blob)
const anchor = document.createElement('a')
anchor.href = url
anchor.download = filename
anchor.click()
URL.revokeObjectURL(url)
}
export function pickBrowserFile(accept: string) {
return new Promise<{ path: string; content: string } | null>((resolve) => {
const input = document.createElement('input')
input.type = 'file'
input.accept = accept
input.onchange = async () => {
const file = input.files?.[0]
resolve(file ? { path: file.name, content: await file.text() } : null)
}
input.click()
})
}