> 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/th/reference/sheet-format.md).

# สเปกของรูปแบบชีต

หน้านี้ระบุรูปแบบ contact-sheet ที่เครื่องมือ Squish สร้างและอ่านใช้ มันคือสิ่งที่ทำให้ชีตหนึ่งแผ่นเป็น *การแสดงแทนที่อ้างอิงได้* ของวิดีโอ ไม่ใช่แค่รูปภาพธรรมดา: เครื่องมือใดก็ตามที่ทำตามนี้จะสร้างชีตที่โมเดลสามารถนำทางได้ และที่อยู่ใดก็ตามที่ชีตแสดง สามารถป้อนกลับเข้าไปเพื่อซูมได้ ดู [วิดีโอในฐานะพื้นที่ที่อยู่](/squish/th/the-primitive/video-as-address-space.md) สำหรับแนวคิดนี้; หน้านี้คือข้อตกลง

## ขอบเขต

ชีตที่เป็นไปตามข้อกำหนดคือภาพแรสเตอร์ภาพเดียว (การใช้งานอ้างอิงส่งออกเป็น JPEG คุณภาพ 0.70) ที่มี:

* ตารางของเฟรมที่สุ่มจากวิดีโอต้นฉบับหนึ่งรายการ (หรือช่วงเวลาหนึ่งของมัน) ตามลำดับเวลาอย่างเคร่งครัด และ
* เวลาที่ปักกำกับบนทุกช่อง ตามไวยากรณ์ด้านล่าง **อิงกับนาฬิกาของวิดีโอต้นฉบับโดยตรง**.

