zframes

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

zframes — your dashboard, generated

zframes — 你的专属仪表板,由AI生成

You set up and run the user's dashboard by driving the zframes CLI and writing a
dashboard.json
spec. The CLI is the runtime: it serves a prebuilt dashboard app pointed at that one file, editable in the browser. You only ever write JSON. Never create or edit
.tsx
files for this task.
Three jobs, one skill — serve, update, or create. Decide which the request is before anything else (step 1). "Start / open / serve my dashboard" just serves the one the user already has — the most common ask once a dashboard exists — and skips the interview and
init
entirely. Only the create path runs the full build below.
你需要通过操作zframes CLI并编写
dashboard.json
配置文件来搭建并运行用户的仪表板。该CLI本身就是运行时环境:它会启动一个预构建的仪表板应用,指向这个配置文件,且可在浏览器中编辑。你只需编写JSON,绝不要为此任务创建或编辑
.tsx
文件。
一项技能,三类任务——运行、更新或创建。 首先要判断用户的需求类型(步骤1)。如果用户说“启动/打开/运行我的仪表板”,只需运行已有的仪表板即可——这是用户拥有仪表板后的最常见需求,可直接跳过调研和
init
步骤。只有创建新仪表板时才需要执行以下完整流程。

0. The CLI

0. CLI工具

The runtime ships as the
zframes
CLI on npm. Always invoke it with
npx --yes zframes@latest <cmd>
— npx fetches the published CLI (which bundles the dashboard runtime) per run, so there's nothing to clone, install, or keep current. The commands you'll use below are
init
,
providers
,
catalogue
,
lint
, and
serve
(written
zframes <cmd>
for brevity — always run them through
npx
).
运行时环境以
zframes
CLI的形式发布在npm上。请始终使用**
npx --yes zframes@latest <cmd>
**调用它——npx会在每次运行时获取已发布的CLI(其中包含仪表板运行时),因此无需克隆、安装或保持版本更新。你将用到的命令包括
init
providers
catalogue
lint
serve
(为简洁起见,下文简写为
zframes <cmd>
——但请始终通过
npx
运行)。

1. Route the request — serve, update, or create

1. 路由用户请求——运行、更新或创建

Classify the ask first; it decides everything below — including which reference files you read. Only one of the four jobs builds anything; never run the interview or
init
unless you're genuinely creating a dashboard the user doesn't have yet.
  • Serve / open / start an existing dashboard — "start my dashboard", "open my terminal", "serve it", or a bare
    /zframes
    when the user already has one. This is the common case once a dashboard exists. Don't init, don't interview, don't read the catalogue or any reference file. Run
    zframes list
    to see what's there, then jump straight to step 6 and serve: a bare
    zframes serve
    opens the default (the
    *
    in the list),
    zframes serve <name>
    a specific one. That's the whole job.
  • Update an existing dashboard — "add X", "swap the tickers", "change the theme". Run
    zframes list
    (the
    *
    marks the default) or find the
    dashboard.json
    the user is serving / one in the current directory. Read it first, then change only what they asked for. If you're adding, resizing, or rearranging frames, read the catalogue (step 2) and
    references/design.md
    (the design method + the card-level fields: events, groups,
    source
    , currency) before editing the
    frames
    array; then lint + serve (steps 5–6). Don't re-init — you'd wipe their frames.
  • Create a brand-new dashboard — only when the user wants one they don't yet have (or explicitly asks for a fresh one alongside their others). Name it,
    init
    it (below), then run the full build: catalogue summary (step 2), the interview (read
    references/interview.md
    before asking anything), the design (read
    references/design.md
    before writing any frame JSON), then lint + serve (steps 5–6).
  • Fork a shared dashboard — the user gives a zframes explorer link (
    .../dashboard/<id>
    or
    .../dashboard/<id>/dashboard.json
    ), or pastes the "fork" prompt. They want that shared dashboard on their machine to keep and extend. Don't interview or build — read
    references/fork.md
    and follow it: fetch, land in the store, lint + serve, offer to personalize.
