--- # Install Oxidoc - Linux, macOS, and Windows (docs/installation) --- title: Install Oxidoc - Linux, macOS, and Windows description: Install Oxidoc with a single command on Linux, macOS, or Windows. Learn how to update, pin versions, and configure your install directory. --- # Installation ## Install Script The recommended way to install Oxidoc is the install script, which detects your platform and downloads the correct binary. ```bash curl -fsSL https://oxidoc.dev/install.sh | sh ``` ```powershell irm https://oxidoc.dev/install.ps1 | iex ``` The script detects your platform, downloads the correct binary, and adds it to your `PATH`. ### Custom Install Directory Set `OXIDOC_INSTALL_DIR` to change the install location: ```bash OXIDOC_INSTALL_DIR=/usr/local/bin \ curl -fsSL https://oxidoc.dev/install.sh | sh ``` ## GitHub Releases Download a pre-built binary directly from [GitHub Releases](https://github.com/oxidoc-lab/oxidoc/releases). | Platform | Architecture | Binary | |:---------|:-------------|:-------| | Linux | x86_64 | `oxidoc-x86_64-unknown-linux-gnu` | | Linux | aarch64 | `oxidoc-aarch64-unknown-linux-gnu` | | macOS | x86_64 | `oxidoc-x86_64-apple-darwin` | | macOS | Apple Silicon | `oxidoc-aarch64-apple-darwin` | | Windows | x86_64 | `oxidoc-x86_64-pc-windows-msvc.exe` | ## Verify Installation ```bash oxidoc --version ``` ## Update Update to the latest stable release: ```bash oxidoc update ``` Install the latest prerelease: ```bash oxidoc update --pre ``` ## Switch Versions Pin a specific version: ```bash oxidoc set-version v0.1.0 ``` This downloads and installs that exact version, useful for locking CI to a known-good release. ## Uninstall Remove the binary and its directory: ```bash rm -rf ~/.oxidoc ``` Remove the `PATH` entry from your shell config (`~/.bashrc`, `~/.zshrc`, etc.) if it was added. --- # Quickstart - Build Your First Docs Site in 5 Minutes (docs/quickstart) --- title: Quickstart - Build Your First Docs Site in 5 Minutes description: Go from zero to a running documentation site in under five minutes. Install Oxidoc, create a project, start the dev server, and build for production. --- # Quickstart Go from zero to a running documentation site in under five minutes. ## 1. Install Oxidoc ```bash curl -fsSL https://oxidoc.dev/install.sh | sh ``` See [Installation](/docs/installation) for other options. ## 2. Create a Project ```bash oxidoc init my-docs cd my-docs ``` This creates a directory with a starter `oxidoc.toml`, a `home.rdx` landing page, and a `docs/` directory with sample content. ## 3. Start the Dev Server ```bash oxidoc dev ``` Open [http://localhost:3000](http://localhost:3000) in your browser. You'll see the starter site with a landing page and sample documentation. The dev server watches for changes and rebuilds automatically: - `.rdx` files in all content directories - `oxidoc.toml` configuration - `assets/` directory (custom CSS, images, JS) - Root-level `.rdx` files (`home.rdx`, etc.) ## 4. Edit Content Open `docs/quickstart.rdx` in your editor and make a change. Save the file — the browser refreshes automatically. RDX files are Markdown with embedded components. For example: --- title: Introduction --- # Introduction Welcome to my docs. Here's a tip: Edit any `.rdx` file and the browser refreshes automatically. See [Writing Content](/docs/writing-content) for the full guide on RDX syntax. ## 5. Add a New Page Create a new file `docs/guide.rdx`: --- title: Guide --- # Guide Your content here. Then add it to the navigation in `oxidoc.toml`: navigation = [ { path = "/docs", dir = "docs", groups = [ { group = "Getting Started", pages = ["quickstart", "guide"] }, ] }, ] Save the file and the dev server rebuilds automatically — the new page appears in the sidebar. ## 6. Build for Production ```bash oxidoc build ``` The output is a fully static site in `dist/`. Deploy it to any static host — see [Deployment](/docs/deployment) for guides on GitHub Pages, Vercel, and Netlify. ## Next Steps Learn RDX syntax, frontmatter, and file organization. Explore all built-in components with examples. Full reference for oxidoc.toml. --- # Writing Content - RDX Syntax and File Organization (docs/writing-content) --- title: Writing Content - RDX Syntax and File Organization description: Learn RDX, Oxidoc's content format. Write Markdown with embedded components, configure frontmatter, organize files, and create Mermaid diagrams. --- # Writing Content Oxidoc uses **RDX** — Markdown with embedded components. Files use the `.rdx` extension. ## File Organization Content lives in directories mapped to site sections via `oxidoc.toml`: ```text my-docs/ ├── oxidoc.toml ├── home.rdx └── docs/ ├── intro.rdx ├── guide.rdx └── advanced/ └── plugins.rdx ``` Nested folders create nested URL paths. `docs/advanced/plugins.rdx` is served at `/docs/advanced/plugins`. ### Ordering with Numbered Prefixes Prefix files with numbers to control sidebar order without changing slugs: ```text docs/ ├── 01-intro.rdx → /docs/intro ├── 02-quickstart.rdx → /docs/quickstart └── 03-advanced.rdx → /docs/advanced ``` The numeric prefix is stripped from the URL slug. ## Frontmatter Every `.rdx` file starts with YAML frontmatter between `---` fences: ```yaml --- title: Page Title — Long Descriptive Title for SEO short_title: Page Title description: Optional meta description for SEO layout: landing --- ``` | Field | Required | Description | |:------|:---------|:------------| | `title` | Yes | Full page title — shown in the browser tab and top bar | | `short_title` | No | Short title shown in the sidebar navigation. Falls back to the filename if omitted | | `description` | No | Meta description for SEO and search snippets | | `layout` | No | Set to `landing` for full-width landing pages (no sidebar/TOC) | ## Markdown Features RDX supports standard Markdown: - **Headings** — `#` through `######`, auto-linked with anchors - **Bold** / *Italic* / ~~Strikethrough~~ - Ordered and unordered lists - [Links](https://example.com) and images `![alt](url)` - Block quotes with `>` - Horizontal rules with `---` ### Code Blocks Fenced code blocks with syntax highlighting: ````markdown ```rust fn main() { println!("Hello!"); } ``` ```` ### Tables Standard Markdown tables with alignment: ```markdown | Left | Center | Right | |:-----|:------:|------:| | a | b | c | ``` ### Mermaid Diagrams Use `mermaid` as the language for a fenced code block: ````markdown ```mermaid graph LR A[Write] --> B[Build] --> C[Deploy] ``` ```` The diagram is rendered automatically — no configuration needed. ## Embedding Components Use HTML-like tags to embed interactive components in your Markdown: ````markdown Here is a callout: This renders as an interactive callout component. And tabs: Content one Content two ```` Components can contain Markdown. See [Components](/docs/components) for the full list. ## File-System Routing vs Explicit Navigation By default, pages appear in the sidebar only if listed in `oxidoc.toml` navigation groups: groups = [ { group = "Getting Started", pages = ["intro", "quickstart"] }, ] Pages not listed in navigation are still built and accessible by URL — they just don't appear in the sidebar. This is useful for pages linked inline but not important enough for the sidebar. ## Root Pages Pages outside of any section (like a landing page) are configured under `[routing.root]`: [routing.root] homepage = "home.rdx" pages = ["about.rdx", "contact.rdx"] The `homepage` is rendered at `/`. Additional `pages` are rendered at `/{name}`. --- # Configuration Reference — oxidoc.toml (docs/configuration) --- title: Configuration Reference — oxidoc.toml description: Complete reference for oxidoc.toml. Configure your project, theme, navigation, search, versioning, i18n, analytics, and more with every field documented. --- # Configuration All configuration lives in `oxidoc.toml` at the project root. ## `[project]` Core project metadata. [project] name = "My Docs" description = "Documentation for my project" logo = "/assets/logo.svg" favicon = "/assets/favicon.svg" base_url = "https://example.com" edit_url = "https://github.com/org/repo/blob/main" edit_label = "Edit this page" debug_islands = false | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `name` | String | **required** | Project name shown in header and metadata | | `description` | String | — | Site description for SEO and feeds | | `logo` | String | — | Path to logo image (relative to assets) | | `favicon` | String | — | Path to favicon (`.ico`, `.svg`, or `.png`) | | `base_url` | String | — | Full base URL for sitemap, feeds, and canonical links | | `edit_url` | String | — | Base URL for "edit this page" links (e.g. GitHub blob URL) | | `edit_label` | String | `"View page source"` | Label for the edit/source link on each page | | `debug_islands` | bool | `false` | Show debug outlines on Wasm island components | ## `[theme]` Visual customization. [theme] primary = "#3b82f6" accent = "#f59e0b" font = "Inter, sans-serif" code_font = "JetBrains Mono, monospace" dark_mode = "system" custom_css = ["assets/custom.css"] | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `primary` | String | `"#2563eb"` | Primary color (links, buttons, active states) | | `accent` | String | `"#f59e0b"` | Accent color for decorative elements | | `font` | String | System font stack | Body text font family | | `code_font` | String | Monospace stack | Code font family | | `dark_mode` | String | `"system"` | Dark mode: `"system"`, `"light"`, or `"dark"` | | `custom_css` | String[] | `[]` | Custom CSS files to load (paths relative to project root) | See [Theming](/docs/theming) for the full CSS variable reference. ## `[routing]` Controls site structure, navigation, and sections. ### `[routing.root]` [routing.root] homepage = "home.rdx" pages = ["about.rdx", "contact.rdx"] | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `homepage` | String | — | RDX file rendered at `/` | | `pages` | String[] | `[]` | Additional root-level pages rendered at `/{name}` | ### `header_links` [routing] header_links = [ { label = "Docs", href = "/docs" }, { label = "GitHub", href = "https://github.com/org/repo" }, ] | Field | Type | Description | |:------|:-----|:------------| | `label` | String | Link text displayed in the header | | `href` | String | URL (internal path or external URL) | ### `navigation` Array of site sections. Each section has its own sidebar and content directory. [routing] navigation = [ { path = "/docs", dir = "docs", groups = [ { group = "Getting Started", pages = ["intro", "quickstart"] }, { group = "Guides", pages = ["guides/styling"] }, ] }, { path = "/api", openapi = "./openapi.yaml" }, ] | Field | Type | Description | |:------|:-----|:------------| | `path` | String | Base URL path (e.g., `"/docs"`, `"/api"`) | | `dir` | String | Content directory for `.rdx` files (relative to project root) | | `groups` | Array | Sidebar groups, each with `group` (title) and `pages` (slug list) | | `openapi` | String | Path to OpenAPI spec — auto-generates API reference pages | Sections are fully independent — each has its own sidebar. You can mix `.rdx` content sections with OpenAPI sections: [routing] navigation = [ { path = "/docs", dir = "docs", groups = [ { group = "Guides", pages = ["intro", "quickstart"] }, { group = "Advanced", pages = ["plugins", "theming"] }, ] }, { path = "/api", openapi = "./openapi.yaml" }, { path = "/internal", dir = "internal-docs", groups = [ { group = "Team", pages = ["onboarding", "runbooks"] }, ] }, ] Each section's `dir` is resolved relative to the project root. You can have as many content directories as you need — they don't have to be called `docs`. Pages can use subdirectories — `"guides/styling"` maps to `docs/guides/styling.rdx`. ## `[search]` [search] provider = "oxidoc" semantic = true model_path = "./models/embedding.gguf" | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `provider` | String | `"oxidoc"` | Search provider: `"oxidoc"`, `"algolia"`, `"typesense"`, `"meilisearch"`, `"custom"` | | `semantic` | bool | `false` | Enable semantic (hybrid) search alongside BM25 | | `model_path` | String | — | Path to custom GGUF embedding model | Provider-specific fields — see [Search](/docs/search) for details: | Provider | Fields | |:---------|:-------| | Algolia | `app_id`, `api_key`, `index_name` | | Typesense | `host`, `port`, `protocol`, `api_key`, `collection_name` | | Meilisearch | `host`, `api_key`, `index_name` | | Custom | `stylesheet`, `script`, `init_script` | ## `[versioning]` [versioning] default = "v2.0" versions = ["v1.0", "v2.0"] | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `default` | String | — | Default version served at the root URL | | `versions` | String[] | `[]` | All available versions | See [Versioning](/docs/versioning) for the full guide. ## `[i18n]` [i18n] default_locale = "en" locales = ["en", "ja", "es"] translation_dir = "i18n" | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `default_locale` | String | `"en"` | Default locale (served at root, no prefix) | | `locales` | String[] | `[]` | All configured locales | | `translation_dir` | String | `"i18n"` | Directory for Fluent `.ftl` translation files | See [i18n](/docs/i18n) for the full guide. ## `[footer]` [footer] copyright_owner = "My Company" copyright_owner_url = "https://example.com" links = [ { label = "Privacy", href = "/privacy" }, { label = "Terms", href = "/terms" }, ] | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `copyright_owner` | String | — | Name shown in copyright notice | | `copyright_owner_url` | String | — | URL for the copyright owner name | | `links` | Array | `[]` | Footer links, each with `label` and `href` | ## `[social]` [social] github = "https://github.com/org/repo" discord = "https://discord.gg/invite" Social links displayed in the header/footer. ## `[analytics]` [analytics] google_analytics = "G-XXXXXXXXXX" # Or inject a custom script: # script = '' | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `google_analytics` | String | — | Google Analytics measurement ID | | `script` | String | — | Custom analytics script tag (injected in ``) | See [Analytics](/docs/analytics) for details. ## `[redirects]` [redirects] redirects = [ { from = "/old-page", to = "/new-page" }, { from = "/guide", to = "/docs/quickstart" }, ] Each entry generates an HTML file at `from` that redirects to `to`. ## `[components.custom]` Register Vanilla JS Web Components: [components.custom] PromoBanner = "assets/js/promo-banner.js" FeedbackWidget = "assets/js/feedback-widget.js" Maps component tag names to JavaScript file paths. See [Custom Components](/docs/guides/custom-components). ## `[attribution]` [attribution] oxidoc = true | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `oxidoc` | bool | `true` | Show "Built with Oxidoc" in the footer | --- # CLI Reference — All Commands and Flags (docs/cli) --- title: CLI Reference — All Commands and Flags description: Complete CLI reference for Oxidoc. Learn every command — init, dev, build, clean, archive, update — with flags, options, and usage examples. --- # CLI Reference ## Global Flags These flags work with any command: | Flag | Description | |:-----|:------------| | `-C, --project ` | Project root directory (defaults to current directory) | | `-v, --verbose` | Enable verbose output with detailed build steps | | `-q, --quiet` | Suppress all output except errors (useful for CI) | ## Commands ### `oxidoc init` Initialize a new Oxidoc project. ```bash oxidoc init my-docs ``` Creates a directory with a starter `oxidoc.toml`, `home.rdx` landing page, and sample docs. | Flag | Description | |:-----|:------------| | `` | Project directory name (optional, defaults to current directory) | | `-f, --force` | Force overwrite existing files | | `-y, --yes` | Skip confirmation prompts | ### `oxidoc dev` Start the development server with hot reload. ```bash oxidoc dev oxidoc dev -p 8080 ``` | Flag | Description | |:-----|:------------| | `-p, --port ` | Port to serve on (default: `3000`) | Edit any `.rdx` file and the browser refreshes automatically. ### `oxidoc build` Build the site for production (static site generation). ```bash oxidoc build oxidoc build -o public ``` | Flag | Description | |:-----|:------------| | `-o, --output ` | Output directory (default: `dist`) | Generates a fully static site with all HTML, CSS, JS, Wasm, and search index files. ### `oxidoc clean` Remove build artifacts (`.oxidoc-dev/` and `dist/` directories). ```bash oxidoc clean ``` ### `oxidoc archive` Manage versioned documentation archives. ```bash # Create an archive from current docs oxidoc archive create v1.0 # List all archives oxidoc archive list # Delete an archive oxidoc archive delete v1.0 ``` | Subcommand | Description | |:-----------|:------------| | `create ` | Snapshot the current docs as a version archive | | `list` | List all available archived versions | | `delete ` | Delete a specific version archive | See [Versioning](/docs/versioning) for the full workflow. ### `oxidoc update` Update to the latest version. ```bash oxidoc update oxidoc update --pre ``` | Flag | Description | |:-----|:------------| | `--pre` | Install the latest prerelease instead of stable | ### `oxidoc set-version` Switch to a specific version. ```bash oxidoc set-version v0.1.0 ``` Downloads and installs the exact version specified. ## Examples Run dev server from a different directory: ```bash oxidoc -C ../my-docs dev ``` Production build with verbose output to a custom directory: ```bash oxidoc -v build -o public ``` Quiet build for CI: ```bash oxidoc -q build ``` --- # Built-in Components — Callouts, Tabs, Cards, and More (docs/components) --- title: Built-in Components — Callouts, Tabs, Cards, and More description: Explore every built-in Oxidoc component with live examples. Callouts, tabs, code blocks, accordions, cards, badges, tooltips, banners, and Mermaid diagrams. --- # Components Oxidoc ships a set of built-in components you can use directly in `.rdx` files. Components use HTML-like syntax and can contain Markdown content. ## Callout Highlighted blocks for notes, warnings, tips, and errors. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `kind` | String | `"info"` | Style: `info`, `warning`, `error`/`danger`, `tip`/`success` | | `title` | String | — | Header text | | `collapsible` | bool | `false` | Make the callout collapsible | This is an informational callout. This is a helpful tip. Something to be careful about. This highlights an error or danger. ## Tabs Switchable content panels. Selection persists via localStorage when a `group` is set. | Prop | Type | Description | |:-----|:-----|:------------| | `group` | String | localStorage key for persisting selection across pages | Each `Tab` takes a `title` prop. ```bash npm install my-package ``` ```bash yarn add my-package ``` ```bash pnpm add my-package ``` ## CodeBlock Syntax-highlighted code with optional header and line highlighting. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `language` | String | — | Language for syntax highlighting | | `filename` | String | — | Filename displayed in the header | | `highlight` | String | — | Line numbers to highlight (e.g., `"2"`, `"1,3-5"`) | | `line_numbers` | bool | `false` | Show line numbers | Includes a copy-to-clipboard button. fn main() { println!("Hello, Oxidoc!"); } ## Accordion Collapsible sections. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `title` | String | — | Trigger text | | `multiple` | bool | `false` | Allow multiple items open simultaneously | Hidden content goes here. You can put any content inside an accordion. More hidden content. ## CardGrid Responsive grid of cards. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `columns` | Number | `3` | Number of columns (1-6) | Each `Card` supports: | Prop | Type | Description | |:-----|:-----|:------------| | `title` | String | Card title | | `icon` | String | Emoji or icon | | `href` | String | Makes the card a link | Learn the basics of Oxidoc. Explore all available components. Customize your documentation site. ## Steps Numbered step-by-step instructions with a connecting line. Each `Step` takes a `title` prop. Run the install script. Run `oxidoc init my-docs`. Create `.rdx` files and run `oxidoc dev`. ## Badge Inline status pill. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `variant` | String | `"info"` | Color: `info`, `tip`, `warning`, `danger`, `new`, `deprecated` | | `outline` | bool | `false` | Outline style | This feature is New in v0.1.0. The old API is Deprecated. Status: Stable Beta Experimental ## Tooltip Hover/focus popup for definitions. | Prop | Type | Description | |:-----|:-----|:------------| | `text` | String | Tooltip content | Oxidoc uses Wasm for interactive components. ## Tag Uppercase inline label for categorization. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `variant` | String | `"info"` | Color: `info`, `tip`, `warning`, `danger`, `new`, `experimental`, `deprecated` | new experimental deprecated ## ThemedImage Swaps images based on color scheme. | Prop | Type | Description | |:-----|:-----|:------------| | `light` | String | Image URL for light theme | | `dark` | String | Image URL for dark theme | | `alt` | String | Alt text | | `width` | String | Width | | `height` | String | Height | ## Banner Dismissible announcement bar. | Prop | Type | Default | Description | |:-----|:-----|:--------|:------------| | `id` | String | — | Unique ID for persistence | | `persist` | String | `"none"` | `"none"`, `"session"`, or `"forever"` | | `dismissible` | bool | `true` | Show close button | This is a banner announcement. ## Embed Embed external content (iframe). | Prop | Type | Description | |:-----|:-----|:------------| | `src` | String | URL to embed | | `width` | String | Width | | `height` | String | Height | ## Mermaid Diagrams Use `mermaid` as the language for fenced code blocks: ```mermaid graph LR A[Write .rdx] --> B[oxidoc build] B --> C[Static HTML] B --> D[Wasm Islands] C --> E[Deploy] D --> E ``` No configuration needed — diagrams render automatically. ## Landing Page Components For `Hero`, `FeatureGrid`, `Section`, `CTA`, and other landing page components, see [Landing Page Components](/docs/components/landing-page). --- # Landing Page Components — Hero, Features, CTA (docs/components/landing-page) --- title: Landing Page Components — Hero, Features, CTA description: Build stunning landing pages with Oxidoc's Hero, FeatureGrid, Section, CTA, and Testimonial components. Full-width layout with zero custom code. --- # Landing Page Components These components are designed for full-width landing pages. Set `layout: landing` in your frontmatter to use them. ```yaml --- title: My Project layout: landing --- ``` The `landing` layout removes the sidebar and table of contents, giving components the full page width. ## Hero The main banner at the top of a landing page. | Prop | Type | Description | |:-----|:-----|:------------| | `title` | String | Large heading text | Use `HeroAction` children for call-to-action buttons and include body text as the tagline. ```markdown A short tagline describing your project. ``` ### HeroAction Buttons inside a Hero. | Prop | Type | Description | |:-----|:-----|:------------| | `label` | String | Button text | | `href` | String | Link URL | | `variant` | String | `"primary"` (filled) or `"secondary"` (outlined) | ## Section A full-width content section with optional background. | Prop | Type | Description | |:-----|:-----|:------------| | `bg` | String | Background style: `"muted"` for subtle contrast, omit for default | ```markdown
Content goes here.
``` ## FeatureGrid A responsive grid of feature cards. Wrap `Feature` components inside it. ```markdown Description of feature. Another feature. ``` ### Feature A single feature card inside a `FeatureGrid`. | Prop | Type | Description | |:-----|:-----|:------------| | `icon` | String | Emoji or icon | | `title` | String | Feature title | | `class` | String | Optional CSS class for animations | ## CTA Call-to-action section. Use `HeroAction` children for buttons. | Prop | Type | Description | |:-----|:-----|:------------| | `title` | String | CTA heading | | `description` | String | Supporting text | ```markdown ``` ## TestimonialGrid A grid of testimonial cards. ```markdown This tool is amazing. Saved us hours of work. ``` ### Testimonial A single testimonial card. | Prop | Type | Description | |:-----|:-----|:------------| | `name` | String | Person's name | | `role` | String | Title or role | | `avatar` | String | Avatar image URL | ## Full Example --- title: My Project layout: landing --- Build something great with zero configuration.
Lightning-fast builds. Built-in full-text search. Zero config to get started.
--- # Search - Built-in Hybrid Search Engine (docs/search) --- title: Search - Built-in Hybrid Search Engine description: Oxidoc ships a production-grade search engine running in-browser via Wasm. BM25 lexical search works with zero config. Add semantic search with one line. --- # Search Oxidoc ships a production-grade search engine that runs entirely in the browser via WebAssembly. No server, no external service, no API keys — just build your site and search works. BM25 keyword search with fuzzy matching, phrase boost, and section-level results. Zero configuration. Understand the meaning of queries with sentence embeddings. Enable with one config line. Use your own GGUF embedding model for non-English docs or specialized domains. Integrate Algolia, Typesense, Meilisearch, or bring your own search service. ## Overview | Feature | Status | Details | |:--------|:-------|:--------| | Lexical (BM25) | Enabled by default | Zero config, always works | | Semantic embeddings | Opt-in | `semantic = true` in config | | Hybrid ranking (RRF) | Automatic | When semantic is enabled, fuses both result sets | | Fuzzy matching | Built-in | Tolerates typos based on term length | | Section-level results | Built-in | Links to the exact heading, not just the page | | Lazy chunk loading | Built-in | Only fetches index data matching query terms | | Custom models | Supported | Provide your own GGUF sentence embedding model | | External providers | Supported | Algolia, Typesense, Meilisearch, or custom JS | ## How It Works ```mermaid graph TD B[oxidoc build] --> L[BM25 Index] B --> S[Embedding Vectors] B --> M[Model Copy] L --> C[Chunked by term prefix] C --> W[Browser / Wasm] S --> W M --> W W --> Q[User Query] Q --> LR[Lexical Results] Q --> SR[Semantic Results] LR --> RRF[Reciprocal Rank Fusion] SR --> RRF RRF --> R[Ranked Results] ``` At build time, Oxidoc generates a search index from all your pages. The index is split into small chunks so the browser only downloads what's needed for each query. When semantic search is enabled, pre-computed embedding vectors and the model file are also included in the output. ## Quick Start Search works out of the box. To enable semantic search: [search] semantic = true That's it. See the subpages for deep dives into each feature. ## Output Files When using the built-in provider, `oxidoc build` generates these search files in `dist/`: | File | Purpose | Loaded | |:-----|:--------|:-------| | `search-meta.bin` | Document metadata + chunk manifest | Always (on page load) | | `search-chunk-{id}.bin` | Lexical postings for term prefixes | On demand (per query) | | `search-vectors.json` | Pre-computed page embeddings | Only if semantic enabled | | `search-model.gguf` | Embedding model for query-time inference | Only if semantic enabled | --- # Lexical Search — BM25 Full-Text Search Engine (docs/search/lexical) --- title: Lexical Search — BM25 Full-Text Search Engine description: Oxidoc's built-in BM25 search engine with fuzzy matching, phrase boost, section-level results, and lazy chunk loading. Works with zero configuration. --- # Lexical Search Lexical search is Oxidoc's default search engine. It uses BM25 — the same ranking algorithm behind Elasticsearch and Apache Lucene — to match pages by keyword relevance. It works out of the box with zero configuration. ## Features | Feature | Description | |:--------|:------------| | **BM25 scoring** | Industry-standard ranking with K1=1.2, B=0.75 tuning | | **Fuzzy matching** | Levenshtein edit distance — tolerates typos automatically | | **Prefix matching** | Results appear as you type, before finishing the word | | **Phrase boost** | 5x score boost when query terms appear consecutively in content | | **Heading boost** | 2x score boost for matches in page headings | | **Section scoring** | Results link to the exact heading section, not just the page | | **CamelCase splitting** | "CodeBlock" matches searches for "code" or "block" | | **Breadcrumb trails** | Results show "Page > H2 > H3" navigation path | | **Context snippets** | 160-character excerpt around the match, aligned to word boundaries | | **Lazy chunk loading** | Only downloads index chunks matching the query's term prefixes | ## How BM25 Works BM25 (Best Matching 25) scores each page based on how often the query terms appear, normalized by document length: - **Term frequency** — pages where the term appears more often score higher, with diminishing returns (saturation at K1=1.2) - **Inverse document frequency** — rare terms are worth more than common ones - **Length normalization** — short, focused pages aren't penalized against long ones (B=0.75) This means a concise page that mentions "versioning" 3 times ranks higher than a sprawling page that mentions it once in passing. ## Fuzzy Matching Oxidoc tolerates typos automatically based on term length: | Term Length | Max Edits | Example | |:------------|:----------|:--------| | 1–3 chars | 0 | "css" → exact match only | | 4–6 chars | 1 | "buld" → matches "build" | | 7+ chars | 2 | "conifgure" → matches "configure" | Fuzzy matching kicks in when an exact match isn't found. You don't need to configure it. ## Section-Level Results Results don't just link to a page — they link to the specific heading section where the match was found. Each result includes: - **Anchor link** — clicking goes directly to the matching section - **Breadcrumb trail** — shows the heading hierarchy (e.g., "Configuration > Theme > Dark Mode") - **Context snippet** — 160-character excerpt from the matching section ## Lazy Chunk Loading The search index is split into chunks by 2-character term prefix (e.g., "co", "se", "bu"). When a user types a query: 1. Oxidoc determines which chunks are needed based on the query terms 2. Only those chunks are fetched from the server 3. Previously loaded chunks are cached in memory This means the browser never downloads the full index — only the small slices relevant to the current query. For large documentation sites, this keeps search fast regardless of total page count. ## Index Size The lexical index is compact. For a documentation site with ~50 pages: - `search-meta.bin` — ~20-50 KB (loaded once on page open) - Each `search-chunk-{id}.bin` — ~1-10 KB (loaded on demand) Total transfer per query is typically under 20 KB. --- # Semantic Search — AI-Powered Conceptual Search (docs/search/semantic) --- title: Semantic Search — AI-Powered Conceptual Search description: Enable semantic search in Oxidoc to understand the meaning behind queries. Uses sentence embeddings and cosine similarity — runs in-browser via Wasm, no API keys. --- # Semantic Search Semantic search uses a sentence embedding model to understand the *meaning* of queries, not just keyword matches. When a user searches for "how do I change colors", it finds the theming page even if it never uses the word "colors". ## Enable Semantic Search [search] semantic = true That's it. Oxidoc bundles a default embedding model — no downloads, no API keys, no external services. ## How It Works ### Build Time 1. Oxidoc loads the embedding model (bundled BGE Micro v2 or your custom model) 2. Every page's text content is embedded into a 384-dimensional vector 3. The vectors are written to `search-vectors.json` in the output 4. The model file is copied to `search-model.gguf` in the output ### Query Time (In Browser) 1. The browser fetches the model file and pre-computed vectors 2. The model initializes in Wasm (CPU-only, no GPU) 3. When the user triggers semantic search, the query text is embedded in real-time 4. Cosine similarity is computed between the query vector and all page vectors 5. Results are ranked by similarity and merged with lexical results via RRF All computation happens in the browser. No data leaves the user's machine. ## Hybrid Ranking When semantic search is enabled, Oxidoc runs **both** engines on every "Ask AI" query and merges results using **Reciprocal Rank Fusion (RRF)**: ```mermaid graph LR Q[User Query] --> L[Lexical / BM25] Q --> S[Semantic / Cosine Similarity] L --> F[RRF Fusion] S --> F F --> R[Ranked Results] ``` | Engine | Weight | Strengths | |:-------|:-------|:----------| | Lexical (BM25) | **70%** | Exact terms, function names, config keys, error messages | | Semantic | **30%** | Conceptual queries, synonyms, "how do I..." questions, paraphrasing | Pages appearing in both result sets get combined scores. A page that matches keywords *and* is semantically relevant ranks highest. ### Why 70/30? Documentation search is keyword-heavy — users often search for exact function names, config fields, or error messages. The 70% lexical weight ensures these exact matches always surface. The 30% semantic weight adds recall for conceptual queries without drowning out precise keyword results. ## The Default Model Oxidoc bundles **BGE Micro v2** — a compact sentence embedding model by BAAI: | Property | Value | |:---------|:------| | Model | [BAAI/bge-micro-v2](https://huggingface.co/aapot/bge-micro-v2-GGUF) | | Format | GGUF (model + tokenizer in one file) | | Size | 17.5 MB | | Dimensions | 384 | | Runtime | CPU-only (no GPU required) | | Language | English (primary) | ### Why This Model? At 17.5 MB, the model is embedded directly in the Oxidoc binary. No download step during install or build. The same 17.5 MB file is served to browsers for query-time inference. Users don't wait for a 500 MB download before search works. BGE Micro v2 produces high-quality embeddings for English technical content — documentation, tutorials, API references. Runs on any device. No GPU, no WebGPU, no special hardware. Works on phones, tablets, old laptops. ### Limitations - **Optimized for English** — for non-English documentation, use a [custom model](/docs/ai/custom-models) - **384 dimensions** — larger models with higher dimensions may capture more nuance, at the cost of size - **17.5 MB browser download** — users on slow connections may experience a delay before semantic search is available (lexical search works immediately while the model loads) ## Build-Time vs Query-Time | Phase | What Happens | Time | |:------|:-------------|:-----| | **Build** | Embed all pages, write vectors + copy model | Seconds (CPU) | | **Page load** | Fetch `search-meta.bin` | Instant (~20 KB) | | **Semantic init** | Fetch model (17.5 MB) + vectors | 1–3 seconds | | **Regular search** | BM25 only (no model needed) | <10 ms | | **AI search** | Embed query + cosine similarity + RRF fusion | 50–200 ms | Lexical search is available immediately on page load. Semantic search becomes available once the model finishes loading in the background. Users are never blocked — they can search right away with keywords while the model downloads. ## Configuration Reference [search] # Enable semantic search (default: false) semantic = true # Custom GGUF model (overrides bundled BGE Micro v2) # model_path = "./models/my-model.gguf" | Field | Type | Default | Description | |:------|:-----|:--------|:------------| | `semantic` | bool | `false` | Enable semantic search alongside BM25 | | `model_path` | String | — | Path to a custom GGUF embedding model | When `model_path` is set, Oxidoc uses your model instead of the bundled one. See [Custom Models](/docs/ai/custom-models) for details. ## Embedding Output Format When semantic search is enabled, `oxidoc build` writes `search-vectors.json` to your output directory. This is a plain JSON file containing every page's embedding: { "dimension": 384, "documents": [ { "id": 0, "title": "Installation", "path": "/docs/installation", "snippet": "Install Oxidoc with a single command on Linux, macOS, or Windows...", "text": "The recommended way to install Oxidoc is the install script...", "headings": [ { "title": "Install Script", "anchor": "install-script", "depth": 2, "offset": 0 }, { "title": "GitHub Releases", "anchor": "github-releases", "depth": 2, "offset": 312 } ] } ], "vectors": [ [0.0231, -0.0412, 0.0889, "... 384 floats total ..."] ] } Each entry in `vectors` corresponds to the document at the same index in `documents`. The vectors are 32-bit floats, one per dimension (384 for the default model). ### Using Embeddings in Your Own RAG Pipeline The `search-vectors.json` file is a portable artifact you can use outside of Oxidoc. After running `oxidoc build`, copy the file and feed it into any vector database or RAG pipeline: import json import numpy as np with open("dist/search-vectors.json") as f: data = json.load(f) vectors = np.array(data["vectors"], dtype=np.float32) docs = data["documents"] # Compute cosine similarity with a query embedding query = your_model.encode("how do I configure search?") similarities = vectors @ query / (np.linalg.norm(vectors, axis=1) * np.linalg.norm(query)) # Top 5 results top_indices = np.argsort(similarities)[::-1][:5] for idx in top_indices: print(f"{docs[idx]['title']}: {similarities[idx]:.4f}") import json import chromadb with open("dist/search-vectors.json") as f: data = json.load(f) client = chromadb.Client() collection = client.create_collection("docs") collection.add( ids=[str(d["id"]) for d in data["documents"]], embeddings=data["vectors"], documents=[d["text"] for d in data["documents"]], metadatas=[{"title": d["title"], "path": d["path"]} for d in data["documents"]], ) # Query results = collection.query(query_texts=["how to deploy"], n_results=5) const data = JSON.parse(fs.readFileSync("dist/search-vectors.json", "utf-8")); // Each vector is a Float32 array of `dimension` length const { documents, vectors, dimension } = data; // Feed into Pinecone, Weaviate, Qdrant, etc. for (let i = 0; i < documents.length; i++) { await vectorDB.upsert({ id: documents[i].path, values: vectors[i], metadata: { title: documents[i].title, snippet: documents[i].snippet, }, }); } ### What's Included Per Document | Field | Description | |:------|:------------| | `id` | Numeric index (0-based) | | `title` | Page title (from first `

