npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openprinttag-js

v0.0.1

Published

JavaScript/TypeScript implementation of OpenPrintTag NFC data format - encoding and decoding for smart 3D printing materials

Downloads

137

Readme

openprinttag-js

JavaScript/TypeScript implementation of OpenPrintTag NFC data format.

This library allows you to encode and decode 3D printing material data into CBOR format compatible with OpenPrintTag NFC tags, which can be used for smart filament spools and resin bottles.

Related Projects

Features

  • High-level class API - Simple, use-case driven interface
  • Full TypeScript support with comprehensive type definitions
  • CBOR encoding/decoding for efficient binary data
  • NFC-V format support with NDEF TLV structure
  • Optional URL records for smartphone scanning
  • Material validation with required and recommended fields
  • Forward compatible - unknown fields preserved during decoding
  • Browser and Node.js compatible - works in both environments
  • Zero configuration - works out of the box
  • Lightweight - minimal dependencies

Installation

npm install openprinttag-js

Quick Start

Creating a New NFC Tag

import { OpenPrintTag, MaterialClass, MaterialType } from 'openprinttag-js';

// Create material data
const tagBinary = OpenPrintTag.create({
  material_class: MaterialClass.FFF,      // Required: FFF (filament) or SLA (resin)
  material_type: MaterialType.PLA,        // Recommended: PLA, PETG, ABS, etc.
  brand_name: 'Prusament',                // Recommended
  material_name: 'PLA Galaxy Black',      // Recommended
  density: 1.24,                          // g/cm³ (was mg/cm³ in older versions)
  min_print_temperature: 205,             // °C
  max_print_temperature: 225,
  min_bed_temperature: 40,
  max_bed_temperature: 60,
  primary_color: { r: 61, g: 62, b: 61 },
}, {
  url: 'https://openprinttag.org/s/abc123', // Optional URL for smartphones
  tagSize: 312, // Default: 312 bytes (SLIX2)
});

// Write to NFC tag or save to file
fs.writeFileSync('nfc_tag.bin', tagBinary);

Reading an NFC Tag

import { OpenPrintTag } from 'openprinttag-js';
import fs from 'fs';

// Read from NFC tag or file
const tagBinary = fs.readFileSync('nfc_tag.bin');

// Decode and get full information
const info = OpenPrintTag.decode(tagBinary);

console.log('Material:', info.data.material_name);
console.log('Brand:', info.data.brand_name);
console.log('Print temp:', info.data.min_print_temperature, '-', info.data.max_print_temperature, '°C');
console.log('URL:', info.url); // If tag contains URL
console.log('Tag size:', info.size, 'bytes');
console.log('Valid:', info.validation.valid);

Updating Existing Tag Data

The update() method allows you to modify an existing NFC tag without rewriting all data. This is useful for:

  • Adjusting print settings (temperature, bed temperature, etc.)
  • Updating material properties
  • Adding or removing optional fields
  • Changing URLs
import { OpenPrintTag } from 'openprinttag-js';

// Read existing tag
const existingTag = fs.readFileSync('nfc_tag.bin');

// Update just the temperature settings
const updatedTag = OpenPrintTag.update(existingTag, {
  min_print_temperature: 210,
  max_print_temperature: 230,
});

// Write back to tag
fs.writeFileSync('nfc_tag.bin', updatedTag);

Key features:

  • Preserves all existing fields not explicitly updated
  • Maintains tag size (important for NFC compatibility)
  • Preserves URL by default
  • Validates data after update

Removing Fields

You can remove optional fields from an existing tag:

// Remove specific fields
const updated = OpenPrintTag.update(existingTag, {
  density: 1.25, // Update this field (g/cm³)
}, {
  remove: ['gtin', 'min_nozzle_diameter'], // Remove these fields
});

Update + Remove Combined

You can update some fields and remove others in a single operation:

const updated = OpenPrintTag.update(existingTag, {
  // Update these fields
  min_print_temperature: 215,
  max_print_temperature: 235,
  density: 1.26,
}, {
  // Remove these fields
  remove: ['gtin', 'min_nozzle_diameter'],
});

URL Management During Updates

By default, update() preserves the existing URL. You can change this behavior:

// Preserve URL (default)
const updated1 = OpenPrintTag.update(existingTag, {
  density: 1.25,
});

// Replace with new URL
const updated2 = OpenPrintTag.update(existingTag, {
  density: 1.25,
}, {
  url: 'https://openprinttag.org/s/new-id',
});

// Remove URL completely
const updated3 = OpenPrintTag.update(existingTag, {
  density: 1.25,
}, {
  preserveUrl: false,
});

Validating Material Data

const validation = OpenPrintTag.validate({
  material_class: MaterialClass.FFF,
  material_type: MaterialType.PLA,
  // ... your data
});

if (!validation.valid) {
  console.error('Errors:', validation.errors);
}

if (validation.warnings.length > 0) {
  console.warn('Missing recommended fields:', validation.warnings);
}

Object-Oriented API (Fluent Style)

import { OpenPrintTag } from 'openprinttag-js';