The only artifact is a single
dashboard.json
. There is no app to scaffold — the runtime comes from the CLI. Dashboards live in a global store (
$XDG_CONFIG_HOME/zframes/dashboards
, default
~/.config/zframes/dashboards
), so the user can run
zframes
from anywhere and keep several side by side, each addressed by a short name (
main
,
crypto
, …).
zframes list
shows them all, the
*
marking the one a bare
zframes serve
will open.
To create one, give it a name and
init
it into the store — don't hand-write the envelope:
bash
npx --yes zframes@latest init <name> --title "<dashboard title>" --author "<who>"
A bare token like
crypto
lands in the store as
<store>/dashboards/crypto/dashboard.json
and becomes the default if you don't have one yet (so a later bare
zframes serve
opens it; pass
--default
to force it). This writes a bare, already-valid dashboard — the fixed envelope, modelled on package.json:
version
(semver string),
title
,
author
(pass
--author
if the user gave a name, else it's left blank), then the 12-column
grid
(geometry — columns/rowHeight/
gap
), the unicorn
background
, the
theme
colours (
accentHue
/
accentSat
for the accent +
baseHue
/
baseSat
for the dark card-surface tint +
upColor
/
downColor
for gain/loss), the
typography
(
fontFamily
sans/mono/serif +
numericStyle
proportional/tabular +
scale
global text size), the card-surface
appearance
(
radius
/
borderStrength
/
surfaceOpacity
/
density
/
elevation
), and the display
currency
(
{ code: "USD" }
by default) — with an empty
frames
array
. You never author that boilerplate or its geometry by hand; you only fill in
frames
(step 4). That single file is everything the user owns; sibling files it references (a local image) live next to it in the dashboard's own
dashboards/<name>/
folder, so each dashboard's assets stay isolated.
init
refuses to clobber an existing file unless you pass
--force
.
(Prefer a plain file over the store? Pass a path —
init ./my-dir
or
init ~/dash.json
— and every command takes that path too. A token with a
/
or a
.json
suffix is always a path; a bare token is always a store name.)
首先对用户需求分类,这将决定后续所有操作——包括需要读取哪些参考文件。四类任务中只有一类需要构建新内容;除非用户确实需要创建一个全新的仪表板,否则绝不要执行调研或
init
步骤。
  • 运行/打开/启动现有仪表板——用户说“启动我的仪表板”、“打开我的终端”、“运行它”,或者在已有仪表板的情况下直接输入
    /zframes
    。这是用户拥有仪表板后的常见场景。不要执行init,不要调研,不要读取catalogue或任何参考文件。 运行
    zframes list
    查看已有仪表板,然后直接跳至步骤6运行:直接执行
    zframes serve
    会打开默认仪表板(列表中标记为
    *
    的那个),
    zframes serve <name>
    则会打开指定名称的仪表板。这就是全部任务。
  • 更新现有仪表板——用户说“添加X”、“更换代码”、“更改主题”。运行
    zframes list
    *
    标记默认仪表板)或找到用户正在运行的
    dashboard.json
    (或当前目录中的该文件)。先读取该文件,然后仅修改用户要求的内容。如果需要添加、调整大小或重新排列框架,请先读取catalogue(步骤2)和**
    references/design.md
    **(设计方法以及卡片级字段:事件、分组、
    source
    、货币),再编辑
    frames
    数组;然后执行lint和运行步骤(步骤5–6)。不要重新执行init——这会清空已有的框架。
  • 创建全新仪表板——仅当用户需要一个尚未拥有的仪表板(或明确要求在已有仪表板之外新建一个)时执行。为其命名,执行
    init
    (如下所示),然后完成完整构建流程:catalogue摘要(步骤2)、用户调研(在提问前先阅读
    references/interview.md
    )、设计(在编写任何框架JSON前先阅读
    references/design.md
    ),然后执行lint和运行步骤(步骤5–6)。
  • 复刻共享仪表板——用户提供zframes浏览器链接(
    .../dashboard/<id>
    .../dashboard/<id>/dashboard.json
    ),或粘贴“复刻”提示。他们希望将该共享仪表板保存到自己的设备以便保留和扩展。不要调研或构建——**阅读
    references/fork.md
    **并按照指示操作:获取文件、保存到存储库、执行lint和运行,然后提供个性化选项。
