blogs/CONTENT_BRIDGE.md
Neeldhara Misra 7aa1fd2372
Some checks are pending
Build / build (push) Waiting to run
Improve callouts and symbol publishing
2026-06-25 15:48:33 +05:30

12 KiB

Blog Content Bridge

The public Obsidian vault is the writing source of truth. The Astro sites are deployable targets that receive copied Markdown and assets.

Folder Map

Vault folder Astro content folder Public domain
blogs/01-research sites/research/src/content/research https://research.neeldhara.blog
blogs/02-vibes sites/vibes/src/content/vibes https://vibes.neeldhara.blog
blogs/03-puzzles sites/puzzles/src/content/puzzles https://puzzles.neeldhara.blog
blogs/04-reflections sites/reflections/src/content/reflections https://reflections.neeldhara.blog
blogs/05-poetry sites/poetry/src/content/poetry https://poetry.neeldhara.blog
blogs/06-reviews sites/reviews/src/content/reviews https://reviews.neeldhara.blog
blogs/07-art sites/art/src/content/art https://art.neeldhara.blog
blogs/micro ../micro/src/content/blog https://micro.neeldhara.blog

The installed Obsidian plugin lives at:

/Users/neeldhara/obsidian/public/.obsidian/plugins/microblog-sync

The versioned copy lives in this repo at:

obsidian-plugin/microblog-sync

The plugin id remains microblog-sync, but Obsidian shows it as Blog Family Sync.

Post Layout

Use one folder per post:

blogs/01-research/example-post/index.md
blogs/01-research/example-post/diagram.png

The folder path becomes the public URL:

blogs/01-research/example-post/index.md
https://research.neeldhara.blog/example-post/

Nested folders are supported:

blogs/04-reflections/exportober/2021/index.md
https://reflections.neeldhara.blog/exportober/2021/

Frontmatter

Every public post needs the fields required by the Astro content schema:

---
title: "Post title"
description: "One or two sentence summary for cards and RSS."
pubDate: "2024-05-10"
authorName: "Neeldhara"
---

Optional fields currently understood by the sites include updatedDate, image, and authorImage. Prefer colocated images in the body over remote stock images.

Use main-feature: true on at most one post per blog to pin a fixed featured post on the neeldhara.blog homepage. The homepage still shows the two newest non-featured posts for that blog, sorted by pubDate.

The Quarto import also preserved sourceCategories and sourcePath. Astro strips unknown schema fields, but they are useful in Obsidian for provenance.

Markdown Conventions

Standard Markdown headings, lists, links, tables, code fences, footnotes, and raw HTML are preserved.

Use colocated relative assets:

![Caption](image.png)

Quarto image attributes such as {width=70%} were removed during import. Going forward, use normal Markdown and let Astro CSS handle presentation.

Callouts

Write callouts as portable blockquotes. This is the canonical form:

> **Note**
>
> Text of the callout.

Supported labels are Note, Tip, Warning, Caution, and Aside:

> **Warning**
>
> This point needs attention.

Obsidian-style labels also work:

> [!tip]
> This is a tip.

For quick writing, a few leading emoji markers are recognized and stripped:

> 📝 This becomes a note.
> 💡 This becomes a tip.
> ⚡ This also becomes a tip.
> ⚠️ This becomes a warning.

In Astro these render as <aside class="callout callout-note">, etc. In the PDF pipeline they render as pastel tcolorbox blocks:

note    -> blognotebox
tip     -> blogtipbox
warning -> blogwarningbox
caution -> blogcautionbox
aside   -> blogasidebox

The LaTeX boxes use tcolorbox with the breakable and enhanced libraries, a light tinted background, a thin frame, a stronger left rule, and a small attached title label. This follows the same design vocabulary as the DM book callouts: compact colored boxes that can split across pages without becoming visually heavy.

Quarto margin notes such as [text]{.aside} were converted to:

> **Aside:** text

Emoji And Symbol Text

Write emoji, chess pieces, and card suits directly in Markdown:

I like this move: ♘f3. Hearts and diamonds are red: ♥ ♦. Spades and clubs are black: ♠ ♣.
This reminder is visible in both outputs: 🎯

Astro wraps these glyphs in small semantic spans so they get stable font fallbacks and accessible labels:

<span class="symbol symbol-chess" data-symbol="white-knight" aria-label="white knight"></span>
<span class="symbol symbol-card" data-symbol="heart" aria-label="heart"></span>
<span class="symbol symbol-emoji">🎯</span>

The PDF pipeline maps the same characters to LaTeX macros:

emoji and emoji sequences -> \BlogEmojiText{...} using the emoji package
♔ ♕ ♖ ♗ ♘ ♙       -> \BlogChessWhite{\symking}, etc. using chessfss
♚ ♛ ♜ ♝ ♞ ♟       -> \BlogChessBlack{\symking}, etc. using chessfss
♥ ♡ ♦ ♢           -> red \heartsuit / \diamondsuit via amssymb + xcolor
♠ ♤ ♣ ♧           -> black \spadesuit / \clubsuit via amssymb + xcolor
playing-card emoji -> \BlogEmojiText{...}

Use Unicode characters in the source. Do not write LaTeX-only symbols in posts unless the post is PDF-only, because raw LaTeX will not generally survive the HTML path.

Semantic Blocks

