# Typst Editor (typst.giit.ch) > Free Typst editor in the browser with the real Typst compiler, no sign-up and no upload. Write Typst with syntax highlighting, see the compiled pages as you type, click text on the page to edit it or to jump to the code, and export to PDF (from the compiler, real text), PNG/JPG/WebP/SVG pages or the .typ source with its files. - Language: English - Cost: free - Data: documents stay in the browser (localStorage, pictures and files in IndexedDB) unless the user sets up a webhook to their own server. - Compiler: Typst 0.14 as WebAssembly (typst.ts, Apache-2.0) in a worker in the browser; nothing is loaded from other servers. Fonts: Libertinus Serif (default), New Computer Modern, New Computer Modern Math, DejaVu Sans Mono, plus fonts added to a document. Packages from Typst Universe (`#import "@preview/…"`) are not downloaded; such an import is reported as a problem that names the package. ## Features - Code and pages side by side; the compiler runs a moment after each change. A click on text on the page puts the cursor at its place in the code; the cursor's place is framed on the page. - Editing on the page: text that is in the code exactly as on the page (plain markup text, also with smart quotes, `--`, `...`, escapes) opens a field when clicked; Enter writes the change into the code (special characters escaped), Escape cancels. Text made by code is edited in the code. - Everything Typst 0.14 has: markup, math, tables, figures, references, footnotes, outline, bibliography, `#set` / `#show` rules, scripting. - Problems: the compiler's errors and warnings with line, column and hint; missing files and packages are named. - Document settings that edit the `#set` rules: paper (also square and story formats), margins, orientation, columns, font, size, language, line spacing, justified text, numbered headings, page numbers, title and author (`#set document`). - Pictures and files stored with the document and given to the compiler: pictures (PNG, JPG, GIF, WebP, SVG, PDF) for `image("name")`, data files (CSV, JSON, YAML, TOML, XML, TXT, CBOR) for `csv("name")` and the like, `.bib` for `bibliography("name")`, other `.typ` files for `#import "name.typ"`, fonts (.otf, .ttf) for `#set text(font: …)`. - Templates: article, letter, exercise sheet, social media post. - My documents: any number of documents in the browser - open, rename, duplicate, download (.typ, or ZIP with its files) and delete. - Light, dark or automatic color theme. ## Writing for a user (for AI assistants) Any AI can put a document into the user's open editor with a link; no server, no API key: - `https://typst.giit.ch/#b64=` - `https://typst.giit.ch/#typ=` - `https://typst.giit.ch/#z=` (shorter) - Add `&mode=add` to add text at the end of the current document. - Add `&file=new&name=` to make a new document next to the user's others, or `&file=` to change that one. Without `&file=` the open document changes. - Long documents: split the encoded text and send one link per part with `&part=N&of=M&id=`. Open the link in the user's browser if you can, otherwise give it to the user to click. The user can undo every change. In the editor, "AI Assistant" > "Copy prompt" gives the AI these instructions together with the current document. ## Saving on your own server (webhook) Set under "Save to server" (cloud button), or for one document with `?webhook=`: only for that one document and only while the page is open - a link never stores a webhook. At the top level the user is asked first; inside a page (iframe or opener) it only works together with `?src=` and only for the document opened with it. On "Save" (Ctrl+S), or automatically a few seconds after each change if chosen, the browser sends: POST Content-Type: application/json Authorization: Bearer (only if a token is set) {"editor":"typst","event":"save","id":"","name":"", "content":"","assets":{"":"data:image/...;base64,..."}, "updated":""} One request carries at most 40 MB (with the pictures and files; `hook.assets:false` leaves them out); the server's error text (e.g. for 413) is shown to the user. The server must answer CORS requests from https://typst.giit.ch (Access-Control-Allow-Origin, and Access-Control-Allow-Headers: Content-Type, Authorization). `?src=` opens a .typ file from a URL (CORS needed), `&name=` names it. ## Embedding in a website Messages (postMessage; check `event.origin === "https://typst.giit.ch"` and `event.source === iframe.contentWindow`): - Editor -> page: `{type:"typsteditor:ready", version:2, editor:"typst", window:false}` when it can take a document. - Page -> editor: `{type:"typsteditor:load", name, content, assets:{"logo.png":"data:..."}}` opens the document (a document of that name is replaced, otherwise made). - Editor -> page: `{type:"typsteditor:loaded", name}`, then `{type:"typsteditor:change", id, name, content}` on each edit (not after load), and `{type:"typsteditor:save", id, name, content, assets, editor, event, updated}` when the user clicks Save or presses Ctrl+S. - Page -> editor: `{type:"typsteditor:get"}` asks for a `typsteditor:save` message; `{type:"typsteditor:save"}` saves as if the user had clicked Save. In embedded mode the page text below the editor is hidden and a Save button is shown. The LaTeX Editor (latex.giit.ch) speaks the same protocol with the prefix `latexeditor:`, the SVG Editor (svg.giit.ch) with `svgeditor:`. Optional fields of `typsteditor:load`: - `context: {host, title, rules}` - plain text about the page (rules up to 2000 characters). "Copy prompt" in the AI Assistant then tells the AI that the document belongs to that page and is saved back there, includes the rules, and leaves out how to build a webhook server. - `hook: {url, token, assets}` - a webhook (https) for this document only, used on Save in addition to the message; kept in memory only (never stored, gone on reload). `assets: false` sends the body without `assets`. If the server answers with an error, its `{"error": "…"}` (or `message`, or a short text) is shown to the user. AI Assistant in a frame: add `allow="clipboard-write"` to the iframe so "Copy prompt" can use the clipboard (without it the editor falls back to the old copy command or shows the prompt to copy by hand). Links from an AI cannot reach an editor inside another website (the browser keeps its storage and channels apart), so in a frame the prompt and the dialog ask to paste the AI's whole answer into the editor; use the own window (below) if links should work. `typsteditor:get` is always answered with a `typsteditor:save` message, also when nothing changed. ### All messages at a glance Editor -> page (sent to the page around the editor, or to window.opener in its own window): - `typsteditor:ready` {version:2, editor, window} - can take a document - `typsteditor:loaded` {id, name, target?} - after each load; remember the id (target:"new" for a new document from the AI, which is not yours) - `typsteditor:change` {id, name, content, assetsChanged, assetsRemoved} - a real edit of your document (not after load); adding, replacing or removing a picture or file counts - `typsteditor:save` {editor, event, id, name, content, assets, assetsChanged, assetsRemoved, updated} - Save / Ctrl+S (from anywhere in the editor), or the answer to get. assets holds ALL pictures and files of your document as data URIs; assetsChanged / assetsRemoved name those that differ from what your page has (after load, save or get) - `typsteditor:closing` {id, name, content} - own window closed with unsaved changes - `typsteditor:reload` {id, unsaved} - inside your page, F5 / Ctrl+R / Cmd+R do not reload the editor; ask the user yourself (Ctrl+W cannot be caught by a page) - `typsteditor:pdf` {id, name, pages, pdf} or {id, error} - the answer to your `typsteditor:pdf`: pdf is a data URI of the PDF made by the Typst compiler (real, selectable text; `dpi` is not needed and ignored); a document with errors gets `error` - `typsteditor:key-request` {reason:"missing"} - the editor has no AI key in this session yet `?embed=1&save=0` hides the editor's Save button (Ctrl+S still sends `typsteditor:save`) - for pages with their own Save button. `?lang=de` shows the editor's interface in German (menus, buttons, dialogs, messages), `?lang=en` in English (the default); the choice is remembered in the browser. The AI prompt is always English. Page -> editor (only from the page around the editor or the opener; after its first message only from that origin; pages without a real origin are ignored): - `typsteditor:load` {name, content, assets?, context?, hook?, ai?, from?, target?} - open your document; with assets, they replace the document's pictures and files (send all of them, as data URIs; the compiler gets them as files next to the document, so `image("logo.png")` or `csv("data.csv")` read them; they come back untouched with save); from:"ai" shows a note, target:"new" opens it as a separate document in the user's browser - `typsteditor:get` - answered with `typsteditor:save` of your document (id and content null before the first load) - `typsteditor:save` - press Save - `typsteditor:pdf` - your document as a PDF from the Typst compiler, answered with `typsteditor:pdf` - `typsteditor:ai` {label?, prompt?, endpoint?, key?, base?} or {clear:true} - AI through your server Your document is the one your page loaded (or opened with ?src=). change, save, closing and get are only ever about it - never about other documents in the user's browser, also when the user opens them in the editor. A load replaces only a document that came from your page before (same name and origin), never the user's own; the AI settings and the hook from load apply only while your document is open. ### AI through your own server (prompt and session key) The editor has no backend; your site keeps the keys and the results. Hand the editor your prompt, an endpoint and a key for this editor session - in `typsteditor:load` as `ai: {…}`, or at any time as its own message: {type:"typsteditor:ai", label:"Example Admin", prompt:"", endpoint:"https://your-site.com/api/ai-result", key:"", base:true} Fields left out keep their value; `{type:"typsteditor:ai", clear:true}` ends it. One key per editor session: once the editor has a key it keeps it until the session ends or `clear`, and does not take a different one. `base:false` leaves out the editor's own instructions. The AI dialog shows "Connected to