Редактор Typst показує ваш код і скомпільовані сторінки поруч. Він запускає справжній компілятор Typst у вашому браузері як WebAssembly, тож сторінки виглядають точно так, як у PDF, - заголовки, списки, таблиці, формули, рисунки, виноски, посилання й ваші власні правила #set і #show. Клацання будь-якого тексту на сторінці переносить вас до його місця в коді, а текст можна редагувати просто на сторінці.
Усе працює у вашому браузері. Документи нікуди не вивантажуються, немає ні реєстрації, ні реклами.
Розмітка, код, формули, рядки й коментарі власними кольорами, номери рядків, списки, що продовжуються після Enter, і помилки компілятора з рядком, стовпцем і підказкою.
Typst 0.14, скомпільований у WebAssembly, працює у воркері поруч із редактором і компілює за мить після кожної зміни - набір залишається плавним.
Клацніть текст на сторінці, щоб змінити його там; зміна потрапляє в код. Клацання формули чи зображення переходить до його місця в коді.
Папір, поля, стовпці, шрифт, розмір, мова, вирівнювання за шириною, нумеровані заголовки й номери сторінок - налаштування змінюють правила #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>
Вебхук отримує POST із JSON { 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>
ШІ-асистент усередині вашої сторінки: він працює і у фреймі. З allow="clipboard-write" на iframe «Копіювати промпт» використовує буфер обміну напряму (інакше редактор вдається до старої команди копіювання або показує промпт, щоб скопіювати його вручну). Посилання, яке надсилає ШІ, не може дістатися до редактора всередині іншого сайту, тому редактор просить ШІ та користувача натомість вставити всю відповідь ШІ в редактор - або відкрити редактор в окремому вікні.
window.open("https://typst.giit.ch/?embed=window", "typsteditor-17") відкриває повний редактор в окремому вікні, і він обмінюється тими самими повідомленнями з window.opener. Посилання від ШІ доходять до нього туди. typsteditor:load може також містити context: { host, title, rules } - тоді промпт для ШІ каже, де розміщено документ, і дотримується ваших правил - і hook: { url, token, assets: false }, вебхук лише для цього документа, який ніколи не зберігається. Якщо закрити вікно з незбереженими змінами, надсилається typsteditor:closing. typsteditor:pdf запитує PDF документа сторінки й отримує його назад як data URI, створений компілятором Typst зі справжнім текстом, який можна виділяти.
Передайте редактору власний промпт, адресу на вашому сайті та ключ для цього сеансу редактора. Тоді діалог ШІ показує «Під’єднано до» вашого сайту, що ви повідомляєте ШІ, і вибір змінити поточний документ або створити новий; Копіювати промпт збирає все разом. ШІ надсилає свій результат із ключем на ваш сервер, а ваша сторінка відкриває його в редакторі - новий документ відкривається окремо й залишається в браузері користувача. Один ключ на сеанс редактора: він дійсний, поки редактор відкрито, і лише поки ключа немає, редактор запитує його через 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);
// запам’ятайте id з typsteditor:loaded та ігноруйте change/save/closing з іншим id
// лише поки редактор не має ключа:
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);
// ваш сервер має результат (polling, 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 - ШІ надсилає сюди (без заголовків CORS: ШІ викликають його із сервера)
$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: дайте його ШІ, і він побудує під’єднання для вашої системи. Редактор LaTeX працює так само з префіксом latexeditor: - latex.giit.ch.
Ні. Редактор і компілятор Typst повністю працюють у вашому браузері. Ваші документи, зображення й файли ніколи не надсилаються на сервер, якщо тільки ви самі не налаштуєте вебхук на свій власний сервер.
Так. Редактор запускає Typst 0.14, скомпільований у WebAssembly (typst.ts), тож сторінки й PDF такі самі, як із командним рядком Typst. Він завантажується один раз (близько 11 МБ), а потім зберігається у вашому браузері.
Натисніть «Експорт», виберіть 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 працюють так само.
Так, будь-який ШІ - ChatGPT, Claude, Gemini, Copilot або ШІ у вашому інструменті для програмування. Натисніть «ШІ-асистент», потім «Копіювати промпт», вставте його у свій ШІ та скажіть, що треба написати. ШІ відповідає посиланням; клацніть його, і документ з’явиться у вашому редакторі. «Скасувати» повертає кожну зміну назад.
Так. Вбудуйте його через iframe й обмінюйтеся документами через postMessage або нехай він надсилає кожну збережену версію на ваш сервер через вебхук. Приклади - у розділі Редактор на вашому сайті.
Ні. Редактор безкоштовний, без реклами й без реєстрації.