# Danmaku renders flying comments over video without taking over the player

> Danmaku is a small MIT licensed JavaScript library that draws scrolling comments over an HTML video or audio element, with a DOM engine and a canvas engine you can import separately, and a live mode for real-time comments with no timeline.

**weizhenye/Danmaku** — A high-performance JavaScript danmaku engine. 高性能弹幕引擎库

- Repository: https://github.com/weizhenye/Danmaku
- Website: https://danmaku.js.org
- Stars: 749 · Forks: 80
- Language: JavaScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/weizhenye-danmaku

## An overlay library, not a media player

Danmaku is a JavaScript library for displaying flying comments on HTML media elements, meaning video and audio, and it can also display comments to a container in real time with no timeline at all. That scoping is the key to understanding what it is and is not. It does not play your media, it does not parse subtitle formats, and it does not fetch a comment track. It draws text that scrolls across an area you give it. The API reflects that separation. You pass a container element, and the documentation notes that the stage to display comments will be appended to that container, so the library creates its own layer inside an element you already control. In practice that means you keep your existing player, your own controls and your own playlist logic, and the comments float above. The repository is a small JavaScript project with an MIT licence, a homepage at danmaku.js.org with an online demo, Chinese documentation in the wiki, and the release history shows version 2.0.10 tagged on 2026-08-15 with the last push on 2026-08-08. The topics are narrow, danmaku and danmu, which tells you the scope of the ambition. This is a rendering engine with a small, sharp API, not a framework.

## Two engines, and you can import only the one you need

Danmaku ships with two rendering engines and lets you import either one on its own, which is the packaging decision that makes it interesting for a bundle-sensitive application:

```bash
npm install danmaku
```

```js
// Full version
import Danmaku from 'danmaku';
// DOM engine only
import Danmaku from 'danmaku/dist/esm/danmaku.dom.js';
// Canvas engine only
import Danmaku from 'danmaku/dist/esm/danmaku.canvas.js';
```

The full version defaults to the DOM engine, and the engine is also a constructor option, so you can switch at runtime by passing engine: 'canvas'. The two approaches differ in more than performance. The DOM engine creates a div node for each comment and sets the style object to node.style directly, which means the style object is plain CSS and you can write rules the way you would for any element. The canvas engine creates a canvas object for each comment and expects a CanvasRenderingContext2D style, with properties like font, textAlign, textBaseline, fillStyle, strokeStyle and lineWidth. There are also layout differences. With the DOM engine you may want to change line spacing by setting line-height on each comment, and a better way is to set line-height on the container. With the canvas engine the line height is 1.2 by default and you set it through style.font, which uses the same syntax as the CSS font specifier, although only px, %, em and rem units are supported. If you are chasing a small bundle, importing just one engine is the lever the package layout gives you.

## Media mode with a timeline, live mode without one

The constructor is where the two modes are chosen. The documentation lists the options and their meaning, and the media option is the switch. Media can be a video or an audio element, and if it is not provided, Danmaku will be in live mode. In media mode you also pass an array of comments, and the time property of each comment is specified in seconds, and if it is not provided when using with media it will be set to media.currentTime, which means a comment emitted while the media plays lands at the current position. The live mode is simpler in a way and heavier in another. To display comments in real time you need to set up a server and use something like Socket.IO, and the library is just receiving comments data and displaying them to the container. The README includes a small Socket.IO example with a Node.js server that broadcasts a danmaku event and a client that passes incoming comments to danmaku.emit. Time is not required in live mode, since there is no timeline to align to. The speed option, which defaults to 144, controls how fast comments travel, and the documentation also points at the danmaku.speed API to change it after construction.

## One comment shape, two very different style contracts

A comment object carries text, a mode, a time, a style and an optional custom render function, and the mode values are rtl by default, with ltr, rtl, top and bottom available. The style object is where the engines diverge, and that is worth internalising before you write the first comment. In DOM mode the style is assigned straight to the node style, so fontSize, color, border and textShadow work as CSS, and the documentation even gives a textShadow example with four offsets for an outline effect. In canvas mode the same object has to describe a CanvasRenderingContext2D, so font replaces fontSize, fillStyle and strokeStyle replace color, and lineWidth gives the stroke. The escape hatch is the custom render function, and its contract is precise. When a render function exists, text and style are ignored. In DOM mode it should return an HTMLElement, and the example builds a div containing an image, which is how you show a picture comment. In canvas mode it should return an HTMLCanvasElement, and the example draws a stroked circle into its own 2D context. That is the mechanism for emoji, images and anything that is not text, and it means the rendering is entirely yours for that comment.

