Public
Edited
4 forks
Importers
26 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
slide.md`
# Hello 👋🏼
- Still reactive: this slide is **${width}px** wide
- Resize your window if you like!
- Math! ${tex`S = k_B \ln{W}`}
`
Insert cell
Insert cell
slide.html`
<h1>HTML can do slides too</h1>
<ul>
<li>This is a range input: <input type=range />
</ul>
`
Insert cell
Insert cell
Insert cell
imageWut = {
const array = [
// ↓ red: top left ↓ orange: top middle ↓ yellow: top right (wrap)
255, 0, 0, 255, 255, 128, 0, 255, 255, 255, 0, 255,
0, 255, 0, 255, 0, 0, 255, 255, 128, 0, 255, 255,
// ↑ green: bottom left ↑ blue: bottom middle ↑ purple: bottom right
]
return new ImageData(Uint8ClampedArray.from(array), 3, 2)
}
Insert cell
notes.md`### Notes

Notes borrow from [literate programming](https://en.wikipedia.org/wiki/Literate_programming) and notebook best practices: they serve a **dual purpose** as speaker notes/script _and_ as shareable blog post content. They’re skipped over when using arrow keys to advance slides, but still exist in the notebook among slides to provide context.

The speaker can then **confidently share the notebook with anyone**, especially people who didn't attend the presentation, and everyone should be able to **_read_ a version of the presentation** and still benefit from it.

When you reference \`keyBindings\` from your notebook, you’ll notice you get a “Notes” button: clicking it opens a pop-up window with speaker notes based on the “current” slide. Try it [below](#keyBindings)!`
Insert cell
Insert cell
slide = ({
md: wrap(md, 'slide'),
html: wrap(html, 'slide')
})
Insert cell
notes = ({
md: wrap(md, 'notes'),
html: wrap(html, 'notes')
})
Insert cell
wrap = (fn, className) => (...args) => (
args[0].raw
? html`<div class="${className}">${fn(...args)}</div>`
: (...rest) => html`
<div class="${className} ${args
.map(s => `${className}--${s}`)
.join(' ')}">${fn(...rest)}</div>
`
)
Insert cell
keyBindings = {
let currentSlide = -1;
let showNotes = () => {};
function keyUp(event) {
const slides = document.querySelectorAll('.observablehq .slide');
switch (event.key) {
case 'ArrowUp':
case 'ArrowLeft':
currentSlide = Math.max(currentSlide - 1, 0);
slides[currentSlide].scrollIntoView();
showNotes(slides[currentSlide]);
break;
case 'ArrowDown':
case 'ArrowRight':
currentSlide = Math.min(currentSlide + 1, slides.length - 1);
slides[currentSlide].scrollIntoView();
showNotes(slides[currentSlide]);
break;
}
}

document.addEventListener('keyup', keyUp);
invalidation.then(() => document.removeEventListener('keyup', keyUp));
return Object.assign(
html`<button>Notes</button>`, {
onclick() {
const notes = open("about:blank", "notes", "width=600,height=400").document.body;
showNotes = slide => {
notes.innerHTML = "";
const cell = slide.parentNode;
const siblings = Array.from(document.querySelectorAll('.observablehq'));
for (const sibling of siblings.slice(siblings.indexOf(cell))) {
if (sibling.querySelector('.notes')) {
notes.innerHTML = sibling.innerHTML;
break;
}
}
}
}
});
}
Insert cell
<style>
.slide,
.notes {
padding: 1% 10%;
width: calc(100% + 28px);
box-sizing: border-box;
margin: 0 -14px;
}

.slide {
min-height: 61vw;
display: flex;
align-items: center;
}
.slide, .slide code {
font-size: 3vw;
}

.slide.slide--small {
padding-bottom: 1%;
min-height: auto;
}

.slide.slide--bleed {
padding: 0;
min-height: 0;
}

.slide h1,
.slide h2,
.slide p,
.slide pre,
.slide img {
max-width: 100%;
}

.slide small {
color: gray;
}

.slide blockquote,
.slide ol,
.slide ul {
max-width: none;
}

.slide > * {
width: 100%;
}
.slide > iframe {
height: 56vw;
}

.slide ul,
.slide ol {
padding-left: 3vw;
margin-bottom: 0;
}
.slide ul li::before,
.slide ol li::before {
margin-left: -2vw;
}

.slide img {
width: 100%;
}
</style>
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more