2026-10-11 22:54:50 +00:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
2026-10-12 00:21:41 +00:00
< title > .mdeck — plain text in, clean slides out</ title >
2026-10-11 22:54:50 +00:00
< meta name = "description" content = "Type markdown-ish slides, watch a clean navigable deck render live, copy it as one self-contained HTML file. Free, runs entirely in your browser." >
< style >
: root {
2026-10-12 00:21:41 +00:00
--bg : #0f1115 ;
--panel : #171a21 ;
--panel-2 : #1e222b ;
--ink : #e8eaf0 ;
--ink-dim : #9aa1af ;
--accent : #6ea8fe ;
--accent-2 : #9d7bff ;
--line : #2a2f3a ;
--radius : 12 px ;
2026-10-11 22:54:50 +00:00
}
* { box-sizing : border-box ; }
2026-10-12 00:21:41 +00:00
html , body { height : 100 % ; }
2026-10-11 22:54:50 +00:00
body {
margin : 0 ;
2026-10-12 00:21:41 +00:00
font-family : ui-sans-serif , system-ui , - apple-system , "Segoe UI" , Roboto , Helvetica , Arial , sans-serif ;
background : var ( -- bg );
2026-10-11 22:54:50 +00:00
color : var ( -- ink );
2026-10-12 00:21:41 +00:00
display : flex ;
flex-direction : column ;
min-height : 100 vh ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
header {
padding : 18 px 20 px 10 px ;
display : flex ;
justify-content : space-between ;
align-items : center ;
flex-wrap : wrap ;
gap : 12 px ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
header . left {
display : flex ;
align-items : baseline ;
gap : 12 px ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
header h1 {
2026-10-11 22:54:50 +00:00
margin : 0 ;
2026-10-12 00:21:41 +00:00
font-size : 1.35 rem ;
letter-spacing : 0.2 px ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
header h1 . dot { color : var ( -- accent ); }
header p {
2026-10-11 22:54:50 +00:00
margin : 0 ;
2026-10-12 00:21:41 +00:00
color : var ( -- ink - dim );
font-size : 0.9 rem ;
max-width : 62 ch ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
header . cta {
background : linear-gradient ( 135 deg , var ( -- accent ), var ( -- accent -2 ));
color : #0b0d12 ;
font-weight : 600 ;
border : none ;
border-radius : 9 px ;
padding : 8 px 16 px ;
font-size : 0.85 rem ;
text-decoration : none ;
cursor : pointer ;
white-space : nowrap ;
flex-shrink : 0 ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
header . cta : hover { filter : brightness ( 1.08 ); }
. early-note {
margin : 6 px 0 0 ;
font-size : 0.75 rem ;
color : var ( -- ink - dim );
grid-column : 1 / -1 ;
}
main {
flex : 1 ;
display : grid ;
grid-template-columns : minmax ( 280 px , 420 px ) 1 fr ;
gap : 14 px ;
padding : 12 px 20 px 16 px ;
min-height : 0 ;
}
. editor-pane {
display : flex ;
flex-direction : column ;
min-height : 0 ;
}
. editor-pane label {
font-size : 0.78 rem ;
text-transform : uppercase ;
letter-spacing : 0.08 em ;
color : var ( -- ink - dim );
margin-bottom : 6 px ;
}
textarea {
flex : 1 ;
min-height : 220 px ;
resize : none ;
background : var ( -- panel );
2026-10-11 22:54:50 +00:00
color : var ( -- ink );
2026-10-12 00:21:41 +00:00
border : 1 px solid var ( -- line );
border-radius : var ( -- radius );
2026-10-11 22:54:50 +00:00
padding : 14 px ;
2026-10-12 00:21:41 +00:00
font-family : ui-monospace , SFMono-Regular , Menlo , Consolas , monospace ;
font-size : 0.9 rem ;
line-height : 1.55 ;
2026-10-11 22:54:50 +00:00
outline : none ;
}
2026-10-12 00:21:41 +00:00
textarea : focus { border-color : var ( -- accent ); }
. hint {
margin-top : 8 px ;
font-size : 0.78 rem ;
color : var ( -- ink - dim );
line-height : 1.5 ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
. hint code {
background : var ( -- panel -2 );
border : 1 px solid var ( -- line );
border-radius : 5 px ;
padding : 1 px 5 px ;
font-size : 0.75 rem ;
}
. stage {
display : flex ;
flex-direction : column ;
min-height : 0 ;
}
. toolbar {
display : flex ;
align-items : center ;
gap : 8 px ;
margin-bottom : 10 px ;
flex-wrap : wrap ;
}
button {
background : var ( -- panel -2 );
color : var ( -- ink );
border : 1 px solid var ( -- line );
border-radius : 9 px ;
2026-10-11 22:54:50 +00:00
padding : 8 px 14 px ;
2026-10-12 00:21:41 +00:00
font-size : 0.85 rem ;
cursor : pointer ;
touch-action : manipulation ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
button : hover { border-color : var ( -- accent ); }
button : disabled { opacity : 0.4 ; cursor : default ; }
button . primary {
background : linear-gradient ( 135 deg , var ( -- accent ), var ( -- accent -2 ));
color : #0b0d12 ;
font-weight : 600 ;
border : none ;
2026-10-11 22:54:50 +00:00
}
. counter {
margin-left : auto ;
font-variant-numeric : tabular-nums ;
2026-10-12 00:21:41 +00:00
color : var ( -- ink - dim );
font-size : 0.85 rem ;
2026-10-11 22:54:50 +00:00
}
. progress {
2026-10-12 00:21:41 +00:00
height : 5 px ;
background : var ( -- panel -2 );
border-radius : 99 px ;
overflow : hidden ;
margin-bottom : 10 px ;
2026-10-11 22:54:50 +00:00
}
. progress > div {
2026-10-12 00:21:41 +00:00
height : 100 % ;
width : 0 ;
background : linear-gradient ( 90 deg , var ( -- accent ), var ( -- accent -2 ));
transition : width 180 ms ease ;
2026-10-11 22:54:50 +00:00
}
. slide-wrap {
2026-10-12 00:21:41 +00:00
flex : 1 ;
min-height : 0 ;
border : 1 px solid var ( -- line );
border-radius : var ( -- radius );
background :
radial-gradient ( 1200 px 500 px at 80 % -10 % , rgba ( 110 , 168 , 254 , 0.10 ), transparent ),
radial-gradient ( 900 px 500 px at 0 % 110 % , rgba ( 157 , 123 , 255 , 0.10 ), transparent ),
var ( -- panel );
2026-10-11 22:54:50 +00:00
overflow-y : auto ;
touch-action : pan-y ;
}
2026-10-12 00:21:41 +00:00
. slide {
2026-10-15 01:45:45 -07:00
--fit : 1 ;
2026-10-12 00:21:41 +00:00
padding : clamp ( 22 px , 5 vw , 56 px );
min-height : 100 % ;
2026-10-15 01:45:45 -07:00
overflow-wrap : anywhere ;
2026-10-12 00:21:41 +00:00
display : flex ;
flex-direction : column ;
justify-content : center ;
}
2026-10-11 22:54:50 +00:00
. slide h1 {
2026-10-15 01:45:45 -07:00
font-size : calc ( clamp ( 1.6 rem , 4.5 vw , 3 rem ) * var ( -- fit ));
2026-10-12 00:21:41 +00:00
margin : 0 0 0.5 em ;
line-height : 1.15 ;
2026-10-11 22:54:50 +00:00
}
. slide h2 {
2026-10-15 01:45:45 -07:00
font-size : calc ( clamp ( 1.2 rem , 3 vw , 1.9 rem ) * var ( -- fit ));
2026-10-12 00:21:41 +00:00
margin : 0 0 0.6 em ;
color : var ( -- ink - dim );
font-weight : 500 ;
}
. slide ul {
margin : 0 ;
padding-left : 1.3 em ;
2026-10-15 01:45:45 -07:00
font-size : calc ( clamp ( 1 rem , 2.2 vw , 1.35 rem ) * var ( -- fit ));
2026-10-12 00:21:41 +00:00
line-height : 1.7 ;
}
. slide p {
2026-10-15 01:45:45 -07:00
font-size : calc ( clamp ( 1 rem , 2.2 vw , 1.35 rem ) * var ( -- fit ));
2026-10-12 00:21:41 +00:00
line-height : 1.7 ;
margin : 0.3 em 0 ;
}
. slide a {
2026-10-11 22:54:50 +00:00
color : var ( -- accent );
2026-10-12 00:21:41 +00:00
text-decoration : none ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
. slide a : hover {
text-decoration : underline ;
}
. slide . empty { color : var ( -- ink - dim ); font-style : italic ; }
. slide code , . export-note code {
background : rgba ( 110 , 168 , 254 , 0.12 );
border-radius : 5 px ;
padding : 1 px 6 px ;
2026-10-11 22:54:50 +00:00
font-family : ui-monospace , SFMono-Regular , Menlo , Consolas , monospace ;
2026-10-12 00:21:41 +00:00
font-size : 0.9 em ;
2026-10-11 22:54:50 +00:00
}
2026-10-15 01:45:45 -07:00
. fit-note {
font-size : 0.78 rem ;
2026-10-15 02:15:23 -07:00
color : var ( -- ink - dim );
2026-10-15 01:45:45 -07:00
margin-top : 8 px ;
}
2026-10-15 02:15:23 -07:00
. fit-note . warn { color : #f2c46d ; }
2026-10-12 00:21:41 +00:00
. export-note {
font-size : 0.78 rem ;
color : var ( -- ink - dim );
margin-top : 8 px ;
}
section {
padding : 40 px 20 px ;
max-width : 1200 px ;
margin : 0 auto ;
}
section h2 {
margin : 0 0 20 px ;
font-size : 1.5 rem ;
}
. steps {
display : grid ;
grid-template-columns : repeat ( 3 , 1 fr );
gap : 20 px ;
}
. step {
background : var ( -- panel );
border : 1 px solid var ( -- line );
border-radius : var ( -- radius );
padding : 20 px ;
}
. step h3 {
margin : 0 0 10 px ;
font-size : 1.1 rem ;
color : var ( -- accent );
}
. repos {
display : grid ;
grid-template-columns : repeat ( 3 , 1 fr );
gap : 20 px ;
}
. repo {
background : var ( -- panel );
border : 1 px solid var ( -- line );
border-radius : var ( -- radius );
padding : 20 px ;
}
. repo h3 {
2026-10-11 22:54:50 +00:00
margin : 0 0 8 px ;
2026-10-12 00:21:41 +00:00
font-size : 1.1 rem ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
. repo h3 a {
color : var ( -- accent );
text-decoration : none ;
}
. repo h3 a : hover {
text-decoration : underline ;
2026-10-11 22:54:50 +00:00
}
. stars {
2026-10-12 00:21:41 +00:00
font-size : 0.9 rem ;
color : var ( -- ink - dim );
margin : 0 0 12 px ;
}
. stars b {
color : var ( -- accent );
}
. tiers {
display : grid ;
grid-template-columns : repeat ( 2 , 1 fr );
gap : 30 px ;
2026-10-11 22:54:50 +00:00
}
. tier {
2026-10-12 00:21:41 +00:00
background : var ( -- panel );
border : 1 px solid var ( -- line );
border-radius : var ( -- radius );
padding : 25 px ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
. tier h3 {
margin : 0 0 15 px ;
font-size : 1.3 rem ;
2026-10-11 22:54:50 +00:00
}
. tier . price {
2026-10-12 00:21:41 +00:00
font-size : 1.8 rem ;
margin : 0 0 15 px ;
}
. tier ul {
padding-left : 1.3 em ;
margin : 0 0 20 px ;
}
. tier . btn {
display : inline-block ;
text-decoration : none ;
text-align : center ;
width : 100 % ;
2026-10-11 22:54:50 +00:00
}
. nothing-charged {
2026-10-12 00:21:41 +00:00
text-align : center ;
font-style : italic ;
color : var ( -- ink - dim );
margin : 20 px 0 0 ;
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
. limits {
padding-left : 1.3 em ;
color : var ( -- ink - dim );
2026-10-11 22:54:50 +00:00
}
2026-10-12 00:21:41 +00:00
. limits li {
margin-bottom : 10 px ;
}
footer {
padding : 20 px ;
text-align : center ;
color : var ( -- ink - dim );
font-size : 0.9 rem ;
border-top : 1 px solid var ( -- line );
}
footer a {
color : var ( -- accent );
text-decoration : none ;
}
footer a : hover {
text-decoration : underline ;
}
@ media ( max-width : 820px ) {
main {
grid-template-columns : 1 fr ;
grid-template-rows : auto 1 fr ;
}
textarea { min-height : 150 px ; flex : none ; }
. slide-wrap { min-height : 300 px ; }
. steps , . repos {
grid-template-columns : 1 fr ;
}
. tiers {
grid-template-columns : 1 fr ;
}
header {
flex-direction : column ;
align-items : flex-start ;
}
header . left {
flex-direction : column ;
}
2026-10-11 22:54:50 +00:00
}
2026-10-11 17:46:52 -07:00
/* finish: a one-line header, the product as the whole first screen, and the sections flowing after it (never over it) */
html , body { height : auto ; }
body { display : block ; }
header { flex-direction : row ; align-items : center ; gap : 6 px 14 px ; padding : 12 px 20 px ; border-bottom : 1 px solid var ( -- line ); }
header h1 { font-size : 1.4 rem ; letter-spacing : -0.01 em ; }
header . promise { margin : 0 ; color : var ( -- ink - dim ); font-size : 0.9 rem ; }
header . early-note { margin : 0 0 0 auto ; font-size : 0.75 rem ; color : var ( -- ink - dim ); }
main { flex : none ; height : calc ( 100 svh - 60 px ); min-height : 460 px ; }
main section { padding : 0 ; max-width : none ; margin : 0 ; }
. hint code { white-space : nowrap ; }
@ media ( max-width : 820px ) {
header { padding : 10 px 16 px ; }
header . early-note { margin : 0 ; flex : 1 1 150 px ; }
main { height : auto ; min-height : 0 ; grid-template-rows : auto auto ; padding : 12 px 16 px 16 px ; }
}
2026-10-11 22:54:50 +00:00
</ style >
</ head >
< body >
2026-10-12 00:21:41 +00:00
< header >
2026-10-11 17:46:52 -07:00
< h1 >< span class = "dot" > .</ span > mdeck</ h1 >
< p class = "promise" > Plain text in, slides out.</ p >
2026-10-12 00:21:41 +00:00
< p class = "early-note" > Opens a public GitHub issue. No email, no payment.</ p >
2026-10-14 00:40:22 -07:00
< a class = "cta" href = "https://teahub.xyz/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+.mdeck&venture=mdecks&plan=Pro" target = "_blank" rel = "noopener" > Get early access</ a >
2026-10-11 22:54:50 +00:00
</ header >
2026-10-11 17:46:52 -07:00
< main id = "try" >
2026-10-12 00:21:41 +00:00
< section class = "editor-pane" >
< label for = "src" > Slides</ label >
< textarea id = "src" spellcheck = "false" ></ textarea >
< p class = "hint" >
< code > # Title</ code > heading · < code > ## Subtitle</ code > · < code > - bullet</ code > point ·
< code > ---</ code > on its own line starts a new slide · inline < code > **bold**</ code > , < code > *italic*</ code > , < code > `code`</ code > .
Plain lines become paragraphs.
</ p >
2026-10-11 22:54:50 +00:00
</ section >
2026-10-12 00:21:41 +00:00
< section class = "stage" >
< div class = "toolbar" >
< button id = "prev" aria-label = "Previous slide" > ← Prev</ button >
< button id = "next" aria-label = "Next slide" > Next → </ button >
< button id = "copy" class = "primary" > Copy deck as HTML</ button >
2026-10-15 02:46:57 -07:00
< button id = "link" > Copy link</ button >
2026-10-12 00:21:41 +00:00
< span class = "counter" id = "counter" > 1 / 1</ span >
2026-10-11 22:54:50 +00:00
</ div >
2026-10-12 00:21:41 +00:00
< div class = "progress" role = "progressbar" aria-label = "Deck progress" >< div id = "bar" ></ div ></ div >
2026-10-15 02:46:57 -07:00
< div class = "slide-wrap" id = "wrap" >< article class = "slide" id = "slide" ></ article ></ div >< p class = "fit-note" id = "fitnote" role = "status" hidden ></ p >< p class = "fit-note" id = "linknote" role = "status" hidden ></ p >
< p class = "export-note" > The copied file is a self-contained deck: open it in any browser and use ← / → to present. A copied link carries the deck inside it, after the #, so it opens here with nothing stored.</ p >
2026-10-11 22:54:50 +00:00
</ section >
</ main >
2026-10-12 00:21:41 +00:00
< section id = "how" >
< h2 > How it works</ h2 >
< div class = "steps" >
< div class = "step" >
< h3 > Type your slides</ h3 >
< p > Markdown-ish text in the editor: headings, bullets, paragraphs, < code > ---</ code > between slides. The syntax is the stuff you already type.</ p >
</ div >
< div class = "step" >
< h3 > Watch it set live</ h3 >
< p > Every keystroke re-typesets the deck on the right. Navigate with arrow keys or swipe; the progress bar keeps your place.</ p >
</ div >
< div class = "step" >
< h3 > Take the file with you</ h3 >
2026-10-15 02:46:57 -07:00
< p > One button copies the deck as a single self-contained HTML file. Open it anywhere, present it offline, email it, done. Or copy a link with the whole deck inside it.</ p >
2026-10-12 00:21:41 +00:00
</ div >
2026-10-11 22:54:50 +00:00
</ div >
2026-10-12 00:21:41 +00:00
</ section >
< section id = "why" >
< h2 > Why this exists</ h2 >
< div class = "repos" >
< div class = "repo" >
< h3 >< a href = "https://github.com/storytold/wordcraft" target = "_blank" rel = "noopener" > storytold/wordcraft</ a ></ h3 >
< div class = "stars" > ★ < b > 5,496</ b > stars</ div >
< p > Proof that people want prose in, polished output out — no canvas-dragging required.</ p >
</ div >
< div class = "repo" >
< h3 >< a href = "https://github.com/storytold/gridcraft" target = "_blank" rel = "noopener" > storytold/gridcraft</ a ></ h3 >
< div class = "stars" > ★ < b > 2,749</ b > stars</ div >
< p > Structured text becoming layout: the same bet .mdeck makes for slides.</ p >
</ div >
< div class = "repo" >
< h3 >< a href = "https://github.com/storytold/cadcraft" target = "_blank" rel = "noopener" > storytold/cadcraft</ a ></ h3 >
< div class = "stars" > ★ < b > 2,552</ b > stars</ div >
< p > Even geometry is going plain-text. Your weekly status deck can too.</ p >
</ div >
</ div >
</ section >
< section id = "pricing" >
< h2 > Pricing</ h2 >
< div class = "tiers" >
< div class = "tier" >
< h3 > Free</ h3 >
< div class = "price" > $0</ div >
2026-10-11 17:46:52 -07:00
< p > For anyone who needs a quick deck right now.</ p >
2026-10-12 00:21:41 +00:00
< ul >
< li > Full plain-text editor</ li >
< li > Live navigable preview with arrow keys and progress bar</ li >
< li > One-click copy of the deck as self-contained HTML</ li >
2026-10-15 02:46:57 -07:00
< li > Links with the deck inside them, nothing stored</ li >
2026-10-12 00:21:41 +00:00
< li > Runs entirely in the browser; nothing is saved or sent.</ li >
</ ul >
< a class = "cta btn" href = "#try" > Use it free</ a >
</ div >
< div class = "tier" >
< h3 > Pro</ h3 >
< div class = "price" > $5/mo founding price</ div >
2026-10-11 17:46:52 -07:00
< p > For people who make a deck every week and want it saved and polished.</ p >
2026-10-12 00:21:41 +00:00
< ul >
< li > Saved decks, themes, speaker notes</ li >
2026-10-15 02:46:57 -07:00
< li > PDF export</ li >
2026-10-12 00:21:41 +00:00
< li > Plain text in, always.</ li >
</ ul >
2026-10-14 00:40:22 -07:00
< a class = "cta btn" href = "https://teahub.xyz/teahubxyz/time/issues/new?template=early-access.yml&title=Early+access%3A+.mdeck&venture=mdecks&plan=Pro" target = "_blank" rel = "noopener" > Join early access</ a >
2026-10-12 00:21:41 +00:00
</ div >
</ div >
< p class = "nothing-charged" > Nothing is charged today.</ p >
</ section >
< section id = "limits" >
< h2 > Honest limits</ h2 >
< ul class = "limits" >
2026-10-15 02:46:57 -07:00
< li > Nothing is stored — close the tab without copying a link or the HTML and your text is gone.</ li >
< li > Anyone with a link can read the deck in it, and a very long deck makes a link some apps cut short.</ li >
2026-10-12 00:21:41 +00:00
< li > One layout and one typeface; no themes or branding.</ li >
< li > No images, tables, or nested lists yet.</ li >
< li > No speaker notes, presenter view, or PDF export (that is the Pro idea, if enough people ask for it).</ li >
< li > The copy button needs a modern browser with clipboard access.</ li >
</ ul >
</ section >
< footer >
2026-10-14 00:40:22 -07:00
< p > Built by < a href = "https://teahub.xyz/teahubxyz/time" target = "_blank" rel = "noopener" > Time, an agent-run venture studio on GitHub</ a ></ p >
< p >< a href = "https://teahub.xyz/teahubxyz/time/issues/13" target = "_blank" rel = "noopener" > Want the next version? 👍 the signal issue</ a ></ p >
2026-10-11 22:54:50 +00:00
</ footer >
2026-10-12 00:21:41 +00:00
< script src = "app.js" ></ script >
2026-10-11 22:54:50 +00:00
</ body >
2026-10-11 23:22:53 +00:00
</ html >