### Install Niconicomments via CDN or npm
Source: https://github.com/xpadev-net/niconicomments/blob/develop/README.en.md
Instructions for adding the niconicomments library to your project. You can use it directly via a script tag linked to the CDN, or install it as a dependency using npm.
```html
```
```bash
npm i @xpadev-net/niconicomments
```
--------------------------------
### Render comments on an HTML canvas with JavaScript
Source: https://github.com/xpadev-net/niconicomments/blob/develop/README.en.md
Example demonstrating how to initialize and use the NiconiComments library in JavaScript. It fetches comment data from a JSON file and renders it onto an HTML canvas, synchronized with video playback.
```javascript
const canvas = document.getElementById("canvas");
const video = document.getElementById("video");
const req = await fetch("sample.json");
const res = await req.json();
const niconiComments = new NiconiComments(canvas, res);
//If video.ontimeupdate is used, the comments will be choppy due to the small number of calls.
setInterval(
() => niconiComments.drawCanvas(video.currentTime * 100),
10
);
```
--------------------------------
### Initialize and Draw Niconicomments (JavaScript)
Source: https://github.com/xpadev-net/niconicomments/blob/develop/docs/sample/test.html
This JavaScript code initializes the NiconiComments library to display comments on a canvas element. It fetches comment data from a JSON file based on URL parameters and then draws the comments at a specified time. It requires the NiconiComments library to be included and a canvas element with the ID 'canvas' in the HTML.
```javascript
void (async () => {
const canvasElement = document.getElementById("canvas");
const urlParams = new URLSearchParams(window.location.search);
const video = Number(urlParams.get("video") || 0);
const time = Number(urlParams.get("time") || 0);
const req = await fetch(`./commentdata/${video}.json`);
const res = await req.json();
const nico = new NiconiComments(canvasElement, res, {
format: "formatted",
});
nico.drawCanvas(time * 100);
const elem = document.createElement("div");
elem.id = "loaded";
document.body.appendChild(elem);
})();
```
--------------------------------
### Implement Custom Plugins for Niconicomments
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Demonstrates how to create custom plugins to extend comment rendering capabilities in Niconicomments. Plugins can modify comment rendering, track analytics, or add custom drawing. The WatermarkPlugin and AnalyticsPlugin are provided as examples.
```javascript
// Custom plugin implementation
class WatermarkPlugin {
static id = "watermark-plugin";
constructor(canvas, comments) {
this.renderer = canvas;
this.comments = comments;
this.watermarkImage = new Image();
this.watermarkImage.src = "/watermark.png";
}
// Optional: Called every frame
draw(vpos) {
// Draw custom content
this.renderer.save();
this.renderer.setGlobalAlpha(0.3);
if (this.watermarkImage.complete) {
this.renderer.drawImage(this.watermarkImage, 10, 10, 100, 50);
}
this.renderer.restore();
}
// Optional: Called when comments are added dynamically
addComments(newComments) {
console.log(`${newComments.length} comments added`);
}
// Optional: Transform comments before rendering
transformComments(comments) {
// Filter or modify comments
return comments.filter(comment => !comment.content.includes("spam"));
}
}
// Use plugin
const niconiComments = new NiconiComments(
canvas,
comments,
{
config: {
plugins: [WatermarkPlugin]
}
}
);
// Multiple plugins
class AnalyticsPlugin {
static id = "analytics-plugin";
constructor(canvas, comments) {
this.commentCount = comments.length;
}
draw(vpos) {
// Track active vpos
if (vpos % 100 === 0) {
console.log(`Analytics: vpos ${vpos}, total comments: ${this.commentCount}`);
}
}
addComments(newComments) {
this.commentCount += newComments.length;
}
}
const niconiCommentsMultiPlugin = new NiconiComments(
canvas,
comments,
{
config: {
plugins: [WatermarkPlugin, AnalyticsPlugin]
}
}
);
```
--------------------------------
### Niconicomments Canvas Styling (CSS)
Source: https://github.com/xpadev-net/niconicomments/blob/develop/docs/sample/test.html
This CSS code provides basic styling for the canvas element used to display Niconicomments. It ensures the canvas covers the full viewport, maintains its aspect ratio, and has a black background. It also resets default margin and padding.
```css
* {
margin: 0;
padding: 0;
}
#canvas {
width: 100vw;
height: 100vh;
position: fixed;
left: 0;
top: 0;
object-fit: contain;
background: black;
}
```
--------------------------------
### Access NiconiComments Internal API and Utilities (JavaScript)
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Demonstrates how to access and utilize internal modules of the NiconiComments library, including comment classes, context managers, parsers, and utility functions. It also shows examples of manual comment parsing and custom error handling. This approach is not recommended for production environments.
```javascript
import NiconiComments from "@xpadev-net/niconicomments";
// Access internal modules (not recommended for production)
const {
comments, // Comment class implementations
contexts, // Context managers (cache, debug, plugins)
definition, // Configuration definitions
errors, // Custom error classes
eventHandler, // Event handling system
inputParser, // Input format parsers
renderer, // Renderer implementations
typeGuard, // Type validation utilities
utils // Utility functions
} = NiconiComments.internal;
// Example: Parse comments manually
const parsedComments = inputParser.default(rawData, "v1");
// Example: Use utility functions
const { parseFont, hex2rgb } = utils;
const font = parseFont("defont", 30);
const rgb = hex2rgb("#FF0000");
console.log("Font:", font); // "30px 'MS PGothic', sans-serif"
console.log("RGB:", rgb); // [255, 0, 0]
// Example: Custom error handling
try {
const niconiComments = new NiconiComments(canvas, invalidData, invalidOptions);
} catch (error) {
if (error instanceof errors.InvalidOptionError) {
console.error("Invalid option provided");
} else if (error instanceof errors.InvalidFormatError) {
console.error("Invalid comment format");
} else {
throw error;
}
}
```
--------------------------------
### Advanced NiconiComments Initialization with Options
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
This snippet shows advanced initialization of NiconiComments, allowing configuration of various options such as input format, rendering mode (HTML5/Flash), video background integration, performance monitoring, and comment art settings. It also demonstrates how to force a re-render and clear the canvas.
```javascript
const canvas = document.getElementById("canvas");
const video = document.getElementById("video");
const rawApiData = await fetch("https://example.com/api/v1/threads").then(r => r.json());
const options = {
format: "v1",
mode: "html5",
video: video,
enableLegacyPiP: false,
showFPS: true,
showCommentCount: true,
showCollision: true,
debug: true,
keepCA: true,
config: {
canvasWidth: 1920,
canvasHeight: 1080,
commentLimit: 100,
hideCommentOrder: "asc",
commentScale: 1.0,
plugins: []
}
};
const niconiComments = new NiconiComments(canvas, rawApiData, options);
// Force re-render (ignore cache)
niconiComments.drawCanvas(video.currentTime * 100, true);
// Clear canvas
niconiComments.clear();
```
--------------------------------
### Initialize NiconiComments and Render Comments
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
This snippet demonstrates basic initialization of NiconiComments with a canvas and video element, fetching comment data, and setting up a render loop synchronized with video playback. It expects comment data in a formatted array structure.
```javascript
const canvas = document.getElementById("canvas");
const video = document.getElementById("video");
// Fetch comment data (formatted comment array)
const response = await fetch("https://example.com/comments.json");
const comments = await response.json();
// Initialize with default options
const niconiComments = new NiconiComments(canvas, comments);
// Render loop - update every 10ms for smooth animation
// vpos = video position in centiseconds (currentTime * 100)
setInterval(() => {
const vpos = Math.floor(video.currentTime * 100);
niconiComments.drawCanvas(vpos);
}, 10);
// Example comment data format
const exampleComments = [
{
id: 1,
vpos: 100,
content: "Hello!",
date: 1640000000,
owner: false,
premium: false,
mail: ["white", "medium", "naka"],
user_id: 12345
},
{
id: 2,
vpos: 500,
content: "Nice video!",
date: 1640000001,
owner: true,
premium: true,
mail: ["red", "big", "ue"],
user_id: 67890
}
];
```
--------------------------------
### Implement Custom WebGL Renderer for Niconicomments
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Provides a template for implementing a custom renderer using WebGL for Niconicomments. This allows for alternative rendering backends. The `WebGLRenderer` class implements the necessary methods for drawing comments on a WebGL canvas.
```javascript
// Custom WebGL renderer implementation
class WebGLRenderer {
constructor(canvas) {
this.canvas = canvas;
this.gl = canvas.getContext("webgl2");
// Initialize WebGL context, shaders, buffers, etc.
}
// Implement IRenderer interface
destroy() {
this.gl = null;
}
drawVideo(enableLegacyPip) {
// WebGL video rendering
}
getFont() {
return this.currentFont;
}
getFillStyle() {
return this.currentFillStyle;
}
setScale(scaleX, scaleY) {
// Update projection matrix
}
fillRect(x, y, width, height) {
// Draw rectangle with WebGL
}
strokeRect(x, y, width, height) {
// Draw stroked rectangle
}
fillText(text, x, y) {
// Render text with WebGL (requires texture atlas)
}
strokeText(text, x, y) {
// Render stroked text
}
quadraticCurveTo(cpx, cpy, x, y) {
// Add quadratic curve to path
}
clearRect(x, y, width, height) {
// Clear region
}
setFont(font) {
this.currentFont = font;
}
setFillStyle(color) {
this.currentFillStyle = color;
}
setStrokeStyle(color) {
this.currentStrokeStyle = color;
}
setLineWidth(width) {
this.lineWidth = width;
}
setGlobalAlpha(alpha) {
this.globalAlpha = alpha;
}
setSize(width, height) {
this.canvas.width = width;
this.canvas.height = height;
}
getSize() {
return { width: this.canvas.width, height: this.canvas.height };
}
measureText(text) {
// Return TextMetrics (may need canvas 2D context for this)
const ctx = document.createElement("canvas").getContext("2d");
ctx.font = this.currentFont;
return ctx.measureText(text);
}
beginPath() {}
closePath() {}
moveTo(x, y) {}
lineTo(x, y) {}
stroke() {}
save() {}
restore() {}
getCanvas(padding) {
return new WebGLRenderer(document.createElement("canvas"));
}
drawImage(image, x, y, width, height) {
// Draw image/renderer to current context
}
}
// Use custom renderer
const glCanvas = document.getElementById("gl-canvas");
const customRenderer = new WebGLRenderer(glCanvas);
const niconiComments = new NiconiComments(customRenderer, comments);
```
--------------------------------
### Handle NicoScript Events - JavaScript
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Shows how to listen for and react to various NicoScript events using `addEventListener`. Supported events include seek disable/enable, comment disable/enable, and jump commands. Event listeners can also be removed.
```javascript
const niconiComments = new NiconiComments(canvas, comments);
// Seek disable event (NicoScript: @シークバー禁止)
niconiComments.addEventListener("seekDisable", (event) => {
console.log("Seek disabled at vpos:", event.vpos);
video.controls = false;
// Disable custom seek bar
document.getElementById("seekbar").disabled = true;
});
// Seek enable event (NicoScript: @シークバー許可)
niconiComments.addEventListener("seekEnable", (event) => {
console.log("Seek enabled at vpos:", event.vpos);
video.controls = true;
document.getElementById("seekbar").disabled = false;
});
// Comment disable event (NicoScript: @コメント禁止)
niconiComments.addEventListener("commentDisable", (event) => {
console.log("Comments disabled at vpos:", event.vpos);
document.getElementById("comment-input").disabled = true;
});
// Comment enable event (NicoScript: @コメント許可)
niconiComments.addEventListener("commentEnable", (event) => {
console.log("Comments enabled at vpos:", event.vpos);
document.getElementById("comment-input").disabled = false;
});
// Jump event (NicoScript: @ジャンプ)
niconiComments.addEventListener("jump", (event) => {
console.log("Jump to:", event.to, "Message:", event.message);
if (event.to.startsWith("http")) {
// External URL
if (confirm(`Jump to ${event.to}? ${event.message || ""}`)) {
window.location.href = event.to;
}
} else {
// Video ID or time code
video.currentTime = parseFloat(event.to);
}
});
// Remove event listener
const jumpHandler = (event) => {
console.log("Jump event:", event);
};
niconiComments.addEventListener("jump", jumpHandler);
niconiComments.removeEventListener("jump", jumpHandler);
```
--------------------------------
### Handle @Button Comments Interaction - JavaScript
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Explains how to create and interact with comments formatted as buttons using the `@button` mail command. It includes setting up click listeners on the canvas to detect button presses and handling hover states.
```javascript
const canvas = document.getElementById("canvas");
const video = document.getElementById("video");
const niconiComments = new NiconiComments(canvas, comments);
// Comment with @button
const buttonComment = {
id: 100,
vpos: 500,
content: "Click me!",
date: Date.now() / 1000,
owner: true,
premium: true,
mail: ["white", "medium", "naka", "@0.5"], // @0.5 creates button with 0.5s duration
user_id: 99999
};
niconiComments.addComments(buttonComment);
// Handle canvas click events
canvas.addEventListener("click", (event) => {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
// Calculate cursor position relative to canvas
const pos = {
x: (event.clientX - rect.left) * scaleX,
y: (event.clientY - rect.top) * scaleY
};
// Check if @button was clicked at current vpos
const vpos = Math.floor(video.currentTime * 100);
niconiComments.click(vpos, pos);
});
// Show hover state by passing cursor position to drawCanvas
canvas.addEventListener("mousemove", (event) => {
const rect = canvas.getBoundingClientRect();
const scaleX = canvas.width / rect.width;
const scaleY = canvas.height / rect.height;
const cursor = {
x: (event.clientX - rect.left) * scaleX,
y: (event.clientY - rect.top) * scaleY
};
const vpos = Math.floor(video.currentTime * 100);
niconiComments.drawCanvas(vpos, false, cursor);
});
```
--------------------------------
### Add Comments Dynamically - JavaScript
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Demonstrates how to add single or multiple comments to a NiconiComments instance at runtime without reinitializing. It also shows how to integrate with live chat via WebSockets.
```javascript
const niconiComments = new NiconiComments(canvas, initialComments);
// Add single comment
const newComment = {
id: 999,
vpos: 1500, // 15 seconds
content: "Live comment!",
date: Date.now() / 1000,
owner: false,
premium: false,
mail: ["cyan", "small", "naka"],
user_id: 54321
};
niconiComments.addComments(newComment);
// Add multiple comments at once
const liveComments = [
{
id: 1000,
vpos: 1600,
content: "First live comment",
date: Date.now() / 1000,
owner: false,
premium: false,
mail: ["white", "medium", "naka"],
user_id: 11111
},
{
id: 1001,
vpos: 1650,
content: "Second live comment",
date: Date.now() / 1000,
owner: false,
premium: false,
mail: ["yellow", "medium", "naka"],
user_id: 22222
}
];
niconiComments.addComments(...liveComments);
// Simulating live chat integration
const chatSocket = new WebSocket("wss://example.com/chat");
chatSocket.onmessage = (event) => {
const chatMessage = JSON.parse(event.data);
const formattedComment = {
id: chatMessage.id,
vpos: Math.floor(video.currentTime * 100),
content: chatMessage.text,
date: chatMessage.timestamp,
owner: chatMessage.isOwner,
premium: chatMessage.isPremium,
mail: chatMessage.commands || ["white", "medium", "naka"],
user_id: chatMessage.userId
};
niconiComments.addComments(formattedComment);
};
```
--------------------------------
### Validate Niconicomments Options and Comment Data
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Demonstrates the use of built-in type guards to validate initialization options and comment data structures for Niconicomments. This ensures that the provided data conforms to the expected format, preventing runtime errors.
```javascript
import NiconiComments from "@xpadev-net/niconicomments";
// Validate options
const options = {
format: "v1",
mode: "html5",
showFPS: true
};
if (NiconiComments.typeGuard.config.initOptions(options)) {
console.log("Valid options");
const niconiComments = new NiconiComments(canvas, comments, options);
} else {
console.error("Invalid options provided");
}
// Validate formatted comments
const comment = {
id: 1,
vpos: 100,
content: "Test",
date: Date.now() / 1000,
owner: false,
premium: false,
mail: ["white"],
user_id: 123
};
// Access internal utilities
const isFlash = NiconiComments.FlashComment.condition(comment);
console.log("Is Flash comment:", isFlash);
// Create Flash comment instance if needed
if (isFlash) {
const flashComment = new NiconiComments.FlashComment.class(
comment,
renderer,
0
);
}
```
--------------------------------
### Parse Legacy Niconico Comments (JavaScript)
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Parses comments from the legacy Niconico API format (pre-2020). It takes an array of legacy comment objects and initializes the NiconiComments library. Dependencies include the NiconiComments class and a canvas element.
```javascript
// Legacy format (pre-2020)
const legacyComments = [
{
thread: "1234567890",
no: 1,
vpos: 100,
date: 1640000000,
date_usec: 123456,
mail: "white medium naka", // Space-separated commands
user_id: "user123",
content: "Legacy comment",
premium: 1, // 1 for premium, 0 for regular
score: 0
},
{
thread: "1234567890",
no: 2,
vpos: 500,
date: 1640000050,
date_usec: 789012,
mail: "red big ue",
user_id: "owner",
content: "Owner comment",
premium: 1,
score: 0
}
];
const niconiComments = new NiconiComments(
canvas,
legacyComments,
{ format: "legacy" }
);
```
--------------------------------
### Parse XML Niconico Comments (JavaScript)
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Handles parsing of Niconico comments from XML formats using either `DOMParser` for `XMLDocument` or a library like `xml2js`. This snippet demonstrates initializing `NiconiComments` with parsed XML data. Requires a canvas element and the `NiconiComments` class.
```javascript
// XMLDocument format (from DOMParser)
const xmlString = `
XML comment 1
XML comment 2
`;
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
const niconiComments = new NiconiComments(
canvas,
xmlDoc,
{ format: "XMLDocument" }
);
// xml2js format (from xml2js library)
const xml2jsData = {
packet: {
chat: [
{
$: {
thread: "1234567890",
no: "1",
vpos: "100",
date: "1640000000",
date_usec: "123456",
mail: "white medium naka",
user_id: "user123",
premium: "1"
},
_: "xml2js comment 1"
},
{
$: {
thread: "1234567890",
no: "2",
vpos: "500",
date: "1640000050",
date_usec: "789012",
mail: "red big ue",
user_id: "owner",
premium: "1"
},
_: "xml2js comment 2"
}
]
}
};
const niconiCommentsXml2js = new NiconiComments(
canvas,
xml2jsData,
{ format: "xml2js" }
);
```
--------------------------------
### Parse V1 API Niconico Comments (JavaScript)
Source: https://context7.com/xpadev-net/niconicomments/llms.txt
Parses comments from the current Niconico API v1 format (2020+). It accepts an array of thread objects, each containing comments, and initializes the NiconiComments library. Requires a canvas element and the NiconiComments class.
```javascript
// V1 API format (2020+)
const v1Threads = [
{
id: "thread_id_1",
fork: "main",
commentCount: 1000,
comments: [
{
id: "comment_abc123",
no: 1,
vposMs: 1000, // Position in milliseconds
body: "V1 format comment",
commands: ["white", "medium", "naka"], // Array of commands
userId: "user_id_123",
isPremium: true,
score: 0,
postedAt: "2024-01-01T00:00:00Z",
nicoruCount: 5,
nicoruId: null,
source: "web",
isMyPost: false
},
{
id: "comment_def456",
no: 2,
vposMs: 5000,
body: "Another comment",
commands: ["cyan", "small", "shita"],
userId: "user_id_456",
isPremium: false,
score: 0,
postedAt: "2024-01-01T00:00:05Z",
nicoruCount: 2,
nicoruId: "nicoru_123",
source: "mobile",
isMyPost: true
}
]
}
];
const niconiComments = new NiconiComments(
canvas,
v1Threads,
{ format: "v1" }
);
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.