{"id":50724439,"url":"https://github.com/p2plabsxyz/p2pmd","last_synced_at":"2026-06-10T03:02:22.805Z","repository":{"id":343120671,"uuid":"1153853070","full_name":"p2plabsxyz/p2pmd","owner":"p2plabsxyz","description":"A real-time peer-to-peer Markdown editor for writing notes and collaboration.","archived":false,"fork":false,"pushed_at":"2026-05-25T03:50:17.000Z","size":3592,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-25T05:27:04.585Z","etag":null,"topics":["holesail","hypercore","ipfs","local-first","markdown-editor","p2p","p2p-markdown","p2pmd","peersky-browser"],"latest_commit_sha":null,"homepage":"peersky://p2p/p2pmd/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/p2plabsxyz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-09T18:36:10.000Z","updated_at":"2026-05-25T03:50:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/p2plabsxyz/p2pmd","commit_stats":null,"previous_names":["p2plabsxyz/p2pmd"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/p2plabsxyz/p2pmd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p2plabsxyz%2Fp2pmd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p2plabsxyz%2Fp2pmd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p2plabsxyz%2Fp2pmd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p2plabsxyz%2Fp2pmd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/p2plabsxyz","download_url":"https://codeload.github.com/p2plabsxyz/p2pmd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p2plabsxyz%2Fp2pmd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34134634,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["holesail","hypercore","ipfs","local-first","markdown-editor","p2p","p2p-markdown","p2pmd","peersky-browser"],"created_at":"2026-06-10T03:02:18.585Z","updated_at":"2026-06-10T03:02:22.799Z","avatar_url":"https://github.com/p2plabsxyz.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# P2P Markdown\n\n\u003cdiv align=\"center\"\u003e\n    \u003cimg src=\"./demo.png\" width=\"639\" alt=\"Three synced devices (laptop, external monitor, and iPhone) running the PeerSky p2pmd editor showing shared markdown text ‘Hello from phone/Desktop/Laptop!’ and a dog photo inserted via IPFS.\"\u003e\n\u003c/div\u003e\n\nP2P Markdown is a real-time, peer-to-peer collaborative markdown editor built into [PeerSky Browser](https://github.com/p2plabsxyz/peersky-browser). It connects peers directly using [Holesail](https://holesail.io/) keys, syncs edits live, and lets you publish or export your content without relying on centralized servers.\n\n## What it does\n- Real-time P2P collaboration over Holesail (direct, encrypted connections)\n- Incremental CRDT document sync with Yjs (plus safe fallback sync path)\n- Join or host rooms using `hs://` keys\n- Local publishing to `hyper://` or `ipfs://`\n- Optional HTTPS sharing for IPFS-published content via `dweb.link` URL mapping\n- Presentation slides mode with speaker notes and navigation\n- Drag-and-drop image upload to IPFS (auto-compressed, inserted as markdown)\n- Draft storage using local Hyperdrive\n- Content generation via local LLMs (with slides format support)\n- Offline KaTeX math rendering for inline (`$...$`) and block (`$$...$$`) LaTeX notation\n- Scientific writing templates (Research Paper with IEEE two-column preview/export, Technical Documentation)\n- Export to HTML, PDF, or Slides — fully offline, no CDN dependencies (check [export examples](./examples))\n- SSE keepalive + auto-reconnect for mobile/idle clients\n- Peer visibility dashboard for connected peers, roles, live editing state, and edit history\n- Colored cursor and line traces with hover name chips for collaborative context\n\n## Features\n\n### Slides Mode\nCreate presentations with markdown using `---` to separate slides:\n```markdown\n# Title Slide\nYour opening content\n\u003c!-- Speaker notes: Introduce yourself and topic --\u003e\n---\n# Key Points\n- Point 1\n- Point 2\n\u003c!-- Speaker notes: Elaborate on each point --\u003e\n```\n\n**Navigation:**\n- Arrow keys: `←` / `→` to navigate slides\n- Click left/right half of screen to navigate\n- Progress bar and slide counter at bottom\n- Auto-detection: slides render automatically when `---` delimiters are present\n\n**Features:**\n- Speaker notes as HTML comments (hidden from slides, visible in markdown)\n- Full-screen preview mode\n- Export/publish as interactive HTML slides\n- Footer with p2pmd and PeerSky branding\n\n### Math \u0026 Scientific Writing\n\np2pmd supports offline LaTeX math rendering via [KaTeX](https://katex.org/) — no internet connection required.\n\n**Enabling LaTeX mode:**\n1. Click the **∞ (Infinity)** button in the toolbar to toggle LaTeX mode ON\n2. The button turns **blue** when active (like slides mode)\n3. Inline Math and Block Math buttons appear adjacent to the toggle\n4. Research Paper and Technical Documentation options appear inline in the toolbar beside the ∞ mode toggle\n\n**KaTeX syntax:**\n- Inline math: `$E = mc^2$` renders as $E = mc^2$\n- Block math:\n  ```\n  $$\n  \\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}\n  $$\n  ```\n\n**Templates:**\n\n| Template | Description |\n|----------|-------------|\n| Research Paper | IEEE-style two-column paper with title, abstract, method, results, and references. Exports with A4 page, IEEE margins, two-column layout. |\n| Technical Documentation | Implementation-focused template with API table, quick start, and throughput estimates. |\n\n**IEEE export mode:**\nWhen LaTeX mode is ON, the document contains a top marker `\u003c!-- ieee --\u003e`, and the Research Paper template is active, the live preview and exported HTML/PDF switch to IEEE-inspired formatting:\n- A4 page with IEEE-standard margins (Top: 0.75in, Bottom: 1.0in, Left/Right: 0.625in)\n- Two-column layout with 0.25in gap\n- Structured title, author, and abstract front matter\n- Times New Roman serif font at 10pt\n- \"made by p2pmd\" footer at bottom right\n\n**Offline exports:**\nAll exported HTML, PDF, and Slides inline KaTeX CSS and bundled font assets — no CDN dependencies. Exported files render math correctly even without internet.\n\n### Formatting Toolbar\n\n![Formatting toolbar](./toolbar.png)\n\nQuick formatting buttons with keyboard shortcuts:\n- **Bold** (`Ctrl/Cmd+B`): `**text**`\n- **Italic** (`Ctrl/Cmd+I`): `*text*`\n- **Heading 1**: `# text`\n- **Heading 2**: `## text`\n- **Bullet List**: `- item`\n- **Numbered List**: `1. item`\n- **Link** (`Ctrl/Cmd+K`): `[text](url)`\n- **Image**: `![alt](url)`\n- **Inline Code**: `` `code` ``\n- **Code Block**: ` ```language\\ncode\\n``` `\n- **Quote**: `\u003e text`\n- **LaTeX Mode** (∞): Toggle math/template toolbar — icon turns blue when active\n- **Inline Math**: `$expression$`\n- **Block Math**: `$$expression$$`\n- **Slides Mode**: Toggle presentation view\n\n### Peers Dashboard\n\n\u003cimg src=\"./peers-dashboard.png\" width=\"500\" alt=\"p2pmd peers dashboard showing connected peers and edit history\"\u003e\n\n- Peer count opens `./peers.html` with room context.\n- Connected peers list with role badges (`host` / `client`) and live cursor status.\n- \"Currently Editing\" panel for active typers.\n- \"Edit History\" panel for join/leave/edit activity.\n\n### In-Editor Visibility\n\n\u003cimg src=\"./peers-visibility.png\" width=\"500\" alt=\"p2pmd editor showing host badge, peer count, and colored collaborative line traces\"\u003e\n\n- Host/client role badge next to the room key.\n- Peer count with quick navigation to the peers dashboard.\n- Colored cursor indicators for active collaborators.\n- Persistent colored line traces with hover labels showing editor names.\n- Fallback naming (`Peer #N`) for unnamed peers.\n\n### Themes\n\n\u003cimg src=\"./themes.png\" width=\"639\" alt=\"Different themes available in p2pmd\"\u003e\n\n## Security\nP2PMD implements production-grade security measures:\n- **Encrypted Seeds**: Room keys encrypted at rest using Electron's `safeStorage` (OS-level keychain)\n- **Rate Limiting**: DoS protection (5 room creations/min, 10 rehosts/min)\n- **CORS Policy**: Protocol-level origin validation prevents external API access\n- **Minimal Logging**: Sensitive data (keys, seeds) redacted from production logs\n- **Modern API**: Uses Electron's `protocol.handle()` with native Request/Response objects\n\n## How it works (high level)\n- The editor hosts a local HTTP session and syncs content using incremental Yjs CRDT updates (with a full-state fallback path when needed).\n- On reconnect, CRDT state is merged so edits made during temporary disconnects are preserved.\n- Peer metadata (role, cursor, typing, and line hints) is shared via SSE + presence endpoints to power the peers page.\n- Holesail creates a direct peer connection using a shared key.\n- Publishing writes to Hyper/IPFS, making content shareable via P2P URLs.\n- Drag an image onto the editor to upload it to IPFS. Images are compressed (resized to max 1920px, re-encoded at 0.8 quality) before upload. GIFs are uploaded as-is to preserve animation. The resulting markdown link uses a `dweb.link` gateway URL.\n\n## Access \n### Desktop\nDownload [PeerSky Browser](https://peersky.p2plabs.xyz/) and open `peersky://p2p/p2pmd/` to access p2pmd.\n\n### Mobile\nTo open p2pmd on your phone:\n1. Download the Holesail mobile app ([iOS](https://apps.apple.com/us/app/holesail-go/id6503728841)/[Android](https://play.google.com/store/apps/details?id=io.holesail.holesail.go\u0026hl=en_US\u0026pli=1))\n2. Enter the room key (`hs://...`) in the app to connect as a client\n3. Open the localhost URL (e.g., `http://127.0.0.1:8989`) in your phone's browser\n4. Edit and collaborate in real-time with desktop peers\n\n**Note:** A dedicated p2pmd iOS/Android app with native editing would provide a similar experience without needing the Holesail app as an intermediary.\n\n## Build a similar P2P realtime app\n\n### 1) Start a Holesail server\n```js\nimport Holesail from \"holesail\";\n\nconst server = new Holesail({\n  server: true,\n  secure: true,\n  port: 8989\n});\n\nawait server.ready();\nconsole.log(\"Share this key:\", server.info.url);\n```\n\n### 2) Connect a client\n```js\nimport Holesail from \"holesail\";\n\nconst client = new Holesail({\n  client: true,\n  key: \"hs://s000yourkeyhere\"\n});\n\nawait client.ready();\nconsole.log(\"Connected:\", client.info);\n```\n\nMore: https://docs.holesail.io/\n\n### 3) Sync realtime state\nUse HTTP endpoints (GET/POST) plus SSE/WebSocket for live updates. In PeerSky, a custom [hs-handler](https://github.com/p2plabsxyz/peersky-browser/blob/main/src/protocols/hs-handler.js) can expose these endpoints while keeping the transport peer-to-peer. Incremental Yjs CRDT updates are exchanged over HTTP/SSE, while peer presence metadata is sent through presence endpoints.\n\n### 4) Publish to Hyper\n```js\nasync function publishToHyper(file) {\n  const response = await fetch(`hyper://localhost/?key=myapp`, { \n    method: 'POST' \n  });\n  const hyperdriveUrl = await response.text();\n  \n  const uploadUrl = `${hyperdriveUrl}${encodeURIComponent(file.name)}`;\n  const uploadResponse = await fetch(uploadUrl, {\n    method: 'PUT',\n    body: file,\n    headers: { 'Content-Type': file.type || 'text/html' }\n  });\n  \n  if (uploadResponse.ok) {\n    console.log('Published to:', uploadUrl);\n    return uploadUrl;\n  }\n}\n```\n\n### 5) Publish to IPFS\n```js\nasync function publishToIPFS(files) {\n  const formData = new FormData();\n  for (const file of files) {\n    formData.append('file', file, file.name);\n  }\n  \n  const response = await fetch('ipfs://bafyaabakaieac/', {\n    method: 'PUT',\n    body: formData\n  });\n  \n  if (response.ok) {\n    const ipfsUrl = response.headers.get('Location');\n    console.log('Published to:', ipfsUrl);\n    return ipfsUrl;\n  }\n}\n```\n\nThese examples show the core patterns used in p2pmd. You can adapt them to build your own P2P apps in PeerSky.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp2plabsxyz%2Fp2pmd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp2plabsxyz%2Fp2pmd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp2plabsxyz%2Fp2pmd/lists"}