pocket-stack/pocketjs

GitHub: pocket-stack/pocketjs

PocketJS 是一个在浏览器外运行的轻量级 JSX UI 框架,通过 Rust 核心实现原生硬件渲染,在 8 MB 内存预算下达成 60 FPS 动画,支持 Solid 和 Vue Vapor 组件语法。

Stars: 490 | Forks: 18

PocketJS

[![@pocketjs/framework](https://img.shields.io/npm/v/%40pocketjs%2Fframework?label=%40pocketjs%2Fframework)](https://www.npmjs.com/package/@pocketjs/framework) [![@pocketjs/cli](https://img.shields.io/npm/v/%40pocketjs%2Fcli?label=%40pocketjs%2Fcli)](https://www.npmjs.com/package/@pocketjs/cli) [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](./LICENSE) [![Discord](https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white)](https://discord.gg/cTce4eXzSK) 浏览器外的高性能 JSX UI,支持原生渲染、标准 Vue Vapor 和 Solid 支持、Tailwind 设计系统,并在 8 MB 内存预算下实现 60 FPS 动画。 编写 Solid 或 Vue Vapor 组件,在 QuickJS 上运行,让 PocketJS 将布局、样式、文本和动画转移到微型的 `no_std` Rust 核心中。 它可以在真实的 PSP 硬件、PPSSPP、浏览器(WASM)、原生 macOS 窗口(wgpu)以及无头 Bun 上运行。完整的设计与契约: [DESIGN.md](./DESIGN.md)。PocketJS 正在发展成为一个专门运行时的家族——Rust 核心、规范固定的接口表面、单一 QuickJS guest——相关文档记录在 [RUNTIMES.md](./RUNTIMES.md) 中;3D 基础位于 [pocket3d/](./pocket3d/) 中,其首个游戏运行时为 [OpenStrike](https://github.com/pocket-stack/open-strike)。 ## 截图 https://github.com/user-attachments/assets/dbbf656f-a3b2-411d-ab52-fece6a10f68a 这些 PocketJS UI 在 8 MB 内存预算内的 Sony PSP 上以 60 FPS 流畅运行,包括动画过渡和输入反馈。 | 画廊 | 设置 | | --- | --- | | ![展示分页纹理网格的画廊演示 UI](https://static.pigsec.cn/wp-content/uploads/repos/cas/36/36d52f2569c5a862b6a7b1a227330417d77c4a7b4b9f726512a1796351b25dc9.png) | ![展示开关、滑块和主题样本的设置演示 UI](https://raw.githubusercontent.com/pocket-stack/pocketjs/main/assets/screenshots/settings.png) | | **运动实验室 — 烘焙的关键帧时间线** | **运动实验室 — 3D pipeline** | | ![运动研究:菜单、d-pad、分享、悬停、重新加载和键盘通过编译时关键帧时间线制作动画](https://static.pigsec.cn/wp-content/uploads/repos/cas/7f/7f6f319774e11c4ebff7a0a30de142503b7ef5436219d897f5e03be2cc789d92.gif) | ![3D 运动研究:摆动的门、旋转的立方体、页面翻转和房间过渡,由核心进行 painter 排序](https://raw.githubusercontent.com/pocket-stack/pocketjs/main/assets/screenshots/motions-3d.gif) | ## 快速开始 ``` bun install bun scripts/build.ts hero # -> dist/hero.js + dist/hero.pak bun scripts/build.ts hero-vue-vapor-main --framework=vue-vapor ``` 或者通过 [`pocket` CLI](https://www.npmjs.com/package/@pocketjs/cli) 驱动一切: `npm i -g @pocketjs/cli`,然后运行 `pocket doctor` 检查 bun / Rust / PSP 工具链(`pocket setup` 会安装缺失的部分),`pocket create ` 用于生成应用脚手架,而 `pocket dev|build|psp|hw|psplink` 封装了下面 的脚本。 构建分为两个阶段:第一阶段对从入口可达的每个模块进行 babel 转换(特定于框架的 JSX + TypeScript,在 `.cache/` 中进行内容哈希缓存),同时从 AST 中收集类字符串和文本码位;然后 Tailwind 编译器写入 `styles.bin` 和 `src/styles.generated.ts`,字体 烘焙器会为你的应用恰好使用的字符光栅化 Inter atlas 插槽, 所有内容都会被打包进 `dist/.pak` 中。第二阶段使用 Bun (iife,未压缩)从缓存的转换结果中打包。 ``` import { createSignal } from "solid-js"; import { Text, View } from "@pocketjs/framework/components"; export default function Counter() { const [count, setCount] = createSignal(0); return ( Count: {count()} setCount(count() + 1)} /> ); } ``` 挂载入口看起来应该像普通的应用引导代码;框架 会处理宿主检测、生成的样式表、pak 图像上传以及 宿主帧回调: ``` import { mount } from "@pocketjs/framework"; import App from "./app.tsx"; mount(() => ); ``` 样式规则(编译时,没有运行时 CSS):当且仅当类字面量中的 *每个* token 都是受支持的 utility 时,该字面量才会被编译(参见 DESIGN.md 中的 "Tailwind subset (v1)"); 动态样式是完整字面量的三元表达式、`style={{...}}` 或 `animate()`。 `classList`、`hover:` 和模板插值类会导致编译错误。 `rounded-full` 要求在同一个字面量中包含 `w-N h-N`。 框架选择是显式的:在 `pocket.config.ts` 中设置 `framework: "solid"` 或 `framework: "vue-vapor"`,或者向 `scripts/build.ts`、 `scripts/dev.ts` 或 `scripts/psp.ts` 传递 `--framework=...`。应用状态和 组件生命周期来自于原生框架包(`solid-js` 或 `vue`); PocketJS 提供宿主组件、输入、动画、资产和原生 运行时连接。 `@pocketjs/framework/components` 还暴露了小型 app-shell 原语: `Screen`、`Focusable`、`FocusScope`、`ActionHandler`、`FocusGrid`、`Portal`、 `Modal` 和 `ActionBar`。`FocusGrid` 为子树提供了当前明确的行/列 d-pad 遍历; 以后虚拟化网格也可以位于相同的焦点契约之后。 `Portal` 挂载到运行时覆盖层根节点,因此模态/操作栏 UI 永远不会参与到当前活动屏幕的 flex 布局中。`Modal` 拥有焦点 作用域,并在保持帧动画生命周期回调运行的同时,阻止后台按钮处理程序; 路由切换仍然是普通的应用状态,而非必需的路由包。 ## 命令 ``` bun run test # spec contract + tailwind parser tests bun scripts/build.ts [--framework=solid|vue-vapor] [--extra-chars=…] bun run psp / bun run dev / bun run wasm # EBOOT / web host / wasm core bun psplink # interactive real PSP switcher over PSPLINK bun run hw hero --trace # real PSP via PSPLINK + host0 trace bunx tsc --noEmit # typecheck (babel owns the JSX transform) ``` ## DevTools + 时间旅行 Pocket DevTools([DEVTOOLS.md](DEVTOOLS.md))内置于每个 bundle 中:一个 带有语义名称(`debugName` / ``)的组件树,在**设备屏幕上**(包括真实的 PSP,通过 PSPLINK USB 线缆)悬停高亮,暂停/单步执行,REPL,来自硬件的 `console.log`,以及常驻的 输入流飞行记录仪——会话能够逐字节精确重放,因为整个 运行时是固定 dt 确定性的。 ``` bun run devtools # panel + hub + USB bridge, one process bun run devtools cards # + build, link and launch cards on a real PSP bun run tape replay --png 60 # render any frame headlessly bun run tape:check # session-golden replay regression ``` 按需设备截图(面板中的 📷)在所有宿主上均可用——在真实的 硬件上,原始 VRAM 通过 usbhostfs 挂载传输,网桥在桌面端对 PNG 进行编码。 ## 确定性 + 模拟宿主 时间是帧计数器,而非挂钟时间([DETERMINISM.md](DETERMINISM.md)): 虚拟时钟(`@pocketjs/framework/clock`)将模拟速率作为一种 宿主策略(web 宿主上的 `?hz=2` 会在真实屏幕上运行 2 FPS 的世界), effect shell(`@pocketjs/framework/effects`)将异步结果量化到 帧边界上,而无头模拟宿主(`host-sim/`)会将脚本化的 用户旅程重放为逐字节精确的逐帧像素轨迹——`test/sim.test.ts` 是 证明,`scripts/flake-lab.ts` 是挂钟时间对照实验。 字体:Inter(OFL),内置在 `assets/fonts/` 中。
标签:QuickJS, Rust, Solid/Vue前端, 信息收集, 可视化界面, 嵌入式开发, 数据可视化, 硬件渲染, 网络流量审计, 自动化攻击, 跨端UI框架