Communitygithub.com

metapages/framejs.io

在 URL 中分享交互式 JavaScript 可视化、图表、仪表盘和应用——无需服务器、构建或账户。可用 AI 生成或手写。

framejs.io 是什么?

framejs 技能允许 AI 代理(如 Claude Code、Cursor 等)在浏览器中运行 ES6 JavaScript 模块,并通过一个稳定的、可分享的 `framejs.app/j/<uuid>` URL 交付交互式可视化或应用。它有两种交付模式:自动化模式(代理可以运行 shell/Node,通过 CLI 自动创建或更新 frame 并返回 URL)和纯代码块模式(无 shell 时仅输出一个 JavaScript 代码块供用户粘贴)。技能支持从提示创建新应用、修改现有应用(通过 frame URL 获取并更新代码),以及可视化本地文件(上传为输入)。自动化模式下,同一 session 内的 frame 会原地更新,保持 URL 不变并实时刷新页面;助手还会自动处理 Open Graph 预览标签和截图,确保分享时显示丰富的预览。支持 Playwright 或 headless Chrome 截图,并可通过环境变量配置本地开发或自托管栈。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add metapages/framejs.io

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

framejs

framejs 在浏览器中运行一个 ES6 JavaScript 模块。一个 frame 就是一个应用:它存在于一个稳定、可分享的 framejs.app/j/<uuid> URL,其内容是可变的——你可以通过 POST 其哈希参数来原地更新应用。你的任务:将用户的请求转换为那段浏览器 JavaScript,并以适合你环境的方式交付。

选择交付模式

根据你能做什么来选择——而不是根据请求:

  • 自动化模式——你可以运行 shell / node: 生成 JavaScript,然后创建或更新 session 的 framejs.app frame,打印其 /j/<uuid> URL,并在浏览器中打开。这是默认模式,只要 shell 可用。
  • 代码块模式——仅聊天 / API,无 shell: 仅回复一个单独的、带围栏的 JavaScript 代码块(以 javascript 信息字符串开头),除此之外没有任何内容——没有周围文字、没有文件、没有 URL。用户将其粘贴到 framejs.io 的编辑器中。

两种模式下你编写的 JavaScript 遵循相同的规则——请阅读 references/coding-guide.md。

请求可能是什么

  1. 从提示创建——"一个弹跳球动画"、"绘制 y = sin(x)"。
  2. 修改现有应用——请求包含一个 frame URL。它可能是一个 https://framejs.app/j/<uuid> 或一个 https://framejs.io/j/<uuid>?token=… URL("为 AI session 复制 frame"操作会复制 framejs.io 运行时表单),一个原始的 32 字符十六进制 id,或者一个遗留的 https://framejs.io/j/<sha256> / 64 字符 id 快照。每当你看到 framejs URL,从其 /j/<uuid> 路径中提取 uuid 并定位到那个 frame(将 URL 直接传给 --id——即使对于 framejs.io URL,助手也会将更新路由到应用层)。你必须先获取现有代码再修改它——请参阅 references/short-url-api.md(§ 修改)。如果 URL 带有 ?token=<key> 查询参数(来自应用的"为 AI session 复制 frame"操作),则将整个 URL 传给 --id(或将 key 传给 --token):助手会存储它并将其作为 bearer 凭证发送,这样即使在 frame 的拥有者认领后,你的更新也能继续工作。传递完整 URL 还能定位到该 URL 命名的后端——因此开发或自托管的 frame URL(例如 https://framejs-app.localhost:13747/j/<uuid>?token=<key>)会更新其自己的栈,无需预先配置环境。--app-origin <url> / --io-origin <url> 可以显式设置后端。请参阅 references/short-url-api.md(§ 本地 / 开发源)。
  3. 可视化本地文件——请求引用了文件路径(./data.csv、/tmp/results.json)。上传它们并作为输入传递——请参阅 references/file-inputs.md。

自动化模式——如何交付

生成代码,然后使用捆绑的助手(首选)或 references/short-url-api.md 中的内联 Node 后备方案:

cat << 'JSCODE' | node scripts/framejs.mjs create --state "${SCRATCHPAD}/framejs-frame.json" --title "<简短标题>" --description "<一句话摘要>" --screenshot
// 你生成的浏览器 JavaScript 代码——$vars、反引号、所有特殊字符在 heredoc 内都是安全的
JSCODE

助手在标准输出上打印两个 URL——主要的 https://framejs.app/j/<uuid> 页面 URL 和一个不可变的 snapshot: https://framejs.io/j/<sha256> URL。它还在标准错误输出上打印一条分享链接生命周期通知,你必须将其转达给用户:

  • /j/<uuid> 页面是可编辑且实时更新的,但一个匿名(未认领)的 frame 是临时的,会过期——告诉用户打开它并认领它(免费账户)以永久保留;
  • /j/<sha256> 快照是当前应用的不可变副本,在最后一次打开后约 30 天过期——是一个稳定的分享/备份链接,但永远不会反映后续编辑。

对于经典脚本,添加 --module <url>;对于输入,添加 --input name=value。

