Showing preview only (241K chars total). Download the full file or copy to clipboard to get everything.
Repository: marp-team/marp
Branch: main
Commit: be6eea91a8bc
Files: 85
Total size: 220.9 KB
Directory structure:
gitextract_8zf9058k/
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── LICENSE
├── README.md
├── netlify.toml
├── package.json
├── tsconfig.json
└── website/
├── .eslintrc.js
├── assets.d.ts
├── babel.config.js
├── blog/
│ ├── 202205-ecosystem-update.md
│ ├── how-to-make-custom-transition.md
│ ├── marp-for-vs-code-v1.md
│ ├── marpit-v2-marp-core-v2-and-marp-cli-v1.md
│ ├── re-creation-of-marp-website.md
│ └── the-story-of-marp-next.md
├── components/
│ ├── Button.tsx
│ ├── CodeBlock.tsx
│ ├── Footer.tsx
│ ├── Header.tsx
│ ├── Layout.tsx
│ ├── Marp.tsx
│ ├── ScrollToTop.tsx
│ ├── Title.tsx
│ ├── Typography.tsx
│ ├── blog/
│ │ └── BlogHeader.tsx
│ ├── docs/
│ │ ├── Breadcrumb.tsx
│ │ ├── Layout.tsx
│ │ ├── Navigation.tsx
│ │ └── layouts/
│ │ ├── Desktop.tsx
│ │ └── Mobile.tsx
│ ├── markdown/
│ │ ├── Anchor.tsx
│ │ ├── Heading.tsx
│ │ ├── Image.tsx
│ │ └── Pre.tsx
│ └── top/
│ ├── Description.tsx
│ ├── Features.tsx
│ ├── GetStarted.tsx
│ └── Hero.tsx
├── css/
│ ├── index.css
│ └── plugin-rem.js
├── docs/
│ ├── guide/
│ │ ├── directives.md
│ │ ├── fitting-header.md
│ │ ├── fragmented-list.md
│ │ ├── heading-divider.md
│ │ ├── how-to-write-slides.md
│ │ ├── image-syntax.md
│ │ ├── math-typesetting.md
│ │ └── theme.md
│ ├── introduction/
│ │ ├── install.md
│ │ └── whats-marp.md
│ ├── manifest.yaml
│ └── tools/
│ ├── marp-cli.md
│ └── marp-for-vs-code.md
├── global.d.ts
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages/
│ ├── 404.tsx
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── blog/
│ │ └── [slug].tsx
│ ├── blog.tsx
│ ├── docs/
│ │ └── [[...slug]].tsx
│ └── index.tsx
├── postcss.config.js
├── public/
│ └── blog/
│ └── .gitignore
├── tailwind.config.js
├── tsconfig.json
└── utils/
├── date.ts
├── hooks/
│ └── useFontFace.tsx
├── markdown/
│ ├── index.tsx
│ ├── parse/
│ │ ├── image-paragraph-to-figure.ts
│ │ ├── index.ts
│ │ └── marp-code-block.ts
│ └── renderer/
│ ├── index.ts
│ └── sanitize.ts
├── title.ts
└── url.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
================================================
FILE: .eslintignore
================================================
.next
coverage
lib
node_modules
out
================================================
FILE: .eslintrc.js
================================================
const path = require('path')
const { workspaces } = require('./package.json')
module.exports = {
root: true,
env: {
browser: true,
node: true,
es6: true,
},
extends: ['eslint:recommended', 'plugin:import/recommended', 'prettier'],
rules: {
// eslint-plugin-import cannot parse exports field in package.json.
// https://github.com/import-js/eslint-plugin-import/issues/1810
'import/no-unresolved': ['error', { ignore: ['^swiper'] }],
'import/order': ['error', { alphabetize: { order: 'asc' } }],
},
overrides: [
{
files: ['**/*.ts', '**/*.tsx'],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:import/typescript',
'prettier',
],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
settings: {
'import/resolver': {
typescript: {
project: ['', ...workspaces].map((dir) =>
path.join(dir, 'tsconfig.json')
),
},
},
},
},
],
}
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: npm
directory: '/'
reviewers:
- 'marp-team/maintainers'
schedule:
interval: daily
allow:
- dependency-name: '@marp-team/*'
versioning-strategy: increase
- package-ecosystem: github-actions
directory: '/'
reviewers:
- 'marp-team/maintainers'
schedule:
interval: weekly
# versioning-strategy: increase-if-necessary
open-pull-requests-limit: 0 # Dependabot does not allow relaxed versioning :(
================================================
FILE: .github/workflows/test.yml
================================================
name: Test
on:
- pull_request
- push
env:
CACHE_PREFIX: v1
YARN_VERSION: '^1.22.4'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'
- name: Install yarn
id: yarn
run: |
cd $HOME && yarn policies set-version $YARN_VERSION
echo "::set-output name=cache_dir::$(yarn cache dir)"
- uses: actions/cache@v3
with:
path: ${{ steps.yarn.outputs.cache_dir }}
key: yarn_cache-${{ env.CACHE_PREFIX }}-${{ hashFiles('**/yarn.lock') }}
restore-keys: yarn_cache-${{ env.CACHE_PREFIX }}-
- run: yarn install
- run: yarn audit
- name: Prettier formatting
run: yarn check:format
- name: ESLint
run: yarn lint:js
- name: TypeScript type checking
run: yarn check:ts
================================================
FILE: .gitignore
================================================
# Created by https://www.toptal.com/developers/gitignore/api/vim,node,linux,emacs,macos,windows,intellij,sublimetext,visualstudiocode
# Edit at https://www.toptal.com/developers/gitignore?templates=vim,node,linux,emacs,macos,windows,intellij,sublimetext,visualstudiocode
### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
dist/
# Flycheck
flycheck_*.el
# server auth directory
/server/
# projectiles files
.projectile
# directory configuration
.dir-locals.el
# network security
/network-security.data
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml
### Linux ###
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
### SublimeText ###
# Cache files for Sublime Text
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
# Workspace files are user-specific
*.sublime-workspace
# Project files should be checked into the repository, unless a significant
# proportion of contributors will probably not be using Sublime Text
# *.sublime-project
# SFTP configuration file
sftp-config.json
sftp-config-alt*.json
# Package control specific files
Package Control.last-run
Package Control.ca-list
Package Control.ca-bundle
Package Control.system-ca-bundle
Package Control.cache/
Package Control.ca-certs/
Package Control.merged-ca-bundle
Package Control.user-ca-bundle
oscrypto-ca-bundle.crt
bh_unicode_properties.cache
# Sublime-github package stores a github token in this file
# https://packagecontrol.io/packages/sublime-github
GitHub.sublime-settings
### Vim ###
# Swap
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
.vscode/*.code-snippets
# Ignore code-workspaces
*.code-workspace
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/vim,node,linux,emacs,macos,windows,intellij,sublimetext,visualstudiocode
================================================
FILE: .nvmrc
================================================
18.18.2
================================================
FILE: .prettierignore
================================================
.next
node_modules
out
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018- Marp team (marp-team@marp.app)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<div align="center">
<p>
<img src="marp.png#gh-light-mode-only" alt="Marp" width="450" />
<img src="marp-dark.png#gh-dark-mode-only" alt="Marp" width="450" />
</p>
<p>
<strong>Marp</strong>: Markdown Presentation Ecosystem
</p>
</div>
**Marp** is the ecosystem to write your presentation with plain Markdown.
<div align="center">
### [🌐 Website ▶︎](https://marp.app) | [💬 Discussion forum ▶︎](https://github.com/marp-team/marp/discussions) | [😎 Awesome list ▶︎](https://github.com/marp-team/awesome-marp)
</div>
## Marp family
Our project is spread over many repos in order to focus on a limited scope per repository.
This repo (**[marp-team/marp][marp]**) is an entrance to the Marp family, and places [our website](https://marp.app/) in `/website`.
### Framework / Core
| Name | Description | Release |
| -------------------------: | :------------------------------------------------------------------------------------------ | :-------------------------------------------------------- |
| **[Marpit]** | The skinny framework for creating slide deck from Markdown. ([marpit.marp.app]) | [![@marp-team/marpit][badge-marpit]][marpit-npm] |
| **[Marp Core][marp-core]** | The core of Marp converter with practical features and [built-in themes][marp-core-themes]. | [![@marp-team/marp-core][badge-marp-core]][marp-core-npm] |
### Apps
| Name | Description | Release |
| -----------------------: | :----------------------------------------------------------------------------------------------- | :----------------------------------------------------- |
| **[Marp CLI][marp-cli]** | [Marp Core][marp-core] / [Marpit]'s CLI interface to convert into HTML, PDF, PPTX, and image(s). | [![@marp-team/marp-cli][badge-marp-cli]][marp-cli-npm] |
### Integrations
| Name | Description | Release |
| ----------------------------------: | :-------------------------------------------------------------------------------- | :---------------------------------------------------------- |
| **[Marp for VS Code][marp-vscode]** | A [VS Code][vscode] extension to preview the slide deck written in Marp Markdown. | [![VS Marketplace][badge-marp-vscode]][marp-vscode-release] |
<details>
<summary>See outdated/inactive projects...</summary><br />
| Name | Description | Release |
| -----------------------: | :--------------------------------------------------------------- | :----------------------------------------------------------- |
| [Marp Web][marp-web] | The Web interface of Marp based on [PWA] and [Preact] framework. | [![tech demo][badge-marp-web]][marp-web-site] |
| [Marp React][marp-react] | Marp renderer component for [React]. | [![@marp-team/marp-react][badge-marp-react]][marp-react-npm] |
| [Marp Vue][marp-vue] | Marp renderer component for [Vue]. | [![@marp-team/marp-vue][badge-marp-vue]][marp-vue-npm] |
And there is a gravesite of classic Marp app in https://github.com/yhatt/marp. :ghost:
[marp-web]: https://github.com/marp-team/marp-web
[marp-react]: https://github.com/marp-team/marp-react
[marp-vue]: https://github.com/marp-team/marp-vue
[pwa]: https://en.wikipedia.org/wiki/Progressive_Web_Apps
[preact]: https://preactjs.com/
[react]: https://reactjs.org/
[vue]: https://vuejs.org/
[marp-web-site]: https://web.marp.app/
[marp-react-npm]: https://www.npmjs.com/package/@marp-team/marp-react
[marp-vue-npm]: https://www.npmjs.com/package/@marp-team/marp-vue
[badge-marp-web]: https://img.shields.io/badge/%E2%80%8B-tech%20demo-%230288d1.svg?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAUUlEQVQokWNgGD6AqePif3Sx9B2PMcQwNKFrTN/x+D9ejTBNyBphmnBqRNYE04isCatGdE1MHRf/o2vC0IhNE1PaXPwacWnCqxGfJoI2Dn4AAN0ZrMM1VUFvAAAAAElFTkSuQmCC
[badge-marp-react]: https://img.shields.io/npm/v/@marp-team/marp-react.svg?style=flat-square&logo=npm
[badge-marp-vue]: https://img.shields.io/npm/v/@marp-team/marp-vue.svg?style=flat-square&logo=npm
</details>
[yhatt/marp]: https://github.com/yhatt/marp
[marp]: https://github.com/marp-team/marp
[marpit]: https://github.com/marp-team/marpit
[marp-core]: https://github.com/marp-team/marp-core
[marp-core-themes]: https://github.com/marp-team/marp-core/tree/main/themes
[marp-cli]: https://github.com/marp-team/marp-cli
[marp-vscode]: https://github.com/marp-team/marp-vscode
[vscode]: https://code.visualstudio.com/
[marpit.marp.app]: https://marpit.marp.app/
[marpit-npm]: https://www.npmjs.com/package/@marp-team/marpit
[marp-core-npm]: https://www.npmjs.com/package/@marp-team/marp-core
[marp-cli-npm]: https://www.npmjs.com/package/@marp-team/marp-cli
[marp-vscode-release]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
[badge-marpit]: https://img.shields.io/npm/v/@marp-team/marpit.svg?style=flat-square&logo=npm
[badge-marp-core]: https://img.shields.io/npm/v/@marp-team/marp-core.svg?style=flat-square&logo=npm
[badge-marp-cli]: https://img.shields.io/npm/v/@marp-team/marp-cli.svg?style=flat-square&logo=npm
[badge-marp-vscode]: https://img.shields.io/visual-studio-marketplace/v/marp-team.marp-vscode.svg?style=flat-square&logo=visual-studio-code&label=Marketplace
## Ecosystem
Marp ecosystem has a lot of cool stuffs for making awesome presentation. Check out **[the awesome list of Marp](https://github.com/marp-team/awesome-marp)**. 😎
## Contributing
Marp and sub-projects are following the [contributing guideline of marp-team][contributing]. Please read this before starting work in our projects.
[contributing]: https://github.com/marp-team/.github/blob/master/CONTRIBUTING.md
## Author
Managed by [@marp-team](https://github.com/marp-team).
- <img src="https://github.com/yhatt.png" width="16" height="16"/> Yuki Hattori ([@yhatt](https://github.com/yhatt))
## Sponsors
We are supported by them! Thanks for our sponsors! :heart:
<!-- [NOTE] Sort sponsors by name when modify. -->
### Organization sponsors
<!-- Logo and links for top-tier sponsors (The image should be up to 400px on a side) -->
<p align="center">
<a href="https://github.com/markslides"><img src="https://github.com/markslides.png" width="64" height="64" alt="@markslides" valign="middle" hspace="4" /></a>
</p>
<!-- [TODO] For mid-tier sponsors: As the same format as personal sponsors, add small icons and links to GitHub organization. -->
<!--
<p>
<a href="https://github.com/xxxxxx"><img src="https://github.com/xxxxxx.png" width="32" height="32" alt="xxxxxx" /></a>
</p>
-->
### Personal sponsors
<!-- [TODO] Currently shows maintainer's sponsors. We should show sponsors for all Marp team members in future. -->
<p align="center">
<img alt="Personal sponsors" src="https://yhatt.github.io/yhatt/sponsors.svg" />
</p>
> Do you want to sponsor [the member of Marp team](https://github.com/orgs/marp-team/people)? See [GitHub Sponsors](https://github.com/sponsors) profile(s) from "♥︎ Sponsor" button [at the top of repository](https://github.com/marp-team/marp).
## License
[MIT License](LICENSE)
================================================
FILE: netlify.toml
================================================
[build]
publish = "website/out"
command = "yarn workspace @marp-team/marp-website export"
[[headers]]
for = "/*"
[headers.values]
Permissions-Policy = "interest-cohort=()"
================================================
FILE: package.json
================================================
{
"name": "@marp-team/marp",
"description": "The entrance repository of Markdown presentation ecosystem",
"private": true,
"license": "MIT",
"author": {
"name": "Marp team",
"url": "https://github.com/marp-team"
},
"contributors": [
{
"name": "Yuki Hattori",
"url": "https://github.com/yhatt"
}
],
"repository": {
"type": "git",
"url": "https://github.com/marp-team/marp"
},
"workspaces": [
"website"
],
"prettier": {
"semi": false,
"singleQuote": true
},
"scripts": {
"check:format": "yarn -s format -c",
"check:ts": "yarn lage check:ts",
"format:write": "yarn -s format --write",
"format": "prettier \"**/*.{css,js,jsx,json,md,mdx,scss,ts,tsx,yaml,yml}\"",
"lint:js": "eslint --report-unused-disable-directives --cache .",
"website": "yarn workspace @marp-team/marp-website dev"
},
"devDependencies": {
"@tsconfig/recommended": "^1.0.1",
"@types/node": "~18.11.18",
"@typescript-eslint/eslint-plugin": "^5.47.1",
"@typescript-eslint/parser": "^5.47.1",
"eslint": "^8.30.0",
"eslint-config-prettier": "^8.3.0",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.25.4",
"lage": "^1.9.6",
"prettier": "^2.8.1",
"typescript": "^4.9.4"
},
"resolutions": {
"json5": "^2.2.2"
}
}
================================================
FILE: tsconfig.json
================================================
{
"extends": "@tsconfig/recommended/tsconfig.json",
"compilerOptions": {
"lib": ["es2015", "dom"],
"noImplicitAny": false,
"resolveJsonModule": true,
"strict": true
}
}
================================================
FILE: website/.eslintrc.js
================================================
const path = require('path')
module.exports = {
extends: ['next', 'prettier'],
rules: {
'@next/next/no-html-link-for-pages': [
'error',
path.join(__dirname, 'pages'),
],
// Marp website is completely static. Automatic Image Optimization by Next.js requires a server for on-demand conversion.
'@next/next/no-img-element': 'off',
},
}
================================================
FILE: website/assets.d.ts
================================================
declare module '*.yaml' {
const yaml: any
export = yaml
}
================================================
FILE: website/babel.config.js
================================================
const path = require('path')
module.exports = {
presets: [
[
'next/babel',
{
'styled-jsx': {
plugins: [
[
require.resolve('styled-jsx-plugin-postcss'),
{ path: path.resolve(__dirname, './postcss.config.js') },
],
],
},
},
],
],
}
================================================
FILE: website/blog/202205-ecosystem-update.md
================================================
---
title: 'Ecosystem update: Marp Core v3 & Slide transitions in CLI v2'
date: 2022-05-26
description: Introduce a stable release of Marp Core v3, and updated CLI v2 with an entirely new slide transition experiment.
author: Yuki Hattori
github: yhatt
image: /og-images/202205-ecosystem-update.jpg
---
We are so excited to introduce a stable release of **[Marp Core](https://github.com/marp-team/marp-core) v3**, and **[Marp CLI](https://github.com/marp-team/marp-cli) v2** update with [an entirely new slide transition experiment](#slide-transition-experiment).
- **[Marp Core v3](#marp-core-v3)**: MathJax rendering as default, updated `default` theme, and new components for auto-scaling.
- **[Marp CLI v2](#marp-cli-v2)**: Bundled core v3, and [brand-new slide transition experiment](#slide-transition-experiment) with 33 built-in effects + CSS custom transitions.
<!-- more -->
# Marp Core v3
[We had released Marp Core v3.0.0 as a release candidate in November 2021.](https://github.com/marp-team/marp-core/releases/tag/v3.0.0) For a half year, it had been available in the `next` tag as an opt-in engine of Marp CLI, and had accepted feedback from the community.
This month [v3.2.0](https://github.com/marp-team/marp-core/releases/tag/v3.2.0) has become a stable release, and **we are starting work to make v3 core the default in downstream Marp tools gradually.**
An updated Marp Core v3 has some major changes, but we also have worked to keep backward compatibility in many existing slides. Most slide authors should not be concerned about regressions as long as your tweaks to the slide theme are not complicated.
If you are a theme author, you may have to modify some of the styles. This update includes a brand-new auto scaling component, the change of `default` theme caused by the update of [`github-markdown-css`](https://github.com/sindresorhus/github-markdown-css), and so on.
Even so, you should not too worry: We worked to v3 core to reduce friction between Marp's CSS and common CSS, so I think the complex part of our theming system (e.g. styling auto-scaled element) must be easier to understand than v2.
## Notable changes
### Drop support for End-of-Life Node.js
First, Marp Core v3 has dropped support for end-of-life Node.js 10.
We have supported EoL Node.js v12 yet, but continuous support may not guarantee depending on the support status of dependency modules. We recommend following up on [the active LTS Node.js](https://nodejs.org/).
> Check out https://endoflife.date/nodejs to know which version of Node.js is EoL.
### MathJax is a default typesetting library for math
[katex]: https://katex.org/
[mathjax]: https://www.mathjax.org/
Marp Core v3 has changed the default library for rendering math, from [KaTeX] to [MathJax].
Marp had used [KaTeX] as a default library for long years for taking better performance. But currently, this opinion has become the past thinking with the advent of MathJax 3. [See this interesting insight.](https://groups.google.com/g/mathjax-users/c/aboJLMb50uQ/m/Y77FexF_AwAJ)
And some incompatibilities of KaTeX with Marp Core's auto scaling feature that are hard to fix had given us a headache. ([marp-team/marp-core#159](https://github.com/marp-team/marp-core/issues/159), [marp-team/marp-core#236](https://github.com/marp-team/marp-core/issues/236))
MathJax implementation in Marp Core has more reliable rendering than KaTeX. In addition, it also has more TeX function supports, and no network is required to show.
Now a lot of Markdown flavors have adopted MathJax for math typesetting (e.g. [GitHub](https://github.blog/2022-05-19-math-support-in-markdown/)), and we expect Marp Markdown would get higher compatibility in several Markdown services.
#### `math` global directive
If your Markdown is not yet ready to migrate math typesettings into MathJax, you can continue to use KaTeX as a math typesetting library by setting [`math` global directive](https://github.com/marp-team/marp-core#math-global-directive) as `katex`.
```markdown
---
math: katex
---
Continue to use KaTeX: $ax^2+bc+c$
```
We have no plans to remove KaTeX integration for a while. So you can keep rendering math with KaTeX if you're using KaTeX specific syntaxes or met rendering performance issues in MathJax.
> For smooth migration of exist slides to v3, Marp for VS Code is [annotating to math use without `math` global directive](https://github.com/marp-team/marp-vscode#diagnostics) since a year ago.
### Renewed auto-scaling component
Marp Core has a tiny runtime script to activate element auto-scaling for a code block, math block, and [fitting header `# <!--fit--> header`](https://github.com/marp-team/marp-core#fitting-header). v3 has updated auto scaling logic into [Web Components](https://developer.mozilla.org/docs/Web/Web_Components) based, to improve output lucidity and compatibility with some CSS selectors.
This update does not change the actual auto-scaling behavior from v2, so most Markdown slide authors should not need to take care of that. But if you have a custom theme that was styled to auto-scaling elements, you should review and modify CSS declarations in your theme to match with v3.
Please refer to the pull request **[marp-team/marp-core#263](https://github.com/marp-team/marp-core/pull/263)** for details of auto-scaling components.
### Updated `default` theme
To provide a familiar Markdown style to users as default, Marp Core `default` theme is based on [GitHub's Markdown CSS](https://github.com/sindresorhus/github-markdown-css).
The latest Marp Core has included the following updates about `default` theme:
- Updated color schemes based on the latest [github-markdown-css v5](https://github.com/sindresorhus/github-markdown-css)
- Match colors for code highlight with GitHub style
- Allow color customization through CSS variables ([See theme docs](https://github.com/marp-team/marp-core/tree/main/themes#custom-color-css-variables))
````markdown:marp
<!-- paginate: true -->
<style>:root { font-size: 40px; }</style>
# This is a new `default` theme
```markdown
<!-- theme: default -->
# This is a new `default` theme
```
---
<!-- class: invert -->
# Updated `invert` color scheme
based on GitHub dark mode
```markdown
<!-- class: invert -->
```
````
### URL without HTTP(S) scheme does no longer auto-linkify
Marp Core up to v2 had detected URL-like strings and converted them to hyperlinks automatically. However, that was too fuzzy and often brought linkify in not intended words, such as "[Amazon.com](https://amazon.com/)" and "[ML.NET](https://dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet)".
But there are no more fuzzy links in v3! Now auto link feature requires the URL string with `https://` or `http://` scheme.
Please make a Markdown link `[Amazon.com](https://amazon.com/)` explicitly if you want the hyperlink in previously auto-linked words.
# Marp CLI v2
According to the time to become core v3 stable, we also worked on **[a major update of Marp CLI](https://github.com/marp-team/marp-cli/releases/tag/v2.0.0)** to bundle a new core.
There are no major changes in the general use of Marp CLI, and I believe your CLI workflow would never break by this update in most cases.
So what feature is a "major" update of CLI? [_Perhaps you may have interested in a hidden gem..._ 💎](#slide-transition-experiment)
## Notable changes
### Required Node.js v14 and later
The new release of Marp CLI is required **the latest Node.js v14 and later**, because depending modules such as Puppeteer (for PDF/PPTX generation) were dropped support for EoL Node.js versions v12 and older.
### Bundled Marp Core v3
As described earlier, Marp CLI v2 has bundled an updated Marp Core v3.2.0 as a core engine.
```bash
$ marp --version
@marp-team/marp-cli v2.0.0 (w/ @marp-team/marp-core v3.2.0)
```
###### Continue to use v2 core in Marp CLI
We recommend getting ready for using the updated v3 core, but Marp CLI also can stick to the v2 core by installing `@marp-team/marp-core@^2` to your project individually.
```bash
npm i --save-dev @marp-team/marp-cli @marp-team/marp-core@^2
npx marp ./your-markdown.md
```
It's useful when your Markdown slide files are not ready for v3 core. But please keep in mind we would hardly provide more updates to v2 core, and **continuous use may bring a risk of unpatched security issues.**
# Slide transitions
A really loving part of this CLI update for me is **[a brand-new slide transition in `bespoke` HTML template.](https://github.com/marp-team/marp-cli/issues/447)**
We had started testing experimental slide transition effects since [Marp CLI v1.4.0](https://github.com/marp-team/marp-cli/releases/tag/v1.4.0) (Aug 2021). `--bespoke.transition` CLI option had been working well, but not so practical compared to the common presentation tools.
As a result of catching up on the new spec of [View Transitions API proposal][view transitions api] in Marp CLI v2, I'm so excited to provide powerful transition features that are in no other Markdown slide tools, such as CSS custom transition effects and morphing animations!
[view transitions api]: https://www.w3.org/TR/css-view-transitions-1/
> The slide transitions feature has made stable in v2.4.0. You can dive into all about of transitions at [the documentation of Marp CLI transitions][transition-docs].
[transition-docs]: https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md
## Quick look

- **[33 built-in transitions](https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md#built-in-transitions)**: Marp CLI provides a lot of transition effects out of the box.
- **[Define custom transitions via CSS](https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md#custom-transitions)**: Markdown author and theme designer can define the custom transition through `@keyframes` declaration in CSS.
- **[Morphing animations](https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md#morphing-animations)**: [`view-transition-name` CSS property](https://www.w3.org/TR/css-view-transitions-1/#view-transition-name-prop) supplied by View Transition API helps to make morphing animation while transition.
## Usage
The slide transitions in HTML output can opt in and out through `--bespoke.transition` CLI option. _It is only working in the browser that supports [View Transitions API], such as Chrome/Chromium 110 and later._
The `--preview` CLI option is helpful see transition effects surely. Try this in Marp CLI v2.4.0+ to open a preview window for the transition showcase:
```bash
curl -o ./showcase.md https://gist.githubusercontent.com/yhatt/d9e86ee53eb8816aaf9c996e773b6f82/raw/transition-showcase.md
marp --preview ./showcase.md
```
## Showcase
You can see online demo slides about Marp CLI brand new transitions! See them in the browser that supports [View Transitions API].
- **[Marp CLI page transition showcase](https://marp-cli-page-transitions.glitch.me/)**: The showcase of built-in transitions
- **[Custom transitions example](https://marp-cli-page-transitions.glitch.me/custom.html)**: Some examples and ideas about custom transitions
- **[Transition with morphing animation](https://marp-cli-page-transitions.glitch.me/morph.html)**: An example of morphing animation powered by [View Transitions API].
## `transition` local directive
You can set and change the kind of transition through `transition` local directive.
```markdown
---
transition: fade
---
Fade transition with 0.5s duration
---
<!-- transition: cover 1s -->
Changed the kind of transition to `cover` with 1s duration
---
<!-- _transition: none -->
Disabled transition for this slide
---
Got back to cover transition
```
Each transition has a default 0.5s duration, but you can also set custom duration by space-separated value such as `<!-- transition: fade 1s -->`.
## Custom transition
The custom transition can define through just a few conventional [`@keyframes` at-rules](https://developer.mozilla.org/docs/Web/CSS/@keyframes) within the inline `<style>` element or custom theme CSS.
<!-- prettier-ignore-start -->
```css
/* Simple definition: "dissolve" custom transition */
@keyframes marp-transition-dissolve {
from { opacity: 1; }
to { opacity: 0; }
}
/* Splitted definitions: "triangle" custom transition */
@keyframes marp-incoming-transition-triangle {
from { clip-path: polygon(0% 0%, 0% 0%, 0% 0%); }
to { clip-path: polygon(0% 0%, 200% 0%, 0% 200%); }
}
@keyframes marp-incoming-transition-backward-triangle {
from { clip-path: polygon(100% 100%, 100% 100%, 100% 100%); }
to { clip-path: polygon(-100% 100%, 100% -100%, 100% 100%); }
}
/* With backward animations: Overloading "zoom" transition */
@keyframes marp-incoming-transition-zoom {
from { transform: scale(0); }
to { transform: scale(1); }
}
@keyframes marp-outgoing-transition-backward-zoom {
from { transform: scale(1); }
to { transform: scale(0); }
}
@keyframes marp-incoming-transition-backward-zoom {
/* Define empty keyframes to disable fallback into incoming animation */
}
```
<!-- prettier-ignore-end -->
It only has a relatively simple definition(s) but great flexibility, and brings out boundless creativity of CSS animation! 🤩
**[👉 Marp CLI: How to make custom transition](/blog/how-to-make-custom-transition)**
We are really looking forward to what creative transition effects our community will create!
## Morphing animations
Thanks to the browser's [View Transitions API], we can apply morphing animations during a transition effect. This is similar to PowerPoint Morph and Keynote Magic Move.
Just sprinkle a few CSS properties!

```markdown
---
theme: gaia
transition: fade
style: |
/* ⬇️ Mark the image of "1" in every pages as morphable image named as "one" ⬇️ */
img[alt="1"] {
view-transition-name: one;
contain: layout;
}
/* Generic image styling for number icons */
img:is([alt="1"], [alt="2"], [alt="3"]) {
height: 64px;
position: relative;
top: -0.1em;
vertical-align: middle;
width: 64px;
}
---
# Today's topics
-  Introduction
-  Features
-  Conclusion
---
<!-- _class: lead -->

# Introduction
---
#  Introduction
Marp is an open-sourced Markdown presentation ecosystem.
```
**[👉 See details at the documentation about transitions on Marp CLI repository...](https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md#morphing-animations)**
# Deprecations
Finally, we have to mention that the latest update has a deprecated Markdown syntax in the Marp ecosystem. It is still can use for now with deprecation warnings and will be obsolete in future Marp tools.
> We have planned to work on [an auto-fixable diagnostic for VS Code extension](https://github.com/marp-team/marp-vscode#diagnostics), to make it easier to update the use of deprecated syntaxes.
### Shorthand for setting colors (Marpit framework)
[Marpit framework](https://marpit.marp.app/) had been provided the color setting shorthand through Markdown image syntax, such as `` and ``. This syntax had been allowed to set a corresponding color style like `color: red` and `background-color: yellow` to only a current slide page.
These are rarely used in reality, and now we have considered as harmful from the point of view of Markdown (CommonMark) compatibility.
Marpit framework has already provided [`color` / `backgroundColor` local directives](https://marpit.marp.app/directives?id=backgrounds), and setting [scoped local directives](https://marpit.marp.app/directives?id=apply-to-a-single-page-spot-directives) to the slide will bring the same result.
If you are using these shorthands for setting colors, please replace them with the alternative scoped local directive.
| Shorthands | Should replace to |
| :----------: | :------------------------------: |
| `` | `<!-- _color: red -->` |
| `` | `<!-- _backgroundColor: red -->` |
> _Track the state of progress at [marp-team/marpit#331](https://github.com/marp-team/marpit/issues/331)._
# Community
Join the Marp community! Our [GitHub Discussions](https://github.com/orgs/marp-team/discussions) is a community forum that gathered discussions all about Marp, and allows you to connect with Marp team and other Marp users. Of course, we welcome your feedback for this ecosystem update too. 😀
- [**Go to GitHub Discussions**](https://github.com/orgs/marp-team/discussions)
- [The support guideline of Marp project](https://github.com/marp-team/.github/blob/master/SUPPORT.md)
<!--
# Titbit
Marpit framework is 5th year and I feel that is beginning to gather a few of dust. Therefore I'm trying to design a new polished engine, as a personal weekend experiment toward the next core v4.
Currently I don't want you too to count on it. I'm just working on for getting a long-lived ecosystem with modern CSS rules :)
-->
================================================
FILE: website/blog/how-to-make-custom-transition.md
================================================
---
title: 'Marp CLI: How to make custom transition'
date: 2022-05-28
description: Marp CLI v2.4.0+ and Marp for VS Code v2.5.0+ have a stable support for page transitions with many useful built-in effects. But if you had not satisfied with any effects? Make your effects with CSS!
author: Yuki Hattori
github: yhatt
image: /og-images/how-to-make-custom-transition.jpg
---
[readme]: https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md
[built-in]: https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md#built-in-transitions
[view transitions api]: https://www.w3.org/TR/css-view-transitions-1/
**[Marp CLI v2](/blog/202205-ecosystem-update#marp-cli-v2)** has supported [brand-new page transitions for the `bespoke` HTML template](/blog/202205-ecosystem-update#slide-transition-experiment). You can use this stable transition support in either Marp CLI v2.4.0+ or Marp for VS Code v2.5.0+.
Effective transitions will help make a dramatic presentation. Adding a touch of effects to slides is often common in great talks. By viewing HTML slide in the browser that supports [View Transitions API] (Chrome 110+), or Marp CLI with `--preview` option, you can start to use [varied 33 transition effects][built-in] out of the box, by [just a simple definition `transition` directive](https://github.com/marp-team/marp-cli/blob/main/docs/bespoke-transitions/README.md#transition-local-directive).
Built-in transitions should be useful for 90% of Marp users. But what you can do if there are no effects you are satisfied with? Make your effects in CSS! Marp can register your custom animation set declared in CSS as a named transition, and use it in the Markdown slide.
<!-- more -->
### Index
This article will describe the following things:
1. **[The anatomy of a transition](#the-anatomy-of-a-transition)**: How the transition effect will work in Marp
1. **[Declare custom transitions](#declare-custom-transitions)**: How to register custom transitions by CSS
1. **[Helpful tips for making your transition](#tips)**
[See also the official documentation about transitions in Marp CLI.][readme]
_If using [built-in transitions made by us][built-in] was enough, you don't need to read this article._ Please save your time, with keeping enjoying our transitions in your Markdown slide! :)
> In this article, the word "transition" is meaning the slide transition effect in Marp. Please note that it is not meaning [`transition` property in CSS](https://developer.mozilla.org/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions).
# The anatomy of a transition
The first what the custom transition author has to know is "How the page transition effect is realized in a presentation slide".
Let's consider what is happening when the slide page was navigated from 1 to 2. If no transitions were set to the slide, the first page will just disappear, and appear on the second page immediately. If it has a transition effect, a certain time for playing animations will insert between switching pages.

An important thing during transition is that 2 slides are presented in the view at the same time like layers. All kinds of effects produce smooth transitions by applying specific animations to one or both slides.
In Marp, the slide page that was shown before transition calls as **"Outgoing slide"**, and the next page to appear after transition calls as **"Incoming slide"**. Slide pages may have an inverse relationship when brought the backward navigation, but the meaning of "incoming" and "outgoing" is always consistent.
If you could figure them out, you probably also grasp that you have to respect the following 2 principles:
- **The outgoing slide** should have **an animation to hide** the slide.
- **The incoming slide** should have **an animation to show** the slide.
If either or both was not respected in a transition effect, it would become a weird transition.
> Marp CLI's `bespoke` template will make two slide layers when navigated, and apply suitable animation keyframes declared in CSS.
# Declare custom transitions
## Simple keyframe declaration
Let's get started with a simple keyframe declaration for [the dissolve effect (also known as the cross-fade effect)](<https://en.wikipedia.org/wiki/Dissolve_(filmmaking)>), to learn how to set custom transition animation. Marp uses [standard syntax for CSS animation `@keyframes`](https://developer.mozilla.org/docs/Web/CSS/@keyframes) to declare transitions.
When applying the dissolve effect to transition principles, you can derive that the effect needs these animations:
- The outgoing slide has an animation to **decrease opacity from 100% to 0%**.
- The incoming slide has an animation to **increase opacity from 0% to 100%**.
There are opposite changes with each other. In this case, you can define animations for both slide layers by one `@keyframes` declaration.
First, declare `@keyframes` at-rule with the conventional name specified by Marp in your Markdown.
```markdown
---
transition: dissolve
style: |
@keyframes marp-transition-dissolve {
/* ... */
}
---
# Slide 1
---
<!-- _class: invert -->
# Slide 2
```
**`marp-transition-xxxxxxxx`** is the rule of animation name to register the transition with a simple declaration. For using declared transition in Marp slide, assign `transition` local directive with the name declared in `xxxxxxxx`.
> This example is using [`style` global directive](https://marpit.marp.app/directives?id=tweak-theme-style) to declare keyframes. Of course, you also can use [the inline `<style>` element](https://marpit.marp.app/theme-css?id=tweak-style-through-markdown) or [custom theme CSS](https://marpit.marp.app/theme-css) to declare.
Well, declare animation details at keyframes. In a simple declaration, you only have to set animation for the outgoing slide. For the incoming slide, Marp will set the animation in the reverse direction automatically.
```css
@keyframes marp-transition-dissolve {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
```
> This example has been declared `from` keyframe for clarity, but you can omit it because `opacity: 1` is a default style.
Did you want more? That's it! Try to test this transition in the HTML slide with the browser that supports [View Transitions API], or [a preview window in Marp CLI](https://github.com/marp-team/marp-cli#preview-window---preview---p).
```bash
npx @marp-team/marp-cli@^2.4.0 --preview ./transition.md
```
You have made the first custom transition!

In this article, the example is simplified for teaching how to make a custom transition, and there is a bit of difference from the built-in transition `fade` for getting the same effect. `dissolve` effect is looking good, but there is [a general pitfall about cross fading](https://jakearchibald.com/2021/dom-cross-fade/).
## Split animations into outgoing and incoming
A simple declaration should work in some transition types well, but it's not that all transitions have exactly contrary animations to each other. In reality, different animations for the outgoing slide and incoming slide are required in most cases.
For example, the slide up effect must have these animations:
- The outgoing slide should **move from the viewport to the upper outer**.
- The incoming slide should **move from the lower outer to the viewport**.
So you can declare split animations for each layer rather than declaring a single animation. Set `@keyframes` with the prefix of the target transition: **`marp-outgoing-transition-xxxxxxxx`** and **`marp-incoming-transition-xxxxxxxx`**.
```markdown
---
transition: slide-up
style: |
@keyframes marp-outgoing-transition-slide-up {
from { transform: translateY(0%); }
to { transform: translateY(-100%); }
}
@keyframes marp-incoming-transition-slide-up {
from { transform: translateY(100%); }
to { transform: translateY(0%); }
}
---
# Slide 1
---
<!-- _class: invert -->
# Slide 2
```
Unlike the simple transition, there is no auto-reversed animation in the incoming slide. Each animation should define in the right direction.

## Transition for backward navigation
If you have tested the above slide-up transition example, you may have noticed that is having a move to up also when slide navigation going to back has occurred.

It brings a wrong user interaction and is not intuitive. You should want to provide the animation for the correct direction when occurred backward navigation.
We are providing several solutions to deal with this.
### `--marp-transition-direction` CSS variable
While playing transition, `--marp-transition-direction` [CSS custom property (as known as CSS variables)](https://developer.mozilla.org/docs/Web/CSS/Using_CSS_custom_properties) will be available in `@keyframes`.
It provides `1` in forwarding navigation, or `-1` in backward navigation. Using [`var(--marp-transition-direction)`](https://developer.mozilla.org/docs/Web/CSS/var) together with [`calc()`](https://developer.mozilla.org/docs/Web/CSS/calc) function would be useful to calculate the position in response to the direction of slide navigation.
<!-- prettier-ignore-start -->
```css
@keyframes marp-outgoing-transition-slide-up {
from { transform: translateY(0%); }
to { transform: translateY(calc(var(--marp-transition-direction, 1) * -100%)); }
}
@keyframes marp-incoming-transition-slide-up {
from { transform: translateY(calc(var(--marp-transition-direction, 1) * 100%)); }
to { transform: translateY(0%); }
}
```
<!-- prettier-ignore-end -->
And now, the slide-up custom transition is working completely in both directional navigation!

> NOTE: Any other CSS variables defined in the context of animation keyframes cannot use in keyframes.
### Set custom animations for backward transition
Alternatively, you also can set more animation keyframes that are specific for backward navigation.
Declare `@keyframes` with the **`backward-` prefix to the custom transition name**, just like as **`marp-transition-backward-xxxxxxxx`**. It is available in both simple keyframes declaration and split keyframes declaration.
<!-- prettier-ignore-start -->
```css
@keyframes marp-incoming-transition-triangle {
/* Wipe effect from left top */
from { clip-path: polygon(0% 0%, 0% 0%, 0% 0%); }
to { clip-path: polygon(0% 0%, 200% 0%, 0% 200%); }
}
@keyframes marp-incoming-transition-backward-triangle {
/* Wipe effect from right bottom */
from { clip-path: polygon(100% 100%, 100% 100%, 100% 100%); }
to { clip-path: polygon(-100% 100%, 100% -100%, 100% 100%); }
}
```
<!-- prettier-ignore-end -->
In backward navigation, each layer will try to use the backward keyframes first, and fall back to the normal keyframes if not declared. To disable unintended fallback in backward animations, set an empty declaration of `@keyframes`.
<!-- prettier-ignore-start -->
```css
@keyframes marp-outgoing-transition-zoom-out {
from { transform: scale(1); }
to { transform: scale(0); }
}
@keyframes marp-incoming-transition-zoom-out {
/* Send the incoming slide layer to back */
from { z-index: -1; }
to { z-index: -1; }
}
/* ⬇️ Declare empty keyframes to disable fallback ⬇️ */
@keyframes marp-outgoing-transition-backward-zoom-out {}
@keyframes marp-incoming-transition-backward-zoom-out {
from { transform: scale(0); }
to { transform: scale(1); }
}
```
<!-- prettier-ignore-end -->
OK, I've described all about declarations for the custom transition!
# Tips
## Easing function
Each transition has a linear easing by default. You can specify [`animation-timing-function` property within individual keyframes](https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#:~:text=A%20keyframe%27s%20timing%20function%20is%20applied%20on%20a%20property%2Dby%2Dproperty%20basis%20from%20the%20keyframe%20on%20which%20it%20is%20specified%20until%20the%20next%20keyframe%20specifying%20that%20property%2C%20or%20until%20the%20end%20of%20the%20animation%20if%20there%20is%20no%20subsequent%20keyframe%20specifying%20that%20property) if you want.
> Setting [`animation-timing-function: step-end;`](https://developer.mozilla.org/docs/Web/CSS/animation-timing-function#step-end) to a keyframe can make paused animation until the next keyframe.
## Duration
We have a fixed duration time of `0.5s` as default for every transition. If you want to set a different default duration for your custom transition, please set `--marp-transition-duration` property in the first keyframe (`from` or `0%`).
<!-- prettier-ignore-start -->
```css
@keyframes marp-incoming-transition-gate {
from {
/* Set the default duration of the "gate" transition as 1 second. */
--marp-transition-duration: 1s;
clip-path: inset(0 50%);
}
to { clip-path: inset(0); }
}
@keyframes marp-outgoing-transition-backward-gate {
from {
/* You also can set a different default for backward transition as necessary. */
/* --marp-transition-duration: 1.5s; */
clip-path: inset(0);
}
to { clip-path: inset(0 50%); }
}
@keyframes marp-incoming-transition-backward-gate {
from { z-index: -1; }
to { z-index: -1; }
}
```
<!-- prettier-ignore-end -->
The slide author can override the default duration at any time, through the `transition` local directive in Markdown (`<!-- transition: fade 2s -->`).
## Fixed property
If some of the properties required a fixed value while playing transition, try to set the same declaration into `from` (0%) and `to` (100%).
<!-- prettier-ignore-start -->
```css
@keyframes marp-outgoing-transition-pin {
/* Use fixed transform-origin */
from {
transform-origin: top left;
animation-timing-function: ease-in;
}
to {
transform-origin: top left;
transform: rotate(90deg);
}
}
@keyframes marp-incoming-transition-pin {
/* Send the incoming slide layer to back */
from { z-index: -1; }
to { z-index: -1; }
}
```
<!-- prettier-ignore-end -->
## Layer order
[As presented in a diagram earlier](#the-anatomy-of-a-transition), the incoming slide layer always will be stacked on the top of the outgoing slide layer. According to the kind of transition, this order may be not suitable.
A fixed property [`z-index: -1`](https://developer.mozilla.org/docs/Web/CSS/z-index) is helpful to send the incoming slide layer to back.
> A fixed `z-index: 1` to the outgoing slide (send to front) is also getting the same result, but currently setting a positive number to `z-index` may bring animation jank in Chrome.
## Change layer order during a transition
If you want to swap the order of layers during animation, try to animate `z-index` property.
<!-- prettier-ignore-start -->
```css
@keyframes marp-incoming-transition-swap {
/* Incoming slide will swap from `back` to `front` at 50% of animation */
from { z-index: -1; }
to { z-index: 0; }
/* Declarations for moving animation */
0% { transform: translateX(0); }
50% { transform: translateX(50%); }
100% { transform: translateX(0); }
}
@keyframes marp-outgoing-transition-swap {
0% { transform: translateX(0); }
50% { transform: translateX(-50%); }
100% { transform: translateX(0); }
}
```
<!-- prettier-ignore-end -->
`z-index` is always taking an integer value, and interpolated `z-index` value by animation does not take any decimal points too. So animating from `z-index: -1` to `z-index: 0` is exactly meaning to set `-1` at the first half of duration and `0` at the last half, except if using a non-linear easing function.
## Frequently used properties in transition
[There are a lot of animatable CSS properties](https://developer.mozilla.org/docs/Web/CSS/CSS_animated_properties), and the following properties are frequently animated in built-in transitions.
- [`opacity`](https://developer.mozilla.org/docs/Web/CSS/opacity)
- [`transform`](https://developer.mozilla.org/docs/Web/CSS/transform)
- [`filter`](https://developer.mozilla.org/docs/Web/CSS/filter)
- [`clip-path`](https://developer.mozilla.org/docs/Web/CSS/clip-path)
- [`mask-image`](https://developer.mozilla.org/docs/Web/CSS/mask-image) (`-webkit-mask-image`)
- [`box-shadow`](https://developer.mozilla.org/docs/Web/CSS/box-shadow)
- [`z-index`](https://developer.mozilla.org/docs/Web/CSS/z-index)
# Try it!
Transitions for Marp CLI's bespoke template backed by [View Transitions API] in the browser, provides flexibility to design your talk as you like. Custom transition brings out your boundless creativity, without complex JS codings, just declarative definitions in CSS.
We are really looking forward to what creative transition effects our community will create!
Share the custom transition you've made with [Marp community](https://github.com/orgs/marp-team/discussions). You can provide custom theme CSS including a bunch of custom transitions too.
================================================
FILE: website/blog/marp-for-vs-code-v1.md
================================================
---
title: 'Marp for VS Code v1: IntelliSense for Marp directives'
date: 2021-05-20
description: I'm happy to announce Marp for VS Code has reached to the stable release v1! This release includes IntelliSense for Marp directives and getting more affinity with VS Code features to get better writing experience.
author: Yuki Hattori
github: yhatt
image: /og-images/marp-for-vs-code-v1.jpg
---
We are continuing development to make stable Marp tools. And today, I'm happy to announce [Marp for VS Code] has reached to the stable release v1!
Tools of Marp ecosystem are made for potentially covering various situations, and especially Marp for VS Code is made for the daily use for the most of users.
This extension can change the familiar Markdown preview into slides preview during editing Marp Markdown. You can write and edit slides by text rapidly together with checking the appearance of slides, and export into PDF/PPTX easily. [Custom theme support](https://github.com/marp-team/marp-vscode#use-custom-theme-css-shield) is useful to create your own theme with CSS.
In this release, we have added IntelliSense extension for Marp directives and got more affinity with [VS Code] features. It provides better experience as integrated environment to write the presentation.
[vs code]: https://code.visualstudio.com/
[marp for vs code]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
<!-- more -->
[**➡️ Go to Visual Studio Marketplace to get Marp for VS Code**][marp for vs code]
# History
[][marp for vs code]
Marp for VS Code has started development since 2019, to replace GUI interface from [the classic Marp app](https://yhatt.github.io/marp). It is focusing to provide better experience for writing Marp presentation.
[We had also thought making another Web app as a primary project at that time](/blog/the-story-of-marp-next#marp-web-tech-demo), but VS Code has drastically grown as time goes by. It is covering Web and mobile devices through [GitHub Codespaces](https://visualstudio.microsoft.com/services/github-codespaces/). Thus, we are still continuing development VS Code extension as an official Marp integration for GUI.
# New features
## IntelliSense for Marp directives 🤓
[Directives](https://marpit.marp.app/directives), the inherited feature from [Marpit framework](https://marpit.marp.app/), is an important syntax to write the deck in Marp.
Our extension is depending on 3 different Marp projects that have unique directives. User had been hard to know all of supported directives because the guidance of them has scattered into each tools.
So we have extended [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense) to cover all of supported Marp directives! Marp for VS Code is now providing powerful editing features for directives: Auto completion, syntax highlight, hover help, and diagnostics.
### Auto completion
Hit `Ctrl` + `Space` within [the front-matter](https://marpit.marp.app/directives?id=front-matter) or [HTML comment](https://marpit.marp.app/directives?id=html-comment) to show the list of directives. You can peek the help of selected directive by hitting `Ctrl` + `Space` again.

I worked hard into refactor of a parser for Marp Markdown to get this improvement. This change would make easier to add new language feature like auto-completion for [the extended image syntax](https://marpit.marp.app/image-syntax) in the future.
### Syntax highlight and hover help
When enabled Marp feature, recognized directives are highlighted by the different color from around. It's useful for finding out meaningless definitions.
And you can peek the help of directive when hovering the cursor.

### Diagnostics
It is accurately not new feature but I'm sure the most of users have not seen because it had used just for migrating outdated syntax.
In this update, we have added some helpful diagnostics for Marp directives. For example, Marp for VS Code can notify not recognized theme name that is specified by `theme` directive.

## Virtual workspace support 🌐
VS Code is still evolving to cover various situations: [Editing remote files](https://code.visualstudio.com/docs/remote/remote-overview), [collaborating with others](https://code.visualstudio.com/learn/collaboration/live-share), and something useful provided by [a lot of third-party extension](https://marketplace.visualstudio.com/vscode). Marp for VS Code is also making an effort to cover them as far as possible.
In the recent update, we have improved the export command and custom theme support within a virtual workspace by followed [the call to action from VS Code team](https://code.visualstudio.com/updates/v1_56#_define-whether-your-extension-supports-a-virtual-workspace).
No problem even if you don't know the virtual workspace! In short, Marp features will become to work correctly in various situation.
### Details
Previously an export command had assumed to deal only local files. So the result of command might miss some resources that have not located in local file system.
We are dealing with this by internally serving resources located in a virtual workspace via HTTP while processing of export ([marp-team/marp-vscode#225](https://github.com/marp-team/marp-vscode/pull/225)). By doing this, the result of export command within [a remote repository](https://code.visualstudio.com/updates/v1_56#_remote-repositories-remotehub), a coming feature of VS Code to edit the content of GitHub repository without clone/download, can include resources correctly.
This behavior is under verifying and may fail to resolve resources in some cases (e.g. [marp-team/marp-vscode#238](https://github.com/marp-team/marp-vscode/issues/238)). We are welcome more feedbacks about the export command in a virtual workspace!
## Workspace Trust 🛡️
[Workspace Trust](https://github.com/microsoft/vscode/issues/106488) is a unified security model for the whole of VS Code. Currently it's an opt-in feature (VS Code 1.56) but it's going to be enabled by default soon. [VS Code team is calling to action into extension authors also for this.](https://code.visualstudio.com/updates/v1_56#_workspace-trust-extension-api)
Based on reflection of [the outdated Marp app](https://yhatt.github.io/marp), Marp team is thinking about users security first. Actually we were passive for supporting a feature that have potentially security concerns (e.g. [marp-team/marp-vscode#123](https://github.com/marp-team/marp-vscode/pull/123)). Making ready for Workspace Trust will become available to contain more advanced features.
Marp for VS Code v1 is supporting Workspace Trust. If the current workspace is not trusted, you can only use basic Marp features (Markdown preview and IntelliSense).
### Restricted features in untrusted workspace
- Export command
- Using custom themes configured in workspace: `markdown.marp.themes`
- Enabling HTML tags in Markdown: `markdown.marp.enableHtml`
# Conclusion
Marp for VS Code is focusing into providing the great experience to write presentation. IntelliSense for Marp directives is a big improvement for that. We are going to continue making an effort to cover update of VS Code.
And Marp team is always thinking about security. Supporting VS Code's Workspace Trust is an important thing to save you from maliciousness.
In addition, a way of thinking about the trusted workspace would open the door to more useful features that were prevented by security concerns: Custom Marp CLI configuration, playing presentation, and so on.
## What's next?
There are no determined things. But supporting Workspace Trust has taken a step toward some advanced features.
We are planning some well-known features in the other presentation software to reduce friction of moving from familiar tools: the sidebar with slide thumbnails ([marp-team/marp#42](https://github.com/marp-team/marp/discussions/42)), presentation button in lower-right, and so on.

Enjoy writing presentation with our extension! And join to [our discussion forum](https://github.com/marp-team/marp/discussions) if you want more Marp tips.
[**➡️ Go to Visual Studio Marketplace to get Marp for VS Code**][marp for vs code]
================================================
FILE: website/blog/marpit-v2-marp-core-v2-and-marp-cli-v1.md
================================================
---
title: Marpit v2, Marp Core v2, and Marp CLI v1
date: 2021-05-06
description: I'm so glad to announce shipping Marpit framework v2, Marp Core v2, and Marp CLI v1! Especially, Marp CLI is getting stable now!
author: Yuki Hattori
github: yhatt
---
[marpit framework]: https://marpit.marp.app/
[marp core]: https://github.com/marp-team/marp-core
[marp cli]: https://github.com/marp-team/marp-cli
I'm so glad to announce shipping [Marpit framework] v2, [Marp Core] v2, and [Marp CLI] v1! Especially, Marp CLI is getting stable now!
They are major update that may be including some breaking changes. However, we have not intended to include any drastic changes. We have recognized well that user hates to break the existing slide.
The biggest reason why bumped major version is ending support for outdated Node.js 10. It has reached to End-of-Life and we are just following that.
Marpit and Marp Core still can use in EOL Node 10, but we are just making a window time for transition. By the security reason, we don't recommend to use outdated Node.js.
<!-- more -->
# Release notes
## [Marpit framework: v2.0.0](https://github.com/marp-team/marpit/releases/tag/v2.0.0)
### Breaking
- Marpit requires Node.js >= 10 to install ([#284](https://github.com/marp-team/marpit/pull/284))
### Fixed
- Reset CSS columns in advanced background ([#283](https://github.com/marp-team/marpit/pull/283))
### Changed
- Upgrade to PostCSS 8 ([#260](https://github.com/marp-team/marpit/issues/260), [#284](https://github.com/marp-team/marpit/pull/284))
- Upgrade Node and dependent packages to the latest version ([#285](https://github.com/marp-team/marpit/pull/285))
### Removed
- Remove deprecated `markdownItPlugins`, the getter of plugin interface for markdown-it ([#286](https://github.com/marp-team/marpit/pull/286))
## [Marp Core: v2.0.0](https://github.com/marp-team/marp-core/releases/tag/v2.0.0)
### Added
- Allow color customization through CSS variables in Gaia and Uncover theme ([#209](https://github.com/marp-team/marp-core/issues/209), [#221](https://github.com/marp-team/marp-core/pull/221))
> May break appearance of existing presentation if you have a slide with custom style.
### Changed
- Upgrade Marpit to [v2.0.0](https://github.com/marp-team/marpit/releases/v2.0.0) ([#220](https://github.com/marp-team/marp-core/pull/220))
- Upgrade Node LTS and dependent packages to the latest version ([#222](https://github.com/marp-team/marp-core/pull/222))
## [Marp CLI: v1.0.0](https://github.com/marp-team/marp-cli/releases/tag/v1.0.0)
### Breaking
- Dropped Node 10 support ([#338](https://github.com/marp-team/marp-cli/pull/338))
### Added
- Build Docker container image for ARM64 ([#328](https://github.com/marp-team/marp-cli/issues/328), [#339](https://github.com/marp-team/marp-cli/pull/339))
- Allow `MARP_USER` env for Docker image to set an explicit UID/GID ([#334](https://github.com/marp-team/marp-cli/pull/334) by [@davebaird](https://github.com/davebaird))
- Test against Node 16 for Windows ([#338](https://github.com/marp-team/marp-cli/pull/338))
### Changed
- Upgrade [Marpit v2.0.0](https://github.com/marp-team/marpit/releases/tag/v2.0.0) and [Marp Core v2.0.0](https://github.com/marp-team/marp-core/releases/tag/v2.0.0) ([#338](https://github.com/marp-team/marp-cli/pull/338))
- Upgrade Node and dependent packages to the latest version ([#338](https://github.com/marp-team/marp-cli/pull/338))
# What's Next?
I've posted about [the unified docs, and future plans for our toolset in the last article](/blog/re-creation-of-marp-website). But it was a mistake! Marp team is still alone and I cannot take full-time working for that, so the most of planned features are delayed. Sorry for late.
For helping us, contribution in [Marp discussion forum](https://github.com/marp-team/marp/discussions) will be good start.
## Marpit framework v3
We have ve already started for working Marpit v3 on [`v3` branch](https://github.com/marp-team/marpit/tree/v3).
It's going to be rewritten fully by TypeScript. We are planning to separate Marp slide specific plugins internally, for improvement of collaboration with other slide renderers. In addition, I want to support async conversion by returning Promise in `render()`.
We also had considered about changing Markdown parser, but we decided not to change. Some Marp users are depending on third party plugins, and it would make a lot of breakings if changed.
# Thanks
Over 5 years have passed from the first release of classic Marp. For keeping maintainability for long time, Marp ecosystem is still aiming to "minimal". And now, Marp has used by projects hosted on [Microsoft](https://github.com/microsoft/lage), [Google](https://github.com/google/applied-machine-learning-intensive), and [Facebook](https://github.com/facebookincubator/cargo-guppy).
In the last year, we opened our [discussion forum](https://github.com/marp-team/marp/discussions) to accept asking and reporting for the whole of Marp toolset. And we have received many feedbacks and contributions from users.
Thanks for our community! Marp will keep a growth with users.
================================================
FILE: website/blog/re-creation-of-marp-website.md
================================================
---
title: Re-creation of Marp website for the unified docs
date: 2020-08-22
description: We are announcing that Marp team is working to the re-creation of marp.app website for hosting the unified documentation.
author: Yuki Hattori
github: yhatt
---
[marpit framework]: https://marpit.marp.app/
[marp core]: https://github.com/marp-team/marp-core
[marp cli]: https://github.com/marp-team/marp-cli
[marp for vs code]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
I could not have imagined that now we are living in a unique pandemic era when I wrote [the last article](/blog/the-story-of-marp-next). Even under those severe circumstances, I'm still making progress of Marp.
Marp gives some tools for making a convincing slide deck with fewer efforts, and they get loved by a lot of users. In early this year, [Marp Core] has reached the stable v1 release, and our tools around the core are keeping steps with it. Needless to mention here, we will keep going to enhance our tools.
Today we are announcing that **Marp team is working to the re-creation of [marp.app](/) website for hosting the unified documentation**. If you are reading this article, you should have already seen the re-created website! Currently the unified docs is not yet ready but we are going to announce here as soon as getting ready.
<!-- more -->
# For the unified documentation
As Marp ecosystem spreads out, Marp team has become to regard the lack of unified documentation as an important issue. Our docs are scattered to many repos per tool, and it would make confusion when learning overall of Marp. In addition, we often have been asked basics of Marp in the issue tracker and sometimes even prevent our works for evolving Marp.
For making users take advantage of Marp easier, I'm going to work improving the documentation together with evolving Marp tools.
## Re-created [marp.app](/)
The re-created web page is the first step for building the unified docs. I had tried various tools to build the website and found a place to rest in [Next.js](https://nextjs.org/) and [Tailwind CSS](https://tailwindcss.com/). I believe we will be able to build more useful documentation pages by these.
It is managed in our entrance repository [marp-team/marp](https://github.com/marp-team/marp) as same as before. If shipped new documentation, we would accept some improvements in the documentation from the community.
---
## Mid-term plans for Marp tools
Might as well, finally let me share some mid-term plans for each tools I'll work shortly.
- [Marpit framework]: Enhance directives
- [Marp Core]: Add new built-in theme and simplify auto-scaling feature
- [Marp CLI]: Handout template
- [Marp for VS Code]: Better auto-completion for Marp directives
We also had announced [long-term plans earlier](/blog/the-story-of-marp-next): [Marp Web](https://web.marp.app/), Marp integration modules with [React](https://github.com/marp-team/marp-react) and [Vue](https://github.com/marp-team/marp-react), and [Marpit v2](https://github.com/marp-team/marpit/issues/194). However, _they are not yet in active and may need to reconsider plans because we have not enough positive feedbacks from community._
================================================
FILE: website/blog/the-story-of-marp-next.md
================================================
---
title: The story of Marp Next
date: 2019-06-06
description: Today, I'm so excited to introduce the story of Marp Next! The full-rewritten Marp is not only just a writer. To be usable in various situations, we build a brand-new Marp ecosystem consisted of multiple modules.
author: Yuki Hattori
github: yhatt
image: /og-images/the-story-of-marp-next.png
---
The first version of [Marp](https://yhatt.github.io/marp/) was released at almost 3 years ago. At first, it was started from a simple tool for personal usage called "mdSlide". And now, Marp has been used by a lot of users who would recognize the real value of the presentation writer. Marp is amassed around [8,000 stars](https://github.com/yhatt/marp/stargazers) until now.
However, our headache brought from lacked maintainability to develop. We had received so many requests to the old Marp app, and it has to evolve to keep providing the best writing environment of presentation deck.
Today, I'm so excited to introduce the story of Marp Next! The full-rewritten Marp is not only just a writer. To be usable in various situations, we build **a brand-new Marp ecosystem** consisted of multiple modules. They are developed with JavaScript and TypeScript, and much more maintainable than the previous Marp.
<!-- more -->
# Marp ecosystem
Marp Next has two core components: **[Marpit]** framework and **[Marp Core]**. Tools by Marp ecosystem are usually based on these.
## Marpit
**[Marpit]** is _the skinny framework_ for creating HTML slide deck from Markdown. It is designed to convert Markdown into only minimum assets consisted of static HTML and CSS, and the output can convert into PDF slide deck by printing through Chrome / Chromium.
Marpit has created for using as the base of Marp ecosystem, but it is also independent framework. You may integrate Marpit's Markdown conversion with your tool, even if it's not Marp: [reveal.js](https://codesandbox.io/embed/nw80vrxvpp), [WebSlides](https://codesandbox.io/embed/j3wo2091yw), and so on.
[marpit]: https://marpit.marp.app/
### [Marpit Markdown]: Keep compatibility with a plain Markdown document
We had received [many requests][issues] to the old Marp, about the additional syntax to help creating beautiful slide deck. On the other hand, we also have received a request that [must respect Markdown syntax strictly](https://github.com/yhatt/marp/issues/87). We have to deal with these contradicted issues.
Additional syntax provided by Marpit should never break [CommonMark](https://commonmark.org/) document. Thus, the result of rendering keeps looking nice even if you open the Marpit Markdown in a general Markdown editor. And you can even extend the additional syntax via [markdown-it plugins](https://marpit.marp.app/usage?id=extend-marpit-by-plugins) if you need.
[marpit markdown]: https://marpit.marp.app/markdown
[issues]: https://github.com/yhatt/marp/issues
### [Theme CSS]: Design your deck with clean markup
Marpit has the theming system to allow designing everything of slides by CSS.
The old Marp had the _limited_ theming system and required deep diving to internal for customization: Build system, [Sass], the logic of Marp app, and so on. So we had to create a brand-new theming system for easy customization of theme with only general CSS knowledge.
Marpit's it only requires a pure CSS, and no additional knowledges! You have only to focus styling HTML semantic elements. It means that you can create theme CSS from now!
In addition, Marpit has the pixel-perfect slide system like PowerPoint and Keynote. Theme creator never needs to worry about the responsive layout, and could provide design exactly as the author wanted with less effort.
[theme css]: https://marpit.marp.app/theme-css
[sass]: https://sass-lang.com/
### [Inline SVG slide] (Experimental)
Our unique idea is wrapping each slides by inline SVG. It might feel a bit strange, but makes many advantages.
- Supports pixel-perfect scaling via style definition and **realizes Zero-JS slide deck**.
- Isolates Markdown contents and prevents that injected DOM by Marpit's advanced feature breaks design defined in theme CSS.
Thanks to the power of SVG, we can keep a framework simple and maintainable. [Marp Core] is based on inline SVG slide by default.
[inline svg slide]: https://marpit.marp.app/inline-svg
## Marp Core
**[Marp Core]** is a base converter for our projects extended from Marpit. In short, it is a battery-included Marpit.
Marpit only has bare essential features, so it might have not enough to start writing your deck. Marp Core provides the practical syntax, additional features, and built-in themes.
Many of the features are based on the old desktop app, and have improved to be suitable to Marpit. Of course, we added the new features for creating more beautiful deck.
[marp core]: https://github.com/marp-team/marp-core
- Built-in themes (Default, Gaia, and _new_ Uncover theme)
- Included Emoji support 😁
- [KaTeX](https://katex.org/) Math typesetting
- `size` global directive
- Auto scaling features (_new_)
- Fitting header via `<!-- fit -->` annotation
- Scale-down overflowed fence, code, and math block
# Applications
## Marp CLI
[marp cli]: https://github.com/marp-team/marp-cli
**[Marp CLI]** is a CLI interface of Marpit and Marp Core converter. It's a Swiss-Army knife for Marp slide deck!
[][marp cli]
You can use it right now by running `npx @marp-team/marp-cli` if [Node.js](https://nodejs.org/) is installed.
- Export to HTML, PDF, and image
- Watch the change of your Markdown and theme (`--watch`)
- Open preview window for presentation (`--preview`)
- Full-customizable engine based on Marpit framework
Marp had a text editor originally, but you might think that want to write the slide deck with your favorite editor. If you use Vim, you would feel uncomfortable not to be usable Vim style key-binding. From now on, use Marp CLI's watch mode together with original Vim!
And Marp CLI can create really practicable static HTML as like as a presentation mode! It is powered by deep integration with [Bespoke.js](https://github.com/bespokejs/bespoke).
Thanks to [Netlify], [Now], and more hosting services, Marp CLI also brings a efficient Git management for creating slide deck just like [GitPitch]. I've created [an example slide](https://yhatt-marp-cli-example.netlify.com/) managed via [GitHub repository](https://github.com/yhatt/marp-cli-example) as a good starter to help writing your slide deck. Try to use it via "Deploy to Netlify" button on [README](https://github.com/yhatt/marp-cli-example/blob/master/README.md#usage)!
[netlify]: https://www.netlify.com/
[now]: https://zeit.co/now/
[gitpitch]: https://gitpitch.com/
## Marp Web (_tech demo_)
**[Marp Web]** is a Web interface of Marp presentation writer. It allows writing your slide deck as like as a traditional desktop app.
> The current Marp Web is just a tech demo. We are planning to re-implement Marp Web based on well-known framework (like React) for building SPA.
[marp web]: https://web.marp.app/
### Progressive Web Apps
It made [some strong oppositions by users that is using Marp in offline](https://github.com/yhatt/marp/issues/174#issuecomment-294594856) when an idea of migration to web-based app is proposed for keeping maintainability of Marp. It was caused that a thinking of PWA was not general at that time.
And 2 years later, the time has come to use PWA! After the first access to **[https://web.marp.app/][marp web]**, Marp Web would be ready to use in both of online and offline. Online resources to use the web interface would be cached in your browser, and use them when network is offline.
[][marp web]
### Use via any devices
By migrating to the web-based app, Marp will be able using in mobile device: Android and iOS. That's sure it's well suited to the tablet device like iPad.

Marp Web would work also in Chrome OS well. Marp especially has many users in the field of education, and supporting Chrome OS that has large share in its field is meaningful.
### Blazing-fast live preview ⚡️
We think Marp's important feature is a blazing-fast live preview. In the web-based app, realizing the same feature had many difficulties.
In currently published tech-demo, you can try Marp's really fast preview on the web. The preview applies as soon as typing, and it would not block your typing even if you have a large Markdown slides over than 100 pages.
# Integrations
The modularized Marp Core brought Marp integrations for some tools.
## [Marp for VS Code][marp vscode]
Honestly, I don't think to want to make a new editor because there are many great Markdown editors in the world. I had been thinking it would be awesome if Marp could integrate with a something else powerful Markdown editor. And now, Marp can use in [Visual Studio Code](https://code.visualstudio.com/)!

It was realized because VS Code is using the same Markdown engine (markdown-it) as Marpit framework. Of course, you can export slides as PDF and HTML easily, powered by [Marp CLI].
[marp vscode]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
## [Marp React] & [Marp Vue] (In development)
[marp react]: https://github.com/marp-team/marp-react
[marp vue]: https://github.com/marp-team/marp-vue
Marp's blazing fast live-preview is not only for ours! We provide Marp renderer component into [React][marp react] and [Vue][marp vue]. Both Marp React and Marp Vue have supported the incremental update using framework's virtual DOM, and they are been easy to build your app.
Especially, Marp React would become to the base of the future of [Marp Web].
# Migration plan
## Desktop app ([yhatt/marp](https://github.com/yhatt/marp))
If you are using an old Marp application, **you should migrate to use Marp Next tools.** I NEVER recommend continue to use the old Marp, because _its maintainance has stopped 2 years ago and there is concern about security issues._
In future, the main interface would become to Marp Web. We have bet to PWA technology that has a lot of advantages. The desktop app is planned as "Marp Desktop" but it just may become a wrapper of Web interface.
I would stop publishing the old Marp and archive its repository if Marp Web has grown to become replaceable the old Marp.
## Your slide deck
Your Markdown slides written in the old Marp syntax should rewrite to suit to the brand-new Marp ecosystem.
In a new Marp, we have reconsidered Markdown syntax based on feedback to the old Marp app. So, some syntaxes are losing compatibility.
### Syntax
- In Marp Core, non-whitelisted HTML elements are disabled by default because of security reason. Currently our whitelist includes only `<br>` element. Some Marp Next tools has provided preference to enable HTML, but you should take care for enabling HTML in untrusted Markdown.
### Directives
- Directives would be parsed by YAML parser tuned for Marp (Marpit). Thus spot directive prefix `*` is changed to `_` for keeping YAML syntax.
- `$` prefix no longer required to global directives.
- Slide size still can choose from "16:9" and "4:3", through `size` global directive (provided by Marp Core). If you want to use custom size or you're using Marpit framework, please use [theme CSS](https://marpit.marp.app/theme-css?id=slide-size).
- `page_number` directive is renamed to `paginate`.
- `template` directive is renewed to use `class` directive. It can define HTML class per slides.
- `prerender` directive is removed. It brings user confusing about exported PDF quality.
### Image
- Background image `![bg]()` has no filter applied by default. Try using `![bg opacity]()` if you want.
- The inline image is no longer scalable by percentage `![50%]()`. (It's not supported in Firefox) Instead you can use `width` (`w`) and `height` (`w`) keyword to resize image as like as `![width:300px]()`.
- `![center]()` won't work. It requires changing image to the block element and brings confusion to theme author. You can tweak style if you still want.
```html
<style>
img[alt~='center'] {
display: block;
margin-left: auto;
margin-right: auto;
}
</style>
```
# Try Marp Next!
Marp Next just focuses to build the ecosystem for Markdown slide deck with pure open source. We expect to expand Marp productivity together with open source community.
We still have stood at the beginning of the brand-new ecosystem. Are you interested to Marp team and our ecosystem? We welcome to start your contribution! See [our contributing guideline](https://github.com/marp-team/.github/blob/master/CONTRIBUTING.md) and get started!
> PS. [GitHub Sponsors](https://github.com/sponsors/yhatt) is also good contribution if you want to help my working for open source.
================================================
FILE: website/components/Button.tsx
================================================
import classNames from 'classnames'
import { ReactNode } from 'react'
export type ButtonProps = {
children?: ReactNode
color?: 'primary'
href?: string
outline?: boolean
[key: string]: unknown
}
export const Button = ({
children,
className,
color,
href,
outline,
...rest
}: ButtonProps) => {
const Tag = href ? 'a' : 'button'
const attrs = {
...rest,
...(Tag === 'a' ? { href, role: 'button', tabIndex: 0 } : {}),
}
return (
<Tag
{...attrs}
className={classNames(
Tag === 'a' && 'custom-anchor',
'button',
color,
{ btnOutline: outline },
className as any
)}
>
{children}
<style jsx>{`
.button {
@apply relative inline-block select-none appearance-none rounded-full bg-white text-center font-bold no-underline shadow-md;
padding: 0.625em 1.25em;
transition: color, background-color, opacity;
}
@screen md {
.button {
@apply tracking-wider;
}
}
.button:hover {
@apply bg-background duration-150;
}
.button:hover:active {
@apply duration-0 bg-gray-300 outline-none ring-1 ring-white ring-offset-2;
}
.button:focus {
@apply outline-none ring-1 ring-white ring-offset-2;
}
/* Primary color */
.button.primary {
@apply bg-marp-brand text-white;
background-image: linear-gradient(
30deg,
transparent,
rgba(255, 255, 255, 0.3)
);
}
.button.primary:hover {
@apply bg-marp-darken;
}
.button.primary:hover:active {
@apply bg-marp-dark;
}
/* Outline */
.button.btnOutline {
@apply text-foreground;
}
.button.btnOutline::after {
@apply pointer-events-none absolute inset-0 block border-2 border-current;
border-radius: inherit;
content: '';
transition: inherit;
}
.button.btnOutline.primary {
@apply text-marp-darken bg-white;
background-image: none;
}
.button.btnOutline.primary:hover {
@apply bg-marp-darken text-white;
}
.button.btnOutline.primary:hover::after {
@apply opacity-0;
}
`}</style>
</Tag>
)
}
================================================
FILE: website/components/CodeBlock.tsx
================================================
/* eslint-disable react/jsx-key */
import classNames from 'classnames'
import Highlight, {
defaultProps,
Language,
PrismTheme,
} from 'prism-react-renderer'
import nightOwlLight from 'prism-react-renderer/themes/nightOwlLight'
import { useRef, useState, MouseEvent } from 'react'
import { Button } from 'components/Button'
const theme: PrismTheme = {
plain: {
...nightOwlLight.plain,
backgroundColor: '#f5f5f5',
},
styles: [
...nightOwlLight.styles,
{ types: ['italic'], style: { fontStyle: 'italic' } },
{ types: ['important', 'bold'], style: { fontWeight: 'bold' } },
],
}
export type CodeBlockProps = {
children: string
copyButton?: boolean
language: Language
lineNumber?: boolean
[key: string]: unknown
}
export const CodeBlock = ({
children,
className,
copyButton,
language,
lineNumber = false,
...rest
}: CodeBlockProps) => {
const [copied, setCopied] = useState(false)
const copiedTimer = useRef<number | undefined>(undefined)
return (
<>
<Highlight
{...defaultProps}
code={children}
language={language}
theme={theme}
>
{({ className: cn, style, tokens, getLineProps, getTokenProps }) => (
<div className={classNames('code-block-container', className as any)}>
<pre
className={classNames(lineNumber && 'line-number', cn)}
style={style}
{...rest}
>
<code className="code-block">
<ol className="code-block">
{tokens.map((line, i) => {
const lineProps = getLineProps({ line, key: i })
return (
<li
{...lineProps}
className={classNames(
lineProps.className,
'code-block'
)}
>
{line.map((token, key) =>
token.empty ? (
<br key={key} />
) : (
<span {...getTokenProps({ token, key })} />
)
)}
</li>
)
})}
</ol>
</code>
</pre>
{copyButton && (
<div className="copy-btn-container">
<Button
className={copied ? 'copied' : undefined}
onClick={(e: MouseEvent<HTMLButtonElement>) => {
const tmpTextarea = document.createElement('textarea')
tmpTextarea.value = children
tmpTextarea.style.position = 'absolute'
tmpTextarea.style.left = '0'
tmpTextarea.style.top = '0'
tmpTextarea.style.opacity = '0'
tmpTextarea.style.pointerEvents = 'none'
document.body.appendChild(tmpTextarea)
tmpTextarea.select()
document.execCommand('copy')
document.body.removeChild(tmpTextarea)
e.currentTarget.focus()
// Update React state
setCopied(true)
if (copiedTimer.current !== undefined) {
window.clearTimeout(copiedTimer.current)
}
copiedTimer.current = window.setTimeout(() => {
copiedTimer.current = undefined
setCopied(false)
}, 1000)
}}
>
{copied ? 'Copied!' : 'Copy'}
</Button>
</div>
)}
</div>
)}
</Highlight>
<style jsx>{`
.code-block-container {
@apply relative;
}
.prism-code {
@apply overflow-x-auto overflow-y-hidden whitespace-pre break-words rounded-md border text-sm leading-5;
font-family: inherit;
background-image: var(--noise-image);
}
.prism-code code {
@apply inline-block min-w-full p-4 font-mono;
}
.prism-code.line-number {
@apply whitespace-pre-wrap;
}
.prism-code.line-number ol {
counter-reset: line 0;
}
.prism-code.line-number li {
@apply relative pl-12;
counter-increment: line;
}
.prism-code.line-number li::before {
@apply absolute inset-0 w-12 pr-3 text-right text-xs leading-5 text-gray-500;
content: counter(line);
}
.copy-btn-container {
@apply absolute top-0 right-0 m-3;
}
.copy-btn-container :global(button) {
@apply w-24 py-1 text-xs opacity-0 transition-opacity duration-300;
}
.code-block-container:hover .copy-btn-container :global(button),
.copy-btn-container :global(button):focus {
@apply opacity-100;
}
`}</style>
</>
)
}
================================================
FILE: website/components/Footer.tsx
================================================
import { ScrollToTop } from 'components/ScrollToTop'
export const Footer = () => (
<footer>
<div className="container mx-auto table">
<p className="mx-6 my-5 mr-20 leading-loose">
Copyright © 2019-{process.env.BUILD_YEAR} Marp team. 
<iframe
className="inline-block align-text-top"
src="https://ghbtns.com/github-btn.html?user=marp-team&repo=marp&type=star&count=true"
frameBorder={0}
scrolling="0"
width={150}
height={20}
title="GitHub"
loading="lazy"
></iframe>
</p>
<ScrollToTop />
</div>
<style jsx>{`
footer {
@apply bg-gray-800 text-gray-500;
min-height: 4.5rem;
background-image: var(--noise-image);
}
`}</style>
</footer>
)
================================================
FILE: website/components/Header.tsx
================================================
import classNames from 'classnames'
import Link from 'next/link'
import MarpLogo from 'public/assets/marp-logo.svg'
const handleMouseUp = (e: React.MouseEvent<HTMLElement>) =>
e.currentTarget.blur()
export type ItemSlug = 'docs' | 'blog'
export const Header = ({ activeItem }: { activeItem?: ItemSlug }) => (
<>
<header className="header">
<Link href="/" legacyBehavior>
<a
className="custom-anchor header-item"
role="link"
tabIndex={0}
onMouseUp={handleMouseUp}
>
<MarpLogo className="block h-16 w-16 p-2 md:h-20 md:w-20 md:p-3" />
<span className="sr-only">Marp</span>
</a>
</Link>
<nav className="ml-2">
<ul className="flex h-16 items-stretch md:h-20">
{process.env.NEXT_PUBLIC_DOCS && (
<li className="relative flex items-center justify-center">
<Link href="/docs" legacyBehavior>
<a
className={classNames('custom-anchor header-item nav-item', {
active: activeItem === 'docs',
})}
role="link"
tabIndex={0}
onMouseUp={handleMouseUp}
>
<span>Docs</span>
</a>
</Link>
</li>
)}
<li className="relative flex items-center justify-center">
<Link href="/blog" legacyBehavior>
<a
className={classNames('custom-anchor header-item nav-item', {
active: activeItem === 'blog',
})}
role="link"
tabIndex={0}
onMouseUp={handleMouseUp}
>
<span>Blog</span>
</a>
</Link>
</li>
<li className="relative flex items-center justify-center">
<a
href="https://github.com/marp-team/marp"
target="_blank"
rel="noopener noreferrer"
className="custom-anchor header-item nav-item"
onMouseUp={handleMouseUp}
>
<span>GitHub</span>
</a>
</li>
</ul>
</nav>
<style jsx>{`
:global(:root) {
@apply [--header-height:theme(spacing.16)] md:[--header-height:theme(spacing.20)];
}
.header {
@apply fixed top-0 left-0 z-50 flex h-[var(--header-height)] w-full justify-center bg-white shadow-sm;
}
.header-item {
@apply text-current no-underline outline-none;
}
.header-item > :global(svg) {
@apply transition-transform duration-200;
}
.header-item:hover:active > :global(svg) {
@apply duration-0 scale-125 transform shadow-none;
}
@media not all and (hover: none) {
.header-item:hover:active > :global(svg) {
@apply scale-110;
}
}
.nav-item {
@apply font-rounded mx-2 text-lg font-medium uppercase leading-none outline-none;
}
.nav-item::before {
@apply absolute inset-0;
content: '';
}
.header-item:focus-visible,
.nav-item:focus-visible::before {
@apply bg-gray-200;
}
.header-item:not(.nav-item) {
-webkit-tap-highlight-color: transparent;
}
@screen md {
.nav-item {
@apply mx-3 tracking-wider;
}
}
.nav-item > span {
@apply relative z-10;
}
.nav-item > span::after {
@apply absolute inset-x-0 mt-1 block h-1 transition-all duration-300;
content: '';
top: 100%;
}
.nav-item:hover > span::after,
.nav-item:focus-within > span::after {
box-shadow: inset 0 -0.25rem theme('colors.gray.400');
}
.nav-item.active > span::after {
@apply duration-0;
box-shadow: inset 0 -0.25rem theme('colors.marp.brand');
}
.nav-item:hover:active > span::after {
@apply duration-0;
box-shadow: inset 0 -0.25rem theme('colors.marp.dark');
}
`}</style>
</header>
</>
)
================================================
FILE: website/components/Layout.tsx
================================================
import Head from 'next/head'
import { useRouter } from 'next/router'
import { Footer } from 'components/Footer'
import { Header, ItemSlug } from 'components/Header'
import { generateTitle } from 'utils/title'
import { absoluteUrl } from 'utils/url'
export type LayoutProps = React.PropsWithChildren<{
activeItem?: ItemSlug
canonical?: string
description?: string
image?: string
noIndex?: boolean
title?: string | string[]
type?: string
}>
const defaultDescription =
'Marp (also known as the Markdown Presentation Ecosystem) provides an intuitive experience for creating beautiful slide decks. You only have to focus on writing your story in a Markdown document.'
export const Layout: React.FC<LayoutProps> = ({
activeItem,
canonical: _canonical,
children,
description = defaultDescription,
image: _image,
noIndex,
title: _title,
type = 'article',
}) => {
const router = useRouter()
const canonical = absoluteUrl(_canonical || router.asPath).href
const image = _image || '/assets/og-image.png'
const title = typeof _title === 'string' ? _title : generateTitle(_title)
return (
<>
<Head>
<title key="title">{title}</title>
{description && (
<>
<meta name="description" key="description" content={description} />
<meta
property="og:description"
key="og:description"
content={description}
/>
</>
)}
{canonical && (
<>
<link rel="canonical" key="canonical" href={canonical} />
<meta property="og:url" key="og:url" content={canonical} />
</>
)}
<meta property="og:title" key="og:title" content={title} />
<meta property="og:type" key="og:type" content={type} />
<meta
property="og:image"
key="og:image"
content={absoluteUrl(image).href}
/>
<meta
property="twitter:card"
key="twitter:card"
content={
type === 'website' || _image ? 'summary_large_image' : 'summary'
}
/>
{noIndex && <meta name="robots" content="noindex,nofollow" />}
</Head>
<Header activeItem={activeItem} />
<main className="relative mt-16 md:mt-20">
{children}
<style jsx>{`
main {
min-height: calc(100vh - 8.5rem);
}
@screen md {
main {
min-height: calc(100vh - 9.5rem);
}
}
`}</style>
</main>
<Footer />
</>
)
}
================================================
FILE: website/components/Marp.tsx
================================================
import { Marp as MarpCore } from '@marp-team/marp-core'
import classNames from 'classnames'
import postcss, { Plugin } from 'postcss'
import postcssImportUrl from 'postcss-import-url'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import type { Swiper as SwiperClass } from 'swiper'
import { Swiper, SwiperSlide } from 'swiper/react'
import { useFontFace } from 'utils/hooks/useFontFace'
export type RenderedMarp = ReturnType<
typeof generateRenderedMarp
> extends Promise<infer T>
? T
: never
export type MarpProps = {
border?: boolean
className?: string
rendered: Pick<RenderedMarp, 'css' | 'html' | 'fonts'>
page?: number
}
const postcssStripFontFace = Object.assign(
(): Plugin => ({
postcssPlugin: 'marp-strip-font-face',
AtRule: (rule, { result }) => {
if (rule.name === 'font-face') {
result['fonts'] = [...(result['fonts'] || []), rule]
rule.remove()
}
},
}),
{ postcss: true as const }
)
export const generateRenderedMarp = async (markdown: string) => {
const marp = new MarpCore({
container: false,
script: false,
printable: false,
})
const { css, html } = marp.render(markdown, { htmlAsArray: true })
const result = await postcss()
.use(postcssImportUrl)
.use(postcssStripFontFace)
.process(css, { from: undefined })
const fonts: string[] = (result['fonts'] || []).map((font) => font.toString())
return { markdown, html, css: result.css, fonts }
}
export const Marp = ({
border = true,
className,
rendered: { css, html, fonts },
page = 1,
}: MarpProps) => {
const element = useRef<HTMLDivElement>(null)
useFontFace(fonts)
useEffect(() => {
if (!element.current) return
if (!element.current.shadowRoot)
element.current.attachShadow({ mode: 'open' })
// Render Marp slide to shadow root (tailwind default styles will break Marp slide CSS)
const root = element.current.shadowRoot as ShadowRoot
root.innerHTML =
html[page - 1] +
`<style>${css}</style><style>:host{all:initial;}:host>[data-marpit-svg]{vertical-align:top;}</style>`
// eslint-disable-next-line @typescript-eslint/no-var-requires
return require('@marp-team/marp-core/browser').browser(root)
}, [css, html, page])
return (
<div className={classNames(border && 'border shadow-lg', className)}>
<span ref={element} />
</div>
)
}
export const MarpSlides = (props) => {
const htmlRaw: string = props['data-html']
const css: string = props['data-css']
const fontsRaw: string = props['data-fonts']
const [activePageIdx, setActivePageIdx] = useState(0)
const swiper = useRef<SwiperClass>()
const html = useMemo(() => JSON.parse(htmlRaw) as string[], [htmlRaw])
const multiple = html.length > 1
const fonts = useMemo(() => JSON.parse(fontsRaw) as string[], [fontsRaw])
const handleActiveIndexChange = useCallback((instance: SwiperClass) => {
setActivePageIdx(instance.activeIndex)
}, [])
const handleSwiper = useCallback(
(instance: SwiperClass) => {
swiper.current = instance
handleActiveIndexChange(instance)
},
[handleActiveIndexChange]
)
return (
<section className={classNames('marp-slides', multiple && 'multiple')}>
{multiple && (
<button
aria-label="Prev"
className="marp-navigation left-0"
disabled={activePageIdx <= 0}
onClick={() => swiper.current?.slidePrev()}
translate="no"
>
«
</button>
)}
<Swiper
enabled={multiple.toString() as any}
allowTouchMove={multiple}
speed={200}
onActiveIndexChange={handleActiveIndexChange}
onSwiper={handleSwiper}
>
{html.map((h, i) => (
<SwiperSlide key={h}>
<div inert={activePageIdx === i ? undefined : ''}>
<Marp
border={false}
rendered={{ html, css, fonts }}
page={i + 1}
/>
</div>
</SwiperSlide>
))}
</Swiper>
{multiple && (
<button
aria-label="Next"
className="marp-navigation right-0"
disabled={activePageIdx >= html.length - 1}
onClick={() => swiper.current?.slideNext()}
translate="no"
>
»
</button>
)}
<style jsx>{`
.marp-slides {
@apply relative my-6 mx-auto w-full max-w-sm border bg-gray-200 shadow-lg lg:max-w-lg;
}
.marp-slides.multiple {
@apply px-8;
}
.marp-navigation {
@apply absolute inset-y-0 z-10 w-8 appearance-none bg-gray-300 text-4xl text-gray-600 outline-none;
user-select: none;
}
.marp-navigation:hover:not(:disabled) {
@apply bg-gray-400;
}
.marp-navigation:hover:active {
@apply text-gray-700;
}
.marp-navigation:disabled {
@apply pointer-events-none text-opacity-30;
}
.marp-navigation:focus-visible {
@apply ring-marp-brand ring-2;
}
`}</style>
</section>
)
}
================================================
FILE: website/components/ScrollToTop.tsx
================================================
import { ArrowUpIcon } from '@primer/octicons-react'
import { useCallback } from 'react'
export const ScrollToTop = () => {
const handleClick = useCallback<React.MouseEventHandler<HTMLElement>>((e) => {
window.scrollTo({ top: 0 })
e.currentTarget.blur()
}, [])
return (
<div className="scroll-to-top">
<button onClick={handleClick} title="Scroll to top">
<ArrowUpIcon className="scroll-to-top-icon" />
<span className="sr-only">Scroll to top</span>
</button>
<style jsx>{`
.scroll-to-top {
@apply pointer-events-none fixed right-0 bottom-0 z-50;
filter: drop-shadow(0 0px 7px rgba(0, 0, 0, 0.3))
drop-shadow(0 0px 4px rgba(0, 0, 0, 0.15));
}
button {
@apply bg-marp-light pointer-events-auto h-20 w-20 appearance-none align-top text-white;
clip-path: polygon(100% 0, 100% 100%, 0 100%);
}
button:hover {
@apply bg-marp-brand;
}
button:focus {
@apply outline-none;
}
button:focus,
button:hover:active {
@apply bg-marp-dark;
}
button :global(.scroll-to-top-icon) {
height: auto;
left: 52%;
position: absolute;
top: 52%;
width: 35%;
}
`}</style>
</div>
)
}
================================================
FILE: website/components/Title.tsx
================================================
// eslint-disable-next-line @typescript-eslint/ban-types
export const Title: React.FC<React.PropsWithChildren<{}>> = ({ children }) => (
<section className="bg-marp-brand border-b py-3 text-white">
<h1 className="font-rounded text-center text-3xl font-bold uppercase">
{children}
<style jsx>{`
& :global(a),
& :global(a:hover),
& :global(a:hover:active) {
@apply text-current no-underline;
}
& :global(a:focus-visible) {
@apply underline outline-none;
}
`}</style>
</h1>
</section>
)
================================================
FILE: website/components/Typography.tsx
================================================
// eslint-disable-next-line @typescript-eslint/ban-types
export const Typography: React.FC<React.PropsWithChildren<{}>> = ({
children,
}) => (
<div className="typography">
{children}
<style jsx>{`
.typography {
@apply break-words text-base leading-relaxed;
}
.typography :global(p) {
@apply my-4;
}
.typography :global(h1) {
@apply relative mt-8 mb-5 text-3xl font-bold;
}
.typography :global(h2) {
@apply relative mt-8 mb-5 text-2xl font-bold;
}
.typography :global(h3) {
@apply relative mt-8 mb-4 text-xl font-bold;
}
.typography :global(h4) {
@apply relative mt-6 mb-4 text-lg font-bold;
}
.typography :global(h5) {
@apply relative mt-6 mb-4 text-base font-bold;
}
.typography :global(h6) {
@apply relative mt-6 mb-4 text-sm font-bold text-gray-600;
}
.typography :global(.anchor-link) {
@apply absolute inset-0 my-auto -ml-5 hidden w-5 overflow-hidden whitespace-nowrap bg-left bg-no-repeat;
background-size: 1rem 1rem;
background-image: url('https://icongr.am/octicons/link.svg?color=718096');
}
.typography :global(h1:hover > .anchor-link),
.typography :global(h2:hover > .anchor-link),
.typography :global(h3:hover > .anchor-link),
.typography :global(h4:hover > .anchor-link),
.typography :global(h5:hover > .anchor-link),
.typography :global(h6:hover > .anchor-link) {
@apply block;
}
.typography :global(hr) {
@apply my-8;
}
.typography :global(blockquote) {
@apply border-marp-light my-6 border-l-4 pl-5 text-gray-600;
}
.typography :global(blockquote blockquote) {
border-left-width: 3px;
}
.typography :global(blockquote blockquote blockquote) {
@apply border-l-2;
}
.typography :global(ul) {
@apply my-6 ml-8 mr-3 list-disc;
}
.typography :global(ul ul) {
list-style-type: circle;
}
.typography :global(ul ul ul) {
list-style-type: square;
}
.typography :global(ol:not(.code-block)) {
@apply my-6 ml-8 mr-3 list-decimal;
}
.typography :global(ul ul),
.typography :global(ul ol:not(._)),
.typography :global(ol:not(._) ul),
.typography :global(ol:not(._) ol:not(._)) {
@apply my-0 mr-0;
}
.typography :global(li:not(.code-block)) {
@apply my-1;
}
.typography :global(code:not(.code-block)) {
@apply rounded border border-gray-400 bg-gray-200;
font-size: 0.9em;
padding: 0.15em 0.35em;
}
.typography :global(pre) {
@apply my-6;
}
.typography :global(img) {
@apply inline;
}
.typography :global(figure) {
@apply my-6;
}
.typography :global(figure img) {
@apply mx-auto block;
max-width: min(theme('screens.md'), 100%);
}
.typography :global(figcaption) {
@apply mx-auto my-4 w-11/12 text-center text-sm text-gray-600;
}
.typography :global(table) {
@apply mx-auto my-8 max-w-full;
}
.typography :global(td),
.typography :global(th) {
@apply border-b border-gray-400 p-2 text-sm;
}
.typography :global(thead tr:last-child td),
.typography :global(thead tr:last-child th) {
@apply border-b-2;
}
@screen sm {
.typography :global(td),
.typography :global(th) {
@apply py-2 px-4;
}
}
@screen md {
.typography :global(td),
.typography :global(th) {
@apply text-base;
}
}
.typography > :global(*:first-child),
.typography > :global(*:first-child *:first-child) {
@apply mt-0;
}
.typography > :global(*:last-child),
.typography > :global(*:last-child *:last-child) {
@apply mb-0;
}
`}</style>
</div>
)
================================================
FILE: website/components/blog/BlogHeader.tsx
================================================
import Link from 'next/link'
import { formatDate, formatDateShort } from 'utils/date'
export type BlogHeaderProps = {
author?: string
date?: Date
github?: string
slug: string
title: string
}
export const BlogHeader = ({
author,
date,
github,
slug,
title,
}: BlogHeaderProps) => (
<div className="text-center text-gray-600">
<Link href={`/blog/${slug}`}>
<h1 className="text-gradient text-3xl font-bold md:text-4xl">{title}</h1>
</Link>
{date && (
<p className="mt-4">
<time dateTime={formatDateShort(date)}>{formatDate(date)}</time>
</p>
)}
<p className="author">
{(author || github) && (
<>
{github && (
<img
src={`https://github.com/${github}.png`}
alt={author || github}
className="mr-4 h-16 w-16 rounded-full bg-white shadow-md"
width={64}
height={64}
/>
)}
<span className="leading-relaxed">
by{' '}
{author && (
<>
{author}
{github && <br />}
</>
)}
{github && (
<a
href={`https://github.com/${github}`}
target="_blank"
rel="noopener noreferrer"
>
@{github}
</a>
)}
</span>
</>
)}
<style jsx>{`
.author {
@apply -mx-6 mt-5 flex items-center text-left;
}
.author::before,
.author::after {
@apply mx-6 block h-px flex-1 bg-gray-400;
content: '';
}
.author:empty {
@apply mx-0 h-px;
}
.author:empty::before,
.author:empty::after {
@apply mx-0;
}
`}</style>
</p>
</div>
)
================================================
FILE: website/components/docs/Breadcrumb.tsx
================================================
import Link from 'next/link'
export type BreadcrumbProps = {
breadcrumbs: {
key: string
link?: string
title: string
}[]
}
export const Breadcrumb = ({ breadcrumbs }: BreadcrumbProps) => (
<ol>
{breadcrumbs.map(({ key, title, link }) => (
<li key={key}>{link ? <Link href={link}>{title}</Link> : title}</li>
))}
<style jsx>{`
ol {
@apply inline-flex flex-1 flex-nowrap whitespace-nowrap;
}
li {
@apply block;
}
li::after {
@apply bg-no-repeat pl-6;
background-image: url('https://icongr.am/octicons/triangle-right.svg?color=718096');
background-position: 0.25rem center;
background-size: 1rem 1rem;
content: '';
}
li:last-child {
@apply font-bold;
}
li:last-child::after {
@apply hidden;
}
`}</style>
</ol>
)
================================================
FILE: website/components/docs/Layout.tsx
================================================
import { useMedia, useMediaLayout } from 'use-media'
import { BreadcrumbProps } from './Breadcrumb'
import { NavigationProps } from './Navigation'
import { Desktop } from './layouts/Desktop'
import { Mobile } from './layouts/Mobile'
import { Layout } from 'components/Layout'
export type LayoutProps = React.PropsWithChildren<
BreadcrumbProps & NavigationProps
>
const useMediaIsomorphic =
typeof window === 'undefined' ? useMedia : useMediaLayout
const DocsLayout: React.FC<LayoutProps> = (props) => {
const isDesktop = useMediaIsomorphic({ minWidth: '768px' }, false)
const Container = isDesktop ? Desktop : Mobile
return (
<Layout
activeItem="docs"
canonical={`/docs/${props.slug.join('/')}`}
title={[props.breadcrumbs.map((b) => b.title).join(' > '), 'Docs']}
noIndex={!process.env.NEXT_PUBLIC_DOCS}
>
<Container {...props} />
</Layout>
)
}
export { DocsLayout as Layout }
================================================
FILE: website/components/docs/Navigation.tsx
================================================
import classNames from 'classnames'
import Link from 'next/link'
export type NavigationProps = {
manifest: Record<string, any>
slug: string[]
}
export const Navigation = ({
manifest,
slug: currentSlug,
}: NavigationProps) => {
const activePage = `/docs/${currentSlug.join('/')}`
return (
<div>
{Object.entries<any>(manifest).map(([slug, meta]) => (
<ul className="category" key={slug}>
<li>
{meta.title && <h3 className="category-title">{meta.title}</h3>}
{meta.pages && (
<ul>
{Object.entries<any>(meta.pages).map(([pSlug, pMeta]) => {
const href = `/docs/${slug}/${pSlug}`
return (
<Link href={href} key={pSlug} legacyBehavior>
<a
className={classNames(
'page-link custom-anchor',
href === activePage && 'active'
)}
>
<li>{pMeta.title}</li>
</a>
</Link>
)
})}
</ul>
)}
</li>
</ul>
))}
<style jsx>{`
.category {
@apply mt-6;
}
.category:first-child {
@apply mt-0;
}
.category-title {
@apply font-rounded mb-2 text-xl font-bold uppercase text-gray-700;
}
.page-link {
@apply text-marp-darken mt-1 block rounded py-1 px-2 outline-none;
transition-property: background-color, border-color, fill, stroke;
}
.page-link:hover,
.page-link:focus {
@apply text-marp-dark bg-gray-200 duration-300;
}
.page-link:hover:active {
@apply duration-0 bg-gray-300;
}
.page-link:focus-visible {
@apply ring-1 ring-white ring-offset-2;
}
.page-link.active {
@apply from-marp-brand to-marp-dark duration-0 bg-gradient-to-br font-bold text-white;
}
.page-link.active:hover:active {
@apply bg-marp-dark from-marp-dark to-marp-darkest;
}
`}</style>
</div>
)
}
================================================
FILE: website/components/docs/layouts/Desktop.tsx
================================================
import {
CSSProperties,
useLayoutEffect,
useRef,
useState,
useMemo,
} from 'react'
import { Breadcrumb } from 'components/docs/Breadcrumb'
import { LayoutProps } from 'components/docs/Layout'
import { Navigation } from 'components/docs/Navigation'
export const Desktop: React.FC<LayoutProps> = ({
breadcrumbs,
children,
manifest,
slug,
}) => {
const sidebarRef = useRef<HTMLDivElement>(null)
const sidebarContentRef = useRef<HTMLDivElement>(null)
const headerHeightDetecterRef = useRef<HTMLDivElement>(null)
const [stickyGap, setStickyGap] = useState(0)
const [isScrollDown, setIsScrollDown] = useState(true)
const [sidebarScrollable, setSidebarScrollable] = useState(false)
useLayoutEffect(() => {
let previousScrollY = window.scrollY
const handleScroll = () => {
// Get header height
const headerHeight = headerHeightDetecterRef.current?.clientHeight || 80
// Detect whether sidebar is scrollable
const sidebarElm = sidebarRef.current
const sidebarRect = sidebarElm?.getBoundingClientRect()
const parentElm = sidebarElm?.parentElement
const parentRect = parentElm?.getBoundingClientRect()
if (sidebarContentRef.current && sidebarRect && parentRect) {
const viewHeight = Math.max(
0,
Math.min(window.innerHeight, parentRect.bottom) - headerHeight
)
setSidebarScrollable(
viewHeight < sidebarContentRef.current.clientHeight
)
}
// Handle scroll
const resetStickyGap = (base: 'top' | 'bottom') => {
if (sidebarRect && parentRect) {
setStickyGap(sidebarRect[base] - parentRect[base])
}
}
const { scrollY } = window
const scrollDelta = scrollY - previousScrollY
if (scrollDelta < 0) {
// Scroll up
setIsScrollDown((prev) => {
if (prev) resetStickyGap('bottom')
return false
})
} else {
// Scroll down
setIsScrollDown((prev) => {
if (!prev) resetStickyGap('top')
return true
})
}
previousScrollY = scrollY
}
window.addEventListener('scroll', handleScroll)
window.addEventListener('resize', handleScroll)
return () => {
window.removeEventListener('scroll', handleScroll)
window.removeEventListener('resize', handleScroll)
}
}, [])
const sidebarStyle = useMemo<CSSProperties>(() => {
if (!sidebarScrollable)
return { alignSelf: 'start', top: 'var(--header-height)' }
return {
alignSelf: isScrollDown ? 'end' : 'start',
top: !isScrollDown ? `var(--header-height)` : '',
bottom: isScrollDown ? `0px` : '',
marginBottom: stickyGap < 0 ? `${-stickyGap}px` : 0,
marginTop: stickyGap >= 0 ? `${stickyGap}px` : 0,
}
}, [isScrollDown, sidebarScrollable, stickyGap])
return (
<>
<div
ref={headerHeightDetecterRef}
className="fixed top-0 left-0 -z-10 h-[var(--header-height)] w-px opacity-0"
/>
<div id="docs-container" className="text-sm xl:text-base">
<div ref={sidebarRef} id="docs-sidebar" style={sidebarStyle}>
<div ref={sidebarContentRef} className="sidebar-nav-content">
<Navigation manifest={manifest} slug={slug} />
</div>
</div>
<div className="my-6 w-px bg-gray-400" style={{ gridArea: 'border' }} />
<div className="[grid-area:contents]">
<div className="px-8 py-10">
{breadcrumbs?.length && (
<div className="mb-6 rounded bg-gray-300 p-2">
<Breadcrumb breadcrumbs={breadcrumbs} />
</div>
)}
<article id="docs-article" className="container">
{children}
</article>
</div>
</div>
</div>
{/* <div ref={docsClearfixRef} /> */}
<style jsx>{`
#docs-container {
@apply grid;
min-height: inherit;
grid-template:
'sidebar border contents' auto
/ minmax(16rem, 20%) 1px minmax(0, 1fr);
}
#docs-sidebar {
@apply sticky [grid-area:sidebar];
}
#docs-article {
@apply mx-auto px-6;
--root-font-size: 0.9rem;
}
.sidebar-nav-content {
@apply mx-auto w-64 px-8 py-10;
min-width: 16rem;
}
@screen xl {
#docs-container {
grid-template:
'sidebar border contents nav' auto
/ minmax(16rem, 20%) 1px minmax(0, 1fr) minmax(8rem, 15%);
}
#docs-article {
--root-font-size: 1rem;
}
.sidebar-nav-content {
@apply w-5/6;
}
}
`}</style>
</>
)
}
================================================
FILE: website/components/docs/layouts/Mobile.tsx
================================================
import { ThreeBarsIcon, XIcon } from '@primer/octicons-react'
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock'
import classNames from 'classnames'
import FocusTrap from 'focus-trap-react'
import { useRouter } from 'next/router'
import { useCallback, useEffect, useRef, useState } from 'react'
import { Breadcrumb } from 'components/docs/Breadcrumb'
import { LayoutProps } from 'components/docs/Layout'
import { Navigation } from 'components/docs/Navigation'
const useOnPageLoad = (callback: () => void, immediate = false) => {
const router = useRouter()
useEffect(() => {
if (immediate) callback()
}, [callback]) // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
router.events.on('routeChangeComplete', callback)
return () => router.events.off('routeChangeComplete', callback)
}, [callback, router.events])
}
const useDrawer = (drawer?: HTMLElement) => {
const [open, setOpen] = useState(false)
const [active, setActive] = useState(false)
const activeTimer = useRef<number>()
const lastFocusedElement = useRef<HTMLElement | undefined>(undefined)
const handleOpen = useCallback((e?: React.SyntheticEvent<HTMLElement>) => {
setActive(true)
setOpen(true)
lastFocusedElement.current = e?.currentTarget
}, [])
const handleClose = useCallback(() => {
setActive(true)
setOpen(false)
}, [])
const toggle = useCallback(
(e?: React.SyntheticEvent<HTMLElement>) => {
open ? handleClose() : handleOpen(e)
},
[open, handleOpen, handleClose]
)
useOnPageLoad(handleClose)
useEffect(() => {
if (drawer && open) {
disableBodyScroll(drawer)
return () => enableBodyScroll(drawer)
}
}, [drawer, open])
useEffect(() => {
if (open) {
const escKeyListener = ({ key }: KeyboardEvent) => {
if (key === 'Escape') handleClose()
}
document.addEventListener('keydown', escKeyListener)
return () => document.removeEventListener('keydown', escKeyListener)
}
}, [handleClose, open])
useEffect(() => {
if (!open && lastFocusedElement.current) {
lastFocusedElement.current.focus()
}
}, [open])
useEffect(() => {
if (active) {
if (activeTimer.current !== undefined)
window.clearTimeout(activeTimer.current)
activeTimer.current = window.setTimeout(() => setActive(false), 300)
}
}, [active])
return { active, handleClose, handleOpen, toggle, open }
}
export const Mobile: React.FC<LayoutProps> = ({
children,
breadcrumbs,
manifest,
slug,
}) => {
const [drawer, setDrawer] = useState<HTMLElement | null>(null)
const { active, handleClose, toggle, open } = useDrawer(drawer ?? undefined)
const breadcrumbsContainer = useRef<HTMLDivElement | null>(null)
useOnPageLoad(
useCallback(() => {
breadcrumbsContainer.current?.scrollTo({
left: breadcrumbsContainer.current.scrollWidth,
behavior: 'instant' as any,
})
}, []),
true
)
return (
<>
<div
className={classNames('docs-backdrop', { active, open })}
onClick={handleClose}
aria-hidden
/>
<FocusTrap
active={open}
focusTrapOptions={{
allowOutsideClick: () => true,
escapeDeactivates: false,
initialFocus: '#docs-nav',
fallbackFocus: '#docs-nav-toggle',
}}
>
<nav
id="docs-nav"
className={classNames({ active, open })}
ref={setDrawer}
tabIndex={-1}
inert={open ? undefined : ''}
>
<div className="p-8">
<p className="mb-6">
<button
className="docs-btn h-8 w-8"
onClick={handleClose}
aria-expanded={open}
>
<XIcon className="docs-btn-close-icon" />
<span className="sr-only">Close navigation</span>
</button>
</p>
<Navigation manifest={manifest} slug={slug} />
</div>
</nav>
</FocusTrap>
<nav className="docs-topbar">
<button
className="docs-btn relative z-20 m-1 h-8 w-8"
id="docs-nav-toggle"
type="button"
onClick={toggle}
aria-controls="docs-nav"
aria-expanded={open}
>
<ThreeBarsIcon className="docs-btn-open-drawer-icon" />
<span className="sr-only">Toggle navigation</span>
</button>
{breadcrumbs?.length && (
<div ref={breadcrumbsContainer} className="docs-breadcrumb-container">
<div className="docs-breadcrumb">
<Breadcrumb breadcrumbs={breadcrumbs} />
</div>
</div>
)}
</nav>
<article id="docs-article" className="container">
{children}
</article>
<style jsx global>{`
:root {
--anchor-margin: calc(var(--header-height) + 2.5rem);
}
`}</style>
<style jsx>{`
.docs-backdrop {
@apply pointer-events-none fixed inset-0 cursor-pointer opacity-0 transition-opacity;
-webkit-tap-highlight-color: transparent;
backdrop-filter: blur(2px);
background: rgba(255, 255, 255, 0.75);
z-index: 60;
}
.docs-backdrop.active {
@apply duration-300;
}
.docs-backdrop.open {
@apply pointer-events-auto opacity-100;
}
.docs-btn {
@apply appearance-none rounded text-gray-700;
}
.docs-btn:hover,
.docs-btn:focus {
@apply bg-gray-200 outline-none;
}
.docs-btn:hover:active {
@apply bg-gray-300 outline-none;
}
.docs-btn:focus-visible {
@apply ring-1 ring-white ring-offset-2;
}
.docs-btn :global(.docs-btn-close-icon) {
@apply h-8 w-8;
}
.docs-btn :global(.docs-btn-open-drawer-icon) {
@apply h-8 w-8 p-1;
}
#docs-nav {
@apply bg-background fixed inset-0 w-64 -translate-x-full transform overflow-hidden border-r outline-none;
transition-property: box-shadow, transform;
z-index: 60;
}
#docs-nav.active {
@apply duration-300;
}
#docs-nav.open {
@apply transform-none overflow-auto shadow-2xl;
}
.docs-topbar {
@apply fixed inset-0 top-16 z-50 flex h-10 items-stretch bg-white shadow-sm;
}
.docs-breadcrumb-container {
@apply flex flex-1 snap-x snap-proximity scroll-px-2 items-center overflow-x-auto;
mask: linear-gradient(to right, transparent, #000 0.5rem, #000)
no-repeat left top;
-ms-overflow-style: none;
scrollbar-width: none;
}
.docs-breadcrumb-container::-webkit-scrollbar {
display: none;
}
.docs-breadcrumb {
@apply relative mr-auto px-2;
@apply after:pointer-events-none after:absolute after:inset-0 after:mx-2 after:snap-end;
}
.docs-breadcrumb :global(li) {
@apply snap-start;
}
#docs-article {
@apply mx-auto p-6 pt-16;
--root-font-size: 0.9rem;
}
`}</style>
</>
)
}
================================================
FILE: website/components/markdown/Anchor.tsx
================================================
import Link from 'next/link'
export const Anchor: React.FC<{ href?: string }> = ({ href, ...rest }) => {
if (!href) return <a {...rest} />
if (href && (href.startsWith('http://') || href.startsWith('https://'))) {
return <a href={href} {...rest} target="_blank" rel="noreferrer noopener" />
}
return <Link href={href} {...rest} />
}
================================================
FILE: website/components/markdown/Heading.tsx
================================================
import { createContext, useContext } from 'react'
// eslint-disable-next-line @typescript-eslint/ban-types
type HOCProps<P extends {} = Record<string, any>> = React.PropsWithChildren<P>
const anchorLinkContext = createContext(true)
const Heading: React.FC<HOCProps<{ level: number; id?: string }>> = ({
children,
level,
id,
...rest
}) => {
const anchorLink = useContext(anchorLinkContext)
const HeadingTag: any = 'h' + level
return (
<HeadingTag id={id} {...rest}>
{id && anchorLink && (
<a
aria-hidden
className="anchor-link"
href={`#${id}`}
tabIndex={-1}
></a>
)}
{children}
</HeadingTag>
)
}
export const H1: React.FC<HOCProps> = ({ children, ...rest }) => (
<Heading level={1} {...rest}>
<span>
{children}
<style jsx>{`
& {
box-shadow: inset 0 -0.2em theme('colors.marp.light');
}
`}</style>
</span>
</Heading>
)
export const H2: React.FC<HOCProps> = ({ children, ...rest }) => (
<Heading level={2} {...rest}>
<span className="headingLv2">
<span className="content">{children}</span>
<span className="divider"></span>
</span>
<style jsx>{`
.headingLv2 {
@apply flex items-center;
}
.content {
@apply flex-initial;
}
.divider {
@apply ml-6 h-0 flex-1 border-t border-gray-400;
}
`}</style>
</Heading>
)
// export const H2: React.FC = (props) => <Heading level={2} {...props} />
export const H3: React.FC<HOCProps> = (props) => (
<Heading level={3} {...props} />
)
export const H4: React.FC<HOCProps> = (props) => (
<Heading level={4} {...props} />
)
export const H5: React.FC<HOCProps> = (props) => (
<Heading level={5} {...props} />
)
export const H6: React.FC<HOCProps> = (props) => (
<Heading level={6} {...props} />
)
export const AnchorLinkProvider = anchorLinkContext.Provider
================================================
FILE: website/components/markdown/Image.tsx
================================================
export type ImageProps = {
src: string
alt: string
[attr: string]: string
}
export const Image = ({ src, alt, ...rest }: ImageProps) => {
const isVideo = src.endsWith('.mp4')
if (isVideo) {
let autoplay: boolean | undefined
let controls: boolean | undefined
let poster: string | undefined
const normalizedAlt = (alt || '')
.replace(
/\b(?:autoplay|controls|poster=([^\s]+))\s*\b/g,
(matched, value) => {
if (matched.startsWith('autoplay')) autoplay = true
if (matched.startsWith('controls')) controls = true
if (matched.startsWith('poster')) poster = value
return ''
}
)
.trim()
return (
<video
className="markdown-video"
src={src}
playsInline
controls={controls}
loop
preload="metadata"
poster={poster}
autoPlay={autoplay}
muted={autoplay}
{...rest}
>
<a href={src} target="_blank" rel="noopener noreferrer">
{normalizedAlt}
</a>
<style jsx>{`
.markdown-video {
@apply mx-auto block w-full max-w-xl shadow-md;
@apply my-6 !important;
}
`}</style>
</video>
)
}
return <img src={src} alt={alt} {...rest} />
}
================================================
FILE: website/components/markdown/Pre.tsx
================================================
import { CodeBlock } from '../CodeBlock'
export const Pre: React.FC = (props) => {
if (props['data-code'] === undefined) return <pre {...props} />
return (
<CodeBlock
className="sm:mx-auto sm:w-11/12 lg:w-5/6"
language={props['data-language']}
copyButton
>
{props['data-code']}
</CodeBlock>
)
}
export const toHastCodeHandler = (h, { position, lang, value, marp }) => {
if (marp) {
return h(position, 'marp-slides', {
'data-comments': JSON.stringify(marp.comments),
'data-css': marp.css,
'data-html': JSON.stringify(marp.html),
'data-fonts': JSON.stringify(marp.fonts),
})
}
return h(
position,
'pre',
{ 'data-code': value, 'data-language': lang?.trim() },
[]
)
}
================================================
FILE: website/components/top/Description.tsx
================================================
import { ChevronDownIcon } from '@primer/octicons-react'
import classNames from 'classnames'
import { useState } from 'react'
import { Button } from 'components/Button'
import { CodeBlock } from 'components/CodeBlock'
import { Marp, RenderedMarp } from 'components/Marp'
export type DescriptionProps = {
example: RenderedMarp
}
export const Description = ({ example }: DescriptionProps) => {
const [showExample, setShowExample] = useState(false)
return (
<section className="container mx-auto py-16">
<h2 className="text-gradient mx-auto w-5/6 text-center text-3xl font-bold md:text-4xl">
Create beautiful slide decks using an intuitive Markdown experience
</h2>
<p className="mx-auto mt-8 w-5/6 md:text-lg lg:w-2/3">
Marp (also known as the Markdown Presentation Ecosystem) provides an
intuitive experience for creating beautiful slide decks. You only have
to focus on writing your story in a Markdown document.
</p>
<figure className="m-8 mb-0 text-center">
<Marp
rendered={example}
page={1}
className="inline-block w-full max-w-sm"
/>
<Marp
rendered={example}
page={2}
className="mt-5 inline-block w-full max-w-sm lg:ml-5 lg:mt-0"
/>
<figcaption className="mt-5 text-sm text-gray-700">
The slides above are from generated directly from{' '}
<a href="https://github.com/marp-team/marp-core">Marp Core</a>
</figcaption>
</figure>
<p className="show-example-section">
<Button
className="show-example-btn"
onClick={() => setShowExample((v) => !v)}
aria-expanded={showExample}
>
{showExample ? 'Hide' : 'Show'} Markdown example...
<ChevronDownIcon
className={classNames(
'show-example-btn-chevron',
showExample && 'show'
)}
/>
</Button>
</p>
<div
aria-hidden={!showExample}
className="overflow-hidden transition-all duration-300"
style={{ maxHeight: showExample ? '1000px' : '0' }}
>
<CodeBlock
language="markdown"
lineNumber
className="mx-auto mt-5 w-5/6 xl:w-2/3"
copyButton={showExample}
>
{example.markdown}
</CodeBlock>
</div>
<style jsx>{`
.show-example-section {
@apply mx-auto mt-8 w-5/6 text-center;
}
.show-example-section :global(.show-example-btn) {
@apply text-sm;
}
.show-example-section :global(.show-example-btn-chevron) {
@apply ml-1 h-4 w-4 transform transition-transform duration-300 md:-my-1 md:h-6 md:w-6;
}
.show-example-section :global(.show-example-btn-chevron:not(.show)) {
@apply relative;
top: -1px;
}
.show-example-section :global(.show-example-btn-chevron.show) {
@apply -rotate-180;
}
@screen md {
.show-example-section :global(.show-example-btn-chevron:not(.show)) {
top: -2px;
}
}
`}</style>
</section>
)
}
================================================
FILE: website/components/top/Features.tsx
================================================
import {
CodeSquareIcon,
FileIcon,
HeartFillIcon,
MarkdownIcon,
PackageIcon,
PaintbrushIcon,
PlugIcon,
} from '@primer/octicons-react'
import type { ReactElement } from 'react'
type CardProps = React.PropsWithChildren<{
name: string
icon: string | ReactElement
index: number
}>
const Card: React.FC<CardProps> = ({ children, name, icon, index }) => {
let cardIcon = icon
if (typeof icon === 'string') {
cardIcon = <img src={icon} alt={name} width={48} height={48} />
}
return (
<section className="card">
<div>
<div className="card-icon">{cardIcon}</div>
<h2 className="text-gradient my-4 text-center text-2xl font-semibold">
{name}
</h2>
<p className="text-sm lg:text-base">{children}</p>
</div>
<style jsx>{`
.card {
@apply relative z-10 mx-4 my-8 mb-0 flex items-center justify-center rounded-lg bg-white p-6 shadow-lg;
grid-column: 1;
}
.card-icon {
@apply my-2 text-center text-gray-700;
}
.card-icon :global(svg),
.card-icon :global(img) {
@apply inline h-12 w-12 lg:h-16 lg:w-16;
}
@screen md {
.card {
grid-row: ${index + 1} / span 2;
}
.card:first-child {
@apply mt-0;
}
.card:nth-of-type(even) {
grid-column: 2;
}
}
`}</style>
</section>
)
}
const cards = [
({ index }) => (
<Card
index={index}
name="Based on CommonMark"
icon={<MarkdownIcon verticalAlign="top" />}
>
If you know how to write a document with Markdown, you already know how to
write a Marp slide deck. Marp's format is based on{' '}
<a
href="https://commonmark.org/"
target="_blank"
rel="noopener noreferrer"
>
CommonMark
</a>
, a consistent Markdown specification. The only important difference is{' '}
<a
href="https://marpit.marp.app/markdown"
rel="noopener noreferrer"
target="_blank"
>
a ruler <code>---</code> for splitting pages.
</a>
</Card>
),
({ index }) => (
<Card
index={index}
name="Directives and extended syntax"
icon={<CodeSquareIcon verticalAlign="top" />}
>
Sometimes simple text content isn't enough to emphasize your voice,
so Marp supports a variety of{' '}
<a
href="https://marpit.marp.app/directives"
rel="noopener noreferrer"
target="_blank"
>
directives
</a>{' '}
and extended syntax (
<a
href="https://marpit.marp.app/image-syntax"
rel="noopener noreferrer"
target="_blank"
>
image syntax
</a>
,{' '}
<a
href="https://github.com/marp-team/marp-core#math-typesetting"
rel="noopener noreferrer"
target="_blank"
>
math typesetting
</a>
,{' '}
<a
href="https://github.com/marp-team/marp-core#auto-scaling-features"
rel="noopener noreferrer"
target="_blank"
>
auto-scaling
</a>
, etc...) to create beautiful slides.
</Card>
),
({ index }) => (
<Card
index={index}
name="Built-in themes and CSS theming"
icon={<PaintbrushIcon verticalAlign="top" />}
>
<a
href="https://github.com/marp-team/marp-core/"
rel="noopener noreferrer"
target="_blank"
>
Our core engine
</a>{' '}
has{' '}
<a
href="https://github.com/marp-team/marp-core/tree/main/themes"
rel="noopener noreferrer"
target="_blank"
>
3 built-in themes called <code>default</code>, <code>gaia</code>, and{' '}
<code>uncover</code>
</a>
, to tell your story beautifully. If you'd rather customize your
design, you can use Marp to{' '}
<a
href="https://marpit.marp.app/theme-css?id=tweak-style-through-markdown"
rel="noopener noreferrer"
target="_blank"
>
tweak styles with Markdown
</a>
, or{' '}
<a
href="https://marpit.marp.app/theme-css"
rel="noopener noreferrer"
target="_blank"
>
create your own Marp theme with plain CSS
</a>
.
</Card>
),
({ index }) => (
<Card
index={index}
name="Export to HTML, PDF, and PowerPoint"
icon={<FileIcon verticalAlign="top" />}
>
Have you finished writing? It's time to share your deck! Marp can
convert Markdown into presentation-ready HTML, PDF and PowerPoint files
directly! (Powered by{' '}
<a
href="https://www.google.com/chrome/"
rel="noopener noreferrer"
target="_blank"
>
Google Chrome
</a>{' '}
/{' '}
<a
href="https://www.chromium.org/Home"
rel="noopener noreferrer"
target="_blank"
>
Chromium
</a>
)
</Card>
),
({ index }) => (
<Card
index={index}
name="Marp family: The official toolset"
icon={<PackageIcon verticalAlign="top" />}
>
The Marp ecosystem contains a rich toolset to assist your work.{' '}
<a
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
rel="noopener noreferrer"
target="_blank"
>
<b>Marp for VS Code</b>
</a>{' '}
is an extension that allows you to edit and preview slide Markdown and
custom theming within VS Code.{' '}
<a
href="https://github.com/marp-team/marp-cli/"
rel="noopener noreferrer"
target="_blank"
>
<b>Marp CLI</b>
</a>{' '}
is a command line tool allows you to convert Markdown with a simple CLI
interface.{' '}
<a
href="https://github.com/marp-team/marp/"
rel="noopener noreferrer"
target="_blank"
>
... and much more!
</a>
</Card>
),
({ index }) => (
<Card
index={index}
name="Pluggable architecture"
icon={<PlugIcon verticalAlign="top" />}
>
As a matter of fact,{' '}
<em>Marp is essentially just a converter for Markdown.</em> The Marp
ecosystem is built on{' '}
<a
href="https://marpit.marp.app"
rel="noopener noreferrer"
target="_blank"
>
<b>the Marpit framework</b>
</a>
, a skinny framework for creating HTML/CSS slide decks. It has a pluggable
architecture and any developer can{' '}
<a
href="https://marpit.marp.app/usage?id=extend-marpit-by-plugins"
rel="noopener noreferrer"
target="_blank"
>
extend features via plugins
</a>
.
</Card>
),
({ index }) => (
<Card
index={index}
name="Fully open-source"
icon={<HeartFillIcon verticalAlign="top" />}
>
The Marp team loves open source! All tools and related libraries are built
by{' '}
<a
href="https://github.com/marp-team"
rel="noopener noreferrer"
target="_blank"
>
the Marp team
</a>{' '}
and are MIT-licensed.
</Card>
),
]
export const Features = () => (
<div className="features">
<div className="features-grid container">
{cards.map((Card, i) => (
<Card index={i} key={i} />
))}
</div>
<style jsx>{`
.features {
@apply relative py-5;
}
.features::before {
@apply absolute inset-0 block;
background-image: var(--noise-image),
linear-gradient(
-8deg,
rgba(120, 197, 233, 0),
rgba(120, 197, 233, 0) 50%,
rgba(120, 197, 233, 0.5)
);
clip-path: polygon(0 15vw, 100% 0, 100% 100%, 0 100%);
content: '';
}
.features-grid {
@apply mx-auto grid px-4;
grid-template-columns: 1fr;
grid-template-rows: repeat(${cards.length + 1}, auto);
}
@screen md {
.features-grid {
grid-template-columns: 1fr 1fr;
}
}
`}</style>
</div>
)
================================================
FILE: website/components/top/GetStarted.tsx
================================================
import classNames from 'classnames'
import { Button } from 'components/Button'
type CardProps = React.PropsWithChildren<{
badge?: string
className?: string
description: string
href: string
name: string
screenShot?: string
ssWidth?: number
ssHeight?: number
summary: string
}>
const Card: React.FC<CardProps> = ({
badge,
children,
className,
description,
href,
name,
screenShot: screenshot,
ssWidth,
ssHeight,
summary,
}) => (
<section className={classNames('card', className, { screenshot })}>
<a
href={href}
target="_blank"
rel="noopener noreferrer"
className="custom-anchor card-link"
>
<h4 className="text-gradient inline-block pr-3 pb-1 text-xl font-bold sm:text-2xl md:text-3xl">
{name}
</h4>
{badge && (
<img
src={badge}
alt=""
className="inline rounded-sm align-text-top sm:align-baseline"
loading="lazy"
/>
)}
<p className="pt-1 text-sm leading-tight text-gray-700">{summary}</p>
</a>
{screenshot && (
<figure>
<img
src={screenshot}
alt={name}
loading="lazy"
width={ssWidth}
height={ssHeight}
/>
</figure>
)}
<p className="mx-5 lg:my-3">{description}</p>
<p className="mx-5 my-4 text-sm">{children}</p>
<style jsx>{`
.card {
@apply text-foreground relative my-8 grid overflow-hidden rounded-lg bg-white p-2 shadow-xl;
grid-template-columns: 1fr;
}
.card::before {
@apply absolute right-0 h-40 w-40 transform bg-contain bg-center bg-no-repeat opacity-25;
content: '';
top: -2rem;
transform: rotate(-15deg);
}
.card.vscode::before {
background-image: url('https://icongr.am/simple/visualstudiocode.svg?color=67b8e3');
}
.card.cli::before {
background-image: url('https://icongr.am/octicons/terminal.svg?color=67b8e3');
}
.card.core::before {
background-image: url('/assets/marp-logo.svg');
}
.card.marpit::before {
background-image: url('/assets/marpit.svg');
}
.card > * {
@apply relative col-start-1 col-end-1;
}
.card > figure {
@apply mx-auto flex items-center justify-center p-4;
}
.card > figure > img {
@apply max-w-full;
width: 28rem;
}
.card-link {
@apply relative z-10 block rounded p-5 transition-all duration-150;
}
.card-link:hover,
.card-link:focus {
@apply shadow;
background-color: rgba(255, 255, 255, 0.5);
}
.card-link:hover:active,
.card-link:focus {
@apply duration-0 outline-none ring-1 ring-white ring-offset-2;
}
@screen lg {
.card.screenshot {
grid-template-columns: 3fr 2fr;
}
.card > figure {
@apply col-start-2 col-end-2 h-full w-full object-contain px-6 py-0;
grid-row: 1 / span 9999;
}
.card::before {
@apply h-64 w-64;
top: -4rem;
}
}
@screen xl {
.card {
@apply mx-auto w-5/6;
}
}
`}</style>
</section>
)
export const GetStarted = () => (
<>
<div id="get-started" className="get-started flow-root">
<section className="container mx-auto py-10 px-8 lg:px-16">
<h3 className="text-center text-2xl font-bold sm:text-3xl">
<mark>Tools and integrations</mark>
</h3>
<Card
description="Enhance VS Code's Markdown preview pane to support writing your beautiful presentations. You can preview the slide deck output as soon as you edit its Markdown."
name="Marp for VS Code"
summary="Create slide decks written in Marp Markdown right in VS Code"
badge="https://img.shields.io/visual-studio-marketplace/v/marp-team.marp-vscode.svg?style=flat-square&label=&colorB=0288d1"
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
screenShot="/assets/marp-for-vs-code.png"
ssWidth={1946}
ssHeight={1424}
className="vscode"
>
<Button
color="primary"
className="mr-2 mb-2"
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
target="_blank"
rel="noopener noreferrer"
>
VS Marketplace
</Button>
<Button
outline
className="mr-2 mb-2"
href="https://github.com/marp-team/marp-vscode"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</Button>
</Card>
<Card
description="The Marp CLI is the swiss army knife of the Marp ecosystem. Convert your Markdown into various formats, watch changes, launch server for on-demand conversion, and customize the core engine."
name="Marp CLI"
summary="A CLI interface for Marp and Marpit based converters"
badge="https://img.shields.io/npm/v/@marp-team/marp-cli.svg?style=flat-square&label=&colorB=0288d1"
href="https://github.com/marp-team/marp-cli"
screenShot="/assets/marp-cli.png"
ssWidth={1400}
ssHeight={800}
className="cli"
>
<Button
color="primary"
className="mr-2 mb-2"
href="https://github.com/marp-team/marp-cli/releases"
target="_blank"
rel="noopener noreferrer"
>
Releases
</Button>
<Button
outline
color="primary"
className="mr-2 mb-2"
href="https://www.npmjs.com/package/@marp-team/marp-cli"
target="_blank"
rel="noopener noreferrer"
>
npm
</Button>
<Button
outline
className="mr-2 mb-2"
href="https://github.com/marp-team/marp-cli"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</Button>
</Card>
<h3 className="text-center text-2xl font-bold sm:text-3xl">
<mark>For developers</mark>
</h3>
<Card
description="All official Marp tooling uses this core as the engine. It is based on the Marpit framework and includes some extra features to help create beautiful slide decks."
name="Marp Core"
summary="The core of the Marp converter"
badge="https://img.shields.io/npm/v/@marp-team/marp-core.svg?style=flat-square&label=&colorB=0288d1"
href="https://github.com/marp-team/marp-core"
className="core"
>
<Button
outline
color="primary"
className="mr-2 mb-2"
href="https://www.npmjs.com/package/@marp-team/marp-core"
target="_blank"
rel="noopener noreferrer"
>
npm
</Button>
<Button
outline
className="mr-2 mb-2"
href="https://github.com/marp-team/marp-core"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</Button>
</Card>
<Card
description="Marpit (independent from Marp) is the framework that transforms Markdown and CSS themes to slide decks composed of HTML/CSS. It is optimized to output only the minimum set of assets required."
name="Marpit framework"
summary="The skinny framework for creating slide decks from Markdown"
badge="https://img.shields.io/npm/v/@marp-team/marpit.svg?style=flat-square&label=&colorB=0288d1"
href="https://marpit.marp.app/"
className="marpit"
>
<Button
color="primary"
className="mr-2 mb-2"
href="https://marpit.marp.app/"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</Button>
<Button
outline
color="primary"
className="mr-2 mb-2"
href="https://www.npmjs.com/package/@marp-team/marpit"
target="_blank"
rel="noopener noreferrer"
>
npm
</Button>
<Button
outline
className="mr-2 mb-2"
href="https://github.com/marp-team/marpit"
target="_blank"
rel="noopener noreferrer"
>
GitHub
</Button>
</Card>
<p className="mt-4 text-center">
Find all of the Marp tools, integrations, and examples in the GitHub
repository!
</p>
<p className="text-foreground mt-4 text-center text-sm">
<Button
href="https://github.com/marp-team/marp/"
rel="noopener"
target="_blank"
>
Check out Marp GitHub repository...
</Button>
</p>
</section>
</div>
<style jsx>{`
.get-started {
@apply bg-marp-brand relative text-white;
background-image: var(--noise-image),
linear-gradient(
-2deg,
theme('colors.marp.darken'),
theme('colors.marp.brand') 500px
);
}
.get-started::before,
.get-started::after {
@apply absolute inset-x-0 block;
background-image: var(--noise-image),
linear-gradient(to bottom, rgba(255, 255, 255, 0.4), transparent 95%);
bottom: calc(100% - 5px);
content: '';
transform: translateZ(0);
z-index: -1;
}
.get-started::before {
@apply bg-marp-light;
clip-path: polygon(0 0, 100% 90%, 100% 100%, 0 100%);
height: calc(120px + 5vw);
}
.get-started::after {
@apply bg-marp-brand;
clip-path: polygon(0 0, 100% 95%, 100% 100%, 0 100%);
height: calc(60px + 5vw);
}
`}</style>
</>
)
================================================
FILE: website/components/top/Hero.tsx
================================================
import Head from 'next/head'
import { Button } from 'components/Button'
import Marp from 'public/assets/marp.svg'
const heroBg = '/assets/hero-background.svg' as const
export const Hero = () => (
<>
<Head>
<link rel="preload" href={heroBg} as="image" />
</Head>
<section className="border-b py-16 px-4 md:py-24 md:tracking-wider">
<h1 className="font-rounded text-center font-bold sm:text-xl md:text-2xl">
<Marp className="mx-auto mb-5 h-auto w-4/5 max-w-xl p-3" />
<span className="sr-only">Marp:</span>
Markdown Presentation Ecosystem
</h1>
<p className="mt-10 text-center">
<Button
href="#get-started"
color="primary"
className="text-xl md:text-2xl"
>
Get started!
</Button>
</p>
<p className="mt-5 text-center">
<Button
href="https://github.com/marp-team/marp"
target="_blank"
rel="noopener noreferrer"
className="text-sm md:text-base"
color="primary"
outline
>
Find Marp tools on GitHub!
</Button>
</p>
<style jsx>{`
section {
background: #fcfcfc url('${heroBg}') no-repeat right center;
background-size: cover;
}
`}</style>
</section>
</>
)
================================================
FILE: website/css/index.css
================================================
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--noise-image: url('/assets/noise.svg');
--header-height: 4rem;
--anchor-margin: var(--header-height);
scroll-padding-top: var(--anchor-margin);
}
@screen md {
:root {
--header-height: 5rem;
}
}
* {
scrollbar-color: theme('colors.gray.500') theme('colors.gray.300');
scrollbar-width: thin;
}
*::-webkit-scrollbar {
width: 8px;
height: 8px;
}
*::-webkit-scrollbar-track {
@apply bg-gray-300;
}
*::-webkit-scrollbar-thumb {
@apply rounded-full bg-gray-500 bg-clip-padding;
border: 1px solid transparent;
}
*::-webkit-scrollbar-thumb:hover {
@apply bg-gray-600;
}
*::-webkit-scrollbar-thumb:hover:active {
@apply bg-gray-700;
}
html:not(.translating) {
scroll-behavior: smooth;
}
body {
@apply text-foreground bg-background relative min-h-full;
}
body::before {
@apply bg-background fixed inset-0 block;
background-image: var(--noise-image),
linear-gradient(
to bottom,
theme('colors.gray.100'),
theme('colors.background') 50%
);
content: '';
z-index: -1;
}
a:not(.custom-anchor) {
@apply text-marp-darken;
}
a:not(.custom-anchor):hover {
@apply text-marp-dark underline transition-colors duration-300;
}
a:not(.custom-anchor):hover:active {
@apply text-marp-darkest duration-0;
}
mark {
background: none;
color: inherit;
box-shadow: inset 0 -0.2em theme('colors.marp.light');
}
/* NProgress */
#nprogress .bar {
@apply bg-marp-brand;
}
#nprogress .peg {
@apply shadow-none;
}
/* Helper classes */
.text-gradient {
@apply text-marp-brand leading-tight;
}
@supports (background-clip: text) {
.text-gradient {
@apply bg-marp-brand bg-clip-text text-transparent;
background-image: linear-gradient(
-1deg,
theme('colors.marp.light'),
theme('colors.marp.brand'),
theme('colors.marp.dark')
);
}
}
================================================
FILE: website/css/plugin-rem.js
================================================
// Based on Marpit PostCSS rem plugin
// https://github.com/marp-team/marpit/blob/main/src/postcss/root/rem.js
const rootFontSizeCustomProp = '--root-font-size'
const skipParsingMatcher = /("[^"]*"|'[^']*'|(?:attr|url|var)\([^)]*\))/g
module.exports = () => ({
postcssPlugin: 'marp-rem',
Once: (css) =>
css.walkDecls((decl) => {
if (decl.prop === rootFontSizeCustomProp) return
decl.value = decl.value
.split(skipParsingMatcher)
.map((v, i) => {
if (i % 2) return v
return v.replace(
/(-?\d*\.?\d+)rem\b/g,
(_, num) => `calc(var(${rootFontSizeCustomProp}, 1rem) * ${num})`
)
})
.join('')
}),
})
module.exports.postcss = true
================================================
FILE: website/docs/guide/directives.md
================================================
# Directives
### This is a stub page!
Marp has an extended syntax called **"Directives"** to control theme, page number, header, footer, and other slide elements.
> The syntax of directives is inherited from [Marpit framework](https://marpit.marp.app/directives). Please note that different directives are used by each Marp tool.
## Usage
Marp parses directives as [YAML](https://yaml.org/).
### HTML comment
```markdown
<!--
theme: default
paginate: true
-->
```
### Front matter
Like many tools (e.g. [Jekyll site generator](https://jekyllrb.com/docs/front-matter/)), Marp uses **YAML front matter**. Directives can be defined in front matter.
YAML front matter must be at the beginning of a Markdown document and enclosed by dashed rulers.
```markdown
---
theme: default
paginate: true
---
```
Note that the dashed ruler is also used to indicate where Marp should [ split slides](/docs/guide/how-to-write-slides#slides). Marp uses the first two dashed rulers to indicate YAML front matter. Subsequent dashed rulers indicate slide breaks.
> TIP: Defining directives in the front matter is equivalent to setting the directives using an HTML comment on the first page. Suppose your favorite Markdown editor does not support the front matter syntax. In that case, you can safely define the directive in an HTML comment instead.
## Type of directives
There are two types of Marp directives:
- **[Global directives](#global-directives)** - Controlling settings for the all slides (e.g. `theme`, `size`)
- **[Local directives](#local-directives)** - Controlling setting values for one slide (e.g. `paginate`, `header`, `footer`)
You can define both directives in the same way. You can mix definitions too. The only difference is that some settings apply to all slides, and some apply to only one slide.
### Global directives
**Global directives** are settings for the entire slide deck.
| Name | Description |
| ---------------- | ------------------------------------------------------------------------------ |
| `theme` | [Set a theme name for the slide deck ▶️](/docs/guide/theme) |
| `style` | Specify CSS for tweaking theme |
| `headingDivider` | [Specify heading divider option ▶️](/docs/guide/heading-divider) |
| `size` | Choose the slide size preset provided by theme |
| `math` | [Choose a library to render math typesetting ▶️](/docs/guide/math-typesetting) |
| `title` | Set a title of the slide deck |
| `author` | Set an author of the slide deck |
| `description` | Set a description of the slide deck |
| `keywords` | Set comma-separated keywords for the slide deck |
| `url` | Set canonical URL for the slide deck (for HTML export) |
| `image` | Set Open Graph image URL (for HTML export) |
| `marp` | Set whether or not enable Marp feature in VS Code |
If you set the same global directive multiple times, Marp will use the last defined value.
### Local directives
**Local directives** are settings for a specific slide.
| Name | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `paginate` | [Show page number on the slide if set to `true` ▶️](#page-number) |
| `header` | [Specify the content of the slide header ▶️](#header-and-footer) |
| `footer` | [Specify the content of the slide footer ▶️](#header-and-footer) |
| `class` | Set [HTML `class` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) for the slide element `<section>` |
| `backgroundColor` | Set [`background-color` style](https://developer.mozilla.org/en-US/docs/Web/CSS/background-color) of the slide |
| `backgroundImage` | Set [`background-image` style](https://developer.mozilla.org/en-US/docs/Web/CSS/background-image) of the slide |
| `backgroundPosition` | Set [`background-position` style](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) of the slide |
| `backgroundRepeat` | Set [`background-repeat` style](https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat) of the slide |
| `backgroundSize` | Set [`background-size` style](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) of the slide |
| `color` | Set [`color` style](https://developer.mozilla.org/en-US/docs/Web/CSS/color) of the slide |
#### Inheritance
Slides will inherit setting values of local directives from the immediately previous slide **unless** a local directive is explicitly set for the current slide. In other words, defined local directives will apply to both the defined page and subsequent pages.
For example, the Markdown for this set of slides defines the `backgroundColor` directive on the second page. Because subsequent pages inherit local directives, the third page will also have the same color.
```markdown
# Page 1
Go to next page :arrow_right:
---
<!-- backgroundColor: lightblue -->
# Page 2
## This page has a light blue background.
---
# Page 3
## This page also has the same light blue background.
```
```markdown:marp
# Page 1
Go to next page :arrow_right:
---
<!-- backgroundColor: lightblue -->
# Page 2
## This page has a light blue background.
---
# Page 3
## This page also has the same light blue background.
```
#### Scoped local directives
If you want a local directive to apply only to the current page, add the underscore prefix `_` to the name of directives.
The value of a scoped directive will be given priority over an inherited value, and subsequent pages will not inherit the value of the scoped directive.
```markdown
<!-- color: red -->
# Page 1
This page has red text.
---
<!-- _color: blue -->
# Page 2
This page has blue text, specified by a scoped local directive.
---
# Page 3
Go back to red text.
```
```markdown:marp
<!-- color: red -->
# Page 1
This page has red text.
---
<!-- _color: blue -->
# Page 2
This page has blue text, specified by a scoped local directive.
---
# Page 3
Go back to red text.
```
The underscore prefix can be added to any local directives.
#### Diagram

## Theme
<!-- TODO: Link to "Theme" section -->
## Page number
To add page number to the slide, set the **`paginate`** local directive to `true`.
```markdown
<!-- paginate: true -->
You can see the slide number in the lower right.
```
```markdown:marp
<!-- paginate: true -->
You can see the slide number in the lower right.
<style>
@keyframes point {
from { background-position: bottom 55px right 55px; }
to { background-position: bottom 40px right 40px; }
}
section {
animation: 0.5s ease-in-out alternate infinite point;
background: #fff url('https://icongr.am/feather/arrow-down-right.svg?color=0288d1') no-repeat bottom 40px right 40px / 100px;
}
@media (prefers-reduced-motion) {
section {
animation: none;
}
}
</style>
```
Refer to [theme guide](/docs/guide/theme) for details on how to style a slide number.
### Skip pagination in the title slide
Just move the definition of the `paginate` directive to the second slide.
```markdown
# Title slide
---
<!-- paginate: true --->
## Start pagination from this slide.
```
```markdown:marp
# Title slide
---
<!-- paginate: true --->
## Start pagination from this slide.
<style scoped>
@keyframes point {
from { background-position: bottom 55px right 55px; }
to { background-position: bottom 40px right 40px; }
}
section {
animation: 0.5s ease-in-out alternate infinite point;
background: #fff url('https://icongr.am/feather/arrow-down-right.svg?color=0288d1') no-repeat bottom 40px right 40px / 100px;
}
@media (prefers-reduced-motion) {
section {
animation: none;
}
}
</style>
```
You can also use [scoped directive](#scoped-local-directives) to disable pagination in the title slide.
```markdown
---
paginate: true
_paginate: false
---
# Title slide
---
## Start pagination from this slide.
```
## Header and footer
Use **`header`** and **`footer`** local directives to add headers and footers to slides.
```markdown
<!--
header: Header content
footer: Footer content
-->
# Header and footer
```
```markdown:marp
<!--
header: Header content
footer: Footer content
-->
# Header and footer
<style>
@keyframes point-up {
from { background-position: 50px 50px; }
to { background-position: 50px 70px; }
}
@keyframes point-down {
from { background-position: left 50px bottom 50px; }
to { background-position: left 50px bottom 70px; }
}
section {
animation: 0.5s ease-in-out alternate infinite point-up;
background: #fff url('https://icongr.am/feather/arrow-up.svg?color=0288d1') no-repeat 50px 50px / 80px;
}
section::before {
content: '';
display: block;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
animation: 0.5s ease-in-out alternate infinite point-down;
background: transparent url('https://icongr.am/feather/arrow-down.svg?color=0288d1') no-repeat left 50px bottom 50px / 80px;
}
@media (prefers-reduced-motion) {
section, section::before {
animation: none;
}
}
</style>
```
Refer to [theme guide](/docs/guide/theme) for details on how to style header and footer.
### Markdown formatting
You can use inline Markdown formatting (italic, bold, inline image, etc) in header and footer like this:
```markdown
---
header: '**bold** _italic_'
footer: ''
---
```
To make directives parsable as valid YAML, you can wrap content with (double-)quotes.
### Reset header and footer
Set the value of a directive to an empty string value to reset the header and footer in the middle of the slide deck.
```markdown
---
header: '**Header**'
footer: '_Footer_'
---
# Example
---
<!--
header: ''
footer: ''
-->
## Reset header and footer
```
```markdown:marp
---
header: '**Header**'
footer: '_Footer_'
---
# Example
---
<!--
header: ''
footer: ''
-->
## Reset header and footer
```
## Styling slide
### Shorthand
## Editor integration
<!-- By using **Marp for VS Code**, you can preview -->
================================================
FILE: website/docs/guide/fitting-header.md
================================================
# Fitting header
When the `<!--fit-->` comment is placed in a heading, the heading will be scaled to fit onto a single line.
```markdown
# <!-- fit --> Fitting header
```
```markdown:marp
# <!-- fit --> Fitting header
```
The syntax is similar to [Deckset's `[fit]` keyword](https://docs.decksetapp.com/English.lproj/Formatting/01-headings.html), but Marp uses an HTML comment to hide the keyword when the Markdown is rendered.
> This feature is inherited from [Marp Core](https://github.com/marp-team/marp-core).
## Examples
### Takahashi-style
You can efficiently make [Takahashi-style](https://en.wikipedia.org/wiki/Takahashi_method) slides like the [Big](https://github.com/tmcw/big) presentation system by using the fitting header. Combining fitting headers with the [heading divider](/docs/guide/heading-divider) directive will allow you to write one slide per line.
```markdown
---
theme: uncover
headingDivider: 1
---
# <!--fit--> Takahashi-style<br />presentation
# <!--fit--> Feature
# <!--fit--> Huge text
# <!--fit--> A few words
```
```markdown:marp
---
theme: uncover
headingDivider: 1
---
# <!--fit--> Takahashi-style<br />presentation
# <!--fit--> Feature
# <!--fit--> Huge text
# <!--fit--> A few words
```
================================================
FILE: website/docs/guide/fragmented-list.md
================================================
# Fragmented list
Marp uses some uncommon list markers to denote a **fragmented list** (also known as an incremental list or builds), which allows list content to appear incrementally.
Fragmented lists are _only available if you export to HTML_. If you export to PDF and PPTX, the fragmented list will be rendered as a normal list.
> Be careful when using fragmented lists. While fragmented lists can help focus the audience's attention on the last displayed item, they may also create confusion about hidden items. Some articles recommend never using builds (e.g. [Presentation Rules](http://www.jilles.net/perma/2020/06/05/presentation-rules.html)).
## For bullet lists
CommonMark's bullet list markers are `-`, `+`, and `*` (https://spec.commonmark.org/0.29/#bullet-list-marker). If you use `*` as the marker, Marp will parse the list as a fragmented list.
<!-- prettier-ignore-start -->
```markdown
# Bullet list
- One
- Two
- Three
---
# Fragmented list
* One
* Two
* Three
```
<!-- prettier-ignore-end -->
## For ordered list
CommonMark's [ordered list marker](https://spec.commonmark.org/0.29/#ordered-list-marker) must have `.` or `)` after digits. If you use `)` as the following character, then Marp will parse the ordered list as a fragmented list.
<!-- prettier-ignore-start -->
```markdown
# Ordered list
1. One
2. Two
3. Three
---
# Fragmented list
1) One
2) Two
3) Three
```
<!-- prettier-ignore-end -->
> These are inherited from [Marpit framework](https://marpit.marp.app/fragmented-list).
>
> [This syntax only indicates that the list _should_ be fragmented](https://marpit.marp.app/fragmented-list?id=rendering). If the tools integrated with Marp do nothing with the syntax, this list would be rendered as a normal list. In the official toolset, [Marp CLI](https://github.com/marp-team/marp-cli)'s default HTML template `bespoke` can reproduce a fragmented list as a build animation.
================================================
FILE: website/docs/guide/heading-divider.md
================================================
# Heading divider
The heading divider directive tells Marp to automatically add a slide break before a heading of the specified level. This directive is particularly useful when converting an existing Markdown document to slides.
Heading dividers is similar to [Pandoc](https://pandoc.org/)'s [`--slide-level` option](https://pandoc.org/MANUAL.html#structuring-the-slide-show) and [Deckset 2](https://www.deckset.com/2/)'s "Slide Dividers" option.
> This feature is inherited from the [Marpit framework](https://marpit.marp.app/directives?id=heading-divider).
## Example
Let’s say you have a Markdown document like this:
```markdown
# Markdown document
The article of Markdown
## What is Markdown?
> Markdown is a lightweight markup language for creating formatted text using a plain-text editor.
>
> _-- https://en.wikipedia.org/wiki/Markdown_
## History
### Origin
Markdown has created by John Gruber in 2004.
https://daringfireball.net/projects/markdown/
### Standardization
CommonMark is a project for a standardization of Markdown launched in 2012.
```
Add the [`headingDivider` global directive](/docs/guide/directives#global-directives).
```markdown
<!-- headingDivider: 2 -->
```
Once you have specified the directive, Marp will automatically split the document into slides by starting a new slide whenever a section has a heading level of 2.
```markdown:marp
<!-- headingDivider: 2 -->
# Markdown document
The article of Markdown
## What is Markdown?
> Markdown is a lightweight markup language for creating formatted text using a plain-text editor.
>
> _-- https://en.wikipedia.org/wiki/Markdown_
## History
### Origin
Markdown was created by John Gruber in 2004.
https://daringfireball.net/projects/markdown/
### Standardization
CommonMark is a project for a standardization of Markdown launched in 2012.
```
The `headingDivider` global directive accepts heading levels from 1 to 6. When the heading level is set as a number, Marp will split slides at headings that are _at the specified level and at all parent levels_. So, `headingDivider: 2` will actually make new slides at headings of levels 1 and 2.
If a section has so much content that it overflows the slide, it might be better to split it by subsection. To do that, just change the base level for `headingDivider` to `3`. Check out the difference from the previous example after the 3rd page:
```markdown:marp
<!-- headingDivider: 3 -->
# Markdown document
The article of Markdown
## What is Markdown?
> Markdown is a lightweight markup language for creating formatted text using a plain-text editor.
>
> _-- https://en.wikipedia.org/wiki/Markdown_
## History
### Origin
Markdown was created by John Gruber in 2004.
https://daringfireball.net/projects/markdown/
### Standardization
CommonMark is a project for a standardization of Markdown launched in 2012.
```
> [Rulers to split pages](/docs/guide/how-to-write-slides#slides) still work normally even if enabled `headingDivider`.
## Advanced
Auto split in parent heading levels is reasonable behavior in most cases, but sometimes you may require finer control of splitting levels. If you set the directive value to an array, you also instruct Marp to split at only the specified levels.
```markdown
<!-- headingDivider: [1, 3] -->
```
This setting will instruct Marp to split slides at heading levels 1 and 3.
================================================
FILE: website/docs/guide/how-to-write-slides.md
================================================
# How to write slides
## Markdown
To write slides using Marp, you have to know basic Markdown syntax. It doesn't take long to learn the basics, and there are many Markdown tutorials on the internet, so this guide will focus on the additional syntax used by Marp that allows you to write slides.
### Resources for learning Markdown
- **[Markdown Guide](https://www.markdownguide.org/)** - A simple guide on how to use Markdown
- **[Markdown Tutorial](https://www.markdowntutorial.com/)** - Step-by-step Markdown tutorials with interactive exercises
## Slides
OK, let's write presentation slides. Marp splits slides in the deck using the horizontal ruler (e.g. `---`).
```markdown
# Slide 1
Hello, world!
---
# Slide 2
Marp splits slides in the deck by horizontal ruler.
```
```markdown:marp
# Slide 1
Hello, world!
---
# Slide 2
Marp splits slides in the deck by horizontal ruler.
```
If you use the `---` ruler, an empty line may be required before the ruler by [the spec of CommonMark](https://spec.commonmark.org/0.29/#example-28). If you do not want to add empty lines around the ruler, you can also use the underline ruler `___`, asterisk ruler `***`, or space-included ruler `- - -` to split slides.
> This feature is inherited from [Marpit framework](https://marpit.marp.app/markdown).
## Syntaxes
Marp's Markdown syntax is based on [CommonMark](https://commonmark.org/). In addition, Marp uses some extended syntax:
- Line breaks in a paragraph will convert to `<br />` tag automatically.
- You also can use `<br />` tag directly (Useful if you need a line break within a [fitting header](/docs/guide/fitting-header)).
- There is special meaning in some (uncommon) list markers `*` and `1)`. [▶️ Fragmented list](/docs/guide/fragmented-list).
- Some extended syntaxes that came from [GitHub Flavored Markdown (GFM)](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) are enabled:
- [Automatic linking for URLs](https://github.github.com/gfm/#autolinks-extension-)
- Emoji shortcode (provided by [markdown-it-emoji](https://github.com/markdown-it/markdown-it-emoji) and [twemoji](https://github.com/twitter/twemoji))
- [Strikethrough](https://github.github.com/gfm/#strikethrough-extension-) (`~~strike~~`)
- Syntax highlighting for code blocks (via [highlight.js](https://highlightjs.org/))
- [Tables](https://github.github.com/gfm/#tables-extension-)
- Most HTML tags are _disabled_ by default for security reasons. Marp only allows users to use two tags by default: the `<style>` tag for tweaking the theme and the `<br />` tag mentioned earlier.
- To enable all HTML tags, you need to opt-in for the Marp tool you are using.
> Many extended syntaxes are inherited from [Marp Core](https://github.com/marp-team/marp-core).
================================================
FILE: website/docs/guide/image-syntax.md
================================================
# Image syntax
### This is a stub page!
> This feature is inherited from [Marpit framework](https://marpit.marp.app/image-syntax).
================================================
FILE: website/docs/guide/math-typesetting.md
================================================
# Math typesetting
[Many Markdown tools support math rendering](https://github.com/cben/mathdown/wiki/math-in-markdown). We have [Pandoc's Markdown style](https://pandoc.org/MANUAL.html#math) math typesetting support. Marp renders math using [MathJax] (or, alternatively, [KaTeX]).
[katex]: https://katex.org/
[mathjax]: https://www.mathjax.org/
### Inline math
Surround your formula with a single dollar character `$...$`.
```markdown
Render inline math such as $ax^2+bc+c$.
```
### Math block
Surround the formula with double dollar characters `$$...$$`. Math in the block element will render with centering. The math in the block element will also scale down automatically if it is sticking out from the horizontal border of the slide (only in supported themes).
<!-- prettier-ignore-start -->
```markdown
$$ I_{xx}=\int\int_Ry^2f(x,y)\cdot{}dydx $$
$$
f(x) =
\int_{-\infty}^\infty
\hat f(\xi)\,e^{2 \pi i \xi x}
\,d\xi
$$
```
<!-- prettier-ignore-end -->
```markdown:marp
## Inline math
Render inline math such as $ax^2+bc+c$.
## Math block
$$ I_{xx}=\int\int_Ry^2f(x,y)\cdot{}dydx $$
$$
f(x) =
\int_{-\infty}^\infty
\hat f(\xi)\,e^{2 \pi i \xi x}
\,d\xi
$$
```
> This feature is inherited from [Marp Core](https://github.com/marp-team/marp-core).
## [MathJax]
By default, Marp uses **[MathJax]** to render math typesetting.
### Declare to use MathJax
Set [`math` global directive](/docs/guide/directives#global-directives) as `mathjax`.
```markdown
---
math: mathjax
---
Render inline math such as $ax^2+bc+c$.
```
For the determined rendering of slide, we recommend always to declare math library to use in the slide. No definition of math directive may bring inconsistent rendering result depending on the version of Marp Core.
## [KaTeX]
**[KaTeX]** is an alternative library to render math typesettings in Marp, and it was former default.
By defining `math` global directive as `katex`, you can continue to render math with KaTeX.
### Enable KaTeX
Set [`math` global directive](/docs/guide/directives#global-directives) as `katex`.
```markdown
---
math: katex
---
Render inline math such as $ax^2+bc+c$.
```
### Define global macro
In KaTeX rendering, macros defined by `\def` will persist only in a local math environment. To persist defined macro for subsequent math environments in Markdown, use `\gdef` (`\global\def`) instead.
```markdown
$$
% macroA can use only in this math block.
\def\macroA{{\color{red}A}}
% macroB has defined globally so you can use it after here.
\gdef\macroB{{\color{blue}B}}
\macroA + \macroB
$$
---
$$
% macroA cannot use, but macroB can.
\macroA + \macroB
$$
```
[See the detail of supported macro functions in KaTeX documentation](https://katex.org/docs/supported.html#macros).
### Configuration
KaTeX options can be configured in [Marp Core's constructor option](https://github.com/marp-team/marp-core#constructor-options). You should use [Marp CLI](https://github.com/marp-team/marp-cli) if you need to set a custom configuration in Marp conversion.
```javascript
// marp.config.js
module.exports = {
options: {
math: {
lib: 'katex',
katexFontPath: 'https://example.com/assets/katex-fonts/'
katexOption: {
errorColor: '#ff0000',
macros: {
'\\RR': '\\mathbb{R}',
},
},
},
},
}
```
```bash
marp -c marp.config.js marp-math.md
```
[See the details of KaTeX option in the documentation.](https://katex.org/docs/options.html)
### mhchem extension
[mhchem](https://mhchem.github.io/MathJax-mhchem/) is an extension for writing chemical equations. To enable mhchem in Marp, you should use a Marp CLI configuration file and follow [a guide of KaTeX for Node.js](https://katex.org/docs/node.html#using-mhchem-extension).
```javascript
// marp.config.js
const katex = require('katex')
require('katex/dist/contrib/mhchem.js') // modify katex module
```
```bash
marp -c marp.config.js marp-mhchem.md
```
A common mistake is [using a client-side `<script>` to load the extension](https://github.com/KaTeX/KaTeX/tree/master/contrib/mhchem#usage). _This will not work because Marp's rendering will be completed within Node.js, not the browser._ See also: [marp-team/marp#99](https://github.com/marp-team/marp/discussions/99)
### Known issues for KaTeX rendering
- KaTeX rendering requires fetching Web Fonts from [jsDelivr](https://www.jsdelivr.com/) CDN. If you are in offline or the limited network by proxy, the slide may not render math.
- Safari does not shrink down the big math block rendered by KaTeX. ([marp-team/marp-core#159](https://github.com/marp-team/marp-core/issues/159))
- Rendering of `\tag{}` is incompatible with the math block. ([marp-team/marp-core#236](https://github.com/marp-team/marp-core/issues/236))
================================================
FILE: website/docs/guide/theme.md
================================================
# Theme
### This is a stub page!
================================================
FILE: website/docs/introduction/install.md
================================================
# Install
### This is a stub page!
There are two ways to use Marp, through a command-line interface (**[Marp CLI][marp cli]**) or through a graphical user interface (**[VS Code extension][marp for vs code]**). To start authoring presentations, you must install either the CLI or the VS Code extension.
## Should I use the Marp CLI or Marp for VS Code?
### Basic Comparison
| | Marp for VS Code | Marp CLI |
| ----------------: | :--------------: | :----------: |
| Editor | VS Code | Any editor |
| Live Preview | Yes | Yes |
| Export Method | Click to export | Command Line |
| Use Marp plugins? | No | Yes |
### Marp for VS Code
If you are not familiar with the command line, use the VS Code extension without hesitation! All of the basic Marp features are available in Marp for VS Code.
Even if you are CLI savvy, you may prefer to author presentations through Marp for VS Code. VS Code has many convenient features for authoring a slide deck, including Marp syntax completion and live preview.
### Marp CLI
Using Marp CLI is suited for following:
- Authoring Markdown and theme CSS with your favorite editor (such as vim)
- Batch processing
- Combination with other tools (through piping and redirection)
- Continuous Integration (CI)
- Server-side conversion
- Set advanced configuration of Marp
- Use Marp in Node.js project
- Use Marp / Marpit / markdown-it plugins
- Use the other Marpit flavored engine
## Installing [Marp for VS Code]
1. Install [Visual Studio Code].
2. Install the [Marp for VS Code] extension.
3. Create and open a new Markdown file (with `.md` extension).
4. Select the `Toggle Marp feature for current Markdown` command from the Marp icon in editor actions (toolbar). This command will add Marp to the front-matter of your Markdown file:
```markdown
---
marp: true
---
```
5. Open VS Code Markdown preview, and start writing your presentation!
[visual studio code]: https://code.visualstudio.com/
[marp for vs code]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
## Installing [Marp CLI]
[marp cli]: https://github.com/marp-team/marp-cli
### [Homebrew](https://brew.sh/) (macOS)
```bash
brew install marp-cli
```
### [Scoop](https://scoop.sh/) (Windows)
```bash
scoop install marp
```
### [Node.js](https://nodejs.org/)
If you have installed Node.js >= 12, you can try one-shot conversion without installing powered by `npx` (`npm exec`).
```bash
npx @marp-team/marp-cli@latest markdown.md
```
#### Install to Node project
```bash
npm install --save-dev @marp-team/marp-cli
npx marp markdown.md
```
```bash
yarn add --dev @marp-team/marp-cli
yarn exec markdown.md
```
[You can also install the `marp` command globally](https://github.com/marp-team/marp-cli#global-installation), but it is _not recommended_.
#### Standalone binary
[➡️ Download the latest standalone binary from the GitHub release page...][standalone binary]
[standalone binary]: https://github.com/marp-team/marp-cli/releases
#### Docker
[➡️ Check out the overview of an official container in Docker Hub...][docker]
[docker]: https://hub.docker.com/r/marpteam/marp-cli/
================================================
FILE: website/docs/introduction/whats-marp.md
================================================
# What's Marp?
### This is a stub page!
**Marp** (**Mar**kdown **P**resentation Ecosystem) provides a great experience for _writing_ presentations with Markdown.
````markdown:marp
---
marp: true
theme: uncover
---

# **Marp**
Markdown Presentation Ecosystem
https://marp.app/
---
<!-- paginate: true -->
## What's Marp?
Marp provides a great experience for _writing_ presentations with Markdown. :pencil:
```markdown
# Slide 1
foo
---
# Slide 2
bar
```
````
## Concepts
### Markdown
[Markdown] is one of the most popular lightweight markup languages. Markdown allows the author to write presentations quickly and focus on the logical structure of the presentation (rather than the code needed
gitextract_8zf9058k/
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── .nvmrc
├── .prettierignore
├── LICENSE
├── README.md
├── netlify.toml
├── package.json
├── tsconfig.json
└── website/
├── .eslintrc.js
├── assets.d.ts
├── babel.config.js
├── blog/
│ ├── 202205-ecosystem-update.md
│ ├── how-to-make-custom-transition.md
│ ├── marp-for-vs-code-v1.md
│ ├── marpit-v2-marp-core-v2-and-marp-cli-v1.md
│ ├── re-creation-of-marp-website.md
│ └── the-story-of-marp-next.md
├── components/
│ ├── Button.tsx
│ ├── CodeBlock.tsx
│ ├── Footer.tsx
│ ├── Header.tsx
│ ├── Layout.tsx
│ ├── Marp.tsx
│ ├── ScrollToTop.tsx
│ ├── Title.tsx
│ ├── Typography.tsx
│ ├── blog/
│ │ └── BlogHeader.tsx
│ ├── docs/
│ │ ├── Breadcrumb.tsx
│ │ ├── Layout.tsx
│ │ ├── Navigation.tsx
│ │ └── layouts/
│ │ ├── Desktop.tsx
│ │ └── Mobile.tsx
│ ├── markdown/
│ │ ├── Anchor.tsx
│ │ ├── Heading.tsx
│ │ ├── Image.tsx
│ │ └── Pre.tsx
│ └── top/
│ ├── Description.tsx
│ ├── Features.tsx
│ ├── GetStarted.tsx
│ └── Hero.tsx
├── css/
│ ├── index.css
│ └── plugin-rem.js
├── docs/
│ ├── guide/
│ │ ├── directives.md
│ │ ├── fitting-header.md
│ │ ├── fragmented-list.md
│ │ ├── heading-divider.md
│ │ ├── how-to-write-slides.md
│ │ ├── image-syntax.md
│ │ ├── math-typesetting.md
│ │ └── theme.md
│ ├── introduction/
│ │ ├── install.md
│ │ └── whats-marp.md
│ ├── manifest.yaml
│ └── tools/
│ ├── marp-cli.md
│ └── marp-for-vs-code.md
├── global.d.ts
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages/
│ ├── 404.tsx
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── blog/
│ │ └── [slug].tsx
│ ├── blog.tsx
│ ├── docs/
│ │ └── [[...slug]].tsx
│ └── index.tsx
├── postcss.config.js
├── public/
│ └── blog/
│ └── .gitignore
├── tailwind.config.js
├── tsconfig.json
└── utils/
├── date.ts
├── hooks/
│ └── useFontFace.tsx
├── markdown/
│ ├── index.tsx
│ ├── parse/
│ │ ├── image-paragraph-to-figure.ts
│ │ ├── index.ts
│ │ └── marp-code-block.ts
│ └── renderer/
│ ├── index.ts
│ └── sanitize.ts
├── title.ts
└── url.ts
SYMBOL INDEX (18 symbols across 17 files)
FILE: website/components/Button.tsx
type ButtonProps (line 4) | type ButtonProps = {
FILE: website/components/CodeBlock.tsx
type CodeBlockProps (line 24) | type CodeBlockProps = {
FILE: website/components/Header.tsx
type ItemSlug (line 8) | type ItemSlug = 'docs' | 'blog'
FILE: website/components/Layout.tsx
type LayoutProps (line 8) | type LayoutProps = React.PropsWithChildren<{
FILE: website/components/Marp.tsx
type RenderedMarp (line 10) | type RenderedMarp = ReturnType<
type MarpProps (line 16) | type MarpProps = {
FILE: website/components/blog/BlogHeader.tsx
type BlogHeaderProps (line 4) | type BlogHeaderProps = {
FILE: website/components/docs/Breadcrumb.tsx
type BreadcrumbProps (line 3) | type BreadcrumbProps = {
FILE: website/components/docs/Layout.tsx
type LayoutProps (line 8) | type LayoutProps = React.PropsWithChildren<
FILE: website/components/docs/Navigation.tsx
type NavigationProps (line 4) | type NavigationProps = {
FILE: website/components/markdown/Heading.tsx
type HOCProps (line 4) | type HOCProps<P extends {} = Record<string, any>> = React.PropsWithChild...
FILE: website/components/markdown/Image.tsx
type ImageProps (line 1) | type ImageProps = {
FILE: website/components/top/Description.tsx
type DescriptionProps (line 8) | type DescriptionProps = {
FILE: website/components/top/Features.tsx
type CardProps (line 12) | type CardProps = React.PropsWithChildren<{
FILE: website/components/top/GetStarted.tsx
type CardProps (line 4) | type CardProps = React.PropsWithChildren<{
FILE: website/global.d.ts
type HTMLAttributes (line 4) | interface HTMLAttributes {
FILE: website/pages/_document.tsx
class MyDocument (line 3) | class MyDocument extends Document {
FILE: website/utils/hooks/useFontFace.tsx
type FontFaceContextInterface (line 3) | interface FontFaceContextInterface {
Condensed preview — 85 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (239K chars).
[
{
"path": ".editorconfig",
"chars": 147,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_"
},
{
"path": ".eslintignore",
"chars": 36,
"preview": ".next\ncoverage\nlib\nnode_modules\nout\n"
},
{
"path": ".eslintrc.js",
"chars": 1256,
"preview": "const path = require('path')\nconst { workspaces } = require('./package.json')\n\nmodule.exports = {\n root: true,\n env: {"
},
{
"path": ".github/dependabot.yml",
"chars": 508,
"preview": "version: 2\n\nupdates:\n - package-ecosystem: npm\n directory: '/'\n reviewers:\n - 'marp-team/maintainers'\n sc"
},
{
"path": ".github/workflows/test.yml",
"chars": 928,
"preview": "name: Test\n\non:\n - pull_request\n - push\n\nenv:\n CACHE_PREFIX: v1\n YARN_VERSION: '^1.22.4'\n\njobs:\n test:\n runs-on:"
},
{
"path": ".gitignore",
"chars": 8282,
"preview": "# Created by https://www.toptal.com/developers/gitignore/api/vim,node,linux,emacs,macos,windows,intellij,sublimetext,vis"
},
{
"path": ".nvmrc",
"chars": 8,
"preview": "18.18.2\n"
},
{
"path": ".prettierignore",
"chars": 23,
"preview": ".next\nnode_modules\nout\n"
},
{
"path": "LICENSE",
"chars": 1088,
"preview": "MIT License\n\nCopyright (c) 2018- Marp team (marp-team@marp.app)\n\nPermission is hereby granted, free of charge, to any pe"
},
{
"path": "README.md",
"chars": 7692,
"preview": "<div align=\"center\">\n <p>\n <img src=\"marp.png#gh-light-mode-only\" alt=\"Marp\" width=\"450\" />\n <img src=\"marp-dark."
},
{
"path": "netlify.toml",
"chars": 185,
"preview": "[build]\n publish = \"website/out\"\n command = \"yarn workspace @marp-team/marp-website export\"\n\n[[headers]]\n for = \"/*\"\n"
},
{
"path": "package.json",
"chars": 1359,
"preview": "{\n \"name\": \"@marp-team/marp\",\n \"description\": \"The entrance repository of Markdown presentation ecosystem\",\n \"private"
},
{
"path": "tsconfig.json",
"chars": 191,
"preview": "{\n \"extends\": \"@tsconfig/recommended/tsconfig.json\",\n \"compilerOptions\": {\n \"lib\": [\"es2015\", \"dom\"],\n \"noImplic"
},
{
"path": "website/.eslintrc.js",
"chars": 369,
"preview": "const path = require('path')\n\nmodule.exports = {\n extends: ['next', 'prettier'],\n rules: {\n '@next/next/no-html-lin"
},
{
"path": "website/assets.d.ts",
"chars": 62,
"preview": "declare module '*.yaml' {\n const yaml: any\n export = yaml\n}\n"
},
{
"path": "website/babel.config.js",
"chars": 349,
"preview": "const path = require('path')\n\nmodule.exports = {\n presets: [\n [\n 'next/babel',\n {\n 'styled-jsx': {\n"
},
{
"path": "website/blog/202205-ecosystem-update.md",
"chars": 17683,
"preview": "---\ntitle: 'Ecosystem update: Marp Core v3 & Slide transitions in CLI v2'\ndate: 2022-05-26\ndescription: Introduce a stab"
},
{
"path": "website/blog/how-to-make-custom-transition.md",
"chars": 17455,
"preview": "---\ntitle: 'Marp CLI: How to make custom transition'\ndate: 2022-05-28\ndescription: Marp CLI v2.4.0+ and Marp for VS Code"
},
{
"path": "website/blog/marp-for-vs-code-v1.md",
"chars": 8724,
"preview": "---\ntitle: 'Marp for VS Code v1: IntelliSense for Marp directives'\ndate: 2021-05-20\ndescription: I'm happy to announce M"
},
{
"path": "website/blog/marpit-v2-marp-core-v2-and-marp-cli-v1.md",
"chars": 5132,
"preview": "---\ntitle: Marpit v2, Marp Core v2, and Marp CLI v1\ndate: 2021-05-06\ndescription: I'm so glad to announce shipping Marpi"
},
{
"path": "website/blog/re-creation-of-marp-website.md",
"chars": 3209,
"preview": "---\ntitle: Re-creation of Marp website for the unified docs\ndate: 2020-08-22\ndescription: We are announcing that Marp te"
},
{
"path": "website/blog/the-story-of-marp-next.md",
"chars": 13147,
"preview": "---\ntitle: The story of Marp Next\ndate: 2019-06-06\ndescription: Today, I'm so excited to introduce the story of Marp Nex"
},
{
"path": "website/components/Button.tsx",
"chars": 2426,
"preview": "import classNames from 'classnames'\nimport { ReactNode } from 'react'\n\nexport type ButtonProps = {\n children?: ReactNod"
},
{
"path": "website/components/CodeBlock.tsx",
"chars": 5148,
"preview": "/* eslint-disable react/jsx-key */\nimport classNames from 'classnames'\nimport Highlight, {\n defaultProps,\n Language,\n "
},
{
"path": "website/components/Footer.tsx",
"chars": 829,
"preview": "import { ScrollToTop } from 'components/ScrollToTop'\n\nexport const Footer = () => (\n <footer>\n <div className=\"conta"
},
{
"path": "website/components/Header.tsx",
"chars": 4292,
"preview": "import classNames from 'classnames'\nimport Link from 'next/link'\nimport MarpLogo from 'public/assets/marp-logo.svg'\n\ncon"
},
{
"path": "website/components/Layout.tsx",
"chars": 2604,
"preview": "import Head from 'next/head'\nimport { useRouter } from 'next/router'\nimport { Footer } from 'components/Footer'\nimport {"
},
{
"path": "website/components/Marp.tsx",
"chars": 5191,
"preview": "import { Marp as MarpCore } from '@marp-team/marp-core'\nimport classNames from 'classnames'\nimport postcss, { Plugin } f"
},
{
"path": "website/components/ScrollToTop.tsx",
"chars": 1358,
"preview": "import { ArrowUpIcon } from '@primer/octicons-react'\nimport { useCallback } from 'react'\n\nexport const ScrollToTop = () "
},
{
"path": "website/components/Title.tsx",
"chars": 583,
"preview": "// eslint-disable-next-line @typescript-eslint/ban-types\nexport const Title: React.FC<React.PropsWithChildren<{}>> = ({ "
},
{
"path": "website/components/Typography.tsx",
"chars": 4052,
"preview": "// eslint-disable-next-line @typescript-eslint/ban-types\nexport const Typography: React.FC<React.PropsWithChildren<{}>> "
},
{
"path": "website/components/blog/BlogHeader.tsx",
"chars": 1884,
"preview": "import Link from 'next/link'\nimport { formatDate, formatDateShort } from 'utils/date'\n\nexport type BlogHeaderProps = {\n "
},
{
"path": "website/components/docs/Breadcrumb.tsx",
"chars": 885,
"preview": "import Link from 'next/link'\n\nexport type BreadcrumbProps = {\n breadcrumbs: {\n key: string\n link?: string\n tit"
},
{
"path": "website/components/docs/Layout.tsx",
"chars": 936,
"preview": "import { useMedia, useMediaLayout } from 'use-media'\nimport { BreadcrumbProps } from './Breadcrumb'\nimport { NavigationP"
},
{
"path": "website/components/docs/Navigation.tsx",
"chars": 2258,
"preview": "import classNames from 'classnames'\nimport Link from 'next/link'\n\nexport type NavigationProps = {\n manifest: Record<str"
},
{
"path": "website/components/docs/layouts/Desktop.tsx",
"chars": 4821,
"preview": "import {\n CSSProperties,\n useLayoutEffect,\n useRef,\n useState,\n useMemo,\n} from 'react'\nimport { Breadcrumb } from "
},
{
"path": "website/components/docs/layouts/Mobile.tsx",
"chars": 7344,
"preview": "import { ThreeBarsIcon, XIcon } from '@primer/octicons-react'\nimport { disableBodyScroll, enableBodyScroll } from 'body-"
},
{
"path": "website/components/markdown/Anchor.tsx",
"chars": 348,
"preview": "import Link from 'next/link'\n\nexport const Anchor: React.FC<{ href?: string }> = ({ href, ...rest }) => {\n if (!href) r"
},
{
"path": "website/components/markdown/Heading.tsx",
"chars": 1950,
"preview": "import { createContext, useContext } from 'react'\n\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype HOCProp"
},
{
"path": "website/components/markdown/Image.tsx",
"chars": 1318,
"preview": "export type ImageProps = {\n src: string\n alt: string\n [attr: string]: string\n}\n\nexport const Image = ({ src, alt, ..."
},
{
"path": "website/components/markdown/Pre.tsx",
"chars": 766,
"preview": "import { CodeBlock } from '../CodeBlock'\n\nexport const Pre: React.FC = (props) => {\n if (props['data-code'] === undefin"
},
{
"path": "website/components/top/Description.tsx",
"chars": 3218,
"preview": "import { ChevronDownIcon } from '@primer/octicons-react'\nimport classNames from 'classnames'\nimport { useState } from 'r"
},
{
"path": "website/components/top/Features.tsx",
"chars": 8286,
"preview": "import {\n CodeSquareIcon,\n FileIcon,\n HeartFillIcon,\n MarkdownIcon,\n PackageIcon,\n PaintbrushIcon,\n PlugIcon,\n} f"
},
{
"path": "website/components/top/GetStarted.tsx",
"chars": 10204,
"preview": "import classNames from 'classnames'\nimport { Button } from 'components/Button'\n\ntype CardProps = React.PropsWithChildren"
},
{
"path": "website/components/top/Hero.tsx",
"chars": 1341,
"preview": "import Head from 'next/head'\nimport { Button } from 'components/Button'\nimport Marp from 'public/assets/marp.svg'\n\nconst"
},
{
"path": "website/css/index.css",
"chars": 1902,
"preview": "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n --noise-image: url('/assets/noise.svg');\n --heade"
},
{
"path": "website/css/plugin-rem.js",
"chars": 740,
"preview": "// Based on Marpit PostCSS rem plugin\n// https://github.com/marp-team/marpit/blob/main/src/postcss/root/rem.js\n\nconst ro"
},
{
"path": "website/docs/guide/directives.md",
"chars": 11410,
"preview": "# Directives\n\n### This is a stub page!\n\nMarp has an extended syntax called **\"Directives\"** to control theme, page numbe"
},
{
"path": "website/docs/guide/fitting-header.md",
"chars": 1242,
"preview": "# Fitting header\n\nWhen the `<!--fit-->` comment is placed in a heading, the heading will be scaled to fit onto a single "
},
{
"path": "website/docs/guide/fragmented-list.md",
"chars": 1925,
"preview": "# Fragmented list\n\nMarp uses some uncommon list markers to denote a **fragmented list** (also known as an incremental li"
},
{
"path": "website/docs/guide/heading-divider.md",
"chars": 3380,
"preview": "# Heading divider\n\nThe heading divider directive tells Marp to automatically add a slide break before a heading of the s"
},
{
"path": "website/docs/guide/how-to-write-slides.md",
"chars": 2798,
"preview": "# How to write slides\n\n## Markdown\n\nTo write slides using Marp, you have to know basic Markdown syntax. It doesn't take "
},
{
"path": "website/docs/guide/image-syntax.md",
"chars": 133,
"preview": "# Image syntax\n\n### This is a stub page!\n\n> This feature is inherited from [Marpit framework](https://marpit.marp.app/im"
},
{
"path": "website/docs/guide/math-typesetting.md",
"chars": 4792,
"preview": "# Math typesetting\n\n[Many Markdown tools support math rendering](https://github.com/cben/mathdown/wiki/math-in-markdown)"
},
{
"path": "website/docs/guide/theme.md",
"chars": 34,
"preview": "# Theme\n\n### This is a stub page!\n"
},
{
"path": "website/docs/introduction/install.md",
"chars": 3243,
"preview": "# Install\n\n### This is a stub page!\n\nThere are two ways to use Marp, through a command-line interface (**[Marp CLI][marp"
},
{
"path": "website/docs/introduction/whats-marp.md",
"chars": 4040,
"preview": "# What's Marp?\n\n### This is a stub page!\n\n**Marp** (**Mar**kdown **P**resentation Ecosystem) provides a great experience"
},
{
"path": "website/docs/manifest.yaml",
"chars": 643,
"preview": "introduction:\n title: Introduction\n pages:\n whats-marp:\n title: What's Marp?\n install:\n title: Install"
},
{
"path": "website/docs/tools/marp-cli.md",
"chars": 37,
"preview": "# Marp CLI\n\n### This is a stub page!\n"
},
{
"path": "website/docs/tools/marp-for-vs-code.md",
"chars": 45,
"preview": "# Marp for VS Code\n\n### This is a stub page!\n"
},
{
"path": "website/global.d.ts",
"chars": 99,
"preview": "import {} from 'react'\n\ndeclare module 'react' {\n interface HTMLAttributes {\n inert?: ''\n }\n}\n"
},
{
"path": "website/next-env.d.ts",
"chars": 201,
"preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n\n// NOTE: This file should not be edite"
},
{
"path": "website/next.config.js",
"chars": 1580,
"preview": "const path = require('path')\nconst withBundleAnalyzer = require('@next/bundle-analyzer')({\n enabled: !!process.env.ANAL"
},
{
"path": "website/package.json",
"chars": 1751,
"preview": "{\n \"name\": \"@marp-team/marp-website\",\n \"version\": \"0.0.0\",\n \"private\": true,\n \"scripts\": {\n \"check:ts\": \"tsc --no"
},
{
"path": "website/pages/404.tsx",
"chars": 1434,
"preview": "import { ArrowLeftIcon } from '@primer/octicons-react'\nimport { Button } from 'components/Button'\nimport { Layout } from"
},
{
"path": "website/pages/_app.tsx",
"chars": 1930,
"preview": "import { Router } from 'next/router'\nimport NProgress from 'nprogress'\nimport { FontFaceProvider, FontFaceRenderer } fro"
},
{
"path": "website/pages/_document.tsx",
"chars": 667,
"preview": "import Document, { Html, Head, Main, NextScript } from 'next/document'\n\nclass MyDocument extends Document {\n render = ("
},
{
"path": "website/pages/blog/[slug].tsx",
"chars": 1924,
"preview": "import { basename } from 'path'\nimport {\n GetStaticPaths,\n GetStaticPropsContext,\n InferGetStaticPropsType,\n} from 'n"
},
{
"path": "website/pages/blog.tsx",
"chars": 6517,
"preview": "import fs from 'fs'\nimport { basename } from 'path'\nimport { ArrowRightIcon } from '@primer/octicons-react'\nimport { Inf"
},
{
"path": "website/pages/docs/[[...slug]].tsx",
"chars": 1964,
"preview": "import path from 'path'\nimport { getProperty } from 'dot-prop'\nimport {\n GetStaticPaths,\n GetStaticPropsContext,\n Inf"
},
{
"path": "website/pages/index.tsx",
"chars": 1201,
"preview": "import { InferGetStaticPropsType } from 'next'\nimport { Layout } from 'components/Layout'\nimport { generateRenderedMarp "
},
{
"path": "website/postcss.config.js",
"chars": 1626,
"preview": "const path = require('path')\nconst remoteInlineCache = new Map()\n\nconst encodeForInlining = (buffer) =>\n encodeURICompo"
},
{
"path": "website/public/blog/.gitignore",
"chars": 9,
"preview": "feed.xml\n"
},
{
"path": "website/tailwind.config.js",
"chars": 1247,
"preview": "const { fontFamily } = require('tailwindcss/defaultTheme')\n\nconst marp = {\n // Brand colors\n brand: '#0288d1',\n light"
},
{
"path": "website/tsconfig.json",
"chars": 496,
"preview": "{\n \"extends\": \"../tsconfig.json\",\n \"compilerOptions\": {\n \"allowJs\": true,\n \"baseUrl\": \".\",\n \"downlevelIterati"
},
{
"path": "website/utils/date.ts",
"chars": 722,
"preview": "const monthNames = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'Septem"
},
{
"path": "website/utils/hooks/useFontFace.tsx",
"chars": 1612,
"preview": "import { createContext, useContext, useEffect, useMemo, useState } from 'react'\n\ninterface FontFaceContextInterface {\n "
},
{
"path": "website/utils/markdown/index.tsx",
"chars": 724,
"preview": "import matter from 'gray-matter'\nimport { parse as mdParse } from './parse'\nimport { renderer } from './renderer'\nimport"
},
{
"path": "website/utils/markdown/parse/image-paragraph-to-figure.ts",
"chars": 1514,
"preview": "import { whitespace } from 'hast-util-whitespace'\nimport { visit } from 'unist-util-visit'\n\n// Based on remark-unwrap-im"
},
{
"path": "website/utils/markdown/parse/index.ts",
"chars": 656,
"preview": "import remarkGfm from 'remark-gfm'\nimport remarkParse from 'remark-parse'\nimport remarkSlug from 'remark-slug'\nimport { "
},
{
"path": "website/utils/markdown/parse/marp-code-block.ts",
"chars": 610,
"preview": "import type { Literal } from 'unist'\nimport { visit } from 'unist-util-visit'\nimport { RenderedMarp, generateRenderedMar"
},
{
"path": "website/utils/markdown/renderer/index.ts",
"chars": 875,
"preview": "import { createElement, FunctionComponent } from 'react'\nimport RemarkReact, { Options } from 'remark-react'\nimport { sa"
},
{
"path": "website/utils/markdown/renderer/sanitize.ts",
"chars": 303,
"preview": "import { defaultSchema } from 'hast-util-sanitize'\n\nexport const sanitize = {\n ...defaultSchema,\n attributes: {\n .."
},
{
"path": "website/utils/title.ts",
"chars": 195,
"preview": "export const generateTitle = (breadcrumbs: string[] = []) =>\n [\n ...breadcrumbs,\n `Marp${\n breadcrumbs.lengt"
},
{
"path": "website/utils/url.ts",
"chars": 91,
"preview": "export const absoluteUrl = (path: string) =>\n new URL(path, process.env.NEXT_PUBLIC_HOST)\n"
}
]
About this extraction
This page contains the full source code of the marp-team/marp GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 85 files (220.9 KB), approximately 58.7k tokens, and a symbol index with 18 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.