Good instinct — there’s no built-in “annotation layer” feature in Obsidian for images, but there is a lightweight trick that works in both Obsidian and Quartz: raw HTML with an absolutely-positioned overlay div.
Both Obsidian’s renderer and Quartz’s markdown pipeline (remark/rehype) pass through raw HTML embedded in a note by default, so something like this in your .md file works in both places:
Use percentages, not pixels, for the box’s left/top/width/height. Image width will vary between Obsidian’s pane and however wide Quartz renders it on desktop vs. mobile, and percentages keep the box locked to the same relative spot on the image regardless of rendered size.
The image itself is untouched — you’re just layering a styled <div> on top of it.
In Obsidian, this renders correctly in Reading View and Live Preview (outside the exact line you’re editing); it won’t render as a box in raw Source Mode, which is expected.
For multiple boxes/labels, just add more absolutely-positioned children inside the same wrapper div.
If you want the boxes to look nicer or need rounded rects/arrows/labels, you can swap the <img> + overlay <div>s for an inline <svg> with an <image> tag as the base layer and <rect>/<text> elements drawn on top at exact coordinates — same principle, more control.
One caveat worth checking: this depends on your Quartz config not sanitizing/stripping raw HTML from markdown (some setups add rehype-sanitize or similar). If you’ve customized your quartz.config.ts plugin list, worth confirming rehype-raw-equivalent behavior is intact — but a stock Quartz v4 setup should pass this straight through.