Skip to content

tom-leamon/downturn

Repository files navigation

Downturn

A markdown web browser. Convert any web page to clean markdown and browse the web in a distraction-free reader. Edit with live preview, open local files and folders, manage bookmarks and history.

Also works as an MCP server for AI agents and a standalone HTTP API.

Web Browser

node worker.mjs

Open http://localhost:4001. Type a URL, search term, or domain and press Enter.

  • Browse the web in markdown — click links to navigate, Ctrl+click to open in a new tab
  • Tabs — drag to reorder, middle-click to close, Ctrl+T/W to create/close
  • Split view — markdown editor + rendered preview, or toggle to single pane
  • Edit — the markdown pane is always editable with live preview
  • Local files — open .md files or entire folders with a file tree sidebar
  • Save — Ctrl+S saves to the opened file, or triggers Save As
  • Bookmarks — star icon bookmarks the current page, viewable in the sidebar
  • History — automatic, searchable, grouped by date in the sidebar
  • Autocomplete — URL bar suggests from history and bookmarks as you type
  • Search — plain text searches Wikipedia; results render as markdown
  • Site navigation — sidebar extracts nav links from the page, with a site home link
  • Themes — Dark, Light, and Black (OLED). Auto-detects system preference
  • Fonts — choose editor and preview fonts from installed system fonts
  • Favicons — shown in tabs, bookmarks, history, and autocomplete
  • PWA — installable as a standalone app with offline support

Deploy

npx wrangler deploy

Or run locally with node worker.mjs. No build step needed.

MCP Server

{
  "mcpServers": {
    "downturn": {
      "command": "npx",
      "args": ["-y", "downturn"]
    }
  }
}

Tools:

  • url_to_markdown — fetch a URL and return markdown
  • html_to_markdown — convert an HTML string to markdown
Parameter Default Description
output_path Full file path to write markdown to
output_dir Directory to write to; filename auto-generated from page title
include_title true Prepend page title as H1
include_links true Include hyperlinks
include_images true Include images
use_readability true Extract article content
absolute_urls true Resolve relative URLs to absolute

HTTP API

PORT=3000 node index.mjs
GET /?url=https://example.com&title=true&links=true&clean=true
POST / with html= and url= parameters

Returns Content-Type: text/markdown with CORS headers.

Pipeline

  1. Fetch page (follows redirects)
  2. Strip scripts and styles
  3. Extract article content (Mozilla Readability)
  4. Convert to markdown (Turndown)
  5. Resolve relative URLs to absolute
  6. Strip link titles and encode parentheses in URLs
  7. Apply site-specific filters (Wikipedia, Medium, Stack Overflow, etc.)

Testing

node --test tests/*.test.mjs

579 tests covering the conversion pipeline, URL resolution, link title stripping, markdown rendering, worker API, MCP integration, nav extraction, title extraction, omnibox, favicons, and debounce.

Structure

worker.mjs                             Cloudflare Worker + local dev server
index.mjs                              HTTP API server
mcp.mjs                                MCP stdio transport
wrangler.toml                          Cloudflare deployment config
url_to_markdown_processor.mjs          Core conversion pipeline
url_to_markdown_common_filters.mjs     Post-processing filters
url_to_markdown_formatters.mjs         Code block and table pre-processing
url_to_markdown_readers.mjs            URL fetching, redirect following
url_to_markdown_apple_dev_docs.mjs     Apple developer docs parser
html_table_to_markdown.mjs             HTML table conversion
title_utils.mjs                        Title extraction and filename slugification

public/
  index.html                           Web UI
  ui.mjs                               Markdown renderer, omnibox, utilities
  db.mjs                               IndexedDB storage (settings, history, bookmarks, cache)
  themes.mjs                           Theme system (dark, light, black)
  sw.js                                Service worker for PWA/offline
  start.md                             Start page content
  site.webmanifest                     PWA manifest

lib/
  html_parser.mjs                      DOM parser (vendored JSDOMParser)
  readability.mjs                      Content extraction (vendored Readability)
  turndown.mjs                         HTML to markdown (vendored Turndown)
  html_entities.mjs                    HTML entity decoder
  http_server.mjs                      HTTP server on node:http
  rate_limiter.mjs                     Sliding window rate limiter

Credits

License

MIT