> For the complete documentation index, see [llms.txt](https://getsquish.gitbook.io/squish/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://getsquish.gitbook.io/squish/zh/can-kao/sheet-format.md).

# Sheet 格式规范

本页规定了 Squish 工具生成和读取的 contact-sheet（缩略图联系表）格式。正是它让一张 sheet 成为一种 *可寻址表示* 视频的表示，而不只是普通图像：任何遵循它的工具都会生成可供模型导航的 sheets，而 sheet 上显示的任何地址都可以再输入进去进行放大。参见 [作为地址空间的视频](/squish/zh/primitive/video-as-address-space.md) 了解这一概念；本页就是该契约。

## 范围

符合规范的 sheet 是一张单独的栅格图像（参考实现输出 JPEG，质量 0.70），其中包含：

* 来自同一个源视频（或其中一个时间窗口）的帧网格，按严格的时间顺序排列；以及
* 每个单元格都标注了一个时间码，格式见下文， **相对于源视频的时钟为绝对时间**.

这里属于规范性的内容：网格的时间顺序、采样规则、时间码语法及其精度规则、绝对时间码语义、文件名约定，以及往返性质。 *非* 规范性内容：视觉样式——颜色、字体、胶囊形几何、页脚品牌、像素尺寸（见 [稳定性不涵盖的内容](/squish/zh/can-kao/stability.md#what-is-not-covered)).

## 网格几何

存在四种密度。密度会固定一次运行中每张 sheet 的单元格数量：

| 密度    | 网格    | 每张 sheet 的单元格数 | 参考导出宽度（信息性） |
| ----- | ----- | -------------: | ----------: |
| `3x3` | 3 × 3 |              9 |     1536 px |
| `4x4` | 4 × 4 |             16 |     1920 px |
| `5x5` | 5 × 5 |             25 |     2304 px |
| `6x6` | 6 × 6 |             36 |     2560 px |

单元格按时间排序， **先从左到右，再从上到下**：单元格索引 *i* （从 0 开始计数）占据第 *i* mod *cols*，第 ⌊*i* / *cols*⌋ 行，并且其采样时间在 *i*中严格非递减。像读文本一样读取 sheet，就等于按时间顺序读取这段剪辑。

一次较长的运行会展开成多张 sheet，覆盖相等且连续的时间片段。参考生成器大约每覆盖 90 秒就打开一张新 sheet，每次运行最多 4 张；sheet *N* 覆盖的时间严格早于 sheet *N*+1.

## 采样规则

帧时间是确定性选择的—— **每个单元格采样其等分子片段的中点** ，该 sheet 窗口：

设覆盖范围长度为 *L* （整段剪辑，或 `end − start` 的 [放大窗口](/squish/zh/can-kao/cli.md#window-semantics)），将其分成 *S* 个相等的 sheet 窗口，每个长度为 *W* = *L* / *S*。在起始于 *w₀*，单元格 *i* 的 *N* 个单元格采样

```
t = w₀ + W · (i + 0.5) / N
```

两个调整：

* **尾端边距。** 没有任何采样会落在剪辑的精确末尾（EOF seek 会返回空）。所有时间戳都会被夹紧到 `duration − min(0.02 s, W/N/2)` ——固定 20 ms 的边距；对于很小的窗口会缩小到半个采样步长，这样末尾单元格就不会塌缩到同一个时间戳上。
* **带窗口的运行仍保持绝对时间。** 带窗口的运行会完全按一段虚拟裁剪后、长度为 `end − start`的剪辑来规划，然后 **每个时间戳都会整体加上 +start**。地址始终指向源视频的时钟——带窗口的运行绝不会对它们重新设基。

## 时间码语法

### 输出格式

符合规范的生成器会用以下格式之一为每个单元格标注其采样时间：

| 格式         | 示例               | 何时使用     |
| ---------- | ---------------- | -------- |
| `m:ss`     | `1:30`, `120:30` | 默认（整秒精度） |
| `m:ss.d`   | `1:07.3`         | 1 位小数    |
| `m:ss.dd`  | `1:07.34`        | 2 位小数    |
| `m:ss.ddd` | `1:07.342`       | 3 位小数    |

规则：

* **分钟没有上限** ——超过一小时的剪辑会标注，绝不会标注 `120:30`，绝不会 `h:mm:ss`。输出格式由结构决定，而不是由数值大小决定。
* 秒会补零到两位（`0:07`, `1:07.3`).
* 数值 **向下取整** 到显示的精度——它们绝不会四舍五入进下一秒或下一分钟，因此时间戳绝不会指向其所标注帧之后的时刻。

### 绝对性

每个时间码都指向 **源视频的时钟**。放大（在一个 `start`/`end` window 上重新运行）会在 *相同* 坐标系中得到更精细的时间码——绝不会重新以窗口为基准。这正是让智能体可以串联多次放大的原因：从任意深度的任何 sheet 上读出的地址，都可以直接作为下一次调用的边界，而且引用对原始视频始终有效。

### 接受的输入格式

符合规范的消费者（ `--start`/`--end` 标志、MCP `start`/`end` 参数）接受：

* **纯秒数**: `90`, `67.4` （以及通过 MCP 传入的原始 JSON 数字）
* **`m:ss[.fraction]`** ——分钟无上限，秒为 1–2 位且小于 60： `1:30`, `120:30`, `1:07.3`
* **`h:mm:ss[.fraction]`** ——分钟小于 60，秒小于 60： `01:02:03`

采用两段式还是三段式由 **冒号数量决定，绝不由数值大小决定**。其他任何形式都会被拒绝为格式错误（CLI 中是用法错误，MCP 中是工具错误）。

## 自适应精度

显示精度会自适应，以便 **相邻单元格始终显示不同的地址**。精度根据采样步长（相邻单元格之间的时间间隔）来选择：

| 采样步长     | 精度    | 格式         |
| -------- | ----- | ---------- |
| ≥ 1 秒    | 整秒    | `m:ss`     |
| ≥ 0.1 秒  | 1 位小数 | `m:ss.d`   |
| ≥ 0.01 秒 | 2 位小数 | `m:ss.dd`  |
| < 0.01 秒 | 3 位小数 | `m:ss.ddd` |

一条规则适用于所有输出表面：标在 sheet 像素上的标签以及 `timecodes[][]` 中的数组 [MCP](/squish/zh/can-kao/mcp.md#result-payload) / hosted-API JSON 都来自同一次计算，绝不能不一致。

### 可寻址下限：每个单元格 2 ms

引擎以毫秒精度进行 seek，而单元格采样的是窗口中点——低于 **每个单元格 2 ms 的窗口范围**时，相邻中点可能会舍入到同一毫秒，地址就会悄悄冲突。因此，符合规范的生成器会 **拒绝** 小于 `cells × 2 ms` （例如 18 ms 时 `3x3`，72 ms 时 `6x6`）会给出教学性错误（“请缩小放大范围或降低密度”），而不是产生重复地址。恰好处于下限的窗口是可以接受的。在每个单元格 2 ms 时，相邻中点至少相差 2 ms，因此它们舍入后的 seek 目标和向下取整后的标签各自至少相差 1 ms——区别是有保证的，不只是期望如此。

## 文件名约定

sheet 的命名为

```
<basename>.sheet-N.jpg
```

其中 `<basename>` 取自生成器接收到的视频路径——也就是去掉扩展名后的文件名——而 `N` 是按时间顺序从 1 开始计数的 sheet 索引（`clip.mov` → `clip.sheet-1.jpg`, `clip.sheet-2.jpg`，…）。CLI 和 MCP 服务器就是这样命名它们写出的文件的，而且该格式是固定的（见 [稳定性与版本控制](/squish/zh/can-kao/stability.md)).

一个有文档说明的例外： [托管 API](/squish/zh/can-kao/http-api.md) 会用自己的固定名称存储上传内容，因此它的响应 URL 总是以 `video.sheet-N.jpg` 结尾，无论上传时的文件名是什么——原始名称会在响应的 `input` 字段中回显。验证托管文件名时，应针对 `*.sheet-N.jpg` 模式进行校验，绝不要针对上传时的名称。

## 往返性质

**`parseTime` 接受所有内容 `fmtTime` 输出**：上面输出的每一种格式，在任何精度下都符合接受输入的语法。因此，sheet 显示的任何内容都是有效的 `--start`/`--end` （CLI）或 `start`/`end` （MCP）输入——智能体可以通过视觉从 sheet 上读出一个地址，并把原样字符串再传回去进行放大。正是这种闭包性让 [导航循环](/squish/zh/primitive/the-navigation-loop.md) 无需任何转换层就能工作。

## 符合性

公共仓库中的测试套件是本规范的可执行黄金示例——见 [`tests/`](https://github.com/getsquish/squish/tree/main/tests)，尤其是 `window.test.ts` （窗口分辨率、尾端夹紧、每单元 2 ms 的下限）以及 `report.test.ts` （输出契约形状）。如果你的实现与这些测试一致，它就符合规范。

## 版本控制

这就是 **v0** 版的 sheet 格式。演进是增量式的——在 v0 之内，现有的几何、语法和语义不会改变；新能力会与它们并存。承载 sheet 元数据的 JSON 接口通过显式的契约字符串进行版本控制——见 [稳定性与版本控制](/squish/zh/can-kao/stability.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://getsquish.gitbook.io/squish/zh/can-kao/sheet-format.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