唯一的产物是单个
dashboard.json
文件。无需搭建应用——运行时环境来自CLI。仪表板存储在全局存储库中(
$XDG_CONFIG_HOME/zframes/dashboards
,默认路径为
~/.config/zframes/dashboards
),因此用户可以在任何位置运行
zframes
,并同时拥有多个仪表板,每个仪表板通过简短的名称(如
main
crypto
等)进行区分。
zframes list
会显示所有仪表板,
*
标记直接执行
zframes serve
时会打开的默认仪表板。
创建仪表板,请为其命名并通过
init
将其添加到存储库——不要手动编写框架结构:
bash
npx --yes zframes@latest init <name> --title "<dashboard title>" --author "<who>"
类似
crypto
这样的简短名称会被保存到
<store>/dashboards/crypto/dashboard.json
,如果用户还没有默认仪表板,它将成为默认仪表板(因此后续直接执行
zframes serve
会打开它;可通过
--default
参数强制设置为默认)。 该命令会生成一个已验证的空仪表板——固定的框架结构,以package.json为模板:包含
version
(语义化版本字符串)、
title
author
(如果用户提供了名称则通过
--author
传递,否则留空),然后是12列的
grid
(布局——列数/行高/
gap
)、独特的
background
theme
颜色(
accentHue
/
accentSat
用于强调色 +
baseHue
/
baseSat
用于深色卡片表面色调 +
upColor
/
downColor
用于涨跌)、
typography
fontFamily
包括无衬线/等宽/衬线 +
numericStyle
包括比例/制表符 +
scale
全局文本大小)、卡片表面
appearance
radius
/
borderStrength
/
surfaceOpacity
/
density
/
elevation
),以及显示
currency
(默认为
{ code: "USD" }
)——还有一个空的
frames
数组
。你无需手动编写这些模板或布局几何结构;只需填充
frames
数组(步骤4)。这个单一文件就是用户拥有的全部内容;它引用的同级文件(如本地图片)会保存在仪表板专属的
dashboards/<name>/
文件夹中,因此每个仪表板的资源都是独立的。除非传递
--force
参数,否则
init
不会覆盖现有文件。
(偏好使用普通文件而非存储库?可传递路径——
init ./my-dir
init ~/dash.json
——所有命令都支持该路径。包含
/
.json
后缀的名称始终被视为路径;简短名称则始终被视为存储库名称。)

2. Read the catalogue — always, before generating

2. 读取catalogue——生成前必须执行

The catalogue is read in two phases — the full dump (~270 frames of JSON Schema, ~400 KB) is far too big to read whole, and you don't need most of it.
Phase 1 — browse. Before choosing anything:
bash
npx --yes zframes@latest catalogue --summary > /tmp/zframes-summary.txt
Read that file fully (~45 KB of plain text): every frame as one
name — description
line grouped by category, the category taxonomy, and the design vocabulary — the named theme presets with the exact spec values to write and the background scenes with their
projectId
s. This is the menu you curate frames and cosmetics from in step 4.
Phase 2 — fetch the schemas you'll actually use. Once the design pass has picked the frame set, get the full entries — config schema plus each frame's designed size and resize floor (
layout
:
w
/
h
/
minW
/
minH
/…) — for exactly those frames:
bash
npx --yes zframes@latest catalogue price-liveline price-chart yield-curve ... > /tmp/zframes-frames.json
Then read the file with your file reader — redirect to a file rather than reading piped stdout, so nothing truncates. Frame names, config fields, enum values, and sizes come from here — never from memory. The catalogue grows; your memory doesn't. An unknown frame name makes the command exit 1 with the valid list — that's your typo feedback, same as lint.
catalogue分为两个阶段读取——完整的catalogue包含约270个框架的JSON Schema,大小约400KB,无法完整读取,且你不需要其中大部分内容。
阶段1——浏览。 在选择任何内容之前:
bash
npx --yes zframes@latest catalogue --summary > /tmp/zframes-summary.txt
完整读取该文件(约45KB纯文本):每个框架以
名称 — 描述
的形式按类别分组,包含分类体系,以及设计词汇——带有精确规范值的命名主题预设,以及包含
projectId
的背景场景。这是你在步骤4中选择框架和外观的菜单。
阶段2——获取实际需要的schema。 设计阶段选定框架集后,获取这些框架的完整条目——配置schema以及每个框架的设计尺寸和最小调整尺寸
layout
:
w
/
h
/
minW
/
minH
/…):
bash
npx --yes zframes@latest catalogue price-liveline price-chart yield-curve ... > /tmp/zframes-frames.json
然后使用文件阅读器读取该文件——将输出重定向到文件而非读取管道stdout,避免内容被截断。框架名称、配置字段、枚举值和尺寸均来自该文件——绝不要依赖记忆。catalogue会不断更新;你的记忆无法同步。如果框架名称未知,命令会以退出码1返回有效列表——这是拼写错误的反馈,与lint的反馈方式相同。