// Load existing tag
const tag = new OpenPrintTag(tagBinary);

// Chain operations
tag
  .updateData({ density: 1.35 })
  .updateData({ min_print_temperature: 215 });

// Get data
const data = tag.getData();
const url = tag.getUrl();
const info = tag.getInfo();

// Export to binary
const updated = tag.toBinary();

Real-World Use Cases

Use Case 1: Initialize Empty Tag

// Equivalent to Python's nfc_initialize.py
const tagBinary = OpenPrintTag.create({
  material_class: MaterialClass.FFF,
  material_type: MaterialType.PLA,
  brand_name: 'Prusament',
  material_name: 'PLA Galaxy Black',
  primary_color: { r: 61, g: 62, b: 61 },
  density: 1.24, // g/cm³
}, {
  url: 'https://openprinttag.org/s/abc123',
  tagSize: 312,
});

// Write to NFC tag...

Use Case 2: Update Temperature Settings

// Equivalent to Python's rec_update.py
const existingTag = await readNFCTag(); // Your NFC reading function

const updated = OpenPrintTag.update(existingTag, {
  min_print_temperature: 210,
  max_print_temperature: 230,
});

await writeNFCTag(updated); // Your NFC writing function

Use Case 3: Read Tag Information

// Equivalent to Python's rec_info.py
const tagBinary = await readNFCTag();

const info = OpenPrintTag.decode(tagBinary);

console.log('--- Tag Information ---');
console.log('Material:', info.data.material_name);
console.log('Brand:', info.data.brand_name);
console.log('URL:', info.url);
console.log('Size:', info.size, 'bytes');
console.log('Valid:', info.validation.valid);

if (info.validation.warnings.length > 0) {
  console.warn('Warnings:', info.validation.warnings);
}

Advanced / Low-level API

For advanced use cases, you can access low-level functions through the Advanced namespace:

import { Advanced, MaterialClass } from 'openprinttag-js';

// Raw CBOR encoding
const cborData = Advanced.encode({
  material_class: MaterialClass.FFF,
  material_type: Advanced.MaterialType.PLA,
  brand_name: 'Test',
});

// Raw decoding
const decoded = Advanced.decode(cborData);

// NDEF utilities
const urlRecord = Advanced.createNDEFUrlRecord('https://example.com', true, false);

// Tag utilities
const maxUrl = Advanced.calculateMaxUrlLength(materialData);
console.log('Max URL length:', maxUrl.maxUrlLength, 'chars');

// Check if data fits
const fits = Advanced.checkDataFits(materialData, 'https://example.com');
if (!fits.fits) {
  console.error('Data too large!');
}

// Get recommended tag type
const tagType = Advanced.getRecommendedTagType(materialData);
console.log('Use', tagType, 'tag'); // e.g., "SLIX2"

More Examples

For detailed examples, see the examples/ directory:

Run examples:

npm install
npx tsx examples/encoding.ts
npx tsx examples/decoding.ts

Material Tags

Material tags describe special properties:

import { MaterialTag } from 'openprinttag-js';

const tagBinary = OpenPrintTag.create({
  // ...
  tags: [
    MaterialTag.GLITTER,              // Visual effects
    MaterialTag.GLOW_IN_THE_DARK,
    MaterialTag.CONTAINS_CARBON_FIBER, // Filled materials
    MaterialTag.ABRASIVE,              // Requires hardened nozzle
    MaterialTag.BIO_BASED,             // Eco-friendly
    // ... see MaterialTag enum for all 70+ tags
  ],
});

Categories include:

  • Visual: Glitter, transparent, silk, matte, glow-in-the-dark
  • Filled materials: Carbon fiber, glass fiber, wood, metal particles
  • Physical properties: Abrasive, flexible, self-extinguishing, foaming
  • Biological: Biocompatible, antibacterial, bio-based
  • Electrical: Conductive, ESD-safe
  • And more...

Field Reference

Required Fields

  • material_class - Material class (FFF or SLA)

Recommended Fields

  • material_type - Specific polymer type (PLA, PETG, etc.)
  • material_name - Brand-specific material name
  • brand_name - Brand of the material
  • gtin - Global Trade Item Number (product ID)
  • manufactured_date - Unix timestamp
  • density - Density in g/cm³
  • min_print_temperature / max_print_temperature - Nozzle temp range in °C
  • min_bed_temperature / max_bed_temperature - Bed temp range in °C
  • primary_color - RGB color { r, g, b }
  • tags - Array of material characteristics

Optional Fields

  • Weight: nominal_netto_full_weight, actual_netto_full_weight, empty_container_weight
  • Temperatures: preheat_temperature, chamber_temperature, drying_temperature, etc.
  • Drying: drying_temperature (°C), drying_time (min)
  • Optical: transmission_distance (HueForge TD, 0.1 = opaque, 100 = transparent)
  • Container: container_outer_diameter, container_width, etc.
  • Colors: secondary_color_0 through secondary_color_4
  • And many more...

See full field documentation for complete list.

Browser Usage