`) | | `path` | URL path (e.g., `/docs/installation`) | | `snippet` | First 160 characters of content | | `text` | Full plain text content (markdown stripped) | | `headings` | Heading positions with title, anchor, depth, and character offset | The `text` and `headings` fields give you everything needed to build section-level retrieval — split text by heading offsets to create chunks mapped to specific sections. For RAG pipelines, combine `search-vectors.json` (pre-computed embeddings) with `llms-full.txt` (full text) and `llms.txt` (page index). All three are generated automatically on every build — your documentation is RAG-ready out of the box. --- # External Search Providers — Algolia, Typesense, Meilisearch (docs/search/providers) --- title: External Search Providers — Algolia, Typesense, Meilisearch description: Integrate external search providers with Oxidoc. Step-by-step setup for Algolia DocSearch, Typesense, Meilisearch, or bring your own custom search solution. --- # External Search Providers Oxidoc's built-in search handles most documentation sites. For larger sites, existing infrastructure, or specific requirements, you can use an external search provider instead. When you set an external provider, Oxidoc skips generating the built-in search index and injects the provider's scripts and styles into your pages. ## Algolia DocSearch [Algolia DocSearch](https://docsearch.algolia.com/) is a popular hosted search for documentation sites. It's free for open-source projects. [search] provider = "algolia" app_id = "YOUR_APP_ID" api_key = "YOUR_SEARCH_API_KEY" index_name = "your_index" | Field | Description | |:------|:------------| | `app_id` | Your Algolia application ID | | `api_key` | **Search-only** API key (never use your admin key) | | `index_name` | Name of the Algolia index to search | Go to [docsearch.algolia.com](https://docsearch.algolia.com/) and apply. Open-source projects get free indexing and hosting. After approval, Algolia provides your `app_id`, `api_key`, and `index_name`. Add the credentials to your `[search]` config as shown above. Algolia's crawler indexes your deployed site automatically. Search works after the first crawl completes. Use the **search-only** API key in your config, not the admin key. The API key is visible in your site's HTML source. The search-only key can only read — it cannot modify your index. ## Typesense [Typesense](https://typesense.org/) is an open-source, typo-tolerant search engine you can self-host or use as a cloud service. [search] provider = "typesense" host = "your-typesense-host.com" port = 443 protocol = "https" api_key = "YOUR_SEARCH_API_KEY" collection_name = "docs" | Field | Description | |:------|:------------| | `host` | Typesense server hostname | | `port` | Server port (typically 443 for HTTPS, 8108 for local) | | `protocol` | `"https"` or `"http"` | | `api_key` | Search-only API key | | `collection_name` | Name of the Typesense collection | Self-host with Docker or use [Typesense Cloud](https://cloud.typesense.org/). ```bash docker run -p 8108:8108 -v /tmp/typesense-data:/data typesense/typesense:latest \ --data-dir /data --api-key=your-admin-key ``` Use the Typesense API or a scraper like [typesense-docsearch-scraper](https://github.com/typesense/typesense-docsearch-scraper) to index your built site. Add your Typesense credentials as shown above. Use a search-only API key. ## Meilisearch [Meilisearch](https://www.meilisearch.com/) is an open-source, fast search engine with typo tolerance and filtering. [search] provider = "meilisearch" host = "https://your-meilisearch-host.com" api_key = "YOUR_SEARCH_API_KEY" index_name = "docs" | Field | Description | |:------|:------------| | `host` | Meilisearch instance URL (including protocol) | | `api_key` | Search-only API key | | `index_name` | Name of the Meilisearch index | Self-host with Docker or use [Meilisearch Cloud](https://www.meilisearch.com/cloud). ```bash docker run -p 7700:7700 -v /tmp/meili-data:/meili_data getmeili/meilisearch:latest ``` Use the Meilisearch API or [docs-scraper](https://github.com/meilisearch/docs-scraper) to index your built site. Add your Meilisearch credentials as shown above. ## Custom Provider For any search service not listed above, inject your own CSS and JavaScript: [search] provider = "custom" stylesheet = "https://cdn.example.com/search.css" script = "https://cdn.example.com/search.js" init_script = "assets/js/search-init.js" | Field | Type | Description | |:------|:-----|:------------| | `stylesheet` | String | CSS file loaded in `` via `` tag | | `script` | String | JS file loaded at end of `` via ` ``` All of this is generated from your page content and `oxidoc.toml` config — no manual meta tags needed. ## Page Title and Description ### Title The page title comes from the first `

