Developer Docs

Hakama.js Documentation

Complete guide to integrating virtual try-on experiences with image upload and persistent storage.

Overview

Hakama.js is a lightweight, ES5-compatible JavaScript library that adds virtual try-on functionality to your e-commerce site. It automatically injects action buttons into product cards, opens a modal for image upload, and optionally integrates with your Try-On API to generate virtual try-on previews.

📤
Single Image Upload
Users can upload exactly one photo in jpeg, jpg, png, or webp format with automatic validation
💾
Persistent Storage
Photos are stored in IndexedDB with localStorage fallback, persisting across sessions
🔄
Auto-Load Images
Previously uploaded images automatically load when the modal opens
🎨
Design Agnostic
Fully configurable selectors and classes to match your site's design
🚀
Try-On API
Optional integration with your Try-On API for generating virtual previews

Key Features

Image Management

  • Upload exactly ONE user image (jpeg/jpg/png/webp)
  • Automatic file type and size validation
  • Persist in IndexedDB (best practice) with base64 fallback
  • Auto-load previously saved image whenever the modal opens
  • Remove/Clear saved photo and allow re-upload

Modal Experience

  • Full-page overlay with customizable styling
  • Side-by-side thumbnail preview (clothing + user photo)
  • Full-width result display area
  • Close on Escape key or backdrop click
  • Scroll lock when modal is open

Try-On Integration

  • POST multipart/form-data with { person, clothing } images
  • Automatic preparation of image blobs
  • Cloudflare Turnstile token injection
  • Custom API headers support
  • Error handling and retry logic

Developer Experience

  • ES5-compatible (works in older browsers)
  • No dependencies required
  • Automatic DOM observation for dynamic content
  • Custom button templates
  • Comprehensive event callbacks
  • TypeScript-friendly API

Installation

CDN (Recommended for Quick Setup)

HTML
<script src="https://hakama.io/hakama.min.js"></script>
💡 Note
The library is ES5-compatible and works without transpilation in all modern browsers and IE11+.

Quick Start

Basic Setup

The simplest way to get started:

HTML
                            
<!-- Your product cards -->
<div class="card">
    <img src="product1.jpg" alt="Product 1">
    <h3>Blue Jacket</h3>
    <div class="actions"></div>
</div>

<!-- Include Hakama -->
<script src="https://hakama.io/hakama.min.js"></script>
<script>
Hakama.init({
    cardSelector: '.card',
    insertIntoSelector: '.actions',
    buttonText: 'Try On',
    buttonClass: 'btn btn-primary',
    key: 'your-api-key',
});
</script>

                        

With Auto-Initialization

Define configuration before loading the script:

HTML

<script>
window.HakamaConfig = {
    cardSelector: '.card',
    buttonText: 'Try On',
    tryOnEnabled: true,
    tryOnEndpoint: '/api/try-on'
};
</script>
<script src="hakama.js"></script>
                            

Configuration Options

Hakama.js provides extensive configuration options to customize behavior, appearance, and integration with your Try-On API.

Card & Button Configuration

Control how buttons are injected into your product cards:

Option Type Default Description
cardSelector String '.card' CSS selector for product cards
insertIntoSelector String null Target element within card (e.g., '.actions')
createActionsIfMissing Boolean false Create container if insertIntoSelector not found
createdActionsTag String 'div' HTML tag for created container
createdActionsClass String 'hakama-actions' Class for created container
buttonText String 'Action' Button text content
buttonClass String '' CSS classes for button
ariaLabel String null Accessibility label (defaults to buttonText)
buttonTemplate Function null Custom button generator function
placement String 'append' 'append' or 'prepend' within target
Custom Button Template Example
Hakama.init({
    buttonTemplate: function(opts, card) {
    var btn = document.createElement('button');
    btn.className = 'custom-tryon-btn';
    btn.innerHTML = '<span>👔</span> Try It On';
        return btn;
    }
});

Filter Options

Option Type Default Description
injectedAttr String 'data-action-injected' Attribute to mark injected cards
skipSelector String '[data-action-disabled]' Skip cards matching this selector
cardMustAlsoMatch String null Additional selector cards must match

DOM Observation

Option Type Default Description
root Element document Root element for querying cards
observe Boolean true Watch for dynamically added cards

Click Behavior

Option Type Default Description
onClick Function null function(cardEl, event) - Custom click handler
dispatchEventName String null Custom event name to dispatch (e.g., 'card:action')
dispatchTarget String 'card' 'card' (bubbles from card) or 'document'

Modal Configuration

Customize the modal appearance and behavior:

Option Type Default Description
modal Boolean true Enable modal functionality
modalTitle String 'Preview' Default modal title
closeOnEsc Boolean true Close modal on Escape key
closeOnBackdrop Boolean true Close modal on backdrop click
renderModal Function null function(cardEl) => { title, html }
onModalOpen Function null function(dialogEl, cardEl, imageUrl)
onModalClose Function null function(dialogEl, cardEl)

Upload Configuration

Control image upload behavior:

Option Type Default Description
enableUpload Boolean true Enable upload functionality
uploadText String 'Upload photo' Upload button text
uploadAccept String 'image/jpeg,image/jpg,image/png,image/webp' Accepted file types
uploadButtonClass String '' CSS classes for upload button
maxFileSizeBytes Number null Maximum file size in bytes
onUpload Function null function(file, cardEl, imageUrl)

Remove/Clear Configuration

Option Type Default Description
enableRemove Boolean true Enable remove functionality
removeText String 'Remove photo' Remove button text
removeButtonClass String '' CSS classes for remove button
onRemove Function null function(cardEl)

Storage Configuration

Configure where and how user images are stored:

Option Type Default Description
storageKey String 'hakama:user-image' localStorage key for fallback storage
idb Object { dbName, storeName, key } IndexedDB configuration
idb.dbName String 'HakamaDB' IndexedDB database name
idb.storeName String 'images' IndexedDB object store name
idb.key String 'user-image' IndexedDB key for user image
💾 Storage Behavior
Hakama prioritizes IndexedDB for storing full-quality images. If IndexedDB is unavailable or fails, it automatically falls back to localStorage with base64 encoding. Both storage methods persist across browser sessions.

Try-On API Configuration

Configure integration with your virtual try-on API:

Option Type Default Description
tryOnEnabled Boolean false Enable Try-On functionality
tryOnButtonText String 'Generate Preview' Try-On button text
tryOnButtonClass String '' CSS classes for Try-On button
tryOnHeaders Object null Additional HTTP headers (DO NOT set Content-Type)
clothingImageSelector String 'img' How to find clothing image in card
getClothingImage Function null Custom clothing image extractor
onTryOnStart Function null function(cardEl)
onTryOnResult Function null function(cardEl, resultObjectURL)
onTryOnError Function null function(cardEl, error)

Styling Configuration

Control CSS injection and styling:

Option Type Default Description
injectStyles String 'minimal' 'minimal' (inject basic styles) or 'none'
namespace String 'hakama' CSS class prefix
zIndexBase Number 2147483000 Base z-index for modal (very high by default)

API Reference

Hakama.init(options) Method

Initialize Hakama with configuration options. This method is idempotent (safe to call multiple times).

Parameters: options (Object)

Returns: Hakama instance (chainable)

Hakama.refresh() Method

Re-scan the DOM and inject buttons into any new cards that match the selector.

Returns: Hakama instance (chainable)

Hakama.destroy() Method

Disconnect the MutationObserver and stop watching for new cards.

Returns: Hakama instance (chainable)

Hakama.removeInjected() Method

Remove all injected buttons from cards and clear the injected attribute.

Returns: Hakama instance (chainable)

Hakama.openModal(payload) Method

Programmatically open the modal with custom content.

Parameters: payload (Object, optional) - { title, html }

Returns: Hakama instance (chainable)

Hakama.closeModal() Method

Programmatically close the modal.

Returns: Hakama instance (chainable)

Storage System

How It Works

Hakama uses a dual-storage strategy to ensure user photos persist reliably across sessions:

🗄️
Primary: IndexedDB
Stores full-quality image blobs with no size limitations. Best practice for modern browsers.
💽
Fallback: localStorage
Stores base64-encoded images. Used when IndexedDB is unavailable or fails.
🔒 Privacy Note
User photos are stored locally in the browser only. No images are automatically sent to any server unless the user clicks "Generate Preview" with Try-On enabled.

Usage Examples

Basic Implementation

Minimal Setup

<script src="hakama.js"></script>
<script>
Hakama.init({
    cardSelector: '.card',
    buttonText: 'Try On',
    buttonClass: 'btn btn-primary'
});
</script>

E-commerce Integration

Full Setup with Analytics

Hakama.init({
    cardSelector: '.product-card',
    buttonText: '👔 Virtual Try-On',
    tryOnEnabled: true,
    tryOnEndpoint: '/api/virtual-tryon',
    key: 'api-key',
    maxFileSizeBytes: 10 * 1024 * 1024,

    onTryOnResult: function(card, resultUrl) {
        gtag('event', 'tryon_success');
    }
});