Use Pandoc-style fenced attributes for blocks that need to render differently in HTML and PDF. This is the preferred form because it works cleanly with both Astro and Pandoc/LuaLaTeX.

Interactive Blocks

An interactive block reserves a place in the post for a React component and also supplies fallback text for PDF or non-JavaScript rendering:

```{.interactive #int:tape-layout caption="Tape layout explorer"}
Drag files along a tape and compare the access cost of each arrangement.
```

The id after # is the semantic label. For interactives, use the int: prefix. The component id is inferred by removing that prefix, so the example above mounts this component when it exists:

sites/<blog>/src/interactives/tape-layout/index.tsx

The component receives:

{
  id: "tape-layout",
  label: "int:tape-layout",
  caption: "Tape layout explorer",
  description: "Drag files along a tape...",
  fallback: "Drag files along a tape...",
  attrs: { caption: "Tape layout explorer" }
}

If the component is not present, Astro renders the fallback text in the interactive frame. For a different PDF fallback, add pdf="...":

```{.interactive #int:tape-layout caption="Tape layout explorer" pdf="The HTML version contains an interactive tape layout explorer."}
Implementation notes for the interactive can go here.
```

Astro also accepts the shorter Obsidian-friendly form:

```interactive id="tape-layout" caption="Tape layout explorer"
Drag files along a tape and compare the access cost.
```

Use the Pandoc-style form for posts that should export to PDF.

LaTeX-Style Environments

Use .env plus the environment class and a label:

```{.env .theorem #thm:hall title="Hall's theorem" html="callout"}
Every bipartite graph satisfying Hall's condition has a matching that covers
the left side.
```

Supported environment types are:

theorem, lemma, proposition, corollary, definition, example, remark, proof

In Astro, html="callout" renders the block like a callout. html="plain" renders it as a quieter left-rule block. If html is omitted, theorem-like blocks default to callout, and proof defaults to plain.

In PDF, the same block becomes a real LuaLaTeX environment:

\begin{theorem}[Hall's theorem]
\label{thm:hall}
...
\end{theorem}

Astro also accepts shorter forms when PDF export is not needed:

```theorem id="thm:hall" title="Hall's theorem"
Every bipartite graph satisfying Hall's condition has a matching...
```

Linking To Semantic Blocks

Use ordinary Markdown links to semantic ids:

The proof of [Hall's theorem](#thm:hall) is constructive.
See the [tape explorer](#int:tape-layout) for an interactive version.

Astro renders these as normal HTML links. The PDF pipeline converts internal links whose target starts with # into \cref{...}, so the first link above becomes \cref{thm:hall}.

Use these label prefixes consistently:

thm: theorem
lem: lemma
prop: proposition
cor: corollary
def: definition
ex: example
rem: remark
prf: proof
int: interactive
fig: figure

Import Rules

The import script is:

scripts/import-quarto-blog.mjs

It reads the Quarto archive, skips draft: true, converts index.qmd to index.md, copies colocated assets, and writes a temporary tree under /private/tmp/quarto-blog-import.

The first import made these category choices:

Blog Rule of thumb
research CS/math exposition, lecture notes, and academic explainers.
vibes LLM-assisted making, interactives, and generated-tool experiments.
puzzles Puzzle/game/problem posts.
reflections Essays, speeches, teaching/career notes, and Exportober context.
poetry Poems.
reviews Tool, workflow, software, website, book-list, and tutorial posts.
art Visual/sketchnote/design/communications-oriented posts.

See IMPORT_REPORT.md for the specific source-to-destination mapping.

Sync Rules

  • Obsidian is the source of truth for day-to-day writing.
  • Auto-sync copies changes from the matching blogs/... folder into the matching local Astro content folder.
  • The plugin includes Markdown plus common web assets: images, PDFs, JSON/YAML, JS, CSS, HTML, and text files.
  • One-way sync does not delete target files unless Delete orphaned target files is enabled.
  • The initial Quarto import used replace-style sync to clear placeholder Astro posts. Day-to-day editing should use the plugin.

Preview And Publish

Use these Obsidian commands:

  • Blog Family Sync: Sync and preview current note
  • Blog Family Sync: Publish current note
  • Blog Family Sync: Publish all changes for current blog

Preview detects the current note's folder, starts the matching Astro dev server on its configured local port, and opens the post URL.

Publish does three things:

  1. Sync vault content into the local repo.
  2. Run the configured Astro build command.
  3. Commit and push to Forgejo, where Dokploy picks up the change.

PDF Export

PDF export uses Pandoc plus LuaLaTeX:

npm run pdf:post -- sites/research/src/content/research/example/index.md --out /tmp/example.pdf

The command runs:

  • scripts/pandoc-filters/semantic-blocks.lua to convert interactive and environment fences, internal links, Markdown callouts, emoji, chess pieces, and card suits.
  • scripts/pandoc-templates/semantic-preamble.tex to load amsthm, cleveref, tcolorbox, emoji, chessfss, and the shared theorem, callout, and symbol definitions.

Current smoke-test PDFs live outside the repo:

/private/tmp/blog-pdf-samples/callout-symbol-test.pdf
/private/tmp/blog-pdf-samples/vibes-building-interactives.pdf

The PDF route is intentionally separate from Astro. Astro owns HTML rendering; Pandoc owns PDF rendering. The Markdown conventions above are the shared contract between both outputs and can be reused for future site families such as neeldhara.courses and books.neeldhara.com.