Skip to main content

Markdown & MDX

EmbedHub renders .md and .mdx files in-page so project documentation is readable without downloading or switching tools.

Upload a .md or .mdx to a project's Documents or Releases section (via the web, embedhub push, or the GitHub Action) and a small eye icon appears next to the file. Clicking it opens an in-page reader.

  • .md renders as plain markdown.
  • .mdx renders markdown plus a small set of interactive components.

Plain markdown

.md files render with GitHub-flavored markdown: tables, task lists, strikethrough, autolinks, fenced code blocks.

# Release 1.4

## What's new

- New flash mode for ESP32-S3
- Faster boot — typical ~1.2 s
- ~~Old serial logger~~ removed

## Test status

| Board | Boot | Network | Sensors |
| ----------- | ---- | ------- | ------- |
| esp32-s3 ||||
| esp32-c6 ||| ⚠️ |

## Checklist

- [x] sign release tag
- [x] upload firmware
- [ ] update changelog

MDX adds components

.mdx is markdown plus a small library of components you can drop into the page. Save the file with an .mdx extension to opt in.

<Note>

A coloured callout for highlighting context. Variants: info, warn, error. The body accepts markdown.

<Note variant="info" title="Heads up">
Run `embedhub config set api-key …` once before pushing from CI.
</Note>

<Note variant="warn">
This board ships with the bootloader **disabled** by default.
</Note>

<Note variant="error" title="Don't do this">
Never commit `.env` to source control.
</Note>

<Chart>

Renders an interactive chart inline. Hover for tooltips; click items in the legend to toggle individual series.

PropTypeDefaultDescription
type"line" | "bar" | "area"lineChart style.
dataArray<object>Required. Each object is one row.
xKeystring"x"Field on each row to use as the x-axis label.
yKeystring | string[]"y"Field(s) to plot. Pass an array for multi-series.
titlestringOptional caption above the chart.
heightnumber280Chart height in pixels.

Single-series bar:

<Chart
type="bar"
title="Defects per build"
xKey="build"
yKey="defects"
data={[
{ build: '#101', defects: 3 },
{ build: '#102', defects: 1 },
{ build: '#103', defects: 5 },
{ build: '#104', defects: 0 },
{ build: '#105', defects: 2 },
]}
/>

Single-series line:

<Chart
type="line"
title="Boot time (ms) by build"
xKey="build"
yKey="bootMs"
data={[
{ build: '1.0', bootMs: 1820 },
{ build: '1.1', bootMs: 1640 },
{ build: '1.2', bootMs: 1510 },
{ build: '1.3', bootMs: 1290 },
{ build: '1.4', bootMs: 1180 },
]}
/>

Single-series area:

<Chart
type="area"
title="Free heap (KB) over runtime"
xKey="t"
yKey="freeKb"
data={[
{ t: '0s', freeKb: 142 },
{ t: '10s', freeKb: 138 },
{ t: '20s', freeKb: 130 },
{ t: '30s', freeKb: 124 },
{ t: '40s', freeKb: 121 },
{ t: '50s', freeKb: 118 },
]}
/>

Multi-series line:

<Chart
type="line"
title="Monthly sales vs refunds"
xKey="month"
yKey={['sales', 'refunds']}
data={[
{ month: 'Jan', sales: 100, refunds: 8 },
{ month: 'Feb', sales: 120, refunds: 15 },
{ month: 'Mar', sales: 95, refunds: 10 },
{ month: 'Apr', sales: 140, refunds: 12 },
]}
/>

Multi-series bar:

<Chart
type="bar"
title="Pass / fail counts per board"
xKey="board"
yKey={['pass', 'fail']}
data={[
{ board: 'esp32-s3', pass: 42, fail: 3 },
{ board: 'esp32-c6', pass: 38, fail: 7 },
{ board: 'rp2040', pass: 45, fail: 1 },
{ board: 'nrf52840', pass: 40, fail: 5 },
]}
/>

Multi-series area:

<Chart
type="area"
title="CPU vs memory usage (%)"
xKey="t"
yKey={['cpu', 'mem']}
data={[
{ t: '0s', cpu: 12, mem: 30 },
{ t: '5s', cpu: 28, mem: 34 },
{ t: '10s', cpu: 65, mem: 42 },
{ t: '15s', cpu: 71, mem: 51 },
{ t: '20s', cpu: 48, mem: 49 },
{ t: '25s', cpu: 22, mem: 45 },
]}
/>

Pass chart data inline via data={[…]}. Sourcing data from a separate project file isn't supported yet.

Embedding images from the project

An .mdx file can reference any image stored in the same project — useful for screenshots, diagrams, or rendered state machines that should always reflect the latest version in the project.

Reference images with a relative path, just like in a normal markdown file:

![Boot flow](../state-machines/diagrams/boot-and-idle.svg)
![Board top](../photos/top.jpg)

The viewer resolves the relative path against the document's location in the project bucket, then loads the image through the project's permission-checked file API. Update the source file and refresh the doc — the embedded image updates with it.

How the path is resolved

The path is resolved relative to the document's own folder, exactly like links in any markdown file — so where you put the image matters:

documents/connectors.mdx                  ← the doc
documents/connectors-assets/panel.png ← an asset next to it
photos/top.jpg ← a root-level photo
From documents/connectors.mdxResolves to
![](connectors-assets/panel.png)documents/connectors-assets/panel.png
![](../photos/top.jpg)photos/top.jpg

A common pattern is to keep a doc's images in a sibling subfolder and push them with --path:

embedhub push assets/ myorg/myproject --path documents/connectors-assets/
embedhub push connectors.mdx myorg/myproject --path documents/
Use markdown image syntax, not raw <img>

The viewer renders markdown but strips raw HTML, so an <img src="…"> tag silently disappears — no image, no error. Always use the markdown form ![alt](path). The same applies to <img> pointing at a data: URI: the tag is dropped before the URL is ever read.

![Back panel](connectors-assets/panel.png)   <!-- ✅ renders -->
<img src="connectors-assets/panel.png" /> <!-- ❌ stripped, shows nothing -->
Don't start the path with /

A leading slash (/photos/top.jpg) is treated as a site-root URL, not a project path — it bypasses the file API and 404s. Use a relative path (connectors-assets/… or ../photos/…) instead.

MDX only

Project-relative image paths only resolve in .mdx files. Inside a plain .md file they're handed straight to the browser, which interprets them relative to the page URL and fails to load. Use .mdx whenever you embed images from the project.

Sizing

Because raw HTML is stripped, there's no width/height attribute to size an image — markdown images render at their natural pixel size. Resize the source file before uploading (e.g. convert in.png -resize 150x out.png) to control how large it appears, especially for thumbnails inside table cells.

Absolute URLs (https://…) work in both .md and .mdx.

Tips

  • Links in MDX use [text](url). MDX treats < as the start of a component tag, so <https://example.com> autolinks don't work in .mdx files. They still work in plain .md.
  • Component names are case-sensitive. <Note> works; <note> is treated as an unknown HTML element.
  • Compile errors surface in the viewer. If the MDX is malformed, the modal shows the parser message with a line and column so you can fix the source and re-upload.

Uploading

.md and .mdx files are uploaded the same way as any other file:

embedhub push README.mdx myorg/myproject --path documents/

See the CLI reference for the full set of flags.