` heading in your content. It's used for ``, `og:title`, `twitter:title`, and JSON-LD `name`. Write titles that are: - Under 60 characters to avoid truncation in search results - Front-loaded with the primary keyword - Unique across all pages ### Description The meta description is **auto-extracted from the first paragraph** of your page content, truncated to 160 characters. Write your opening paragraph with SEO in mind — it becomes your search snippet. Make it: - 150–160 characters with a clear summary of the page - Action-oriented ("Learn how to...", "Configure...", "Set up...") - Unique per page to avoid internal competition <Callout kind="tip" title="First paragraph matters"> Since Oxidoc uses your first paragraph as the meta description, craft it like a micro-advertisement for the page. This is what appears in Google results and social shares. </Callout> ## Open Graph Tags Open Graph tags control how your pages appear when shared on social platforms (Facebook, LinkedIn, Slack, Discord). Oxidoc generates these automatically: | Tag | Source | |:----|:-------| | `og:title` | First `<h1>` heading | | `og:description` | First paragraph (160 chars) | | `og:url` | `base_url` + page path | | `og:type` | `article` | | `og:site_name` | `project.name` from config | ### Adding og:image Oxidoc doesn't generate `og:image` automatically, but you can add it per-page using the `<Head>` component: <CodeBlock language="markdown" filename="docs/intro.rdx"> <Head> <meta property="og:image" content="https://example.com/social-card.png"> <meta property="og:image:width" content="1200"> <meta property="og:image:height" content="630"> </Head> # Introduction Your page content here. </CodeBlock> For a site-wide social image, add it to every page or create a shared component. ## Twitter Cards Oxidoc generates `twitter:card` (set to `summary`) and `twitter:title` for every page. Add more Twitter meta tags with `<Head>`: ```markdown <Head> <meta name="twitter:image" content="https://example.com/card.png"> <meta name="twitter:site" content="@yourhandle"> <meta name="twitter:description" content="Custom Twitter description"> </Head> ``` ## The `<Head>` Component The `<Head>` component lets you inject any HTML into the `<head>` of a page. Use it for custom meta tags, preload hints, alternate language links, or anything Oxidoc doesn't generate automatically. ```markdown <Head> <meta property="og:image" content="/social-card.png"> <meta name="keywords" content="rust, documentation, static site"> <meta name="author" content="Your Name"> <link rel="alternate" hreflang="es" href="/es/docs/intro"> <link rel="preload" href="/fonts/custom.woff2" as="font" type="font/woff2" crossorigin> </Head> ``` Content inside `<Head>` is moved from the body to `<head>` during rendering. Only raw HTML is supported — no components inside `<Head>`. ## JSON-LD Structured Data Every page includes a `WebPage` JSON-LD block with `@context`, `@type`, `name`, `description`, `url`, and `site.name`. This helps search engines and AI systems understand your content structure. The structured data is generated from: - Page title (from `<h1>`) - Page description (from first paragraph, or `project.description`) - Full URL (from `base_url` + slug) - Site name (from `project.name`) ## Canonical URLs When `base_url` is set in `oxidoc.toml`, every page gets a `<link rel="canonical">` tag. This prevents duplicate content issues when the same page is accessible at multiple URLs. <CodeBlock language="toml" filename="oxidoc.toml"> [project] base_url = "https://example.com" </CodeBlock> ## Auto-Generated SEO Files ### sitemap.xml Generated automatically with URLs for every page in your navigation. Search engines use this to discover and index your content. ### robots.txt Generated with permissive defaults: ```text User-agent: * Allow: / Sitemap: https://example.com/sitemap.xml ``` ### Atom Feed (feed.xml) An Atom feed of all documentation pages. Each entry includes the first paragraph as a summary. Useful for RSS readers and content aggregators. ### llms.txt and llms-full.txt Machine-readable files for AI tools and RAG pipelines. See [llms.txt](/docs/ai/llms-txt) for details. ## Versioned Content and SEO Archived (non-default) versions automatically get: ```html <meta name="robots" content="noindex, nofollow"> ``` This prevents search engines from indexing outdated documentation while keeping it accessible to users who navigate to it directly. ## Edit Links Connect each page to its source for transparency and community contributions: <CodeBlock language="toml" filename="oxidoc.toml"> [project] edit_url = "https://github.com/org/repo/blob/main" edit_label = "Edit this page" </CodeBlock> Each page shows a link to its source file, encouraging contributions and signaling content freshness. ## Redirects Set up redirects for moved or renamed pages to preserve link equity: <CodeBlock language="toml" filename="oxidoc.toml"> [redirects] redirects = [ { from = "/old-page", to = "/new-page" }, ] </CodeBlock> Each redirect generates an HTML file with `<meta http-equiv="refresh">`. ## SEO Checklist Use this checklist when writing documentation pages: <Steps> <Step title="Write a descriptive first paragraph"> This becomes your meta description. Keep it under 160 characters, action-oriented, and unique per page. </Step> <Step title="Use a clear, keyword-rich H1"> The `<h1>` becomes your `<title>`, `og:title`, and JSON-LD name. Front-load the primary keyword. </Step> <Step title="Set base_url in config"> Required for canonical URLs, sitemap, feeds, and absolute OG URLs. </Step> <Step title="Add og:image for key pages"> Use the `<Head>` component to add social sharing images, especially for landing pages and high-traffic docs. </Step> <Step title="Keep titles unique"> Every page must have a unique `<h1>` to avoid competing with your own pages in search results. </Step> </Steps> --- # Analytics — Google Analytics and Custom Scripts (docs/analytics) --- title: Analytics — Google Analytics and Custom Scripts description: Add analytics to your Oxidoc site. Configure Google Analytics with one line, or inject custom scripts for Plausible, Fathom, Umami, and other providers. --- # Analytics Oxidoc supports Google Analytics and custom analytics scripts. ## Google Analytics Add your measurement ID: <CodeBlock language="toml" filename="oxidoc.toml"> [analytics] google_analytics = "G-XXXXXXXXXX" </CodeBlock> Oxidoc injects the Google Analytics gtag.js snippet into every page. ## Custom Script For other analytics providers (Plausible, Fathom, Umami, etc.), inject a custom script tag: <CodeBlock language="toml" filename="oxidoc.toml"> [analytics] script = '<script defer data-domain="example.com" src="https://plausible.io/js/script.js"></script>' </CodeBlock> The `script` value is injected directly into the `<head>` of every page. You can use any analytics provider that works via a script tag. ## Using Both You can set both `google_analytics` and `script` if needed — both will be injected. --- # Theming - CSS Variables, Dark Mode, and Custom Styles (docs/theming) --- title: Theming - CSS Variables, Dark Mode, and Custom Styles description: Customize every visual aspect of your Oxidoc site. Override 50+ CSS variables for colors, typography, layout, shadows, and transitions. Dark mode included. --- # Theming Oxidoc is styled entirely with CSS custom properties (`--oxidoc-*` variables). Override any variable to customize your site — from a single color change to a complete visual redesign. ## Quick Config For simple changes, set values directly in `oxidoc.toml`: <CodeBlock language="toml" filename="oxidoc.toml"> [theme] primary = "#8b5cf6" accent = "#f59e0b" font = "Inter, sans-serif" code_font = "JetBrains Mono, monospace" dark_mode = "system" </CodeBlock> | Field | What it controls | |:------|:----------------| | `primary` | Links, active sidebar items, buttons, callout info borders | | `accent` | Accent highlights and decorative elements | | `font` | Body text font stack | | `code_font` | Code blocks and inline code font stack | | `dark_mode` | `"system"` (default), `"light"`, or `"dark"` | These fields are convenience shortcuts. For full control, use custom CSS. ## Dark Mode The `dark_mode` setting controls initial behavior: - `"system"` — follows OS preference via `prefers-color-scheme`, with a toggle in the header - `"light"` — always light mode - `"dark"` — always dark mode In `system` mode, users can toggle manually. The preference is stored in the browser. ## Custom CSS Load one or more CSS files that override any `--oxidoc-*` variable: <CodeBlock language="toml" filename="oxidoc.toml"> [theme] custom_css = ["assets/variables.css", "assets/overrides.css"] </CodeBlock> Files are concatenated in order. All Oxidoc styles are wrapped in `@layer oxidoc`, so your custom CSS **always wins** the cascade — no `!important` needed. ## CSS Variable Reference Every visual property in Oxidoc is controlled by a CSS variable. Override them in `:root` for light mode and `[data-theme="dark"]` for dark mode. ### Core Colors <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-primary: #2563eb; --oxidoc-accent: #f59e0b; --oxidoc-bg: #ffffff; --oxidoc-bg-secondary: #f8fafc; --oxidoc-text: #1e293b; --oxidoc-text-secondary: #64748b; --oxidoc-border: #e2e8f0; --oxidoc-code-bg: #f1f5f9; } [data-theme="dark"] { --oxidoc-primary: #3b82f6; --oxidoc-accent: #fbbf24; --oxidoc-bg: #0f172a; --oxidoc-bg-secondary: #1e293b; --oxidoc-text: #e2e8f0; --oxidoc-text-secondary: #94a3b8; --oxidoc-border: #334155; --oxidoc-code-bg: #1e293b; } </CodeBlock> ### Primary Color Shades Auto-generated from your primary color using `color-mix()`: ```css :root { --oxidoc-primary-light /* 70% primary + white */ --oxidoc-primary-dark /* 70% primary + black */ --oxidoc-primary-lighter /* 40% primary + white */ --oxidoc-primary-darker /* 40% primary + black */ } ``` These adapt automatically when you change `--oxidoc-primary`. ### Semantic Colors Used by callouts, badges, tags, API method badges, and status indicators: <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-success: #10b981; --oxidoc-success-text: #059669; --oxidoc-warning: #f59e0b; --oxidoc-warning-text: #b45309; --oxidoc-error: #ef4444; --oxidoc-error-text: #dc2626; --oxidoc-info: #3b82f6; --oxidoc-info-text: #2563eb; --oxidoc-new: #8b5cf6; --oxidoc-new-text: #7c3aed; --oxidoc-deprecated: #6b7280; --oxidoc-deprecated-text: #4b5563; } </CodeBlock> All semantic colors have dark mode variants applied automatically. ### Utility Colors <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-text-muted: #6b7280; --oxidoc-bg-subtle: #f3f4f6; --oxidoc-on-primary: #fff; --oxidoc-shadow: rgba(0, 0, 0, 0.1); --oxidoc-overlay: rgba(0, 0, 0, 0.4); } </CodeBlock> ### Callout Customization Each callout type exposes its own variables: <CodeBlock language="css" filename="assets/custom.css"> .oxidoc-callout-warning { --oxidoc-callout-color: #ea580c; --oxidoc-callout-bg: #fff7ed; --oxidoc-callout-border: #ea580c; --oxidoc-callout-text: #1e293b; } </CodeBlock> ### Typography <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-font-sans: system-ui, -apple-system, sans-serif; --oxidoc-font-mono: "SF Mono", "Fira Code", monospace; } </CodeBlock> ### Layout <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-content-max: 48rem; --oxidoc-sidebar-width: 16rem; --oxidoc-toc-width: 14rem; --oxidoc-header-height: 3.5rem; } </CodeBlock> ### Border Radius <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-radius-sm: 0.25rem; --oxidoc-radius-md: 0.375rem; --oxidoc-radius-lg: 0.5rem; } </CodeBlock> ### Shadows <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); --oxidoc-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1); --oxidoc-shadow-lg: 0 12px 36px rgba(0, 0, 0, 0.15); } </CodeBlock> ### Z-Index <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-z-tooltip: 10; --oxidoc-z-back-to-top: 50; --oxidoc-z-sidebar: 90; --oxidoc-z-header: 100; --oxidoc-z-skip-nav: 200; --oxidoc-z-overlay: 1000; } </CodeBlock> ### Transitions <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-transition-fast: 0.15s ease; --oxidoc-transition-normal: 0.25s ease; --oxidoc-transition-slow: 0.4s ease; --oxidoc-transition-spring: 0.5s cubic-bezier(0.19, 1, 0.22, 1); } </CodeBlock> ## Community Themes Community themes are `.css` files that override `--oxidoc-*` variables. To use one: <CodeBlock language="toml" filename="oxidoc.toml"> [theme] custom_css = ["assets/dracula.css"] </CodeBlock> To create a theme, write a CSS file that sets the variables above for both `:root` (light) and `[data-theme="dark"]` (dark), then share it. --- # API Reference — OpenAPI Integration Guide (docs/api-reference) --- title: API Reference — OpenAPI Integration Guide description: Generate interactive API documentation from OpenAPI specs. Auto-generated parameter tables, response schemas, and a live Wasm-powered API playground. --- # API Reference Oxidoc generates interactive API documentation directly from your OpenAPI specification. Drop a YAML or JSON spec into your project and Oxidoc does the rest — parameter tables, request/response schemas, and a live API playground on every endpoint page. <Callout kind="tip" title="Try the sample"> Click **API** in the header or go to [/api](/api) to see the generated pages with the interactive playground. </Callout> ## Setup Add a navigation entry with `openapi` pointing to your spec: <CodeBlock language="toml" filename="oxidoc.toml"> [routing] navigation = [ { path = "/api", openapi = "./openapi.yaml" }, ] </CodeBlock> Run `oxidoc dev` or `oxidoc build`. Oxidoc parses the spec, generates a page for every endpoint, groups them by tag in the sidebar, and creates an index page at `/api/`. ## What Gets Generated For each endpoint in the spec, Oxidoc creates a page with: <CardGrid> <Card title="Method & Path" icon="🔗"> Color-coded HTTP method badge with the endpoint path. </Card> <Card title="Parameters Table" icon="📋"> Auto-generated table of query, path, and header parameters with types and descriptions. </Card> <Card title="Request Body" icon="📤"> Schema display for endpoints that accept a request body, with content type. </Card> <Card title="Response Schemas" icon="📥"> All documented response codes with their descriptions and schemas. </Card> <Card title="API Playground" icon="⚡"> Interactive Wasm-powered playground to fill in parameters and test the endpoint live. </Card> </CardGrid> ## Endpoint Grouping Endpoints are grouped by their OpenAPI `tags`. Each tag becomes its own sidebar section. Untagged endpoints appear under a default group. ## The API Playground Every endpoint page includes an interactive playground powered by WebAssembly: - Pre-fills parameters from the spec (name, type, required) - Supports path, query, and header parameters - Sends real HTTP requests to your configured base URL - Shows response status, headers, and body - Generates code snippets for `curl`, `fetch`, and other clients <Callout kind="info" title="Base URL"> Set `servers` in your OpenAPI spec to configure the target URL for the playground. The first server entry is used by default. </Callout> ## Supported Features | Feature | Status | |:--------|:-------| | OpenAPI 3.0 | <Badge variant="tip">Supported</Badge> | | OpenAPI 3.1 | <Badge variant="tip">Supported</Badge> | | Path parameters | <Badge variant="tip">Supported</Badge> | | Query parameters | <Badge variant="tip">Supported</Badge> | | Header parameters | <Badge variant="tip">Supported</Badge> | | Request body schemas | <Badge variant="tip">Supported</Badge> | | Response schemas | <Badge variant="tip">Supported</Badge> | | Multiple tags | <Badge variant="tip">Supported</Badge> | | `$ref` references | <Badge variant="tip">Supported</Badge> | | Deprecation notices | <Badge variant="tip">Supported</Badge> | | Authentication schemes | <Badge variant="new">Coming soon</Badge> | | Webhook endpoints | <Badge variant="new">Coming soon</Badge> | --- # Animations — CSS Keyframes, Scroll Triggers, and Stagger (docs/guides/animations) --- title: Animations — CSS Keyframes, Scroll Triggers, and Stagger description: Add animations to your Oxidoc site. 15 built-in keyframes, scroll-triggered entrances, stagger delays, and animatable CSS variables — pure CSS, no JS. --- # Animations Oxidoc ships a built-in animation system — 15 reusable `@keyframes`, scroll-triggered entrances, and animatable CSS variables. Pure CSS, no JavaScript required. ## Built-in Component Animations Landing page components animate automatically: - **Hero** — title fades down, tagline and actions fade up with stagger - **Features** — each card fades in from below, staggered by position - **Testimonials** — cards fade in with stagger - **CTA** — fades in from below - **Search dialog** — overlay fades in, dialog scales in - **Tooltips** — fade in on hover No configuration needed — these work out of the box. ## Using Animation Classes Components that accept a `class` prop can use animation utility classes: ```rdx <Feature icon="⚡" title="Fast" class="oxidoc-animate-bounce-in"> Sub-second builds. </Feature> <FeatureGrid class="oxidoc-animate-fade-in-up"> ... </FeatureGrid> ``` | Class | Effect | |:------|:-------| | `oxidoc-animate-fade-in` | Opacity 0 → 1 | | `oxidoc-animate-fade-in-up` | Fade in + slide up from below | | `oxidoc-animate-bounce-in` | Bouncy entrance with overshoot | | `oxidoc-animate-pop` | Quick scale-up pop | | `oxidoc-animate-float` | Gentle up-and-down floating (infinite) | | `oxidoc-animate-spin` | 360° rotation (infinite) | | `oxidoc-animate-shimmer` | Loading skeleton shimmer (infinite) | ### Stagger Delays Add stagger classes for sequential timing: ```rdx <Feature icon="⚡" title="First" class="oxidoc-animate-fade-in-up oxidoc-stagger-1">...</Feature> <Feature icon="🧩" title="Second" class="oxidoc-animate-fade-in-up oxidoc-stagger-2">...</Feature> <Feature icon="🔍" title="Third" class="oxidoc-animate-fade-in-up oxidoc-stagger-3">...</Feature> ``` `oxidoc-stagger-1` through `oxidoc-stagger-5` add incremental delays (0.1s each by default). ## Custom CSS Animations Use the shipped `@keyframes` in your own custom CSS: <CodeBlock language="css" filename="assets/custom.css"> .my-element { animation: oxidoc-fade-in-up var(--oxidoc-transition-normal) both; } .my-modal { animation: oxidoc-scale-in var(--oxidoc-transition-spring) both; } </CodeBlock> ### Available Keyframes | Keyframe | Description | |:---------|:------------| | `oxidoc-fade-in` | Opacity 0 → 1 | | `oxidoc-fade-out` | Opacity 1 → 0 | | `oxidoc-fade-in-up` | Fade in + translate up | | `oxidoc-fade-in-down` | Fade in + translate down | | `oxidoc-slide-in-left` | Slide in from left edge | | `oxidoc-slide-in-right` | Slide in from right edge | | `oxidoc-scale-in` | Scale up from 0.9 + fade in | | `oxidoc-scale-out` | Scale up to 1.05 + fade out | | `oxidoc-bounce-in` | Bouncy scale entrance | | `oxidoc-pop` | Quick snap-in from scale 0 | | `oxidoc-spin` | 360° rotation | | `oxidoc-pulse` | Gentle scale pulse | | `oxidoc-shake` | Horizontal shake | | `oxidoc-float` | Gentle vertical float | | `oxidoc-shimmer` | Loading skeleton shimmer | ## Scroll-Triggered Animations In browsers that support scroll-driven animations, use the `oxidoc-animate-on-scroll` class to trigger entrance animations as elements scroll into view. In unsupported browsers, content appears normally. ## Animatable CSS Variables Color variables are registered with `@property`, so the browser can smoothly interpolate them. This means you can animate theme colors with CSS transitions: <CodeBlock language="css" filename="assets/custom.css"> .my-element { transition: --oxidoc-primary var(--oxidoc-transition-normal); } .my-element:hover { --oxidoc-primary: #8b5cf6; } </CodeBlock> Registered animatable properties: `--oxidoc-primary`, `--oxidoc-accent`, `--oxidoc-bg`, `--oxidoc-text`, `--oxidoc-success`, `--oxidoc-warning`, `--oxidoc-error`. ## Transition Presets All component transitions use these variables. Override them to change the feel of the entire site: <CodeBlock language="css" filename="assets/custom.css"> :root { --oxidoc-transition-fast: 0.15s ease; /* Hover states */ --oxidoc-transition-normal: 0.25s ease; /* UI movements */ --oxidoc-transition-slow: 0.4s ease; /* Page-level */ --oxidoc-transition-spring: 0.5s cubic-bezier(0.19, 1, 0.22, 1); /* Elastic */ } </CodeBlock> <Callout kind="tip"> Set all transitions to `0s` for an instant-feel UI, or increase them for a more relaxed, cinematic feel. </Callout> ## Accessibility All animations automatically respect `prefers-reduced-motion`. When a user has reduced motion enabled in their OS, animation durations collapse to near-zero and iterations run once. No configuration needed. --- # Custom Web Components — Vanilla JS Escape Hatch (docs/guides/custom-components) --- title: Custom Web Components — Vanilla JS Escape Hatch description: Register custom Vanilla JS Web Components in Oxidoc. Write standard HTML Custom Elements and use them in your RDX content alongside built-in components. --- # Custom Web Components Oxidoc lets you register Vanilla JS Web Components as an escape hatch for UI that doesn't need the Wasm pipeline. ## Configuration Map component tag names to JavaScript file paths in `oxidoc.toml`: <CodeBlock language="toml" filename="oxidoc.toml"> [components.custom] PromoBanner = "assets/js/promo-banner.js" FeedbackWidget = "assets/js/feedback-widget.js" </CodeBlock> ## Writing a Component Each JS file should define and register an HTML Custom Element: <CodeBlock language="javascript" filename="assets/js/promo-banner.js"> class PromoBanner extends HTMLElement { connectedCallback() { const message = this.getAttribute('message') || 'Check this out!'; this.innerHTML = `<div class="promo-banner">${message}</div>`; } } customElements.define('promo-banner', PromoBanner); </CodeBlock> ## Using in RDX Use the component tag in your `.rdx` files just like any built-in component: <CodeBlock language="markdown" filename="docs/intro.rdx"> <PromoBanner message="New release available!" /> </CodeBlock> <Callout kind="info"> Custom components bypass the Wasm hydration pipeline entirely. Oxidoc renders the HTML element directly and loads your JS file with `<script type="module" async>`. </Callout> ## When to Use <CardGrid columns="2"> <Card title="Use Custom Components" description="Quick UI experiments, third-party widget wrappers, simple interactive elements that don't need Leptos reactivity." /> <Card title="Use Built-in Components" description="Rich interactivity with ARIA keyboard navigation, Shadow DOM isolation, and full Leptos reactivity." /> </CardGrid> ## Attributes All attributes you pass to the component in RDX are forwarded as HTML attributes on the custom element. Your JS `connectedCallback` can read them with `this.getAttribute()`. --- # Troubleshooting — Common Issues and FAQ (docs/guides/troubleshooting) --- title: Troubleshooting — Common Issues and FAQ description: Fix common Oxidoc issues fast. Solutions for port conflicts, missing assets, config errors, hot reload problems, and answers to frequently asked questions. --- # Troubleshooting ## Common Issues ### Port Already in Use ```text Error: Address already in use (os error 98) ``` Another process is using port 3000. Use a different port: ```bash oxidoc dev -p 8080 ``` Or find and kill the existing process: ```bash lsof -i :3000 kill <PID> ``` ### Config Validation Errors Oxidoc validates your `oxidoc.toml` and suggests corrections for typos: ```text Error: unknown field `colour` in [theme], did you mean `color`? ``` Check the [Configuration Reference](/docs/configuration) for valid field names. ### Missing Assets If images or other assets aren't showing up, make sure they're in the `assets/` directory. Oxidoc copies everything in `assets/` to the output directory during build. ```text my-docs/ ├── assets/ │ ├── logo.svg → /assets/logo.svg │ └── images/ │ └── hero.png → /assets/images/hero.png ``` ### Pages Not Appearing in Sidebar Pages must be listed in the `navigation` groups in `oxidoc.toml` to appear in the sidebar. Unlisted pages are still built and accessible by URL. <CodeBlock language="toml" filename="oxidoc.toml"> groups = [ { group = "Getting Started", pages = ["intro", "quickstart"] }, ] </CodeBlock> ### Build Warnings About Missing Pages If `oxidoc build` warns about missing pages, check that: 1. The `.rdx` file exists in the correct directory 2. The filename matches the slug in `oxidoc.toml` (without the `.rdx` extension) 3. Nested pages include the subdirectory (e.g., `"guides/styling"` not just `"styling"`) ### Hot Reload Not Working If changes don't appear in the browser during `oxidoc dev`: 1. Make sure you saved the file 2. Check the terminal for build errors 3. Try a hard refresh (Ctrl+Shift+R) 4. Restart the dev server ### Custom CSS Not Applied 1. Verify the path in `custom_css` is relative to the project root 2. Check that the CSS file exists 3. Remember that Oxidoc styles use `@layer oxidoc`, so your custom CSS wins automatically — no `!important` needed ## FAQ ### Can I use Markdown files (.md) instead of .rdx? No. Oxidoc uses `.rdx` files, which are Markdown with component support. The syntax is the same as Markdown with the addition of embedded components. ### Do I need Node.js or npm? No. Oxidoc is a single binary with no runtime dependencies. Install it, run it, done. ### How do I add syntax highlighting for a new language? Syntax highlighting is built in for all common languages. If your language isn't highlighted, use the `language` prop on `CodeBlock` with the language name. ### Can I deploy to my own server? Yes. Run `oxidoc build` and serve the `dist/` directory with any static file server (nginx, Apache, Caddy, etc.). ### How do I add a custom domain on GitHub Pages? Add a `CNAME` file in your `assets/` directory with your domain name. Oxidoc copies it to `dist/` automatically. --- # AI-Ready Output — llms.txt, Embeddings, and RAG (docs/ai/llms-txt) --- title: AI-Ready Output — llms.txt, Embeddings, and RAG description: Oxidoc auto-generates llms.txt, llms-full.txt, and pre-computed embeddings so AI tools, LLMs, and RAG pipelines can consume your documentation out of the box. --- # AI-Ready Output Every `oxidoc build` generates machine-readable files that make your documentation consumable by AI tools, LLMs, and RAG pipelines — with zero configuration. ## What Gets Generated ### llms.txt A lightweight index of every page — title and URL, one per line: <CodeBlock language="text" filename="dist/llms.txt"> - /docs/installation: Install Oxidoc - /docs/quickstart: Quickstart - /docs/configuration: Configuration Reference - /docs/components: Built-in Components - /docs/search: Search </CodeBlock> AI tools use this to understand what your docs cover and which page to fetch for a given question. ### llms-full.txt The complete plain text content of every page, separated by `---` markers: <CodeBlock language="text" filename="dist/llms-full.txt"> --- # Install Oxidoc (docs/installation) The recommended way to install Oxidoc is the install script... --- # Quickstart (docs/quickstart) Go from zero to a running documentation site in under five minutes... </CodeBlock> This is the file AI tools ingest when they need full context. A single fetch gives the LLM your entire documentation in a format optimized for comprehension. ## Zero Configuration Both files are generated automatically on every `oxidoc build`. No config flags, no opt-in — they're always there in `dist/`. ## How AI Tools Use These Files | Tool | How it uses llms.txt | |:-----|:---------------------| | ChatGPT / Claude | Users paste `llms-full.txt` as context to ask questions about your project | | Cursor / Codex | Agents fetch the file to understand your API before writing code | | RAG pipelines | Index `llms-full.txt` as a document source for retrieval | | AI search | Use `llms.txt` as a sitemap for selective page fetching | <Callout kind="tip" title="Link it from your README"> Add a note in your project README pointing AI users to your `llms.txt` URL. For example: `https://your-docs-site.com/llms-full.txt` </Callout> ## The llms.txt Standard The `llms.txt` format is an emerging convention for making websites machine-readable. By generating these files automatically, Oxidoc ensures your documentation is ready for the AI-native web without any extra work from you. Other documentation tools require plugins or manual setup. Oxidoc does it out of the box. ## Pre-Computed Embeddings When [semantic search](/docs/search/semantic) is enabled (`semantic = true`), Oxidoc also generates `search-vectors.json` — a JSON file containing a 384-dimensional embedding vector for every page, along with full metadata (title, path, text, heading positions). This file is a portable artifact you can feed directly into any vector database (ChromaDB, Pinecone, Weaviate, Qdrant) or custom RAG pipeline. See [Semantic Search > Embedding Output Format](/docs/search/semantic#embedding-output-format) for the schema and code examples in Python and JavaScript. ## All AI Output Files | File | Always Generated | Description | |:-----|:-----------------|:------------| | `llms.txt` | Yes | Page index — title and URL per line | | `llms-full.txt` | Yes | Full plain text of all pages | | `search-vectors.json` | When `semantic = true` | Pre-computed embedding vectors + metadata | | `search-model.gguf` | When `semantic = true` | The GGUF embedding model (for re-embedding queries) | Together, these files make your documentation fully RAG-ready. Users can build custom AI assistants that understand your project without scraping HTML or parsing Markdown. --- # Custom Embedding Models — Use Your Own GGUF Model (docs/ai/custom-models) --- title: Custom Embedding Models — Use Your Own GGUF Model description: Replace Oxidoc's default search model with your own GGUF sentence embeddings. Optimize for your language, domain, or performance requirements. --- # Custom Embedding Models Oxidoc's bundled BGE Micro v2 model works well for English documentation, but you may want a different model for non-English content, specialized domains, or different quality/size tradeoffs. ## Using a Custom Model Point `model_path` to your GGUF file: <CodeBlock language="toml" filename="oxidoc.toml"> [search] semantic = true model_path = "./models/my-custom-model.gguf" </CodeBlock> Oxidoc loads your model instead of the bundled one. At build time, it embeds all pages using your model. The model file is copied to the output directory for browser-side query embedding. ## Model Requirements Your model must meet three requirements: <Steps> <Step title="GGUF format"> A single `.gguf` file with the tokenizer embedded. This is the standard format for efficient model distribution — one file contains everything needed for inference. </Step> <Step title="Sentence embedding model"> The model must produce fixed-size vectors from text input. It must be a sentence-transformer or embedding model, **not** a generative LLM. Models like BERT, BGE, E5, GTE, and MiniLM work. </Step> <Step title="Compatible architecture"> Standard BERT-family sentence transformers work out of the box with Oxidoc's `boostr` GGUF loader. This covers the vast majority of embedding models on Hugging Face. </Step> </Steps> ## When to Use a Custom Model <CardGrid columns="2"> <Card title="Non-English documentation" icon="🌍"> The bundled model is optimized for English. For Japanese, Chinese, Korean, Arabic, or multilingual docs, use a model trained on your target language. Semantic search quality drops significantly when the model doesn't understand the content language. </Card> <Card title="Domain-specific content" icon="🔬"> Medical, legal, scientific, or financial documentation uses specialized terminology. A domain-fine-tuned model understands that "injection" means something different in medicine vs. software security. </Card> <Card title="Higher quality embeddings" icon="📈"> Larger models (100MB+) with more dimensions (768, 1024) capture more semantic nuance. If search quality is critical and your users have fast connections, a larger model is worth the tradeoff. </Card> <Card title="Smaller footprint" icon="📦"> If 17.5 MB is too large for your users (mobile-first docs, users on slow connections), use a smaller quantized model. Q4 quantization can cut size by 50-75% with modest quality loss. </Card> </CardGrid> ## Finding Models Search [Hugging Face](https://huggingface.co/models?sort=downloads&search=gguf+embedding) for GGUF sentence embedding models. When evaluating models, look for: - **"sentence-transformers"** or **"embedding"** in the model name - **GGUF variants** — look for filenames like `model-q5_k_m.gguf` or `model-f16.gguf` - **Language coverage** — check the model card for supported languages - **Embedding dimensions** — higher dimensions = better quality but larger vectors - **MTEB benchmark scores** — the standard benchmark for embedding quality ### Recommended Models by Use Case | Use Case | Model | Size | Dimensions | Notes | |:---------|:------|:-----|:-----------|:------| | English (default) | BGE Micro v2 | 17.5 MB | 384 | Bundled, good quality/size ratio | | English (high quality) | `bge-small-en-v1.5` | ~130 MB | 384 | Better quality, larger download | | Multilingual | `multilingual-e5-small` | ~120 MB | 384 | 100+ languages, good for i18n sites | | Japanese / CJK | `multilingual-e5-small` | ~120 MB | 384 | Strong CJK support | | Chinese | `bge-small-zh-v1.5` | ~100 MB | 512 | Optimized specifically for Chinese | | Minimal size | `all-MiniLM-L6-v2` | ~23 MB | 384 | Smallest useful model | <Callout kind="warning" title="Model size = browser download"> Your custom model file is served to the browser for query-time embedding. A 500 MB model means a 500 MB download before semantic search works. Lexical search still works immediately — semantic search becomes available once the model loads. </Callout> ## Converting Models to GGUF If you find a model on Hugging Face in safetensors or PyTorch format but not GGUF, you can convert it: <Steps> <Step title="Clone the model"> ```bash git clone https://huggingface.co/BAAI/bge-small-en-v1.5 ``` </Step> <Step title="Convert to GGUF"> Use the conversion tools from `llama.cpp` or `ggml`: ```bash python convert-hf-to-gguf.py bge-small-en-v1.5 --outtype f16 ``` </Step> <Step title="Quantize (optional)"> Reduce file size with quantization: ```bash ./quantize bge-small-en-v1.5-f16.gguf bge-small-en-v1.5-q5_k_m.gguf Q5_K_M ``` Quantization levels (smaller = less quality): - **F16** — full precision, largest file - **Q8_0** — near-lossless, ~50% smaller - **Q5_K_M** — good balance, ~65% smaller - **Q4_K_M** — aggressive, ~75% smaller </Step> <Step title="Use in Oxidoc"> <CodeBlock language="toml" filename="oxidoc.toml"> [search] semantic = true model_path = "./models/bge-small-en-v1.5-q5_k_m.gguf" </CodeBlock> </Step> </Steps> <Callout kind="info" title="Embedding models only"> Only convert sentence/embedding models (BERT, BGE, E5, GTE, MiniLM). Do **not** use generative LLMs (GPT, Llama, Mistral) — they don't produce fixed-size embeddings and won't work with Oxidoc's search engine. </Callout> ## Testing Your Model After switching models, test search quality by trying: 1. **Exact term searches** — "oxidoc.toml", "CodeBlock" (should still work via lexical) 2. **Conceptual searches** — "how to change colors" (should find theming page) 3. **Synonym searches** — "setup" (should find installation page) 4. **Your domain terms** — whatever specialized vocabulary your docs use If semantic results are poor, try a larger model or one specifically trained on your domain/language. --- # Embedding Export — Export Embeddings for RAG Pipelines (docs/ai/embedding-export) --- title: "Embedding Export — Export Embeddings for RAG Pipelines " description: "Generate and export documentation embeddings in JSON, JSONL, NumPy, Safetensors, or Parquet format. Build custom RAG chatbots and AI search from your docs." --- # Embedding Export <Badge variant="new">Planned</Badge> <Callout kind="info" title="Coming soon"> This feature is planned but not yet implemented. Track progress at [oxidoc-lab/oxidoc#1](https://github.com/oxidoc-lab/oxidoc/issues/1). </Callout> A standalone command that generates embeddings from your documentation and exports them in standard formats — for RAG pipelines, vector databases, and custom AI tools. Today, embeddings are only generated as part of `oxidoc build` in a JSON format designed for the browser. `oxidoc embed` will make Oxidoc a first-class tool for making documentation AI-ready, with proper export formats and chunking strategies. ## Proposed Usage ```bash # Default: JSON output, one embedding per page oxidoc embed # Choose export format oxidoc embed --format jsonl oxidoc embed --format safetensors oxidoc embed --format npy oxidoc embed --format parquet # Custom output directory oxidoc embed -o embeddings/ # Use a custom embedding model oxidoc embed --model ./models/multilingual-e5-small.gguf # Control chunking granularity oxidoc embed --chunk section # One embedding per heading section oxidoc embed --chunk paragraph # One embedding per paragraph # Combine options oxidoc embed --format jsonl --chunk section --model ./models/custom.gguf -o rag/ ``` ## Export Formats | Format | Extension | Best For | |:-------|:----------|:---------| | JSON | `.json` | Quick inspection, small sites, JavaScript pipelines | | JSONL | `.jsonl` | Streaming ingestion, large sites, line-by-line processing | | NumPy | `.npy` + `.json` | Python ML workflows (`np.load()`) | | Safetensors | `.safetensors` | HuggingFace ecosystem, safe tensor sharing | | Parquet | `.parquet` | Analytics (pandas, polars, DuckDB), columnar queries | ### JSON (default) Same schema as the current `search-vectors.json`, with added model metadata: ```json { "dimension": 384, "model": "bge-micro-v2", "chunk_strategy": "page", "documents": [ { "id": 0, "title": "Installation", "path": "/docs/installation", "text": "Install Oxidoc with a single command...", "anchor": null, "headings": [...] } ], "vectors": [[0.023, -0.041, 0.089, "..."]] } ``` ### JSONL One JSON object per document — streaming-friendly for large doc sites: ```jsonl {"id":0,"title":"Installation","path":"/docs/installation","text":"...","vector":[0.023,-0.041,...]} {"id":1,"title":"Quickstart","path":"/docs/quickstart","text":"...","vector":[0.015,0.089,...]} ``` ### Safetensors A single `.safetensors` file loadable with the HuggingFace `safetensors` Python package: ```python from safetensors import safe_open with safe_open("embeddings.safetensors", framework="numpy") as f: vectors = f.get_tensor("vectors") # (N, 384) float32 # Metadata in tensor attributes ``` ### NumPy Two files: `embeddings.npy` (float32 matrix) + `metadata.json` (document info): ```python import numpy as np import json vectors = np.load("embeddings.npy") # (N, 384) float32 with open("metadata.json") as f: docs = json.load(f)["documents"] ``` ### Parquet Columnar format with all data in one file: ```python import polars as pl df = pl.read_parquet("embeddings.parquet") # Columns: id, title, path, text, anchor, vector (list[f32]) ``` ## Chunking Strategies Control how documents are split before embedding: ### Page (default) One embedding per page. Simple and effective for small-to-medium documentation sites. ### Section Split at heading boundaries (H2, H3). Each section gets its own embedding with an `anchor` field linking directly to that section. Better retrieval granularity for long pages. ```text Page "Configuration" splits into: → "Configuration > Project" (anchor: #project) → "Configuration > Theme" (anchor: #theme) → "Configuration > Routing" (anchor: #routing) → "Configuration > Search" (anchor: #search) ``` ### Paragraph Most granular — each paragraph gets its own embedding. Produces many more vectors but enables precise retrieval. Includes character offset for reconstructing context. ## Use Cases <CardGrid columns="2"> <Card title="RAG Chatbot" icon="🤖"> Embed your docs, store in ChromaDB or Pinecone, and build an "ask the docs" chatbot that answers questions with citations. </Card> <Card title="CI Pipeline" icon="🔄"> Run `oxidoc embed` on every docs commit in CI. Push fresh embeddings to your vector database automatically. </Card> <Card title="Multi-Project Search" icon="🔗"> Combine embeddings from multiple Oxidoc sites into one search index for unified cross-project search. </Card> <Card title="Enterprise Search" icon="🏢"> Feed embeddings into your existing enterprise search infrastructure (Elasticsearch, OpenSearch, Vespa). </Card> </CardGrid> ## Current Workaround Until `oxidoc embed` ships, you can extract embeddings from the build output: ```bash # Build with semantic search enabled oxidoc build # Embeddings are in dist/search-vectors.json cp dist/search-vectors.json ./embeddings.json ``` See [Semantic Search > Embedding Output Format](/docs/search/semantic#embedding-output-format) for the schema and code examples for ingesting this file into vector databases. --- # Oxidoc Skills for AI Agents — Claude, Codex, Cursor (docs/ai/agent-skills) --- title: Oxidoc Skills for AI Agents — Claude, Codex, Cursor description: Ready-made skill files to teach AI coding agents how to use Oxidoc. Works with Claude Code, Codex, Cursor, Windsurf, and any LLM-powered tool that supports the Agent Skills standard. --- # Oxidoc Skills for AI Agents AI coding agents like Claude Code, Codex, and Cursor have no built-in knowledge of Oxidoc. These ready-made skills give them everything they need to create, edit, and build Oxidoc sites. These skills follow the [Agent Skills](https://agentskills.io) open standard — a `SKILL.md` file with YAML frontmatter that works across multiple AI tools. ## How to Use <Tabs> <Tab title="Claude Code"> Save the skill as a `SKILL.md` file inside your skills directory: ```bash # Personal (all projects) mkdir -p ~/.claude/skills/oxidoc # then save as ~/.claude/skills/oxidoc/SKILL.md # Project-scoped mkdir -p .claude/skills/oxidoc # then save as .claude/skills/oxidoc/SKILL.md ``` Claude will automatically load the skill when relevant, or you can invoke it directly with `/oxidoc`. </Tab> <Tab title="Cursor"> Save the skill as a `SKILL.md` file inside the skills directory: ```bash # Project-scoped mkdir -p .cursor/skills/oxidoc # then save as .cursor/skills/oxidoc/SKILL.md # Personal (all projects) mkdir -p ~/.cursor/skills/oxidoc # then save as ~/.cursor/skills/oxidoc/SKILL.md ``` Also discovers skills from `.agents/skills/` and `.claude/skills/`. </Tab> <Tab title="Codex"> Save the skill as a `SKILL.md` file inside the `.agents/skills/` directory: ```bash # Project-scoped mkdir -p .agents/skills/oxidoc # then save as .agents/skills/oxidoc/SKILL.md # Personal (all repos) mkdir -p ~/.agents/skills/oxidoc # then save as ~/.agents/skills/oxidoc/SKILL.md ``` Codex automatically detects skill changes — no restart needed. </Tab> <Tab title="Windsurf"> Save the skill as a `SKILL.md` file inside the skills directory: ```bash # Project-scoped mkdir -p .windsurf/skills/oxidoc # then save as .windsurf/skills/oxidoc/SKILL.md # Personal (all workspaces) mkdir -p ~/.codeium/windsurf/skills/oxidoc # then save as ~/.codeium/windsurf/skills/oxidoc/SKILL.md ``` Also discovers skills from `.agents/skills/` and `.claude/skills/`. </Tab> <Tab title="Other"> Most AI coding agents that support the [Agent Skills](https://agentskills.io) standard use `.agents/skills/` as the common directory: ```bash mkdir -p .agents/skills/oxidoc # then save as .agents/skills/oxidoc/SKILL.md ``` For tools without skills support, paste the content into the system prompt or project instructions. </Tab> </Tabs> ## Full Oxidoc Skill This single skill covers the CLI, RDX syntax, configuration, and components. For most projects, this is all you need. <Accordion title="Full Oxidoc Skill — click to expand"> <CodeBlock language="markdown" filename="SKILL.md"> --- name: oxidoc description: Complete guide to the Oxidoc documentation engine — CLI, RDX content format, components, configuration, theming, and project structure. Use when creating, editing, configuring, or building Oxidoc documentation sites. --- # Oxidoc Documentation Engine ## Overview Oxidoc generates static documentation sites from `.rdx` files (Markdown with embedded components). Single Rust binary, zero Node.js dependency. **Keywords**: oxidoc, documentation, static site, rdx, components, configuration, theming, CLI, build ## CLI ``` oxidoc init [name] New project (-f force, -y skip prompts) oxidoc dev [-p port] Dev server + hot reload (default: 3000) oxidoc build [-o dir] Production build (default: dist/) oxidoc clean Remove .oxidoc-dev/ and dist/ oxidoc archive create|list|delete <ver> Version snapshots oxidoc update [--pre] Update binary oxidoc set-version <ver> Pin specific version ``` Global flags: `-C <path>` project dir, `-v` verbose, `-q` quiet. ## RDX Content Format Files use `.rdx` extension (NOT `.md` or `.mdx`). YAML frontmatter + Markdown + components. ### Frontmatter Every `.rdx` page requires `title` and `description`: ```yaml --- title: Page Title description: Meta description for SEO (150-160 chars) layout: landing # Optional: full-width, no sidebar — for landing/marketing pages --- ``` ### Components All components use PascalCase. **Code blocks**: Always prefer native fenced code blocks (` ```lang `) over `<CodeBlock>`. Only use the `<CodeBlock>` component when you need the `filename`, `highlight`, or `line_numbers` props. | Component | Usage | |-----------|-------| | Callout | `<Callout kind="info\|warning\|error\|tip" title="T">text</Callout>` (aliases: `error`=`danger`, `tip`=`success`) | | Tabs | `<Tabs><Tab title="A">content</Tab><Tab title="B">content</Tab></Tabs>` | | CodeBlock | `<CodeBlock language="rust" filename="main.rs" highlight="2">code</CodeBlock>` (only when you need filename/highlight/line_numbers) | | Accordion | `<Accordion title="Label">hidden content</Accordion>` | | CardGrid | `<CardGrid><Card title="T" icon="icon" href="/url">desc</Card></CardGrid>` | | Steps | `<Steps><Step title="First">content</Step></Steps>` | | Badge | `<Badge variant="new\|deprecated\|tip\|warning\|danger">label</Badge>` | | Tag | `<Tag variant="new\|experimental\|deprecated">label</Tag>` | | Tooltip | `<Tooltip text="Explanation">hover text</Tooltip>` | | Banner | `<Banner id="unique" persist="none\|session\|forever">text</Banner>` | | ThemedImage | `<ThemedImage light="/l.png" dark="/d.png" alt="Alt" />` | | Head | `<Head><meta property="og:image" content="/img.png"></Head>` | | Mermaid | Use fenced code block with `mermaid` language | ### Landing Page Components Set `layout: landing` in frontmatter (full-width, no sidebar), then use: | Component | Usage | |-----------|-------| | Hero | `<Hero title="Name"><HeroAction label="CTA" href="/url" variant="primary\|secondary" />Tagline.</Hero>` | | Section | `<Section bg="muted">content</Section>` | | FeatureGrid | `<FeatureGrid><Feature icon="icon" title="T">desc</Feature></FeatureGrid>` | | CTA | `<CTA title="T" description="D"><HeroAction label="Go" href="/url" variant="primary" /></CTA>` | | TestimonialGrid | `<TestimonialGrid><Testimonial name="N" role="R">quote</Testimonial></TestimonialGrid>` | ## Configuration (oxidoc.toml) ### Required ```toml [project] name = "Project Name" [routing.root] homepage = "home.rdx" [routing] navigation = [ { path = "/docs", dir = "docs", groups = [ { group = "Getting Started", pages = ["quickstart", "guide"] }, ] }, ] ``` ### All Sections | Section | Key fields | |---------|------------| | `[project]` | name, description, logo, favicon, base_url, edit_url, edit_label | | `[theme]` | primary, accent, font, code_font, dark_mode (`"system"\|"light"\|"dark"`), custom_css | | `[routing.root]` | homepage, pages | | `[routing]` | header_links `[{label, href}]`, navigation `[{path, dir, groups, openapi}]` | | `[search]` | provider (`"oxidoc"\|"algolia"\|"typesense"\|"meilisearch"\|"custom"`), semantic | | `[versioning]` | default, versions | | `[i18n]` | default_locale, locales, translation_dir | | `[footer]` | copyright_owner, copyright_owner_url, links `[{label, href}]` | | `[social]` | github, discord, twitter, mastodon | | `[analytics]` | google_analytics, script | | `[redirects]` | redirects `[{from, to}]` | | `[components.custom]` | `TagName = "path/to/file.js"` | | `[attribution]` (bool, default true) | ### Navigation Rules - `path` = URL prefix (e.g., `"/docs"`), `dir` = content directory containing `.rdx` files - `pages` = list of slugs — the filename without `.rdx` (e.g., `"quickstart"` → `docs/quickstart.rdx`) - `groups` = sidebar sections with `group` (display title) and `pages` (slug list) - `openapi` = path to an OpenAPI/Swagger spec file — Oxidoc auto-generates interactive API reference pages from it - Pages only appear in the sidebar if listed in a navigation group - Nested slugs: `"guides/styling"` maps to `docs/guides/styling.rdx` ## Theming ### Quick theming via oxidoc.toml Set colors and fonts in `[theme]`. For deeper customization, create a CSS file and register it: ```toml [theme] primary = "#3b82f6" accent = "#f59e0b" dark_mode = "system" # controls toggle: "system", "light", or "dark" custom_css = ["assets/custom.css"] # path relative to project root ``` The CSS file goes in `assets/` (e.g., `assets/custom.css`). Everything in `assets/` is copied to `dist/` on build. ### CSS variable overrides All built-in styles use `@layer oxidoc`, so your custom CSS always wins — no `!important` needed. Override variables in `:root` (or scope to dark mode with `[data-theme="dark"]`): ```css /* assets/custom.css */ :root { --oxidoc-primary: #2563eb; --oxidoc-accent: #f59e0b; } [data-theme="dark"] { --oxidoc-primary: #3b82f6; } ``` | Category | Variables | |----------|-----------| | Core | `--oxidoc-primary`, `--oxidoc-accent`, `--oxidoc-bg`, `--oxidoc-bg-secondary`, `--oxidoc-text`, `--oxidoc-text-secondary`, `--oxidoc-border`, `--oxidoc-code-bg` | | Semantic | `--oxidoc-success`, `--oxidoc-warning`, `--oxidoc-error`, `--oxidoc-info`, `--oxidoc-new`, `--oxidoc-deprecated` (each has `-text` variant) | | Typography | `--oxidoc-font-sans`, `--oxidoc-font-mono` | | Layout | `--oxidoc-content-max` (48rem), `--oxidoc-sidebar-width` (16rem), `--oxidoc-toc-width` (14rem), `--oxidoc-header-height` (3.5rem) | ## Project Structure ``` project/ ├── oxidoc.toml # Site configuration (required) ├── home.rdx # Landing page (layout: landing) ├── assets/ # Static files — copied as-is to dist/ on build │ ├── logo.svg # referenced in config as "/assets/logo.svg" │ └── custom.css # registered via [theme] custom_css ├── docs/ # Content directory (matches routing dir) │ ├── intro.rdx # slug: "intro" │ └── advanced/ │ └── plugins.rdx # slug: "advanced/plugins" └── i18n/ # Translation files (if i18n enabled) └── en.ftl ``` ## Build Output `oxidoc build` produces in `dist/`: static HTML, Wasm islands, search index, sitemap.xml, robots.txt, feed.xml, llms.txt, llms-full.txt. </CodeBlock> </Accordion> ## Skill: RDX Content Writer Focused on writing `.rdx` content pages. Use this when you only need the agent to create or edit documentation content, not configure the site. <Accordion title="RDX Content Writer Skill — click to expand"> <CodeBlock language="markdown" filename="SKILL.md"> --- name: rdx-content-writer description: Write and edit RDX content pages for Oxidoc — covers frontmatter, Markdown, embedded components, and SEO. Use when creating or editing .rdx documentation files. --- # RDX Content Writing ## Overview RDX files are Markdown with YAML frontmatter and embedded components. Extension: `.rdx` (NOT `.md` or `.mdx`). **Keywords**: rdx, content, markdown, components, frontmatter, SEO, documentation pages ## Frontmatter Every `.rdx` page requires `title` and `description`: ```yaml --- title: Page Title — Descriptive Hook | Brand description: 150-160 char meta description with action verb and CTA. layout: landing # Optional: full-width, no sidebar — for landing/marketing pages --- ``` ## Components All components use PascalCase. **Code blocks**: Always prefer native fenced code blocks (` ```lang `) over `<CodeBlock>`. Only use the `<CodeBlock>` component when you need the `filename`, `highlight`, or `line_numbers` props. | Component | Usage | |-----------|-------| | Callout | `<Callout kind="info\|warning\|error\|tip" title="T">text</Callout>` (aliases: `error`=`danger`, `tip`=`success`) | | Tabs | `<Tabs><Tab title="A">content</Tab></Tabs>` | | CodeBlock | `<CodeBlock language="rust" filename="main.rs" highlight="2">code</CodeBlock>` (only when you need filename/highlight/line_numbers) | | Accordion | `<Accordion title="Label">hidden content</Accordion>` | | CardGrid | `<CardGrid><Card title="T" icon="icon" href="/url">desc</Card></CardGrid>` | | Steps | `<Steps><Step title="First">content</Step></Steps>` | | Badge | `<Badge variant="new\|deprecated\|tip\|warning\|danger">label</Badge>` | | Tag | `<Tag variant="new\|experimental\|deprecated">label</Tag>` | | Tooltip | `<Tooltip text="Explanation">hover text</Tooltip>` | | Banner | `<Banner id="unique" persist="none\|session\|forever">text</Banner>` | | ThemedImage | `<ThemedImage light="/l.png" dark="/d.png" alt="Alt" />` | | Head | `<Head><meta property="og:image" content="/img.png"></Head>` | | Mermaid | Use fenced code block with `mermaid` language | ## SEO Rules - **Title**: under 60 chars, front-load keyword, format `Primary — Hook | Brand` - **Description**: 150-160 chars, action verb, unique per page - First paragraph is auto-extracted as meta description (max 160 chars) - Every page must have unique title and description ## Markdown Standard Markdown: headings (#-######), bold, italic, links, images, lists, tables, code blocks, blockquotes, horizontal rules. Headings auto-generate anchor links. </CodeBlock> </Accordion> ## Skill: Oxidoc CLI Operator For CI/CD automation or when the agent needs to run Oxidoc commands. <Accordion title="CLI Operator Skill — click to expand"> <CodeBlock language="markdown" filename="SKILL.md"> --- name: oxidoc-cli description: Run Oxidoc CLI commands — init, dev, build, clean, archive, update. Use for CI/CD automation, local development, or any task requiring Oxidoc command execution. --- # Oxidoc CLI ## Overview Single Rust binary, no runtime dependencies. Install with `curl -fsSL https://oxidoc.dev/install.sh | sh`. **Keywords**: oxidoc, CLI, build, dev server, init, deploy, CI/CD, install ## Commands ``` oxidoc init [name] New project (-f force, -y skip prompts) oxidoc dev [-p port] Dev server + hot reload (default: 3000) oxidoc build [-o dir] Production build (default: dist/) oxidoc clean Remove .oxidoc-dev/ and dist/ oxidoc archive create|list|delete <ver> Version snapshots oxidoc update [--pre] Update binary oxidoc set-version <ver> Pin specific version ``` Global flags: `-C <path>` project dir, `-v` verbose, `-q` quiet. ## CI/CD (GitHub Actions) ```yaml - run: curl -fsSL https://oxidoc.dev/install.sh | sh - run: oxidoc build ``` ## Build Output `oxidoc build` produces a fully static site in `dist/`: HTML, CSS, JS, Wasm islands, search index, sitemap.xml, robots.txt, feed.xml, llms.txt. Serve with any static host. </CodeBlock> </Accordion> ## Skill: Oxidoc Site Configurator For when the agent needs to set up or modify `oxidoc.toml`. <Accordion title="Site Configurator Skill — click to expand"> <CodeBlock language="markdown" filename="SKILL.md"> --- name: oxidoc-configurator description: Set up and modify oxidoc.toml — covers all configuration sections including project, theme, routing, search, versioning, i18n, and analytics. Use when configuring an Oxidoc documentation site. --- # Oxidoc Configuration (oxidoc.toml) ## Overview All site configuration lives in `oxidoc.toml` at the project root. **Keywords**: oxidoc.toml, configuration, routing, navigation, search, versioning, i18n, theme, footer, social, analytics ## Minimal Config ```toml [project] name = "My Docs" [routing.root] homepage = "home.rdx" [routing] navigation = [ { path = "/docs", dir = "docs", groups = [ { group = "Guide", pages = ["intro", "quickstart"] }, ] }, ] ``` ## All Sections | Section | Key fields | |---------|------------| | `[project]` | name (required), description, logo, favicon, base_url, edit_url, edit_label | | `[theme]` | primary, accent, font, code_font, dark_mode (`"system"\|"light"\|"dark"`), custom_css | | `[routing.root]` | homepage, pages | | `[routing]` | header_links `[{label, href}]`, navigation `[{path, dir, groups, openapi}]` | | `[search]` | provider (`"oxidoc"\|"algolia"\|"typesense"\|"meilisearch"\|"custom"`), semantic | | `[versioning]` | default, versions | | `[i18n]` | default_locale, locales, translation_dir | | `[footer]` | copyright_owner, copyright_owner_url, links `[{label, href}]` | | `[social]` | github, discord, twitter, mastodon | | `[analytics]` | google_analytics, script | | `[redirects]` | redirects `[{from, to}]` | | `[components.custom]` | `TagName = "path/to/file.js"` | | `[attribution]` (bool, default true) | ### Search Providers - **Oxidoc** (default): zero-config BM25, optional `semantic = true` - **Algolia**: app_id, api_key, index_name - **Typesense**: host, port, protocol, api_key, collection_name - **Meilisearch**: host, api_key, index_name - **Custom**: stylesheet, script, init_script ## Navigation Rules - `path` = URL prefix (e.g., `"/docs"`), `dir` = content directory containing `.rdx` files - `pages` = list of slugs — the filename without `.rdx` (e.g., `"quickstart"` → `docs/quickstart.rdx`) - `groups` = sidebar sections with `group` (display title) and `pages` (slug list) - `openapi` = path to OpenAPI/Swagger spec — auto-generates interactive API reference pages - Pages only appear in sidebar if listed in a navigation group - Nested slugs: `"guides/styling"` maps to `docs/guides/styling.rdx` </CodeBlock> </Accordion> ## Skill: Oxidoc Theme Customizer For when the agent needs to customize the visual design. <Accordion title="Theme Customizer Skill — click to expand"> <CodeBlock language="markdown" filename="SKILL.md"> --- name: oxidoc-theme description: Customize Oxidoc's visual design — theme config in oxidoc.toml, CSS custom properties, dark mode overrides, and layout tokens. Use when styling or theming an Oxidoc documentation site. --- # Oxidoc Theming ## Overview Oxidoc uses CSS custom properties (`--oxidoc-*`) for all visual styling. All built-in styles use `@layer oxidoc`, so your custom CSS always wins without `!important`. **Keywords**: theme, CSS variables, dark mode, colors, typography, layout, custom CSS, styling, branding ## Quick Theming (oxidoc.toml) Set colors, fonts, and dark mode toggle behavior in `[theme]`: ```toml [theme] primary = "#3b82f6" # Primary brand color accent = "#f59e0b" # Accent color for highlights font = "Inter, sans-serif" code_font = "JetBrains Mono, monospace" dark_mode = "system" # "system" (follows OS), "light", or "dark" custom_css = ["assets/custom.css"] # paths relative to project root ``` ## Custom CSS Setup 1. Create a CSS file in `assets/` (e.g., `assets/custom.css`) — this directory is copied to `dist/` on build 2. Register it in `oxidoc.toml` via `custom_css = ["assets/custom.css"]` 3. Override any `--oxidoc-*` variable in `:root` or scope to dark mode with `[data-theme="dark"]` All built-in styles use `@layer oxidoc`, so your CSS always wins — no `!important` needed. ```css /* assets/custom.css */ :root { --oxidoc-primary: #2563eb; --oxidoc-font-sans: "My Font", sans-serif; } [data-theme="dark"] { --oxidoc-primary: #3b82f6; } ``` ## CSS Variables Reference | Category | Variables | |----------|-----------| | Core | `--oxidoc-primary`, `--oxidoc-accent`, `--oxidoc-bg`, `--oxidoc-bg-secondary`, `--oxidoc-text`, `--oxidoc-text-secondary`, `--oxidoc-border`, `--oxidoc-code-bg` | | Semantic | `--oxidoc-success`, `--oxidoc-warning`, `--oxidoc-error`, `--oxidoc-info`, `--oxidoc-new`, `--oxidoc-deprecated` (each has `-text` variant) | | Utility | `--oxidoc-text-muted`, `--oxidoc-bg-subtle`, `--oxidoc-on-primary`, `--oxidoc-shadow`, `--oxidoc-overlay` | | Typography | `--oxidoc-font-sans`, `--oxidoc-font-mono` | | Layout | `--oxidoc-content-max` (48rem), `--oxidoc-sidebar-width` (16rem), `--oxidoc-toc-width` (14rem), `--oxidoc-header-height` (3.5rem) | | Radius | `--oxidoc-radius-sm`, `--oxidoc-radius-md`, `--oxidoc-radius-lg` | | Shadows | `--oxidoc-shadow-sm`, `--oxidoc-shadow-md`, `--oxidoc-shadow-lg` | | Z-index | `--oxidoc-z-tooltip` (10), `z-back-to-top` (50), `z-sidebar` (90), `z-header` (100), `z-skip-nav` (200), `z-overlay` (1000) | | Transitions | `--oxidoc-transition-fast`, `--oxidoc-transition-normal`, `--oxidoc-transition-slow`, `--oxidoc-transition-spring` | ## Dark Mode The `dark_mode` setting in `oxidoc.toml` controls the toggle behavior (system/light/dark). To customize dark mode colors, override CSS variables under `[data-theme="dark"]` in your custom CSS file. Primary shades auto-generate via `color-mix()` — you only need to set the base color. </CodeBlock> </Accordion> ## Combining Skills You can install multiple skills side by side. In Claude Code, each goes in its own directory under `.claude/skills/`. For other tools, combine the skill contents in a single config file. For most projects, the **Full Oxidoc Skill** is all you need. Use the focused skills when you want to keep the agent's context lean. <Callout kind="tip" title="Keep it updated"> When you upgrade Oxidoc, check this page for updated skill files. New components and config options get added to the skills as they ship. </Callout> --- # Deployment — Deploy Your Docs Site (docs/deployment) --- title: Deployment — Deploy Your Docs Site description: Deploy your Oxidoc site to any static host. Step-by-step guides for GitHub Pages, Vercel, and Netlify with CI/CD configuration. --- # Deployment Oxidoc generates a fully static site in the `dist/` directory. Run the build command: ```bash oxidoc build ``` This produces a `dist/` folder with all HTML, CSS, JS, and Wasm files ready to serve. Deploy it to any static hosting provider. <CardGrid> <Card title="GitHub Pages" icon="🐙" href="/docs/deployment/github-pages"> Free hosting for public repos with GitHub Actions CI/CD. </Card> <Card title="Vercel" icon="▲" href="/docs/deployment/vercel"> Instant deployments with preview URLs for every pull request. </Card> <Card title="Netlify" icon="🌐" href="/docs/deployment/netlify"> Continuous deployment with branch previews and form handling. </Card> </CardGrid> --- # Deploy to GitHub Pages — Free Hosting with CI/CD (docs/deployment/github-pages) --- title: Deploy to GitHub Pages — Free Hosting with CI/CD description: Deploy your Oxidoc site to GitHub Pages with GitHub Actions. Free hosting, automatic builds on push, and custom domain support. --- # GitHub Pages GitHub Pages is free for public repositories and supports custom domains. It integrates directly with GitHub Actions for automated deployments. <Steps> <Step title="Create a GitHub Actions workflow"> Create `.github/workflows/deploy.yml` in your repository: <CodeBlock language="yaml" filename=".github/workflows/deploy.yml"> name: Deploy to GitHub Pages on: push: branches: [main] permissions: contents: read pages: write id-token: write concurrency: group: "pages" cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Install Oxidoc run: curl -fsSL https://oxidoc.dev/install.sh | sh - name: Build site run: oxidoc build - name: Upload artifact uses: actions/upload-pages-artifact@v4 with: path: dist deploy: needs: build runs-on: ubuntu-latest environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 </CodeBlock> </Step> <Step title="Enable GitHub Pages"> Go to your repository **Settings > Pages**. Under **Source**, select **GitHub Actions**. </Step> <Step title="Push and deploy"> Push to `main` and the workflow will build and deploy your site automatically. </Step> </Steps> <Callout kind="tip" title="Custom domain"> To use a custom domain, add a `CNAME` file in your `assets/` directory with your domain name. Oxidoc copies everything in `assets/` to the output, so it will end up in `dist/` automatically. </Callout> <Callout kind="info" title="Base URL"> If your site is hosted at a subpath (e.g., `https://user.github.io/repo-name/`), set `base_url` in your `oxidoc.toml`: <CodeBlock language="toml" filename="oxidoc.toml"> [project] base_url = "https://user.github.io/repo-name" </CodeBlock> </Callout> --- # Deploy to Vercel — Instant Deploys with Preview URLs (docs/deployment/vercel) --- title: Deploy to Vercel — Instant Deploys with Preview URLs description: Deploy your Oxidoc site to Vercel. Instant deployments, preview URLs for pull requests, and zero-config build setup. --- # Vercel Vercel provides instant deployments with preview URLs for every pull request. <Steps> <Step title="Import your repository"> Go to [vercel.com](https://vercel.com), click **Add New Project**, and import your GitHub repository. </Step> <Step title="Configure build settings"> Set the following in the project settings: | Setting | Value | |:--------|:------| | **Build Command** | `curl -fsSL https://oxidoc.dev/install.sh | sh && oxidoc build` | | **Output Directory** | `dist` | | **Install Command** | _(leave empty)_ | </Step> <Step title="Deploy"> Click **Deploy**. Vercel will build and deploy your site. Every push to `main` triggers a production deploy, and pull requests get preview URLs. </Step> </Steps> <Callout kind="info" title="Build cache"> The install script downloads a pre-built binary, so builds are fast without any compilation step. </Callout> --- # Deploy to Netlify — Continuous Deployment with Previews (docs/deployment/netlify) --- title: Deploy to Netlify — Continuous Deployment with Previews description: Deploy your Oxidoc site to Netlify. Continuous deployment from Git, branch previews, and configuration via netlify.toml. --- # Netlify Netlify offers continuous deployment with branch previews and form handling. <Steps> <Step title="Connect your repository"> Go to [netlify.com](https://netlify.com), click **Add new site > Import an existing project**, and select your repository. </Step> <Step title="Configure build settings"> Set the following: | Setting | Value | |:--------|:------| | **Build Command** | `curl -fsSL https://oxidoc.dev/install.sh | sh && oxidoc build` | | **Publish Directory** | `dist` | </Step> <Step title="Deploy"> Click **Deploy site**. Netlify builds and deploys on every push. Branch deploys and deploy previews are enabled by default. </Step> </Steps> <Callout kind="tip" title="netlify.toml"> You can also configure builds with a `netlify.toml` file in your repository root: <CodeBlock language="toml" filename="netlify.toml"> [build] command = "curl -fsSL https://oxidoc.dev/install.sh | sh && oxidoc build" publish = "dist" </CodeBlock> </Callout>