ส่วนที่เป็นข้อกำหนดบังคับในที่นี้: ลำดับเวลาของตาราง, กฎการสุ่ม, ไวยากรณ์ของ timecode และกฎความละเอียด, ความหมายของเวลาแบบสัมบูรณ์, ข้อตกลงเรื่องชื่อไฟล์, และคุณสมบัติการส่งกลับไปกลับมาได้ *ไม่ใช่* ข้อกำหนดบังคับ: รูปลักษณ์ภายนอก — สี, ฟอนต์, รูปร่างของป้าย, แบรนด์ที่ส่วนท้าย, ขนาดพิกเซล (ดู [สิ่งที่ความเสถียรไม่ครอบคลุม](/squish/th/reference/stability.md#what-is-not-covered)).

## รูปทรงของตาราง

มีความหนาแน่น 4 แบบ ความหนาแน่นจะกำหนดจำนวนช่องของชีตทุกแผ่นในหนึ่งรอบการสร้าง:

| ความหนาแน่น | ตาราง | จำนวนช่องต่อชีต | ความกว้างเอาต์พุตอ้างอิง (เพื่อข้อมูล) |
| ----------- | ----- | --------------: | -------------------------------------: |
| `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*เพิ่มขึ้นอย่างเคร่งครัด การอ่านชีตเหมือนอ่านข้อความจะอ่านคลิปตามลำดับเวลา

เมื่อรันยาว ๆ ระบบจะแบ่งออกเป็นหลายชีตที่ครอบคลุมช่วงย่อยต่อเนื่องที่มีความยาวเท่ากัน โดยเวอร์ชันอ้างอิงจะเปิดชีตใหม่ทุกช่วงที่ครอบคลุมประมาณ 90 วินาที และจำกัดไว้ที่ 4 ชีตต่อหนึ่งรอบ; ชีต *N* ครอบคลุมเวลาที่เก่ากว่าชีต *N*+1.

## กฎการสุ่ม

เวลาเฟรมจะถูกเลือกอย่างกำหนดแน่นอน — **แต่ละช่องจะสุ่มจากจุดกึ่งกลางของช่วงย่อยที่แบ่งเท่า ๆ กัน** ของหน้าต่างของชีต:

ให้ช่วงที่ครอบคลุมมีความยาว *L* (ทั้งคลิป หรือ `end − start` ของ [หน้าต่างซูม](/squish/th/reference/cli.md#window-semantics)) แบ่งเป็น *S* หน้าต่างของชีตที่เท่ากัน โดยมีความยาว *W* = *L* / *S*. ภายในหน้าต่างของชีตที่เริ่มที่ *w₀*, ช่อง *i* ของ *N* ช่องจะสุ่มตัวอย่าง

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

มีการปรับ 2 อย่าง:

* **ขอบท้าย** จะไม่มีตัวอย่างใดตกที่ตำแหน่งท้ายสุดของคลิปพอดี (การ seek ไปที่ EOF จะไม่ได้ผลอะไร) ทุกเวลา stamp จะถูกบังคับให้อยู่ไม่เกิน `duration − min(0.02 s, W/N/2)` — เว้นระยะคงที่ 20 มิลลิวินาที และจะลดลงครึ่งหนึ่งของช่วงสุ่มตัวอย่างสำหรับหน้าต่างที่เล็กมาก เพื่อไม่ให้ช่องท้าย ๆ ไปทับกันที่เวลาเดียวกัน
* **รันแบบหน้าต่างยังคงอิงแบบสัมบูรณ์** การรันแบบหน้าต่างจะวางแผนเหมือนการรันบนคลิปที่ถูกตัดความยาวออกทางความคิดให้เหลือ `end − start`, แล้ว **เวลาทุกค่าจะถูกเลื่อน +start**. ที่อยู่จะอ้างถึงนาฬิกาของวิดีโอต้นฉบับเสมอ — การรันแบบหน้าต่างจะไม่กำหนดฐานใหม่ให้มัน

## ไวยากรณ์ของ timecode

### รูปแบบที่ส่งออก

ผู้ผลิตที่เป็นไปตามข้อกำหนดจะปักกำกับเวลาที่สุ่มได้ให้กับทุกช่องในรูปแบบใดรูปแบบหนึ่งต่อไปนี้:

| รูปแบบ     | ตัวอย่าง         | เมื่อใด                                 |
| ---------- | ---------------- | --------------------------------------- |
| `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`).
* ค่า **ปัดลง** ตามความละเอียดที่แสดง — จะไม่มีการปัดขึ้นไปยังวินาทีหรือนาทีถัดไป ดังนั้น timecode จึงไม่เคยชี้เลยเฟรมที่มันระบุ

### ความเป็นแบบสัมบูรณ์

timecode ทุกตัวอ้างถึง **นาฬิกาของวิดีโอต้นฉบับ**. การซูม (รันซ้ำบนหน้าต่าง `start`/`end` ) จะได้ timecode ที่ละเอียดขึ้นในระบบพิกัด *เดียวกัน* — ไม่เคยกำหนดฐานใหม่ตามหน้าต่าง สิ่งนี้ทำให้เอเจนต์ซูมต่อกันได้: ที่อยู่ที่อ่านจากชีตใด ๆ ไม่ว่าลึกแค่ไหน ก็ใช้เป็นขอบเขตสำหรับการเรียกครั้งถัดไปได้โดยตรง และการอ้างอิงยังคงใช้ได้กับวิดีโอต้นฉบับ

### รูปแบบอินพุตที่ยอมรับ

ผู้รับที่เป็นไปตามข้อกำหนด ( `--start`/`--end` แฟล็ก, พารามิเตอร์ของ MCP `start`/`end` ) ยอมรับ:

* **วินาทีแบบตรง ๆ**: `90`, `67.4` (และตัวเลข JSON ดิบผ่าน MCP)
* **`m:ss[.fraction]`** — นาทีไม่มีขอบเขต วินาทีมี 1–2 หลัก และน้อยกว่า 60: `1:30`, `120:30`, `1:07.3`
* **`h:mm:ss[.fraction]`** — นาทีน้อยกว่า 60 วินาทีน้อยกว่า 60: `01:02:03`

จะเป็นแบบ 2 ส่วนหรือ 3 ส่วนขึ้นกับ **จำนวนเครื่องหมายโคลอน ไม่ใช่ขนาดของค่า**. อะไรก็ตามที่ไม่ใช่แบบนี้จะถูกปฏิเสธว่าไม่ถูกต้องรูปแบบ (เป็นข้อผิดพลาดในการใช้งานบน CLI หรือเป็นข้อผิดพลาดของเครื่องมือผ่าน MCP)

## ความละเอียดแบบปรับอัตโนมัติ

ความละเอียดที่แสดงจะปรับให้ **ช่องที่ติดกันแสดงที่อยู่ที่ต่างกันเสมอ**. ความละเอียดจะถูกเลือกจากช่วงสุ่มตัวอย่าง (ระยะห่างของเวลาระหว่างช่องที่ติดกัน):

| ช่วงสุ่มตัวอย่าง | ความละเอียด      | รูปแบบ     |
| ---------------- | ---------------- | ---------- |
| ≥ 1 วินาที       | วินาทีเต็ม       | `m:ss`     |
| ≥ 0.1 วินาที     | ทศนิยม 1 ตำแหน่ง | `m:ss.d`   |
| ≥ 0.01 วินาที    | ทศนิยม 2 ตำแหน่ง | `m:ss.dd`  |
| < 0.01 วินาที    | ทศนิยม 3 ตำแหน่ง | `m:ss.ddd` |

มีกฎข้อเดียวที่ใช้ได้กับทุกพื้นที่เอาต์พุต: ป้ายที่ปักบนพิกเซลของชีตและอาร์เรย์ `timecodes[][]` ใน [MCP](/squish/th/reference/mcp.md#result-payload) หรือ JSON ของ hosted API มาจากการคำนวณเดียวกัน และต้องไม่ขัดกัน

### ขั้นต่ำที่อ้างอิงได้: 2 มิลลิวินาทีต่อช่อง

เครื่องยนต์จะ seek ด้วยความละเอียดระดับมิลลิวินาที และช่องจะสุ่มที่จุดกึ่งกลางของหน้าต่าง — ต่ำกว่า **2 มิลลิวินาทีของหน้าต่างต่อช่อง**, จุดกึ่งกลางที่ติดกันอาจปัดได้เป็นมิลลิวินาทีเดียวกัน และที่อยู่จะชนกันโดยไม่รู้ตัว ดังนั้นผู้ผลิตที่เป็นไปตามข้อกำหนดจึง **ปฏิเสธ** หน้าต่างที่เล็กกว่า `ช่อง × 2 มิลลิวินาที` (เช่น 18 มิลลิวินาทีที่ `3x3`, 72 มิลลิวินาทีที่ `6x6`) ด้วยข้อผิดพลาดเชิงแนะนำ ("ซูมออกหรือเลือกความหนาแน่นต่ำลง") แทนที่จะสร้างที่อยู่ซ้ำ หน้าต่างที่พอดีกับขั้นต่ำจะยอมรับได้ ที่ 2 มิลลิวินาทีต่อช่อง จุดกึ่งกลางที่ติดกันจะแตกต่างกันอย่างน้อย 2 มิลลิวินาที ดังนั้นเป้าหมายของการ seek หลังการปัดและป้ายกำกับที่ปัดลงของแต่ละอันก็จะแตกต่างกันอย่างน้อย 1 มิลลิวินาที — รับประกันได้ว่าไม่ซ้ำ ไม่ใช่แค่หวังเอา

## ข้อตกลงเรื่องชื่อไฟล์

ชีตจะตั้งชื่อเป็น

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

โดยที่ `<basename>` มาจากเส้นทางวิดีโอที่ผู้ผลิตได้รับ — ชื่อไฟล์โดยไม่รวมส่วนขยาย — และ `N` คือดัชนีชีตแบบเริ่มจาก 1 ตามลำดับเวลา (`clip.mov` → `clip.sheet-1.jpg`, `clip.sheet-2.jpg`, …). นี่คือวิธีที่ CLI และเซิร์ฟเวอร์ MCP ตั้งชื่อไฟล์ที่เขียน และรูปแบบนี้ถูกตรึงไว้แล้ว (ดู [ความเสถียรและการกำหนดเวอร์ชัน](/squish/th/reference/stability.md)).

ข้อยกเว้นที่ระบุไว้ข้อหนึ่ง: [hosted API](/squish/th/reference/http-api.md) จะเก็บไฟล์อัปโหลดไว้ภายใต้ชื่อคงที่ของตัวเอง ดังนั้น URL ของคำตอบจึงลงท้ายด้วย `video.sheet-N.jpg` เสมอ ไม่ว่าจะอัปโหลดชื่ออะไร — ชื่อเดิมจะถูกสะท้อนกลับไปในฟิลด์ `input` ของคำตอบแทน ให้ตรวจสอบชื่อไฟล์ของ hosted เทียบกับรูปแบบ `*.sheet-N.jpg` เท่านั้น อย่าตรวจเทียบกับชื่อไฟล์ที่อัปโหลด

## คุณสมบัติการส่งกลับไปกลับมาได้

**`parseTime` ยอมรับทุกอย่าง `fmtTime` ส่งออก**: รูปแบบที่ส่งออกทั้งหมดข้างต้นอยู่ในไวยากรณ์ของอินพุตที่ยอมรับได้ในทุกระดับความละเอียด ดังนั้น อะไรก็ตามที่ชีตแสดงจึงเป็นอินพุตที่ถูกต้องของ `--start`/`--end` (CLI) หรือ `start`/`end` (MCP) — เอเจนต์สามารถอ่านที่อยู่จากชีตด้วยการมองเห็นแล้วส่งสตริงนั้นกลับไปเพื่อซูมได้โดยตรง การปิดวงจรนี้ทำให้ [วงจรการนำทาง](/squish/th/the-primitive/the-navigation-loop.md) ทำงานได้โดยไม่ต้องมีชั้นแปลงข้อมูลใด ๆ

## การเป็นไปตามข้อกำหนด

ชุดทดสอบในรีโพสาธารณะทำหน้าที่เป็นตัวอย่างทองคำแบบรันได้ของสเปกนี้ — ดู [`tests/`](https://github.com/getsquish/squish/tree/main/tests), โดยเฉพาะ `window.test.ts` (ความละเอียดของหน้าต่าง, การบังคับขอบท้าย, ขีดขั้นต่ำ 2 มิลลิวินาที/ช่อง) และ `report.test.ts` (รูปแบบของสัญญาเอาต์พุต) ถ้าการทำงานของคุณตรงกับการทดสอบเหล่านั้น ก็ถือว่าเป็นไปตามข้อกำหนด

## การกำหนดเวอร์ชัน

นี่คือ **v0** ของรูปแบบชีต การพัฒนาจะเพิ่มความสามารถเข้าไปเท่านั้น — รูปทรง, ไวยากรณ์, และความหมายที่มีอยู่จะไม่ถูกเปลี่ยนภายใน v0; ความสามารถใหม่จะปรากฏควบคู่ไปกับของเดิม พื้นที่ JSON ที่เก็บข้อมูลเมตาของชีตจะกำหนดเวอร์ชันด้วยสตริงข้อตกลงที่ระบุชัดเจน — ดู [ความเสถียรและการกำหนดเวอร์ชัน](/squish/th/reference/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/th/reference/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.