3. Interview the user — read
references/interview.md
first

3. 用户调研——先阅读
references/interview.md

On the create path, interview the user before building — but read
references/interview.md
before asking anything
. It holds the whole funnel: a three-round narrowing (asset class → categories → 3–5 specific tickers, with one optional theme-preset question riding along), the option menus per asset class, and the xyz symbol reference that maps every category to the tickers the dex actually carries. The interview picks symbols and (optionally) a look — never frames; you assemble the board yourself in step 4.
在创建新仪表板的流程中,构建前需先调研用户——但在提问前必须先阅读
references/interview.md
。该文件包含完整的调研流程:三轮筛选(资产类别→分类→3–5个特定代码,同时可选择询问一个主题预设问题)、每个资产类别的选项菜单,以及xyz符号参考,该参考将每个分类映射到交易所实际支持的代码。调研仅选择代码和(可选的)外观——绝不选择框架;你将在步骤4中自行组装仪表板。

4. Design the dashboard — read
references/design.md
first

4. 设计仪表板——先阅读
references/design.md

Fill the
frames
array of the file
init
scaffolded (or the existing file for updates). This is a design job, not a dump, and
references/design.md
is the method — read it before writing any frame JSON.
It covers the three passes (4a apply ONE theme preset, 4b curate 20–35 cards in 3–5 zones from a mandatory spine, 4c compose the layout — catalogue sizes, rows packed to 12, headed zones, hierarchy, small asset-logo tiles as decoration and row fillers) plus the card-level fields you'll need while writing: event annotations,
group
clusters, pinning a frame to a second venue with
source
, and per-board/per-card display currency.
填充
init
生成的文件(或现有文件,用于更新)中的
frames
数组。这是一项设计任务,而非简单的内容填充,
references/design.md
是设计方法——在编写任何框架JSON前必须阅读
。它涵盖了三个阶段(4a 应用一个主题预设,4b 从核心框架中挑选20–35个卡片并分为3–5个区域,4c 组合布局——使用catalogue中的尺寸,每行填满12列,带有标题的区域,层级结构,使用小型资产徽标卡片作为装饰和行填充),以及编写时需要的卡片级字段:事件注释、
group
集群、通过
source
将框架固定到第二个数据源,以及全局/单卡片的显示货币。

5. Lint — the feedback loop

5. Lint——反馈循环

bash
npx --yes zframes@latest lint <name>   # the store name (or a path to a dashboard.json)
If it reports issues, fix the JSON and re-lint until clean. The error messages name the frame instance and the exact field. Unknown frame names come back with the list of valid ones — use it. Lint also enforces the design floor: a frame placed under its
layout
minimums, overlapping cards, a group child overflowing its group's own
columns
/
rows
, and a group-in-a-group all fail with the offending numbers named.
Renderer-level failures (a frame whose capability no provider covers) show up as error cards in the running dashboard; treat those the same way.
bash
npx --yes zframes@latest lint <name>   # 存储库名称(或dashboard.json的路径)
如果报告问题,请修复JSON并重新执行lint直到无错误。错误消息会指出框架实例和具体字段。未知框架名称会返回有效列表——请使用该列表。Lint还会强制执行设计下限:框架尺寸小于
layout
最小值、卡片重叠、分组子项超出分组自身的
columns
/
rows
、嵌套分组等情况都会失败并显示具体数值。
渲染级别的失败(框架功能无数据源支持)会在运行的仪表板中显示为错误卡片;请以相同方式处理。

6. Hand off — serve it, then open it

6. 交付——运行并打开

