Typst エディターは、コードとコンパイルされたページを並べて表示します。本物の Typst コンパイラーを WebAssembly としてブラウザー内で動かすので、ページは PDF とまったく同じ見た目になります。見出し、リスト、表、数式、図、脚注、相互参照、そしてあなた自身の #set と #show ルールもそのとおりです。ページ上のテキストをクリックするとコード内のその位置へ移動し、ページ上で直接テキストを編集することもできます。
すべてブラウザー内で動作します。ドキュメントはアップロードされず、登録も広告もありません。
マークアップ、コード、数式、文字列、コメントを色分けし、行番号、Enter で続くリスト、行、列、ヒント付きのコンパイラーのエラーを備えています。
WebAssembly にコンパイルされた Typst 0.14 がエディターの横のワーカーで動き、変更のたびに少し遅れてコンパイルします。入力はなめらかなままです。
ページ上のテキストをクリックしてその場で変更すると、変更がコードに反映されます。数式や画像をクリックすると、コード内のその位置へ移動します。
用紙、余白、段組み、フォント、サイズ、言語、両端揃え、番号付きの見出し、ページ番号。設定はコードの #set ルールを編集します。
画像、CSV、JSON、YAML、参考文献、フォント、ほかの .typ ファイルをドキュメントに追加し、image、csv、json、#import で使えます。
選択できる本物のテキストを含むコンパイラー製の PDF、全ページの PNG、JPG、WebP、SVG、またはファイル付き .typ ソースの ZIP。
https のページ (および localhost) なら、<iframe> と ?embed=1 でエディターを埋め込めます。登録もキーも不要です。埋め込まれたエディターはこの説明文を隠し、保存ボタンを表示します。ドキュメントを受け渡す方法は 2 つあります。
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 { editor, event: "save", id, name, content, assets, updated } を含む POST を受け取ります。それを保存する小さな 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 が送るリンクはほかの Web サイト内のエディターには届かないため、エディターは 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 を要求し、Typst コンパイラーが作った選択可能な本物のテキストを含む PDF をデータ URI として受け取ります。
エディターに独自のプロンプト、サイト上のアドレス、このエディターセッション用のキーを渡します。すると AI ダイアログには、あなたのサイトへの「接続先」、AI に伝える内容、そして 現在のドキュメントを変更 か 新しいドキュメントを作成 の選択肢が表示され、プロンプトをコピー ですべてがまとめられます。AI はキーを付けて結果をあなたのサーバーに送り、ページがそれをエディターで開きます。新しいドキュメントは別に開き、ユーザーのブラウザー内に残ります。キーはエディターセッションごとに 1 つです。エディターを開いている間は有効で、キーがないときだけエディターが typsteditor:key-request で要求します。エディターがキーを自分で送ったり保存したりすることはありません。アドレスはあなた自身のホストまたはそのサブドメイン上の https である必要があります。
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // エディターセッションごとにキーを 1 つ
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 がここに POST する (CORS ヘッダーなし: AI はサーバーから呼び出す)
$key = preg_replace('/^Bearer\s+/', '', $_SERVER['HTTP_AUTHORIZATION'] ?? '');
$row = find_key(hash('sha256', $key)); // データベース: 無効になっておらず、直近 3 分以内に seen があるもの
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 ビット以上のランダム値で作り、ハッシュだけを保存し、それぞれをログイン中のユーザー、ドキュメント、このエディターセッションに結び付けてください。キーはセッションごとに 1 つ作り、ページがセッションを開いていると報告している間だけ有効にし、エディターまたはページが閉じたら無効にしてください。
プロトコルの全体は llms.txt にあります。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 で保存した版をすべて自分のサーバーに送れます。例は エディターを自分の Web サイトで使う をご覧ください。
いいえ。エディターは無料で、広告も登録もありません。