El Editor de Typst muestra tu código y las páginas compiladas una al lado de la otra. Ejecuta el compilador real de Typst en tu navegador como WebAssembly, así que las páginas se ven exactamente como en el PDF: encabezados, listas, tablas, fórmulas, figuras, notas al pie, referencias y tus propias reglas #set y #show. Un clic en cualquier texto de la página te lleva a su lugar en el código, y puedes editar el texto directamente en la página.
Todo se ejecuta en tu navegador. Los documentos no se suben, no hay registro ni publicidad.
Marcado, código, fórmulas, cadenas y comentarios con sus propios colores, números de línea, listas que continúan al pulsar Enter y los errores del compilador con línea, columna y sugerencia.
Typst 0.14 compilado a WebAssembly se ejecuta en un worker junto al editor y compila un instante después de cada cambio: escribir sigue siendo fluido.
Haz clic en un texto de la página para cambiarlo allí; el cambio va al código. Un clic en una fórmula o una imagen salta a su lugar en el código.
Papel, márgenes, columnas, fuente, tamaño, idioma, texto justificado, encabezados numerados y números de página: los ajustes editan las reglas #set de tu código.
Añade imágenes, CSV, JSON, YAML, bibliografías, fuentes y otros archivos .typ a un documento y úsalos con image, csv, json o #import.
Un PDF del compilador con texto real y seleccionable, cada página como PNG, JPG, WebP o SVG, o la fuente .typ con sus archivos como ZIP.
Cualquier página https (y localhost) puede integrar el editor con un <iframe> y ?embed=1, sin registro y sin clave. Integrado, el editor oculta este texto y muestra un botón Guardar. Hay dos formas de meter y sacar el documento.
src= abre un archivo (tu servidor debe permitir CORS), webhook= hace que «Guardar» (Ctrl+S) envíe el documento a esa dirección. Añade &token=… para una cabecera Authorization: Bearer … y &auto para guardar después de cada cambio.
<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>
El webhook recibe un POST con JSON { editor, event: "save", id, name, content, assets, updated }. Un pequeño script PHP que lo guarda:
<?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}';
El editor dice typsteditor:ready, tu página responde con typsteditor:load, el editor informa con typsteditor:loaded, con typsteditor:change en cada edición real y con typsteditor:save cuando el usuario guarda. Tu página puede enviar typsteditor:get (el estado actual) o typsteditor:save (pulsar Guardar). Así el guardado pasa por tu propio inicio de sesión y tu sesión.
<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') { // el editor está listo: pásale el documento
ed.contentWindow.postMessage({
type: 'typsteditor:load',
name: 'Flyer',
content: await (await fetch('/docs/flyer.typ')).text(),
assets: { 'logo.png': 'data:image/png;base64,…' } // imágenes y archivos de datos opcionales
}, ORIGIN);
}
if (m.type === 'typsteditor:change') document.title = '● not saved'; // una edición real
if (m.type === 'typsteditor:save') { // el usuario hizo clic en «Guardar»
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';
}
});
// Un botón de guardar en tu propia página: la respuesta llega como typsteditor:save
function saveNow() { ed.contentWindow.postMessage({ type: 'typsteditor:get' }, ORIGIN); }
</script>
Asistente de IA dentro de tu página: también funciona en el marco. Con allow="clipboard-write" en el iframe, «Copiar prompt» usa el portapapeles directamente (si no, el editor recurre al antiguo comando de copiar o muestra el prompt para copiarlo a mano). Un enlace que envía la IA no puede llegar a un editor dentro de otro sitio web, así que el editor indica a la IA y al usuario que peguen la respuesta completa de la IA en el editor, o que abran el editor en una ventana propia.
window.open("https://typst.giit.ch/?embed=window", "typsteditor-17") abre el editor completo en su propia ventana y usa los mismos mensajes con window.opener. Ahí sí le llegan los enlaces de una IA. typsteditor:load también puede llevar context: { host, title, rules } (el prompt de IA dice entonces a dónde pertenece el documento y sigue tus reglas) y hook: { url, token, assets: false }, un webhook solo para este documento que nunca se guarda. Al cerrar la ventana con cambios sin guardar se envía typsteditor:closing. typsteditor:pdf pide el PDF del documento de la página y lo recibe como data URI, creado por el compilador de Typst con texto real y seleccionable.
Pasa al editor tu propio prompt, una dirección en tu sitio y una clave para esta sesión del editor. El diálogo de IA muestra entonces «Conectado a» tu sitio, lo que le dices a la IA y la opción cambiar el documento actual o crear uno nuevo; Copiar prompt lo junta todo. La IA envía su resultado con la clave a tu servidor, y tu página lo abre en el editor: un documento nuevo se abre aparte y se queda en el navegador del usuario. Una clave por sesión del editor: sigue siendo válida mientras el editor esté abierto, y solo mientras no tenga ninguna el editor la pide con typsteditor:key-request. El editor nunca envía la clave por sí mismo ni la guarda; la dirección debe ser https en tu propio host o en un subdominio suyo.
const key = async () => (await fetch('/api/ai-key.php?doc=17')).json(); // una clave por sesión del editor
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);
// recuerda el id de typsteditor:loaded e ignora change/save/closing con otro id
// solo mientras el editor no tenga clave:
if (m.type === 'typsteditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'typsteditor:ai', key: k.key }, ORIGIN); }
// mientras el editor esté abierto, avisa a tu servidor cada minuto; cerrar el editor o la página anula la clave
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// tu servidor tiene un resultado (polling, SSE …): target es «current» o «new»
ed.contentWindow.postMessage({ type: 'typsteditor:load', name: 'Flyer', content: draft, from: 'ai', target }, ORIGIN);
<?php // api/ai-key.php - la clave de esta sesión del editor del usuario con sesión iniciada (la llama tu página)
session_start(); // comprueba que el usuario puede editar este documento
$key = bin2hex(random_bytes(24));
$_SESSION['ai'][hash('sha256', $key)] = ['doc' => (int)$_GET['doc'], 'seen' => time()]; // o en tu base de datos; ?alive= vuelve a fijar seen
echo json_encode(['key' => $key]);
<?php // api/ai-result.php - la IA envía aquí (sin cabeceras CORS: las IA lo llaman desde un servidor)
$key = preg_replace('/^Bearer\s+/', '', $_SERVER['HTTP_AUTHORIZATION'] ?? '');
$row = find_key(hash('sha256', $key)); // tu base de datos: no anulada, vista en los últimos 3 minutos
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'); // tu página lo muestra con typsteditor:load
echo '{"ok":true}';
Crea claves con al menos 128 bits aleatorios, guarda solo su hash, vincula cada una al usuario con sesión iniciada, al documento y a esta sesión del editor, crea una por sesión, mantenla válida solo mientras tu página informe de que la sesión está abierta, y anúlala cuando se cierre el editor o la página.
El protocolo completo está en llms.txt: dáselo a una IA y construirá la conexión para tu sistema. El Editor de LaTeX funciona igual con el prefijo latexeditor:: latex.giit.ch.
No. El editor y el compilador de Typst se ejecutan por completo en tu navegador. Tus documentos, imágenes y archivos nunca se envían a un servidor, salvo que tú mismo configures un webhook a tu propio servidor.
Sí. El editor ejecuta Typst 0.14 compilado a WebAssembly (typst.ts), así que las páginas y el PDF son los mismos que con la línea de comandos de Typst. Se carga una vez (unos 11 MB) y luego tu navegador lo conserva.
Haz clic en «Exportar», elige PDF y haz clic en «Descargar». El PDF sale directamente del compilador de Typst, con texto real que se puede seleccionar y buscar.
No directamente: el editor no carga nada de otros servidores, así que #import "@preview/…" muestra un problema que nombra el paquete. Puedes añadir los archivos .typ de un paquete al documento en la pestaña Imágenes e importarlos por su nombre de archivo.
Las fuentes que trae Typst: Libertinus Serif (la predeterminada), New Computer Modern y su fuente matemática, y DejaVu Sans Mono para código. Añade tus propios archivos .otf o .ttf a un documento y úsalos con #set text(font: "Name").
Arrastra o pega una imagen en el editor, o añádela en la pestaña Imágenes de la derecha. Se guarda con el documento en tu navegador y la usa #image("name.png"). Los archivos CSV, JSON, YAML y .bib funcionan igual.
Sí, cualquier IA: ChatGPT, Claude, Gemini, Copilot o la IA de tu herramienta de programación. Haz clic en «Asistente de IA» y luego en «Copiar prompt», pégalo en tu IA y dile qué debe escribir. La IA responde con un enlace; haz clic en él y el documento aparece en tu editor. «Deshacer» revierte cada cambio.
Sí. Intégralo con un iframe e intercambia documentos con postMessage, o deja que envíe cada versión guardada a tu servidor con un webhook. Mira Usa el editor en tu propio sitio web para ver ejemplos.
No. El editor es gratuito, sin anuncios y sin registro.