Serve the dashboard and open it in the user's browser — a printed link is not a hand-off.
serve
blocks, so background it (a background shell, a multiplexer window — whatever your harness has), wait for the port to answer, then open the URL:
bash
npx --yes zframes@latest serve <name>   # background this; the store name (or a path)
until curl -sf http://localhost:37263 >/dev/null; do sleep 1; done
open http://localhost:37263             # macOS · xdg-open on Linux · start on Windows
Always write and open the URL as
http://localhost:37263
, never the bare IP — that's what the CLI prints and what the user expects to click. Poll the port rather than sleeping blind: opening before the server binds lands the browser on a connection error. If you passed
--port <n>
, open that port.
Live data is installed once, not assumed. A bare install ships no data providers: it renders plainly-simulated demo numbers, badges the header "demo data", and
serve
says so at startup. Before the first serve on a machine (or whenever
serve
prints the demo notice / the header shows the badge), install the free keyless fleet:
bash
npx --yes zframes@latest providers add keyless   # one-time; prints what it contacts + where the terms live
That printout is the point — it is the user's consent surface, so let it show rather than suppressing it.
zframes providers
lists what's installed. (An older published CLI without this command always streams live data — if
providers
errors as unknown, just serve.)
serve
hosts the prebuilt runtime pointed at that dashboard, streaming live keyless data once the fleet is installed. A bare
zframes serve
(no name) opens the default store dashboard, and when the store holds several the header title becomes a dashboard chooser — the user opens it, picks another, and the page reloads into it, no restart. The user can drag, resize, add, and configure frames in the browser — Save writes the changes straight back to
dashboard.json
. Edits to the file (yours or theirs) show on reload, so further "add X to my dashboard" requests are just another edit + the page reloads. Pass
--port <n>
if 37263 is taken.
Verify it renders designed, not just valid. Lint proves the JSON; it can't see pixels. After serving a newly built or reshaped board, if you have a browser tool, open
http://localhost:37263
and sweep once for: error cards ("Invalid configuration", "Unknown frame", missing-capability), cards stuck empty, rows with holes, and clipped card interiors — fix the spec and reload. A "demo data" pill in the header is not a bug: it means no data providers are installed — run
zframes providers add keyless
and restart the serve. (Give live data a few seconds to settle before judging a card empty; a chart's draw-in animation is not a bug.) No browser tool? Tell the user exactly what to glance for and fix what they report. Skip this sweep for a plain serve or a one-field update — the diff is the proof there.
运行仪表板并在用户浏览器中打开——仅提供链接不算完成任务。
serve
会阻塞进程,因此请在后台运行(后台shell、多路复用窗口——无论你的环境支持哪种方式),等待端口响应,然后打开URL:
bash
npx --yes zframes@latest serve <name>   # 在后台运行;存储库名称(或路径)
until curl -sf http://localhost:37263 >/dev/null; do sleep 1; done
open http://localhost:37263             # macOS · Linux使用xdg-open · Windows使用start
请始终将URL写为**
http://localhost:37263
**,不要使用裸IP——这是CLI输出的URL,也是用户期望点击的链接。轮询端口而非盲目等待:如果在服务器绑定前打开浏览器,会显示连接错误。如果传递了
--port <n>
参数,请打开对应端口。
实时数据需手动安装,默认不包含。 初始安装不包含任何数据源:它会显示模拟的演示数据,页眉会标记“演示数据”,
serve
启动时也会提示。在设备上首次运行前(或每当
serve
显示演示提示/页眉显示演示徽章时),请安装免费的无密钥数据源集群:
bash
npx --yes zframes@latest providers add keyless   # 一次性操作;会显示连接的数据源以及服务条款位置
该输出非常重要——这是用户的同意界面,请不要隐藏。
zframes providers
会显示已安装的数据源。 (如果使用旧版本CLI,
providers
命令可能不存在,此时默认会流式传输实时数据——如果
providers
命令报错,直接运行即可。)
serve
会托管指向该仪表板的预构建运行时,安装数据源集群后会流式传输实时无密钥数据。直接执行
zframes serve
(不带名称)会打开默认存储库仪表板,当存储库中有多个仪表板时,页眉标题会成为仪表板选择器——用户点击它,选择另一个仪表板,页面会重新加载,无需重启。用户可在浏览器中拖动、调整大小、添加和配置框架——保存操作会将更改直接写入
dashboard.json
。对文件的编辑(你或用户进行的)会在刷新后显示,因此后续“把X添加到我的仪表板”的请求只需再次编辑并刷新页面即可。如果37263端口被占用,可传递
--port <n>
参数。
验证仪表板是否按设计渲染,而不仅是验证有效性。 Lint仅能验证JSON的有效性,无法检查视觉效果。运行新建或重构的仪表板后,如果有浏览器工具,请打开
http://localhost:37263
并检查以下内容:错误卡片(“无效配置”、“未知框架”、功能缺失)、空白卡片、行内空隙、卡片内容被截断——修复配置并刷新页面。页眉中的**“演示数据”标记不是bug**:它表示未安装数据源——运行
zframes providers add keyless
并重新启动服务。 (实时数据加载需要几秒钟时间,请不要立即判断卡片为空;图表的绘制动画不是bug。)如果没有浏览器工具?请明确告知用户需要检查的内容,并根据用户反馈进行修复。对于直接运行或单字段更新的情况,可跳过此检查——差异就是验证依据。

Hard rules

硬性规则

  • Serve when they just want to look. If a dashboard already exists and the user says start / open / serve (or sends a bare
    /zframes
    ), serve it (step 1 → step 6) — no interview, no
    init
    , no rebuild. Build or re-interview only when they're creating a new dashboard or changing an existing one. Serving means backgrounding
    serve
    and opening
    http://localhost:37263
    in their browser — the ask was "open my dashboard", so a printed link isn't the job done.
  • The interview picks tickers (and at most a look), never frames. The onboarding funnel — asset class → categories → specific tickers, with one optional theme-preset question riding along — exists only to choose the symbols and the vibe. You assemble the board: never ask which frames or widgets to include, never show or read back frame names as options.
  • Curate and compose — the two design invariants. 20–35 cards in 3–5 headed zones, sizes from each frame's catalogue
    layout
    (never outside its
    minW
    /
    minH
    maxW
    /
    maxH
    envelope), every row packed to 12 columns, exactly one theme preset applied verbatim. A catalogue dump and a sparse husk are both failures.
  • dashboard.json is the only artifact. No React, no CSS, no new frames. If the user wants a frame that doesn't exist, say so and list what does.
  • Free data only: 29 keyless sources — Hyperliquid (crypto + HIP-3 stock perps), Nasdaq, CoinGecko, DeFiLlama, Deribit, Cboe, mempool.space, the U.S. Treasury, the NY Fed, BLS, SEC EDGAR, FRED, LBMA metals, and more. The whole fleet is one
    zframes providers add keyless
    (step 6); there are no API keys to configure — never ask for one.
  • Re-read the catalogue every session; never trust remembered frame names.
  • 用户仅需查看时直接运行。 如果仪表板已存在且用户说启动/打开/运行(或直接输入
    /zframes
    ),直接运行即可(步骤1→步骤6)——不要调研,不要执行init,不要重建。仅当用户创建新仪表板或修改现有仪表板时才进行构建或重新调研。运行意味着在后台启动
    serve
    并在用户浏览器中打开
    http://localhost:37263
    ——用户的需求是“打开我的仪表板”,因此仅提供链接不算完成任务。
  • 调研仅选择代码(最多包含外观),绝不选择框架。 入门流程——资产类别→分类→特定代码,同时可选择询问一个主题预设问题——仅用于选择符号和风格。由你组装仪表板:绝不要询问用户需要哪些框架或小部件,绝不要将框架名称作为选项展示或回读。
  • 精心挑选与组合——两个设计不变量。 20–35个卡片分为3–5个带标题的区域,尺寸来自每个框架的catalogue
    layout
    (绝不要超出其
    minW
    /
    minH
    maxW
    /
    maxH
    范围),每行填满12列,精确应用一个主题预设。直接导出catalogue内容或过于稀疏的布局都是失败的。
  • dashboard.json是唯一产物。不要编写React、CSS或新框架。如果用户需要的框架不存在,请告知并列出已有的框架。
  • 仅使用免费数据:29个无密钥数据源——Hyperliquid(加密货币+HIP-3股票永续合约)、Nasdaq、CoinGecko、DeFiLlama、Deribit、Cboe、mempool.space、美国财政部、纽约联邦储备银行、BLS、SEC EDGAR、FRED、LBMA金属等。整个集群只需执行一次
    zframes providers add keyless
    (步骤6);无需配置API密钥——绝不要询问用户的API密钥。
  • 每次会话都重新读取catalogue;绝不要依赖记忆中的框架名称。