Typst 编辑器将你的代码和编译后的页面并排显示。它以 WebAssembly 形式在你的浏览器中运行真正的 Typst 编译器,因此页面与 PDF 中的效果完全一致,包括标题、列表、表格、公式、插图、脚注、引用以及你自己的 #set 和 #show 规则。点击页面上的任意文字,即可跳到它在代码中的位置,你也可以直接在页面上编辑文字。
一切都在你的浏览器中运行。文档不会上传,无需注册,也没有广告。
标记、代码、公式、字符串和注释各有颜色,带行号,按 Enter 自动续写列表,并显示编译器的错误及其行号、列号和提示。
编译为 WebAssembly 的 Typst 0.14 在编辑器旁的 Worker 中运行,每次更改后稍候即编译,输入依然流畅。
点击页面上的文字即可直接修改,更改会写入代码。点击公式或图片则会跳转到代码中的对应位置。
纸张、页边距、分栏、字体、字号、语言、两端对齐、编号标题和页码:这些设置会编辑你代码中的 #set 规则。
为文档添加图片、CSV、JSON、YAML、参考文献、字体和其他 .typ 文件,并通过 image、csv、json 或 #import 使用它们。
由编译器生成、文字真实可选的 PDF,每页导出为 PNG、JPG、WebP 或 SVG,或带文件的 .typ 源文件 ZIP。
任何 https 页面(以及 localhost)都可以用 <iframe> 和 ?embed=1 嵌入编辑器,无需注册,无需密钥。嵌入后,编辑器会隐藏这段文字并显示“保存”按钮。有两种方式传入和取出文档。
src= 打开一个文件(你的服务器必须允许 CORS),webhook= 让“保存”(Ctrl+S)把文档发送到该地址。加上 &token=… 可发送 Authorization: Bearer … 请求头,加上 &auto 则每次更改后都会保存。
<iframe src="https://typst.giit.ch/?embed=1&src=https://your-site.com/docs/flyer.typ&webhook=https://your-site.com/save.php"
allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
Webhook 会收到一个带 JSON 的 POST 请求 { editor, event: "save", id, name, content, assets, updated }。一个保存它的简短 PHP 脚本:
<?php
header('Access-Control-Allow-Origin: https://typst.giit.ch');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
header('Access-Control-Allow-Methods: POST, OPTIONS');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') exit;
if (($_SERVER['HTTP_AUTHORIZATION'] ?? '') !== 'Bearer SECRET') { http_response_code(403); exit; }
$d = json_decode(file_get_contents('php://input'), true);
$name = preg_replace('/[^\w\- ]/u', '_', $d['name']);
file_put_contents(__DIR__ . "/docs/$name.typ", $d['content']);
echo '{"ok":true}';
编辑器发送 typsteditor:ready,你的页面以 typsteditor:load 回应,编辑器报告 typsteditor:loaded,有实际编辑时发送 typsteditor:change,用户保存时发送 typsteditor:save。你的页面可以发送 typsteditor:get(获取当前状态)或 typsteditor:save(相当于点击“保存”)。这样保存就通过你自己的登录和会话进行。
<iframe id="ed" src="https://typst.giit.ch/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://typst.giit.ch';
addEventListener('message', async e => {
if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
const m = e.data;
if (m.type === 'typsteditor:ready') { // 编辑器已就绪:把文档交给它
ed.contentWindow.postMessage({
type: 'typsteditor:load',
name: 'Flyer',
content: await (await fetch('/docs/flyer.typ')).text(),
assets: { 'logo.png': 'data:image/png;base64,…' } // 可选的图片和数据文件
}, ORIGIN);
}
if (m.type === 'typsteditor:change') document.title = '● not saved'; // 一次实际编辑
if (m.type === 'typsteditor:save') { // 用户点击了“保存”
await fetch('/api/save', { method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: m.name, content: m.content, assets: m.assets }) });
document.title = 'Saved';
}
});
// 你自己页面上的保存按钮:回应以 typsteditor:save 返回
function saveNow() { ed.contentWindow.postMessage({ type: 'typsteditor:get' }, ORIGIN); }
</script>
页面内的 AI 助手:在框架中同样可用。在 iframe 上设置 allow="clipboard-write" 后,“复制提示词”会直接使用剪贴板(否则编辑器会退回旧的复制命令,或显示提示词供手动复制)。AI 发送的链接无法到达另一个网站中的编辑器,因此编辑器会提示 AI 和用户把 AI 的完整回答粘贴到编辑器中,或在单独的窗口中打开编辑器。
window.open("https://typst.giit.ch/?embed=window", "typsteditor-17") 会在单独的窗口中打开完整的编辑器,并通过 window.opener 使用相同的消息。AI 的链接可以到达那里。typsteditor:load 还可以带上 context: { host, title, rules }(AI 提示词随后会说明文档属于哪里,并遵循你的规则),以及 hook: { url, token, assets: false },即仅用于此文档、从不保存的 Webhook。关闭有未保存更改的窗口时会发送 typsteditor:closing。typsteditor:pdf 会请求页面文档的 PDF,并以 Data URI 形式返回,由 Typst 编译器生成,文字真实可选。
向编辑器提供你自己的提示词、你网站上的一个地址和本次编辑器会话的密钥。AI 对话框随后会显示“已连接到”你的网站、你告诉 AI 的内容,以及修改当前文档或新建一个文档的选项;复制提示词会把这些都组合起来。AI 带着密钥把结果发送到你的服务器,你的页面再在编辑器中打开它;新文档会单独打开,并保留在用户的浏览器中。每个编辑器会话一个密钥:编辑器打开期间有效,只有在没有密钥时,编辑器才会用 typsteditor:key-request 请求。编辑器自己从不发送密钥,也从不保存它;地址必须是你自己主机或其子域名上的 https 地址。
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // 每个编辑器会话一个密钥
const k = await key();
ed.contentWindow.postMessage({ type: 'typsteditor:load', name: 'Flyer', content, ai: {
label: 'My Site', prompt: 'Keep the [[placeholders]]. Write in German.',
endpoint: 'https://your-site.com/api/ai-result.php', key: k.key } }, ORIGIN);
// 记住 typsteditor:loaded 中的 id,忽略 id 不同的 change/save/closing
// 仅在编辑器没有密钥时:
if (m.type === 'typsteditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'typsteditor:ai', key: k.key }, ORIGIN); }
// 编辑器打开期间,每分钟通知你的服务器;关闭编辑器或页面会使密钥作废
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// 你的服务器有了结果(轮询、SSE …):target 为 "current" 或 "new"
ed.contentWindow.postMessage({ type: 'typsteditor:load', name: 'Flyer', content: draft, from: 'ai', target }, ORIGIN);
<?php // api/ai-key.php:已登录用户本次编辑器会话的密钥(由你的页面调用)
session_start(); // 检查用户是否可以编辑此文档
$key = bin2hex(random_bytes(24));
$_SESSION['ai'][hash('sha256', $key)] = ['doc' => (int)$_GET['doc'], 'seen' => time()]; // 或存入你的数据库;?alive= 会重新设置 seen
echo json_encode(['key' => $key]);
<?php // api/ai-result.php:AI 向这里发送(无需 CORS 头:AI 从服务器调用它)
$key = preg_replace('/^Bearer\s+/', '', $_SERVER['HTTP_AUTHORIZATION'] ?? '');
$row = find_key(hash('sha256', $key)); // 你的数据库:未作废,且在最近 3 分钟内出现过
if (!$row) { http_response_code(401); exit('{"ok":false,"error":"key not valid"}'); }
$d = json_decode(file_get_contents('php://input', false, null, 0, 2000000), true);
save_draft($row['doc'], $d['content'], $d['target'] === 'new' ? 'new' : 'current'); // 你的页面用 typsteditor:load 显示它
echo '{"ok":true}';
密钥至少使用 128 位随机数,只保存其哈希值,将每个密钥绑定到已登录用户、文档和本次编辑器会话,每个会话一个,仅在你的页面报告会话仍打开时有效,并在编辑器或页面关闭时作废。
完整协议见 llms.txt,把它交给 AI,AI 就能为你的系统建立连接。LaTeX 编辑器的用法相同,前缀为 latexeditor:,见 latex.giit.ch。
不会。编辑器和 Typst 编译器完全在你的浏览器中运行。你的文档、图片和文件绝不会发送到服务器,除非你自己设置了指向自己服务器的 Webhook。
是的。编辑器运行编译为 WebAssembly 的 Typst 0.14(typst.ts),因此页面和 PDF 与 Typst 命令行的结果相同。它只加载一次(约 11 MB),之后由你的浏览器缓存。
点击“导出”,选择 PDF,再点击“下载”。PDF 直接由 Typst 编译器生成,文字真实,可以选中和搜索。
不能直接使用:编辑器不会从其他服务器加载任何内容,因此 #import "@preview/…" 会报告一个指明该包的问题。你可以在“图片”标签页中把包的 .typ 文件添加到文档,并按文件名导入。
Typst 自带的字体:Libertinus Serif(默认)、New Computer Modern 及其数学字体,以及用于代码的 DejaVu Sans Mono。你可以向文档添加自己的 .otf 或 .ttf 文件,并通过 #set text(font: "Name") 使用。
将图片拖入或粘贴到编辑器中,或在右侧的“图片”标签页中添加。图片与文档一起保存在你的浏览器中,通过 #image("name.png") 使用。CSV、JSON、YAML 和 .bib 文件的用法相同。
能,任何 AI 都可以:ChatGPT、Claude、Gemini、Copilot 或你编程工具中的 AI。点击“AI 助手”,再点击“复制提示词”,粘贴到你的 AI 中并说明要写什么。AI 会回复一个链接;点击它,文档就会出现在你的编辑器中。“撤销”可撤回每一处更改。
可以。用 iframe 嵌入它并通过 postMessage 交换文档,或让它通过 Webhook 把每个保存的版本发送到你的服务器。示例见在你自己的网站上使用编辑器。
不收费。编辑器免费,没有广告,无需注册。