openprinttag-js
v0.0.1
Published
JavaScript/TypeScript implementation of OpenPrintTag NFC data format - encoding and decoding for smart 3D printing materials
Downloads
137
Maintainers
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
- OpenPrintTag - Official website and documentation
- OpenPrintTag Web Generator - Online generator using this library
- OpenPrintTag Python Implementation - Python reference implementation
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-jsQuick 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 functionUse 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:
encoding.ts- Complete encoding examplesdecoding.ts- Complete decoding examples
Run examples:
npm install
npx tsx examples/encoding.ts
npx tsx examples/decoding.tsMaterial 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 namebrand_name- Brand of the materialgtin- Global Trade Item Number (product ID)manufactured_date- Unix timestampdensity- Density in g/cm³min_print_temperature/max_print_temperature- Nozzle temp range in °Cmin_bed_temperature/max_bed_temperature- Bed temp range in °Cprimary_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_0throughsecondary_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 smartphonestagSize?: 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 removeurl?: string- Replace URLpreserveUrl?: boolean- Keep existing URL (default: true)
OpenPrintTag.decode(tagBinary): TagInfo
Decode tag and get full information.
Returns:
data: MaterialData- Decoded material dataurl?: string- URL from NDEF (if present)size: number- Tag size in bytesvalidation: ValidationResult- Validation resultunknown_fields?: UnknownFieldsMap- Unknown fields (for forward compatibility)
OpenPrintTag.validate(data): ValidationResult
Validate material data.
Returns:
valid: boolean- Whether all required fields are presenterrors: string[]- Missing required fieldswarnings: string[]- Missing recommended fields
Instance Methods
load(binary): this- Load tag binarygetData(): MaterialData- Get decoded datagetUrl(): string | undefined- Get URLgetInfo(): TagInfo- Get full infoupdateData(updates, options?): this- Update data (fluent API)setUrl(url): this- Set URL (fluent API)toBinary(options?): Uint8Array- Export to binaryvalidate(): 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 frommain_fields.yamlandaux_fields.yaml)MaterialClass- FFF (0) or SLA (1) enum (generated frommaterial_class_enum.yaml)MaterialType- PLA, PETG, ABS, ASA, TPU, PC, PA, PEEK, etc. (40+ types, generated frommaterial_type_enum.yaml)MaterialTag- 70+ material characteristics (generated fromtags_enum.yaml)MaterialCertification- Material certifications enum (generated frommaterial_certifications_enum.yaml)WriteProtection- Write protection status enum (generated fromwrite_protection_enum.yaml)Color- RGB or RGBA color interfaceCreateTagOptions- Options for tag creationUpdateTagOptions- Options for updatingTagInfo- Full tag informationUnknownFieldsMap- 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 testType 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(viapostinstallscript) - Types are also regenerated before
npm run build
Manual generation:
# Regenerate types manually
npm run generateUpdating 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 testYou can also update manually:
cd spec
git pull origin main
cd ..
npm run generateThe 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 typefields.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 distributionLicense
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
See CONTRIBUTING.md for guidelines.
