Markdown Editor online

Code

Export

The print dialog opens with the document only. Choose Save as PDF (or "Microsoft Print to PDF") as the printer. In Chrome and Edge, untick "Headers and footers" if the browser offers it. The text in the PDF stays sharp and can be selected.

My documents

Click a document to open it. They are stored only in this browser - nothing is uploaded. Clearing the browser's site data removes them, so download the ones you want to keep.

AI Assistant

Any AI can write with you - ChatGPT, Claude, Gemini, Copilot.

  1. Click Copy prompt.
  2. Paste it into your AI and say what it should write.
The AI should

The document travels in the link after the “#”, which no server sees. What you paste into your AI is handled by its provider.

Save to your server

The editor can send each saved version to your own server (a webhook), so your work is kept where you want it. Nothing is sent until you enter an address here.

What your server receives

A POST request with JSON (your server must allow CORS from https://md.giit.ch):

{ "editor": "md", "event": "save", "id": "…", "name": "Notes",
  "content": "# Notes\n\n…",
  "assets": { "logo.png": "data:image/png;base64,…" },
  "updated": "YYYY-MM-DDTHH:MM:SS.000Z" }
Embed the editor in your website
<iframe src="https://md.giit.ch/?embed=1" style="width:100%;height:80vh;border:0"></iframe>
<script>
const frame = document.querySelector('iframe');
addEventListener('message', e => {
  if (e.origin !== 'https://md.giit.ch' || e.source !== frame.contentWindow) return;
  if (e.data.type === 'mdeditor:ready')
    frame.contentWindow.postMessage({ type: 'mdeditor:load', name: 'Notes',
      content: '# Notes\n\n…', assets: {} }, 'https://md.giit.ch');
  if (e.data.type === 'mdeditor:save') saveOnYourServer(e.data.content, e.data.assets);
});
</script>

Also possible: ?src=<URL of a .md file> opens a file, &webhook=<URL> saves this document there. The editor can also open in a window of its own (?embed=window), and your page can hand it its own AI prompt and a session key so the AI sends its result to your server (mdeditor:ai, mdeditor:key-request) - see "Use the editor on your own website" below the editor. Details are in llms.txt.

Help

How it works

  1. Write Markdown on the left - or start with New and one of the templates. The preview in the middle shows the document as you type.
  2. Click text in the preview to edit it right there: the cursor is where you clicked, and the code's cursor goes to the same place. Enter or a click elsewhere writes the change into the code (one step for Undo), Escape cancels; characters such as * or _ are escaped so they stay text. A click on math, a picture or code jumps to its place in the code instead. Ctrl + click follows a link. A check box of a task list ticks the task in the code.
  3. Insert on the right has ready-made pieces (headings, lists, tables, math, symbols); Pictures holds the pictures of the document; Outline lists the headings.
  4. Problems (a missing picture, a link to a heading that is not there, a code block that is never closed, a table row with too many cells) are listed above the code - click one to go there.
  5. My documents (the folder button at the top left) lists every document kept in this browser.
  6. Export makes an HTML page, a PDF (via the print dialog) or plain text. Download .md saves the code (with its pictures as ZIP).

The preview understands CommonMark with GitHub's tables, task lists, strikethrough, autolinks and footnotes, and math in $…$ and $$…$$. HTML in the Markdown is shown without scripts, styles, frames and forms.

Keyboard shortcuts

Ctrl + B / I
Bold / italic around the selected text
Ctrl + K
Link
Ctrl + M
Math: $…$ around the selection
Ctrl + /
Lines in or out of a comment (<!-- -->)
Ctrl + Enter
Show the cursor's place in the preview
Tab / Shift + Tab
Indent / outdent
Ctrl + Z / Y
Undo / redo
Ctrl + S / E
Save (download .md, or to your server) / export
Ctrl + O
My documents
Ctrl + P
Print / save as PDF

Enter in a list starts the next item (-, 1., - [ ], >); on an empty item it ends the list. * _ ` ~ $ [ ( close by themselves around a selection.

Pisz Markdown online z podglądem na żywo

Edytor Markdown pokazuje kod i gotowy dokument obok siebie. Wszystko, co wpiszesz, od razu pojawia się w podglądzie - nagłówki, listy, tabele, listy zadań, przypisy i wzory - a kliknięcie dowolnego tekstu w podglądzie przenosi do jego miejsca w kodzie. Tekst można też edytować bezpośrednio w podglądzie. Dzięki temu szybko napiszesz pliki README, notatki, dokumentację i artykuły.

Wszystko działa w przeglądarce. Dokumenty nie są nigdzie wysyłane, nie ma rejestracji ani reklam.

Co potrafi edytor

Kod z podświetlaniem

Nagłówki, listy, linki, kod, wzory i HTML we własnych kolorach, numery wierszy, listy kontynuowane po naciśnięciu Enter i przejrzysta lista problemów z numerem wiersza.

Markdown GitHub

CommonMark z tabelami, listami zadań, przekreśleniem, autolinkami i przypisami. Nagłówki dostają te same kotwice co na GitHubie, a linki do nich są sprawdzane.

Wzory

Wzory w tekście w $…$ i wyeksponowane w $$…$$, składane przez KaTeX bezpośrednio w podglądzie.

Edycja w podglądzie

Kliknij zdanie, nagłówek, punkt listy lub komórkę tabeli w podglądzie i zmień je tam - Markdown nadąża, a znaki specjalne są poprzedzane ukośnikiem.

Obrazy

Przeciągnij obraz do edytora i użyj go przez ![description](name.png). Obrazy są przechowywane razem z dokumentem w przeglądarce.

Eksport

Jeden plik HTML z obrazami w środku, PDF przez okno drukowania, zwykły tekst albo Markdown z obrazami jako ZIP.

Jak to działa

  1. Start - wybierz szablon w menu „Nowy”, otwórz plik .md lub wklej Markdown.
  2. Pisanie - wpisuj kod; podgląd nadąża za nim. Tabele, listy i wzory znajdziesz w „Wstaw”.
  3. Eksport - zapisz stronę HTML, PDF lub plik .md.

Edytor na własnej stronie

Każda strona https (i localhost) może osadzić edytor za pomocą <iframe> i ?embed=1 - bez rejestracji, bez klucza. Po osadzeniu edytor ukrywa ten tekst i pokazuje przycisk Zapisz. Dokument można przekazywać do edytora i z niego na dwa sposoby.

1. Otwieranie pliku z linku, zapis na twoim serwerze

src= otwiera plik (twój serwer musi zezwalać na CORS), webhook= sprawia, że „Zapisz” (Ctrl+S) wysyła dokument pod ten adres. Dodaj &token=…, aby wysyłać nagłówek Authorization: Bearer …, i &auto, aby zapisywać po każdej zmianie.

<iframe src="https://md.giit.ch/?embed=1&src=https://your-site.com/docs/notes.md&webhook=https://your-site.com/save.php"
        allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>

Webhook otrzymuje żądanie POST z JSON { editor, event: "save", id, name, content, assets, updated }. Mały skrypt PHP, który go zapisuje:

<?php
header('Access-Control-Allow-Origin: https://md.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.md", $d['content']);
echo '{"ok":true}';

2. Dokument przechowuje twoja strona (postMessage)

Edytor zgłasza mdeditor:ready, twoja strona odpowiada mdeditor:load, edytor zgłasza mdeditor:loaded, mdeditor:change przy rzeczywistych zmianach i mdeditor:save, gdy użytkownik zapisuje. Twoja strona może wysłać mdeditor:get (bieżący stan) lub mdeditor:save (naciśnięcie Zapisz). Zapis odbywa się wtedy przez twoje własne logowanie i sesję.

<iframe id="ed" src="https://md.giit.ch/?embed=1" allow="clipboard-write" style="width:100%;height:800px;border:0"></iframe>
<script>
const ed = document.getElementById('ed');
const ORIGIN = 'https://md.giit.ch';

addEventListener('message', async e => {
  if (e.source !== ed.contentWindow || e.origin !== ORIGIN) return;
  const m = e.data;
  if (m.type === 'mdeditor:ready') {                // edytor jest gotowy: przekaż mu dokument
    ed.contentWindow.postMessage({
      type: 'mdeditor:load',
      name: 'Notes',
      content: await (await fetch('/docs/notes.md')).text(),
      assets: { 'logo.png': 'data:image/png;base64,…' }   // opcjonalne obrazy
    }, ORIGIN);
  }
  if (m.type === 'mdeditor:change') document.title = '● not saved';   // rzeczywista zmiana
  if (m.type === 'mdeditor:save') {                 // użytkownik kliknął „Zapisz”
    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';
  }
});

// Przycisk zapisu na twojej stronie: odpowiedź przychodzi jako mdeditor:save
function saveNow() { ed.contentWindow.postMessage({ type: 'mdeditor:get' }, ORIGIN); }
</script>

Asystent AI na twojej stronie: działa także w ramce. Z allow="clipboard-write" w iframe „Kopiuj prompt” korzysta bezpośrednio ze schowka (w przeciwnym razie edytor używa starego polecenia kopiowania albo pokazuje prompt do ręcznego skopiowania). Link wysłany przez AI nie dotrze do edytora osadzonego w innej stronie, więc edytor prosi AI i użytkownika o wklejenie całej odpowiedzi AI do edytora - albo o otwarcie edytora we własnym oknie.

3. We własnym oknie

window.open("https://md.giit.ch/?embed=window", "mdeditor-17") otwiera pełny edytor we własnym oknie, który wymienia te same wiadomości z window.opener. Linki od AI docierają do niego tam. mdeditor:load może też zawierać context: { host, title, rules } - prompt dla AI mówi wtedy, gdzie należy dokument, i stosuje twoje zasady - oraz hook: { url, token, assets: false }, webhook tylko dla tego dokumentu, który nigdy nie jest zapisywany. Zamknięcie okna z niezapisanymi zmianami wysyła mdeditor:closing.

4. AI przez twój własny serwer

Przekaż edytorowi własny prompt, adres w twojej witrynie i klucz dla tej sesji edytora. Okno AI pokazuje wtedy „Połączono z” twoją witryną, to, co przekazujesz AI, oraz wybór: zmienić bieżący dokument lub utworzyć nowy; Kopiuj prompt łączy to wszystko. AI wysyła swój wynik z kluczem na twój serwer, a twoja strona otwiera go w edytorze - nowy dokument otwiera się osobno i zostaje w przeglądarce użytkownika. Jeden klucz na sesję edytora: pozostaje ważny, dopóki edytor jest otwarty, a edytor prosi o niego przez mdeditor:key-request tylko wtedy, gdy go nie ma. Edytor nigdy sam nie wysyła klucza i nigdy go nie zapisuje; adres musi być adresem https na twoim własnym hoście lub jego subdomenie.

const key = async () => (await fetch('/api/ai-key.php?doc=17')).json();   // jeden klucz na sesję edytora
const k = await key();
ed.contentWindow.postMessage({ type: 'mdeditor:load', name: 'Notes', 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);
// zapamiętaj id z mdeditor:loaded i ignoruj change/save/closing z innym id
// tylko gdy edytor nie ma klucza:
if (m.type === 'mdeditor:key-request') { const k = await key(); ed.contentWindow.postMessage({ type: 'mdeditor:ai', key: k.key }, ORIGIN); }
// dopóki edytor jest otwarty, informuj serwer co minutę; zamknięcie edytora lub strony unieważnia klucz
setInterval(() => fetch('/api/ai-key.php?alive=' + k.key.slice(0, 8)), 60000);
// twój serwer ma wynik (polling, SSE …): target to "current" lub "new"
ed.contentWindow.postMessage({ type: 'mdeditor:load', name: 'Notes', content: draft, from: 'ai', target }, ORIGIN);
<?php // api/ai-key.php - klucz tej sesji edytora zalogowanego użytkownika (wywołuje go twoja strona)
session_start();                                     // sprawdź, czy użytkownik może edytować ten dokument
$key = bin2hex(random_bytes(24));
$_SESSION['ai'][hash('sha256', $key)] = ['doc' => (int)$_GET['doc'], 'seen' => time()];  // lub w twojej bazie danych; ?alive= ponownie ustawia seen
echo json_encode(['key' => $key]);

<?php // api/ai-result.php - tu AI wysyła wynik (bez nagłówków CORS: AI wywołują go z serwera)
$key = preg_replace('/^Bearer\s+/', '', $_SERVER['HTTP_AUTHORIZATION'] ?? '');
$row = find_key(hash('sha256', $key));               // twoja baza danych: nieunieważniony, widziany w ciągu ostatnich 3 minut
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');   // twoja strona pokazuje go przez mdeditor:load
echo '{"ok":true}';

Twórz klucze z co najmniej 128 losowymi bitami, przechowuj tylko ich hash, wiąż każdy z zalogowanym użytkownikiem, dokumentem i tą sesją edytora, twórz jeden na sesję, utrzymuj go ważnym tylko wtedy, gdy twoja strona zgłasza sesję jako otwartą, i unieważniaj go, gdy edytor lub strona zostaną zamknięte.

Cały protokół jest opisany w llms.txt - przekaż go AI, a zbuduje połączenie dla twojego systemu. Edytor LaTeX i Edytor SVG działają tak samo z prefiksami latexeditor: i svgeditor: - latex.giit.ch, svg.giit.ch.

Najczęstsze pytania

Czy mój dokument jest gdzieś wysyłany?

Nie. Edytor działa w całości w przeglądarce. Dokumenty i obrazy nigdy nie są wysyłane na serwer, chyba że sam skonfigurujesz webhook do własnego serwera.

Jaki Markdown rozumie edytor?

CommonMark z rozszerzeniami GitHub: tabele, listy zadań, przekreślenie, autolinki i przypisy, a do tego wzory w $…$ i $$…$$. Nagłówki dostają te same kotwice co na GitHubie, więc linki takie jak [see below](#my-heading) działają.

Jak uzyskać PDF lub stronę HTML?

Kliknij „Eksportuj”. Wybierz PDF i kliknij „Drukuj / zapisz jako PDF” - w oknie drukowania wybierz „Zapisz jako PDF”. Albo wybierz stronę HTML, aby dostać jeden plik z obrazami i stylami w środku.

Jak dodać obrazy?

Przeciągnij lub wklej obraz do edytora albo dodaj go w karcie Obrazy po prawej. Jest przechowywany razem z dokumentem w przeglądarce i używany przez ![description](name.png).

Gdzie zapisywane są moje dokumenty?

Tylko w przeglądarce. Kliknij przycisk folderu w lewym górnym rogu (Moje dokumenty), aby je otwierać, zmieniać ich nazwy, duplikować, pobierać lub usuwać. Wyczyszczenie danych witryny w przeglądarce je usuwa, więc pobierz te, które chcesz zachować - albo pozwól edytorowi wysyłać je na własny serwer („Zapis na serwerze”).

Czy AI może pisać w Edytorze Markdown?

Tak, każda AI - ChatGPT, Claude, Gemini, Copilot lub AI w twoim narzędziu programistycznym. Kliknij „Asystent AI”, potem „Kopiuj prompt”, wklej go do swojej AI i napisz, co ma napisać. AI odpowiada linkiem; kliknij go, a dokument pojawi się w edytorze. „Cofnij” cofa każdą zmianę.

Czy mogę używać edytora na własnej stronie?

Tak. Osadź go w iframe i wymieniaj dokumenty przez postMessage albo pozwól mu wysyłać każdą zapisaną wersję na twój serwer przez webhook. Przykłady znajdziesz w sekcji Edytor na własnej stronie.

Czy Edytor Markdown coś kosztuje?

Nie. Edytor jest darmowy, bez reklam i bez rejestracji.