<script type="module">
  import { OpenPrintTag, MaterialClass, MaterialType } from 'https://unpkg.com/openprinttag-js';

  // Create tag
  const tagBinary = OpenPrintTag.create({
    material_class: MaterialClass.FFF,
    material_type: MaterialType.PLA,
    brand_name: 'Test',
    material_name: 'Test PLA',
    min_print_temperature: 200,
    max_print_temperature: 220,
  });

  // Download as file
  const blob = new Blob([tagBinary], { type: 'application/octet-stream' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'material.bin';
  a.click();

  // Decode (e.g., from file upload)
  const info = OpenPrintTag.decode(tagBinary);
  console.log(info);
</script>

API Reference

OpenPrintTag Class

Static Methods

OpenPrintTag.create(data, options?): Uint8Array

Create a new NFC tag binary ready to write.

Options:

  • url?: string - Optional URL for smartphones
  • tagSize?: number - Total tag size in bytes (default: 312)
OpenPrintTag.update(tagBinary, updates, options?): Uint8Array

Update existing tag with new data.

Options:

  • remove?: string[] - Field names to remove
  • url?: string - Replace URL
  • preserveUrl?: boolean - Keep existing URL (default: true)
OpenPrintTag.decode(tagBinary): TagInfo

Decode tag and get full information.

Returns:

  • data: MaterialData - Decoded material data
  • url?: string - URL from NDEF (if present)
  • size: number - Tag size in bytes
  • validation: ValidationResult - Validation result
  • unknown_fields?: UnknownFieldsMap - Unknown fields (for forward compatibility)
OpenPrintTag.validate(data): ValidationResult

Validate material data.

Returns:

  • valid: boolean - Whether all required fields are present
  • errors: string[] - Missing required fields
  • warnings: string[] - Missing recommended fields

Instance Methods

  • load(binary): this - Load tag binary
  • getData(): MaterialData - Get decoded data
  • getUrl(): string | undefined - Get URL
  • getInfo(): TagInfo - Get full info
  • updateData(updates, options?): this - Update data (fluent API)
  • setUrl(url): this - Set URL (fluent API)
  • toBinary(options?): Uint8Array - Export to binary
  • validate(): ValidationResult - Validate current data

TypeScript Types

All types are fully typed and exported. Types are automatically generated from the OpenPrintTag specification and kept in sync with the official spec:

  • MaterialData - Main data interface (generated from main_fields.yaml and aux_fields.yaml)
  • MaterialClass - FFF (0) or SLA (1) enum (generated from material_class_enum.yaml)
  • MaterialType - PLA, PETG, ABS, ASA, TPU, PC, PA, PEEK, etc. (40+ types, generated from material_type_enum.yaml)
  • MaterialTag - 70+ material characteristics (generated from tags_enum.yaml)
  • MaterialCertification - Material certifications enum (generated from material_certifications_enum.yaml)
  • WriteProtection - Write protection status enum (generated from write_protection_enum.yaml)
  • Color - RGB or RGBA color interface
  • CreateTagOptions - Options for tag creation
  • UpdateTagOptions - Options for updating
  • TagInfo - Full tag information
  • UnknownFieldsMap - Map of unknown fields by region (for forward compatibility)

Note: Types are automatically regenerated after npm install if the spec submodule is present. Generated files are committed to the repository, so users don't need to run the generator manually.

Development

Getting Started

# Clone the repository
git clone https://github.com/OpenPrintTag/openprinttag-js.git
cd openprinttag-js

# Initialize the spec submodule (contains OpenPrintTag YAML definitions)
git submodule update --init

# Install dependencies (automatically generates types from spec)
npm install

# Run tests
npm test

Type Generation

This library uses the official OpenPrintTag specification as a git submodule. TypeScript types, enums, and field definitions are automatically generated from the YAML files in spec/data/.

Automatic generation:

  • Types are regenerated automatically after npm install (via postinstall script)
  • Types are also regenerated before npm run build

Manual generation:

# Regenerate types manually
npm run generate

Updating from spec changes:

# Check current spec submodule status
npm run spec:status

# See what changed (compares to origin/main)
npm run spec:diff

# Update spec submodule to latest and regenerate types
npm run spec:update
npm run generate

# Run tests to verify compatibility
npm test

You can also update manually:

cd spec
git pull origin main
cd ..
npm run generate

The generator (scripts/generate-types.ts) creates files in src/generated/:

  • enums.ts - All enum definitions (MaterialType, MaterialTag, MaterialCertification, WriteProtection)
  • types.ts - MaterialData interface and Color type
  • fields.ts - Field definitions for encoding/decoding (FIELD_DEFINITIONS, AUX_FIELD_DEFINITIONS)

Note: Generated files are committed to the repository so users don't need to run the generator. CI automatically verifies that generated files are in sync with the spec.

Building and Testing

npm install              # Install dependencies and generate types
npm run typecheck        # TypeScript type checking
npm run lint             # ESLint
npm test                 # Run tests
npm run build            # Build for distribution

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

See CONTRIBUTING.md for guidelines.