
Marquee is a markup language!
It's designed to be a mash-up of Markdown, BBCode, RST, and the old web.
For more information about dumb questions like "why it exists", "what it does", or "how to integrate with it", you should check the GitHub.
This? This is the DEMO.
Let's take a look at how to write Marquee!
This page is, of course, written in Marquee, at WRITING.mq.
This paragraph is written
across several source lines,
and none of those breaks survive — it flows.
Roses are red\
violets are blue,\
these lines end in backslashes\
so each one renders new.
This paragraph is written across several source lines, and none of those breaks survive — it flows.
Roses are red
violets are blue,
these lines end in backslashes
so each one renders new.
And no blank line is needed to start a block — here's my list:
- it starts anyway
- jammed right against the prose
And no blank line is needed to start a block — here's my list:
it starts anyway
jammed right against the prose
### A heading with *emphasis*, [color=goldenrod]color[/color], and [blink]blink[/blink]
######## Eight hashes still works — deeper than HTML dares.
######### Nine hashes is just a paragraph, rendered literally.
Eight hashes still works — deeper than HTML dares.
######### Nine hashes is just a paragraph, rendered literally.
*emphasis*, **strong**, **strong with *emphasis* inside**, ~~struck through~~, and
`inline code with *stars* nobody parses`.
Underscores are safe in snake_case_names, ***three stars are literal***, and a
lone * asterisk just sits there. Escapes work too: \*not emphasis\*, and a line that starts with
\- an escaped dash, which is not a list.
[blink]forgot the closer — so this whole run renders literally, brackets and all.
emphasis, strong, strong with emphasis inside, struck through, and
inline code with *stars* nobody parses.
Underscores are safe in snake_case_names, ***three stars are literal***, and a lone * asterisk just sits there. Escapes work too: *not emphasis*, and a line that starts with
- an escaped dash, which is not a list.
[blink]forgot the closer — so this whole run renders literally, brackets and all.
A [plain link](https://example.org), a [relative link](other-page), and a
[parenthetical Wikipedia link](https://en.wikipedia.org/wiki/Hat_(disambiguation)).



A bare URL alone in a paragraph becomes a turbolink:
https://example.org/interesting-post
https://commons.wikimedia.org/wiki/Special:FilePath/Cat03.jpg
https://commons.wikimedia.org/wiki/Special:FilePath/Meow.ogg
https://www.youtube.com/watch?v=kiTpHaShznE
%% You can also trigger link expansion directly, like this:
:::turbolink target=https://www.youtube.com/watch?v=kiTpHaShznE level=title:::
A plain link, a relative link, and a parenthetical Wikipedia link.
One embed syntax — the file's own type decides whether it's a picture, a song, or a film:
(I apologize for the generative nature of these media assets, but it keeps them public domain so that I can distribute them freely as examples.)

A bare URL alone in a paragraph becomes a turbolink:
https://example.org/interesting-post
Link kinds get their own expanders, plugged in by the host. An image link unfurls into the picture, a sound into play controls, a video link arrives playable:
Wrap embeds in a :::media block — its knobs apply to everything inside. Width and height
take exact pixels (like 200) or the tokens small / medium / large / full. One
dimension scales (aspect ratio kept); both dimensions make a frame the media fills, cropped,
never squashed:
:::media width=200 height=300

:::
:::media width=200 height=300

:::
:::media width=full

:::

Embeds are inline, so pictures sharing one paragraph flow and wrap like words — a gallery with no gallery element:
:::media width=150




:::

Known shortcodes resolve — :tophat: :sparkles: :blobcat: — and a host can map a slug to a
little image: :angry-burger: is a custom image emoji this host provides, worn at character
size right in the line. Unknown ones stay literal, like :thisoneisnotreal:, typed emoji 🎩
are just text, and 3:30 is just a time.
Known shortcodes resolve — 🎩 ✨ :blobcat: — and a host can map a slug to a
little image:
is a custom image emoji this host provides, worn at character
size right in the line. Unknown ones stay literal, like :thisoneisnotreal:, typed emoji 🎩
are just text, and 3:30 is just a time.
E = mc[sup]2[/sup], H[sub]2[/sub]O, [small]the fine print[/small], colors by
[color=goldenrod]name[/color] or [color=#f06]hex[/color], and
asides[sidenote]like this one[/sidenote] that never interrupt the sentence
(and [footnote]this[/footnote] and [aside]this[/aside] are the same tag —
sidenote, aside, footnote: whichever word your fingers find).
The size dial goes [size=1]one[/size] [size=2]two[/size] [size=3]three[/size]
[size=4]four[/size] [size=5]five[/size] [size=6]six[/size] [size=7]SEVEN[/size],
and [big]big[/big] is [small]small[/small]'s mirror.
When numbers feel cold, the rungs have names: [teeny]teeny[/teeny],
[tiny]tiny[/tiny], [huge]huge[/huge], [enormous]ENORMOUS[/enormous].
Fonts are picked from a closed list, never uploaded: [font=orbitron]SPACE STATION[/font],
[font=vt323]terminal green[/font], [font=im-fell-english]ye olde booke[/font],
[font=press-start]INSERT COIN[/font], [font=lobster]a fancy lobster[/font],
[font=creepster]the abomination approves[/font], [font=comic]the people's classic[/font],
[font=kablammo]KABLAMMO[/font], and [font=rye]howdy, partner[/font].
E = mc2, H2O, the fine print, colors by name or hex, and asides1 that never interrupt the sentence (and 2 and 3 are the same tag — sidenote, aside, footnote: whichever word your fingers find).
The size dial goes one two three four five six SEVEN, and big is small's mirror.
When numbers feel cold, the rungs have names: teeny, tiny, huge, ENORMOUS.
Fonts are picked from a closed list, never uploaded: SPACE STATION,
terminal green, ye olde booke,
INSERT COIN, a fancy lobster,
the abomination approves, the people's classic,
KABLAMMO, and howdy, partner.
(Thirty-one real, self-hosted faces ship in the @cube-drone/marquee-fonts package, each with
its license riding along — your host serves them itself, or inlines just the ones a page
wears; no reader ever pings a font CDN.)
The full menu makes a fine specimen chart — and a fine use of a nested list. Every name renders as itself:
- standard stacks (no files needed)
- [font=sans]sans[/font]
- [font=serif]serif[/font]
- [font=mono]mono[/font]
- [font=comic]comic[/font]
- clean sans
- [font=radio-canada]radio-canada[/font]
- [font=atkinson-hyperlegible]atkinson-hyperlegible[/font]
- [font=lexend]lexend[/font]
- [font=quicksand]quicksand[/font]
- serif & slab
- [font=playfair-display]playfair-display[/font]
- [font=cormorant]cormorant[/font]
- [font=zilla-slab]zilla-slab[/font]
- old book & gothic
- [font=im-fell-english]im-fell-english[/font]
- [font=uncial-antiqua]uncial-antiqua[/font]
- [font=unifraktur]unifraktur[/font]
- mono & terminal
- [font=jetbrains-mono]jetbrains-mono[/font]
- [font=vt323]vt323[/font]
- [font=major-mono]major-mono[/font]
- [font=special-elite]special-elite[/font]
- pixel
- [font=press-start]press-start[/font]
- [font=silkscreen]silkscreen[/font]
- [font=bitcount]bitcount[/font]
- display & neon
- [font=orbitron]orbitron[/font]
- [font=audiowide]audiowide[/font]
- [font=bungee]bungee[/font]
- [font=monoton]monoton[/font]
- [font=creepster]creepster[/font]
- loud & weird
- [font=kablammo]kablammo[/font]
- [font=oi]oi[/font]
- [font=henny-penny]henny-penny[/font]
- [font=rye]rye[/font]
- script & hand
- [font=lobster]lobster[/font]
- [font=pacifico]pacifico[/font]
- [font=caveat]caveat[/font]
- [font=fredericka]fredericka[/font]
- [font=comic-neue]comic-neue[/font]
standard stacks (no files needed)
sans
serif
mono
comic
clean sans
radio-canada
atkinson-hyperlegible
lexend
quicksand
serif & slab
playfair-display
cormorant
zilla-slab
old book & gothic
im-fell-english
uncial-antiqua
unifraktur
mono & terminal
jetbrains-mono
vt323
major-mono
special-elite
pixel
press-start
silkscreen
bitcount
display & neon
orbitron
audiowide
bungee
monoton
creepster
loud & weird
kablammo
oi
henny-penny
rye
script & hand
lobster
pacifico
caveat
fredericka
comic-neue
[marquee]THE CLASSIC — scrolling since 1995, stoppable since Marquee[/marquee]
[blink]blink[/blink] · [rainbow]rainbow[/rainbow] · [bounce]bounce[/bounce] ·
[jitter]jitter[/jitter] · [wave]wave[/wave] · [rubber]rubber[/rubber] ·
[typewriter speed=30]typewriter — it types itself out, letter by letter, in pure CSS[/typewriter]
Nesting is the point: [marquee][blink]still open at 3am[/blink][/marquee]
[rainbow by=letter]EVERY LETTER ITS OWN HUE[/rainbow] ·
[wave by=letter]a true undulating wave[/wave] ·
[bounce by=word]each word takes its turn[/bounce] ·
[jitter by=letter]scattered nerves[/jitter] ·
[rubber by=letter]SQUASH AND STRETCH[/rubber]
[rainbow by=letter phase=scatter]CONFETTI HUES[/rainbow] ·
[bounce by=letter phase=scatter]popcorn letters[/bounce] ·
[jitter by=letter phase=ramp]an orderly shudder[/jitter]
[fadein]a ghostly fade-in[/fadein] ·
[fadein by=letter]drifting in letter by letter[/fadein] ·
[fadein by=word phase=scatter]apparition weather: words materializing in no particular order at all[/fadein]
[blink by=letter]CHASE LIGHTS[/blink] ·
[blink by=letter phase=scatter rate=2]twinkle twinkle[/blink]
:::media width=48
[bounce][/bounce]
:::
THE CLASSIC — scrolling since 1995, stoppable since Marquee
blink · rainbow · bounce · jitter · wave · rubber · typewriter — it types itself out, letter by letter, in pure CSS
Nesting is the point: still open at 3am
And by=letter / by=word give every unit its own offset cycle:
EVERY LETTER ITS OWN HUE · a true undulating wave · each word takes its turn · scattered nerves · SQUASH AND STRETCH
Offsets sweep smoothly by default; phase=scatter scrambles them (and phase=ramp can
smooth even jitter):
CONFETTI HUES · popcorn letters · an orderly shudder
The reveals enter once and then behave — a ghostly fade, whole or per-unit:
a ghostly fade-in · drifting in letter by letter · apparition weather: words materializing in no particular order at all
And blink splits too — sweeping in order is a theater marquee, scattering is a night sky:
CHASE LIGHTS · twinkle twinkle
And effects wrap anything — transforms carry their children, so an embed inside a bounce is simply a bouncing picture:

If your reduced-motion setting is on, everything above is calmly standing still — yes, even the burger.
- unordered
* with mixed markers (same list)
+ because markers are synonyms
1. ordered
7. with numbers that don't matter —
3. the renderer counts
- outer
- inner
- deeper (three or four spaces would also have worked)
- an item with a second paragraph
which is indented to stay inside the bullet, image included:

- and a normal next item
1. this ordered list is about to be interrupted
2. by an unindented line
oops — this line ends the list
1. and the numbering restarts, which is how you *see* the mistake
unordered
with mixed markers (same list)
because markers are synonyms
ordered
with numbers that don't matter —
the renderer counts
outer
inner
deeper (three or four spaces would also have worked)
Items hold whole paragraphs — even images — as long as they stay indented:
an item with a second paragraph
which is indented to stay inside the bullet, image included:
and a normal next item
this ordered list is about to be interrupted
by an unindented line
oops — this line ends the list
and the numbering restarts, which is how you see the mistake
Only lists mean anything by indentation (see above). Everywhere else, an indent demotes structure to prose — visibly, fixably, on purpose:
# an indented heading is just text
::: and an indented closer closes nothing
# an indented heading is just text
::: and an indented closer closes nothing
So keep directive bodies flat, and use named closers when nesting gets deep.
Rows are paragraphs, cells are [c]-spans, and the blank line between rows is the ordinary paragraph break. header=row makes the first row real header cells (screen readers get the association, not just the bold):
:::table header=row
[c]dish[/c] [c]price[/c]
[c]*Spaghetti* al Limone[/c] [c]$12[/c]
[c]Linguine alle Vongole[/c] [c]$18 :sparkles:[/c]
:::
| dish | price |
|---|---|
| Spaghetti al Limone | $12 |
| Linguine alle Vongole | $18 ✨ |
Line the source up into columns or don't — spacing between cells is yours, and it renders the same either way. There is deliberately no way to put a table inside a table.
> Every line of the quote is marked,
> line by line — no lazy continuation.
> > And quotes nest.
Every line of the quote is marked, line by line — no lazy continuation.
And quotes nest.
```python
for hat in attic.hats():
print(hat.vibe, hat.dampness)
```
```
:::page layout=basic
*none of this* is parsed [blink]in here[/blink] — fences are raw
:::
```
for hat in attic.hats():
print(hat.vibe, hat.dampness)
:::page layout=basic
*none of this* is parsed [blink]in here[/blink] — fences are raw
:::
Need literal triple-backticks inside a block? Fence with four:
````
``` even literal triple-backticks, inside a longer fence ```
````
``` even literal triple-backticks, inside a longer fence ```
%% notes to self — readers never see this
%% consecutive comment lines merge into one comment
\%% but escape the marker and the line stays in prose
:::meta title="Writing Marquee, live" date=2026-07-10 tags="guide, demo":::
There is a live comment in this very spot — and rendering it as nothing is the demo:
%% but escape the marker and the line stays in prose
The live :::meta is at the top of this file, describing the document to any tool that asks,
rendering nothing.
The <center> tag is back, and it brought company — :::right, and :::left for
un-aligning inside the other two:
:::center
**CENTERED**, like the old gods intended
:::left
(and this line ducks back to the left rail)
:::
:::
:::right
signed, ~~the management~~
:::
CENTERED, like the old gods intended
(and this line ducks back to the left rail)
signed, the management
:::section scheme=terminal
sys.status: [color=#33ff66]COZY[/color] · uptime 11,315 days
:::
sys.status: COZY · uptime 11,315 days
Hark — the same markup, an entirely different mood (this one says scheme=parchment).
THE CONDIMENT KING'S OWN COLORWAY (scheme=hotdog-stand)
And backgrounds tile images, exactly as the old web intended — any image target, honoring the host's media policy like every other embed:
:::section background=tile:example-media/angry-burger-emoji.png color=#fff8dc
**WELCOME TO THE BURGER ZONE.** We regret nothing.
:::
WELCOME TO THE BURGER ZONE. We regret nothing.
And a whole page-in-miniature, wrapping slotted sections:
:::page layout=nav-footer scheme=noir
:::section slot=nav
**a tiny demo page** — layout picked from a list, never authored
:::
:::section slot=main
Nav above, footer below, this in the middle.
:::
:::section slot=footer
[small]est. 2026 · probably part of a webring[/small]
::: section
:::
(That footer closed with ::: section — a named closer: :::name opens, ::: name
closes. Pure readability in deep nesting, plus a safety net — a named closer that doesn't
match the innermost open block gets flagged right at that line instead of silently
mis-nesting the rest of the page. And notice the sections inside the noir page needed no
scheme of their own: styling flows down by containment, and whichever knob sits closest
wins — that's the entire cascade.)
These depend on where you're posting — here they render labeled placeholder boxes, the graceful deal that lets old clients meet new vocabulary:
:::counter theme=retro:::
:::webring ring=cozy-comics:::
And one deliberate mistake — spaces around = — so you can see "strict but never
destructive":
:::oops key = broken
You have now seen each effect alone: polite, purposeful, stoppable. The spec says effects nest freely — that this "is not an edge case, it is the point." We are therefore obligated to conclude that the following is the point. All seven effects, one heading, eight levels deep — which used to ride the inline nesting cap exactly, until v0 sealed the cap at sixteen. There is now officially room for a second abomination inside this one. We mention this fact and immediately regret it:
:::section scheme=terminal
# [marquee][blink][wave][bounce][jitter][typewriter][rainbow by=letter phase=scatter]**WELCOME TO MY HOMEPAGE**[/rainbow][/typewriter][/jitter][/bounce][/wave][/blink][/marquee]
:::
(The typewriter is in there too — but its content is a whole nested effect rather than bare letters, so it sits this one out: the per-letter machinery splits text, not other spans. On its own it types in pure CSS now; see the effects section. And if your reduced-motion setting is on, the abomination is a perfectly still green-on-black heading — the exit is contractual, even from this.)
This document is CC0, like everything in vectors/ — copy it, break it, preview what
happens. You cannot hurt it. ✨