每个 session 一个 frame,原地更新。 始终传递 --state "<你的 scratchpad 中的路径>/framejs-frame.json"(任何可写文件路径)。第一次 create 会创建 frame;使用相同的 --state 重新运行 create 来更新同一个 frame——/j/<uuid> URL 保持不变,任何打开的 framejs.app 页面都会实时更新,所以只给用户一次 URL。只有当用户想在同一个 session 中创建独立的应用时,才添加 --new 来启动一个新的 frame(后续更新会定位到那个新 frame)。要忽略 state 更新某个特定的 frame,请传递 --id <uuid>。在这种原地更新中,当你没有传递 --og/--title/--description 时,助手会自动向前保留 frame 现有的 Open Graph 数据,因此裸重新运行时永远不会丢失标题/描述(保留的 og.image 会跳过重复截图)。只有在想要更改预览文案时才再次传递 --title/--description。

浏览器仅在 frame 首次创建时自动打开(使用 --no-open 来跳过)。后续对同一个 frame 的更新——相同的 --state 或显式的 --id——不会重新打开浏览器:已经打开的页面通过同 frame 订阅实时接收到更新,再次打开只会产生一个多余的标签页。

如果本地开发检出存在,助手会自动加载其 .env 并定位到开发栈(FRAMEJS_APP_ORIGIN / FRAMEJS_IO_ORIGIN)而不是生产环境——你无需任何操作。

如果助手打印了一条 out of date(过时)更新通知(在标准错误输出上,最多每小时一次),请向用户逐字转达一次——他们安装的技能已落后于最新版本,通知会告诉他们更新所需的唯一命令。

始终传递 --screenshot:助手会渲染完成的应用并保存捕获作为 og:image 预览。它是自保护的——仅在应用还没有 og.image 时捕获,因此不会覆盖之前运行(或用户)已经设置的图像,并且如果渲染器不可用,它会悄悄回退到无图像的 URL。当可以导入时,捕获优先使用 Playwright(真正的 network-idle 等待——最适合从输入获取数据的应用),否则使用系统 headless Chrome。Playwright 是可选的:安装它(npm i -g playwright && npx playwright install chromium)以获得更可靠的路径,或者将 $FRAMEJS_PLAYWRIGHT 指向一个其 node_modules 中包含 Playwright 的目录。通过 --screenshot-wait <ms>(默认 6000——对于加载慢的应用可以提高它)和 --screenshot-size <w,h>(默认 1200,630)调整。用 $CHROME_PATH 覆盖 Chrome 二进制文件。

scripts/framejs.mjs 是相对于此技能目录解析的,而不是你当前的工作目录——从技能文件夹运行它,或使用其绝对路径(Claude Code 将该目录暴露为 ${CLAUDE_SKILL_DIR},因此 ${CLAUDE_SKILL_DIR}/scripts/framejs.mjs 始终有效)。如果你无法定位或运行捆绑的助手,请使用 references/short-url-api.md 中的内联 Node 后备方案——它不需要脚本文件。

始终包含 Open Graph 预览标签,以便链接在分享时能良好地展开——请参阅 references/short-url-api.md 中的 OG 规则:

  • 新应用: 使用 --title / --description 生成新的文案,并传递 --screenshot 来捕获预览图像。
  • 修改现有应用: 获取到的应用已经带有 og(fetch 命令会返回它)。不要重新计算它——直接将获取的对象通过 --og '<获取到的 og JSON>' 传回,这可以保留所有字段(包括 image)。使用 --id <uuid>(或相同的 --state)更新同一个 frame。只有当用户明确要求更改预览文案时才设置新的 --title/--description。你仍然可以传递 --screenshot:如果获取到的 og 已经有 image,它不会被修改;如果没有,则会添加新的捕获。

绝对规则(两种模式)

  • 仅限浏览器 JavaScript——它在 iframe 中运行,不是 Node.js。
  • 必须使用 ES6 模块语法:export function onInputs(inputs) {}。
  • 绝对不要创建 HTML 文件。绝对不要编写本地的 .js 文件。绝对不要使用你自己的可视化/渲染/小部件工具来渲染结果。
  • 绝对不要修改 root.style.position、root.style.height 或 root.style.width。
  • 重要:可视化必须在手机上看起来良好并能适应屏幕尺寸——使用响应式尺寸(读取 root 的尺寸 / 监听 resize),避免固定像素宽度导致溢出,保持小屏幕上的文本和触摸目标清晰易读。
  • 在自动化模式下,绝对不要输出让用户复制的代码块,也绝对不要手动构建长哈希 URL 作为交付物——始终通过 frame API(助手的 create)进行 POST。给用户 /j/<uuid> 页面 URL。
  • 在代码块模式下,仅输出单个带围栏的 JavaScript 代码块——没有其他内容。

参考

  • references/coding-guide.md——全局变量、导出、模式、CDN 库、常见错误。
  • references/short-url-api.md——创建/更新 frame(POST /j/<uuid>.json)、每 session 一 frame 的状态、Open Graph 标签、API 令牌(在 frame 被认领后继续更新)、内联后备方案。
  • references/file-inputs.md——上传本地文件并将其作为输入引入。
  • scripts/framejs.mjs——Node 助手:create(stdin JS → framejs.app frame)、fetch <id>、upload <path>。源:FRAMEJS_APP_ORIGIN / FRAMEJS_IO_ORIGIN(在本地开发中自动从附近的 .env 加载),或通过 --app-origin/--io-origin 或传递给 --id/fetch 的完整 frame URL 的源进行每次运行设置。

相关技能