## The canvas hitbox rule that makes comments disappear

The tips section contains one rule that has cost other people hours, and it is worth quoting in detail because the failure is invisible rather than obvious. There is a hitbox for each comment, and its height is determined by the comment's line height. With the canvas engine, when style.textBaseline is top or hanging the baseline is set to the top of the hitbox, when it is middle the baseline is the middle of the hitbox, and otherwise the baseline is the bottom of the hitbox. So if you set style.textBaseline to alphabetic or hanging, the comment's head or foot may fall out of the hitbox and become invisible. The comment is still being drawn, it is just clipped away by whatever masking the engine applies. The practical rule is to keep the baseline at the default of bottom unless you know what you are doing, and to test any new textAlign and textBaseline combination against the actual renderer rather than reasoning about it. The canvas engine also exposes style.filter, which the documentation links to the browser API reference, so filters are part of the supported surface for canvas comments.

## A committed dist directory and a rollup build you can inspect

The package is published as danmaku at version 2.0.10, with main pointing at dist/danmaku.js, a module field pointing at the ESM build in dist/esm, types at types/index.d.ts, and sideEffects set to false so that a bundler can drop the import if the module is unused. The files field ships three directories, dist, src and types, so the sources travel with the package. The build itself is rollup, configured in rollup.config.js, and the test stack is karma with mocha and chai, plus an istanbul plugin for coverage. The scripts are conventional: a dev script that runs the bundler in watch mode, a lint script over src and test with eslint, a unit script that starts karma, a bundle script that calls rollup with the config, and a test script that runs lint and unit in sequence. The release flow is worth a note, because the version script builds and then stages the dist directory into git, and postversion pushes the commit and the tags. That means the built artefact is committed to the repository rather than built on the consumer's machine, which is convenient for a library that is often loaded straight from a CDN, and it also means a release is a diff of generated files that you can inspect before it ships.

## Conclusion

Adopt Danmaku if you need bullet comments on top of an existing HTML5 player and you want the overlay to be a separate layer you control rather than a player you fork. Do not adopt it expecting a full comment platform, because the library only receives and displays comments, so the transport, storage and moderation are yours to build, and do not assume the canvas engine behaves like the DOM one, since the two interpret the same style object differently. Before you integrate, decide which engine you want, check that your comment times match the media timeline, and read the canvas textBaseline rules, because a comment drawn partly outside its hitbox is invisible.

## FAQ

### How do I install and import the Danmaku library?

Install it with npm install danmaku, then import the full version from 'danmaku', or import only the DOM engine from 'danmaku/dist/esm/danmaku.dom.js' or only the canvas engine from 'danmaku/dist/esm/danmaku.canvas.js'. The package is also available on jsDelivr and unpkg.

### What is the difference between the DOM and canvas engines in Danmaku?

The DOM engine creates a div for each comment and applies the style object as CSS on the node style, and line spacing is best controlled with line-height on the container. The canvas engine creates a canvas for each comment and expects CanvasRenderingContext2D properties such as font, fillStyle and lineWidth, with a default line height of 1.2 and only px, %, em and rem units supported in style.font.

### How do I show live comments with Danmaku?

You need a server and a transport such as Socket.IO, because the library only receives comment data and displays it in the container. In live mode the time property is not required, and the README includes a small Node.js server that broadcasts a danmaku event plus the matching client code.

### Why does my canvas comment disappear?

Each comment has a hitbox whose height comes from its line height, and the baseline is placed at the top of the hitbox for textBaseline top or hanging, in the middle for middle, and at the bottom otherwise. Setting textBaseline to alphabetic or hanging can push the head or foot of the comment outside the hitbox, which makes it invisible.

## Sources

- [License: MIT](https://github.com/weizhenye/Danmaku/blob/master/LICENSE)
- [Project website](https://danmaku.js.org)
- [README](https://github.com/weizhenye/Danmaku/blob/master/README.md)
- [Releases](https://github.com/weizhenye/Danmaku/releases)
- [weizhenye/Danmaku on GitHub](https://github.com/weizhenye/Danmaku)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/weizhenye-danmaku
