remark-music-plugins
v0.4.0
Published
remark plugins to insert music notation and guitar fretboard chart in markdown files
Downloads
1,145
Maintainers
Readme
remark music plugins
Remark plugins to insert music notation and guitar fretboard chart in markdown files
Markdown Extensions
LilyPond Integration
The LilyPond extension allows you to embed musical notation directly in your markdown:
```lilypond
\version "2.20.0"
{
\clef treble
\time 4/4
\key c \major
c'4 d'4 e'4 f'4 |
g'4 a'4 b'4 c''2
}
```The plugin will:
- Detect fenced code blocks with the
lilypondlanguage identifier - Compile the LilyPond code to SVG using the LilyPond CLI
- Embed the resulting SVG as inline images in your output
Guitar Fretboard Charts
The svguitar extension uses the svguitar library and Text Guitar Chart to render guitar fretboard diagrams:
```guitar-charts
A min
######
oo o
------
||||o|
||o*||
||||||
D
######
xoo
------
||||||
|||o|o
||||*|
```Installation
Prerequisites
- Node.js (version 16 or higher)
- LilyPond (for musical notation rendering)
- Google Chrome or Chromium (for guitar chord rendering)
To install LilyPond:
- macOS:
brew install lilypond - Ubuntu/Debian:
apt install lilypond - Windows: Download from lilypond.org
For guitar chord rendering, the plugin uses Puppeteer which will automatically download a suitable version of Chromium. No additional installation is required.
Usage
Basic Usage
import { remark } from "remark";
import remarkHtml from "remark-html";
import remarkLilypond from "./plugins/remark-lilypond/index.js";
import remarkGuitarChart from "./plugins/remark-guitar-chart/index.js";
const processor = remark()
.use(remarkLilypond)
.use(remarkGuitarChart)
.use(remarkHtml, { sanitize: false }); // Required: Allow raw HTML/SVG for musical notation
const result = await processor.process(markdownContent);
console.log(result.toString());Important: The sanitize: false option is required for the SVG musical notation to display. For production use with untrusted content, consider using remark-rehype with rehype-raw instead for better security.
Plugin Options
LilyPond Plugin Options
const processor = remark().use(remarkLilypond, {
binaryPath: "lilypond", // Path to LilyPond executable
errorInline: false, // Show errors inline vs console
skipOnMissing: false, // Skip processing if LilyPond not found
compact: true, // Remove attribution and crop whitespace (default: true)
});GuitarChart Plugin Options
const processor = remark().use(remarkGuitarChart, {
errorInline: false, // Show errors inline vs console
skipOnMissing: false, // Skip processing if Puppeteer fails to launch
puppeteerOptions: {
// Options passed to puppeteer.launch()
headless: true,
args: ["--no-sandbox", "--disable-setuid-sandbox"],
},
});Using the Markdown Renderer
The package includes a convenient renderer() function that processes markdown files and generates complete HTML output with embedded styles:
import renderer from "./markdownRenderer/index.js";
// Process a markdown file and generate HTML
await renderer("input.md", "output.html");Features:
- Automatically applies both LilyPond and GuitarChart plugins
- Generates complete HTML document with embedded CSS styles
- Includes both screen and print stylesheets
- Handles errors gracefully with helpful error messages
- Automatically cleans up browser resources
Default Configuration:
The renderer uses these plugin settings by default:
errorInline: true- Shows errors inline in the generated HTMLskipOnMissing: true- Continues processing even if LilyPond or Puppeteer are unavailablesanitize: false- Allows raw SVG/HTML output (required for musical notation)
Example:
import renderer from "./markdownRenderer/index.js";
// Convert markdown with musical notation to HTML
await renderer("./songs/my-song.md", "./output/my-song.html");The generated HTML file will include all rendered musical notation and guitar charts, with styling optimized for both screen display and printing.
Command Line Tool
The package includes a CLI tool that processes markdown from stdin and outputs HTML to stdout:
# Process a markdown file
markdown-music-renderer < input.md > output.html
# Or pipe from another command
cat songs/my-song.md | markdown-music-renderer > my-song.html
# Using with node (before installing globally)
node cli.js < input.md > output.htmlFeatures:
- Reads markdown from stdin
- Writes complete HTML with embedded styles to stdout
- Includes both LilyPond and GuitarChart processing
- Error messages go to stderr, keeping stdout clean
- Same configuration as
markdownRenderer()(errorInline: true, skipOnMissing: true)
Installation:
After installing the package globally, the markdown-music-renderer command will be available:
npm install -g remark-music-plugins
markdown-music-renderer < input.md > output.htmlOr use it locally in your project:
npm install remark-music-plugins
npx markdown-music-renderer < input.md > output.htmlRunning the Demo
Try the included demo to see the plugin in action:
node demo/demo.jsThis will process demo/example.md and generate demo/output.html with rendered musical notation and guitar chord diagrams.
Development
Scripts
npm test- Run tests using Node.js test runnernpm run format- Format code using Prettier (no semicolons)npm run types- Generate TypeScript definitions from JSDoc comments
Contributing
- Write comprehensive JSDoc comments with TypeScript type annotations
- Add tests for new functionality using the Node.js test runner
- Format code using Prettier (no semicolons)
- Ensure all tests pass before submitting
Troubleshooting
LilyPond Not Found Error
If you see errors like lilypond: not found or LilyPond executable not found, LilyPond is not installed or not in your system PATH.
Solutions:
Install LilyPond:
- macOS:
brew install lilypond - Ubuntu/Debian:
sudo apt install lilypond - Windows: Download from lilypond.org
- macOS:
Verify Installation:
lilypond --versionSpecify Custom Path:
const processor = remark().use(remarkLilypond, { binaryPath: "/usr/local/bin/lilypond", // Custom path });Skip Missing LilyPond:
const processor = remark().use(remarkLilypond, { skipOnMissing: true, // Skip blocks if LilyPond not available });
Compilation Errors
LilyPond compilation errors are usually due to invalid syntax. Common issues:
- Missing version declaration: Add
\\version "2.20.0"at the top - Unmatched braces: Ensure all
{have matching} - Invalid note names: Use proper LilyPond syntax
Set errorInline: true to see errors in the generated HTML instead of just the console.
SVG Output Control
The plugin generates compact, clean SVG output by default:
- Compact mode (
compact: true, default): Removes attribution text and crops excessive whitespace - Full mode (
compact: false): Preserves original LilyPond output including attribution
Compact mode automatically:
- Removes "Music engraving by LilyPond" attribution text
- Crops whitespace to focus on musical content
- Significantly reduces SVG file size
To disable compact mode:
const processor = remark().use(remarkLilypond, {
compact: false, // Keep full LilyPond output
});GuitarChart Chord Data Format
The GuitarChart plugin expects uses the syntax described here
HTML Sanitization
The plugin generates raw SVG content that needs to pass through HTML processing:
Quick Fix (for trusted content):
.use(remarkHtml, { sanitize: false })Recommended for Production (more secure):
import { remark } from "remark";
import remarkRehype from "remark-rehype";
import rehypeRaw from "rehype-raw";
import rehypeStringify from "rehype-stringify";
const processor = remark()
.use(remarkLilypond)
.use(remarkGuitarChart)
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeRaw)
.use(rehypeStringify);TypeScript Usage
Full TypeScript definitions are included. You can import the plugins and option types:
import { remark } from "remark";
import remarkHtml from "remark-html";
import {
remarkLilypond,
remarkGuitarChart,
closeBrowser,
type LilyPondOptions,
type SVGuitarOptions,
} from "music-md";
const lilyOptions: LilyPondOptions = { compact: true };
const svguitarOptions: SVGuitarOptions = { keepAlive: true };
const processor = remark()
.use(remarkLilypond, lilyOptions)
.use(remarkGuitarChart, svguitarOptions)
.use(remarkHtml, { sanitize: false });
const result = await processor.process(markdown);
// When using keepAlive you should close the browser manually after all processing:
await closeBrowser();SVGuitar keepAlive Option
The keepAlive option (default false) trades memory for speed across multiple markdown files:
const processor = remark()
.use(remarkGuitarChart, { keepAlive: true })
.use(remarkHtml, { sanitize: false });
for (const file of files) {
await processor.process(await fs.promises.readFile(file, "utf8"));
}
await closeBrowser(); // Important when keepAlive = true| Scenario | Recommendation |
| ------------------------- | ----------------------------------------------------------- |
| Single file CLI run | leave keepAlive false |
| Batch convert many files | set keepAlive: true |
| Long-lived server process | set keepAlive: true and call closeBrowser() on shutdown |
License
ISC
