Skip to content

Commit 24546ad

Browse files
committed
Add .agents/SKILL.md — authoring guide for HTML docs
1 parent b5dae6a commit 24546ad

1 file changed

Lines changed: 94 additions & 0 deletions

File tree

.agents/SKILL.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
name: obsidian-html-docs
3+
description: Author HTML files for the Obsidian HTML Docs plugin (smcllns/obsidian-plugin-html-docs). Use when creating .html docs intended to render inline in Obsidian — covers the context the plugin provides, sandbox constraints, asset rules, and the things that silently don't work.
4+
---
5+
6+
# Obsidian HTML Docs — authoring guide
7+
8+
The plugin enables the user to view html files inside Obsidian, similar to md files. The plugin renders `.html` in a sandboxed iframe via Blob URL. The iframe is sealed (`sandbox="allow-scripts allow-popups allow-forms"`, no `allow-same-origin`) so it can't reach into Obsidian or the vault. Everything below works within that envelope.
9+
10+
## Default to Obsidian's context — unless asked otherwise
11+
12+
Before sealing the iframe, the plugin can prepend a `<style>` block to your HTML containing a snapshot of the user's current Obsidian design tokens. The iframe doesn't reach out for these values — they're written as static CSS into your document at load time, then the sandbox is applied. **Security boundary unchanged** (no `allow-same-origin`, no reads from the iframe back into Obsidian); the iframe just has a few extra CSS variables declared in its own document.
13+
14+
If the user just wants a styled doc that "fits" their vault, use these as your defaults. If they're asking for a specific aesthetic (brutalist poster, retro terminal, Linear-style, an exact brand palette), design freely — Obsidian context is a *hint*, not a constraint.
15+
16+
**Injected as static CSS** (proposed plugin enhancement; today only `color-scheme: light dark` via OS preference works):
17+
18+
- A `color-scheme: light | dark` declaration matching the user's current Obsidian theme
19+
- A small set of `--obsidian-*` CSS variables holding snapshot values from the user's active Obsidian theme: `--obsidian-bg`, `--obsidian-bg-2`, `--obsidian-text`, `--obsidian-text-muted`, `--obsidian-accent`, `--obsidian-border`, `--obsidian-font`, `--obsidian-font-mono`
20+
21+
**Graceful pattern** — use Obsidian tokens if present, fall back if not:
22+
23+
```css
24+
:root {
25+
color-scheme: light dark;
26+
--bg: var(--obsidian-bg, light-dark(#ffffff, #0e1014));
27+
--text: var(--obsidian-text, light-dark(#16161a, #e7e9ec));
28+
}
29+
```
30+
31+
Today this CSS already follows OS light/dark via `prefers-color-scheme`. Once the plugin ships theme injection, the snapshot reflects the user's exact Obsidian theme — including custom themes and snippets — and your variable fallbacks resolve to those values automatically. No code change needed on the HTML side.
32+
33+
## Assets — vault paths do NOT cross into the iframe
34+
35+
The iframe has no base URL pointing into the vault. Obsidian themes, snippets, and `attachments/...` images don't reach the iframe.
36+
37+
| Pattern | Works? |
38+
|---|---|
39+
| `<img src="attachments/foo.png">` | No — fails silently |
40+
| `<img src="data:image/png;base64,...">` | Yes — fully self-contained |
41+
| `<img src="https://example.com/foo.png">` | Yes — CORS permitting |
42+
| Inline `<svg>...</svg>` | Yes — best for icons / diagrams |
43+
| `<link rel="stylesheet" href="https://cdn...">` | Yes — HTTPS only |
44+
45+
Rules of thumb:
46+
47+
- Small graphics & icons → inline SVG or `data:` URL
48+
- Photos / large images → upload to a host (R2, CDN) and reference HTTPS
49+
- Fonts → system stack, or HTTPS CDN
50+
- Never reference `attachments/` or any vault path — the iframe can't see them
51+
52+
## What works
53+
54+
- HTML / CSS (grid, `light-dark()`, custom properties, animations, gradients, SVG with CSS animations)
55+
- JavaScript (ES2020+, fetch with CORS, Promises, DOM events, requestAnimationFrame, Canvas 2D)
56+
- Forms (`allow-forms` is set; intercept `submit` if you don't want navigation)
57+
- `window.parent.postMessage(msg, '*')` — works even with opaque origin
58+
- External HTTPS resources (images, fonts on CDNs, fetch APIs that allow CORS)
59+
- Anchor links (`#section`) and the History API — Blob URL preserves both
60+
61+
## What's blocked
62+
63+
- `localStorage`, `sessionStorage`, `IndexedDB``SecurityError`
64+
- `document.cookie` — throws or silently no-ops
65+
- Reading `window.parent.*` — cross-origin (postMessage still works)
66+
- Service workers, geolocation, clipboard, notifications, most permission-gated APIs
67+
- Top-level navigation from inside the iframe (no `allow-top-navigation`)
68+
- Vault-relative URLs (see Assets above)
69+
70+
## Linking from markdown to HTML
71+
72+
Wikilinks to `.html` files need the explicit extension:
73+
74+
```markdown
75+
See: [[my-doc.html]]
76+
```
77+
78+
`[[my-doc]]` won't resolve to `.html` in stock Obsidian.
79+
80+
## Embed sizing
81+
82+
```markdown
83+
![[doc.html|width=600 height=400]]
84+
```
85+
86+
Sets `--html-docs-width` / `--html-docs-height` on the embed container. Default embed height is ~600px; tab views fill the pane.
87+
88+
## Pitfalls (skip the turn cost)
89+
90+
- **Theme scripts that read `window.parent`** — always throw under this plugin's sandbox. Don't write them.
91+
- **Images via `attachments/foo.png`** — won't resolve. Inline as data URL or use HTTPS.
92+
- **`localStorage` / cookies for state** — blocked. Use URL hash or postMessage to parent.
93+
- **Hard-coding a palette when Obsidian tokens are available** — defeats the contextual fit. Use `var(--obsidian-*)` with `light-dark()` fallbacks.
94+
- **Assuming `prefers-color-scheme` == Obsidian theme** — usually true, sometimes not. Once the plugin ships theme injection, this is fully resolved.

0 commit comments

Comments
 (0)