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

@clikvn/showroom-visualizer

v0.5.1-dev-01

Published

Showroom Visualizer

Readme

Showroom Visualizer

A powerful, flexible 360° virtual tour visualizer với Headless Architecture support.

✨ Features

  • 🎨 Flexible UI: Sử dụng default UI hoặc build custom UI hoàn toàn
  • 🔧 Headless Hooks: Full control với React hooks
  • 📦 Component Library: Reusable components để compose custom layouts
  • 🎯 Type-safe: Full TypeScript support
  • Performance: Optimized với React best practices
  • 🔄 Backwards Compatible: Code cũ vẫn hoạt động bình thường

📖 Documentation

🚀 Quick Start

1. Sử dụng Default UI

import { ShowroomVisualizer } from 'showroom-visualizer';

function App() {
  return (
    <ShowroomVisualizer
      config={{ tourCode: 'my-tour' }}
      mobile={false}
      apiHost="https://api.clik.vn/vt360"
    />
  );
}

2. Custom UI với Headless Hooks

import { ShowroomVisualizer, useShowroomControls } from 'showroom-visualizer';

function CustomUI() {
  const controls = useShowroomControls();
  
  return (
    <div>
      <h1>{controls.activeScene?.name}</h1>
      <button onClick={controls.goToNextScene}>Next →</button>
      <button onClick={controls.toggleFloorplan}>Toggle Map</button>
</div>
  );
}

function App() {
  return (
    <ShowroomVisualizer
      config={{ tourCode: 'my-tour' }}
      customLayout={<CustomUI />}
    />
  );
}

3. Headless Mode (No UI)

import { ShowroomVisualizer, useShowroomControls } from 'showroom-visualizer';

function ExternalControls() {
  const controls = useShowroomControls();
  return <div>Build your UI here...</div>;
}

function App() {
  return (
    <>
      <ExternalControls />
      <ShowroomVisualizer
        config={{ tourCode: 'my-tour' }}
        disableDefaultUI={true}
      />
    </>
  );
}

📚 API Reference

Headless Hooks

  • useShowroomControls() - Main hook với tất cả controls
  • useTourCore() - Tour engine state (read-only)
  • useSceneNavigation() - Scene navigation controls
  • useFloorplanControl() - Floorplan/minimap controls
  • useScenarioControl() - Scenario auto-play controls
  • usePOIInteraction() - POI interaction controls
  • useViewportControl() - Viewport/camera controls

Exported Components

  • DefaultLayout - Default UI layout
  • PinActions, Floorplan, SceneCategories
  • PlayBar, GalleryFullScreen, ModalPopupPoi
  • ...và nhiều components khác

Xem HEADLESS_API.md để biết chi tiết.

🎓 Examples

Xem EXAMPLES.md để xem 9+ examples:

  • Simple Custom Header
  • Scene Grid Selector
  • Sidebar Navigation
  • External Dashboard
  • Auto-play Controls
  • POI Explorer
  • Complete Custom UI
  • Mobile-first UI
  • ...và nhiều hơn nữa!

🔧 Development

# Install dependencies
yarn install

# Run development server
yarn dev

# Build for production
yarn build

# Serve built files
serve dist --cors 

📝 License

MIT

Installation

npm install @clikvn/showroom-visualizer
# or
yarn add @clikvn/showroom-visualizer

Basic Usage

<!-- public/index.html -->
<script type="module">
  import ShowroomVisualizer from 'http://localhost:3000/web.js';
  ShowroomVisualizer.initVisualizer({
    apiHost: 'https://ci-api.clik.vn/vt360',
    config: {
      tourCode: 'TOUR_FXYCEN7ZZVW6',
      language: 'EN',
    },
    onLoaded: (tool) => {
      window.tool = tool;
    },
    mobile: false,
  });
</script>
<div style="width: 100vw; height: 100vh">
  <showroom-visualizer></showroom-visualizer>
</div>

Features

  • 🌐 360° Virtual Tours - Interactive panoramic experiences powered by Krpano
  • 🎯 Points of Interest (POI) - Multiple POI types: Gallery, Video, Sound, Navigation, Texture, Promotions
  • 🎬 Automated Scenarios - Guided tour playback with camera movements and narration
  • 🗺️ Floorplan/Minimap - Interactive navigation with radar positioning
  • 📱 Mobile Optimized - Touch controls and responsive layout for mobile devices
  • 🌍 Multi-language - Support for EN, CN, JP, KR, VI
  • 🎨 Customizable UI - Theme support and configurable components
  • 📊 Comprehensive Analytics - 35+ tracking actions covering all user interactions (see below)

Comprehensive Analytics & Tracking

The library includes a powerful tracking middleware system with 35+ actions covering all user interactions:

import ShowroomVisualizer from '@clikvn/showroom-visualizer';

ShowroomVisualizer.initVisualizer({
  apiHost: 'https://api.clik.vn',
  config: { tourCode: 'TOUR_123' },

  // Add tracking middleware
  middleware: (event) => {
    // Event structure:
    // {
    //   actionName: 'onCardItemClick',
    //   payload: { itemCode, itemTitle, itemType, sceneCode, ... },
    //   timestamp: '2025-01-15T10:00:00.000Z',
    //   metadata: { tourCode, sceneCode, categoryCode }
    // }

    // Send to your analytics service
    analytics.track(event.actionName, event.payload);
  },
});

What's Tracked (35+ Actions)

Search & Discovery (6 actions)

  • Panel open/close, search queries
  • Category header clicks (Products, Features, Locations, etc.)
  • Promotion actions (show more, auto play)
  • Individual scenario clicks

Individual Items (1 universal action covering all types)

  • Product clicks
  • POI clicks (Information, Features, Brands, Locations, Facilities, Multimedia)
  • Feature clicks
  • Promotion item clicks

POI Detail Panel (5 actions)

  • Open/close, audio playback
  • Action buttons (AI Assistant, Save, Audio, Share)
  • Tab switching (Gallery, AR, Web Rotate, Info, Specification)
  • Gallery item clicks

Scenario Playback (8 actions)

  • Scenario start, play/pause
  • Skip (next/previous), loop toggle
  • Sound toggle, playlist toggle
  • Playbar close

Navigation (6 actions)

  • Scene group selection
  • Floorplan changes
  • Minimap expand/minimize
  • View scenes button

UI Components (1+ actions)

  • Guide open/close
  • Other UI interactions

Key Features

Deep-level tracking - Not just categories, but individual items within each category ✅ Rich payloads - Codes, names, types, and contextual data for every action ✅ User journey mapping - Complete visibility from discovery to engagement ✅ Zero overhead - No performance impact when middleware not configured ✅ Fire-and-forget - Non-blocking, error-safe pattern ✅ Analytics-ready - Easy integration with GA4, Mixpanel, or custom backends

Complete List of Tracked Events (35+ Actions)

Search & Discovery (6 events)

| Event Name | Trigger | Payload | | ----------------------------------- | --------------------------- | ---------------------------------- | | onSearchAndDiscoveryClose | Panel closed | {} | | onSearchAndDiscoverySearch | User types in search | { searchQuery } | | onSearchAndDiscoveryItemClick | Category header clicked | { itemKey, itemTitle, itemType } | | onSearchAndDiscoveryScenarioClick | Scenario clicked from panel | { scenarioCode, scenarioName } | | onPromotionShowMore | Show more button clicked | { totalPromotions } | | onPromotionAutoPlay | Auto play button clicked | { totalPromotions } |

Categories tracked: HOME, AMENITIES, SCENE, PROMOTION, FEATURES, PRODUCT_LIST, INFORMATION, BRAND, LOCATION, FACILITY, MULTIMEDIA, SWAP_ELEMENT, SCENARIO, PLAYLIST, DISPLAY_HOTSPOT, DETAIL

Individual Items - Universal (1 event covering ALL types)

| Event Name | Trigger | Payload | | ----------------- | ---------------------------------------------- | -------------------------------------------------------------------- | | onCardItemClick | Any item clicked (product, POI, feature, etc.) | { itemCode, itemTitle, itemType, sceneCode, hotspotCode, isVideo } |

Item types covered: Products, Information POIs, Features, Brands, Locations, Facilities, Multimedia, Swap Elements, Promotions

POI Detail Panel (5 events)

| Event Name | Trigger | Payload | | ------------------------- | ------------------------- | ----------------------------------------------------------- | | onPoiDetailClose | Detail panel closed | { poiCode, poiName, poiType } | | onPoiDetailAudioPlay | Audio play button clicked | { poiCode, poiName, poiType } | | onPoiDetailGalleryClick | Gallery item clicked | { poiCode, poiName, poiType, galleryItemId, galleryType } | | onPoiDetailActionClick | Action button clicked | { actionKey, productCode, productName, productType } | | onPoiDetailTabChange | Tab switched | { tabKey, productCode, productName, galleryType } |

Action keys: ai_assistant, save, audio, share Tab keys: gallery, ar, webRotate, info, specification

Scenario Playback (8 events)

| Event Name | Trigger | Payload | | ---------------------- | -------------------------- | ----------------------------- | | onStartScenario | Scenario started from list | scenarioCode (string) | | onPlayBarClose | Playbar closed | { scenarioCode } | | onPlayListToggle | Playlist toggled | { show } | | onPlayBarPlayClick | Play button clicked | { scenarioCode } | | onPlayBarPauseClick | Pause button clicked | { scenarioCode } | | onPlayBarLoopToggle | Loop toggled | { loop, scenarioCode } | | onPlayBarSoundToggle | Sound toggled | { playing } | | onPlayBarSkip | Skip button clicked | { direction, scenarioCode } |

Direction values: 'previous' or 'next'

Navigation (6 events)

| Event Name | Trigger | Payload | | ------------------------- | -------------------------- | ------------------------------------------ | | onSceneGroupSelected | Scene group selected | { sceneGroupCode, sceneGroupName } | | onSubSceneGroupSelected | Sub scene group selected | { subSceneGroupCode, subSceneGroupName } | | onFloorplanViewScenes | View scenes button clicked | {} | | onFloorplanChange | Floorplan changed | { floorplanCode, floorplanName } | | onMinimapExpand | Minimap expanded | {} | | onMinimapMinimize | Minimap minimized | {} |

UI Components (1+ events)

| Event Name | Trigger | Payload | | -------------- | -------------------- | ------- | | onGuideClose | Guide overlay closed | {} |

Analytics Integration Examples

Google Analytics 4:

middleware: (event) => {
  gtag('event', event.actionName, {
    event_category: 'showroom',
    tour_code: event.metadata?.tourCode,
    ...event.payload,
  });
};

Mixpanel:

middleware: (event) => {
  mixpanel.track(event.actionName, {
    tour_code: event.metadata?.tourCode,
    ...event.payload,
  });
};

Custom Backend:

middleware: async (event) => {
  await fetch('/api/analytics', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(event),
  });
};

📚 Detailed Documentation: For complete examples, user journey scenarios, and implementation patterns, see Complete Tracking Guide

Available Listeners

The library provides 21+ event listeners for custom app logic:

| Listener | Description | Payload | | ----------------------- | --------------------- | ------------------------- | | POI Events | | onPoiClicked | POI clicked | POI object | | onPoiOver | Mouse over POI | POI object | | onPoiHover | Mouse hovering POI | POI object | | onPoiOut | Mouse left POI | - | | onPoiInCenter | POI nearest to center | POI object | | Scene Events | | onSceneCompleted | Scene loaded | sceneCode, categoryCode | | onSceneChanged | Scene navigated | Scene object | | Scenario Events | | onStartScenario | Scenario started | scenarioCode | | onScenarioPaused | Scenario paused | scenarioCode | | onScenarioEnded | Scenario ended | scenarioCode | | UI Events | | onToggleSlideIn | Slide-in toggled | { open, offset } | | onPlaybarOpen | Playbar opened | - | | onPlaybarClosed | Playbar closed | - | | onPinActionClicked | Pin button clicked | Button key string | | Tour Lifecycle | | onStartLoadingTour | Tour load started | tourCode | | onFinishedLoadingTour | Tour load finished | tourCode | | onLoaded | Tool ready | Tool object | | onDataLoaded | Tour data loaded | tour, tourData | | Product Events | | onAIProductClicked | AI product clicked | Product code | | onShareProductClicked | Share product clicked | Product code | | Other Events | | onChanged | Config changed | Config object | | onTourSwitchLoaded | Tour switch ready | TourSwitch object | | onStateChanged | State changed | State values |

Key Differences: Listeners vs Middleware

| Feature | Listeners | Middleware (Tracked Actions) | | -------------- | ------------------ | ------------------------------ | | Purpose | Custom app logic | Analytics & tracking | | When fires | Only if configured | Always (if middleware set) | | Count | 21+ events | 35+ actions | | Use case | App functionality | User behavior insights | | Blocking | Can be blocking | Non-blocking (fire-and-forget) |

Example:

  • Use listeners to trigger custom UI updates when a scene changes
  • Use middleware to track that scene change in your analytics platform

Both can be used together - listeners for app logic, middleware for analytics!

Configuration Options

ShowroomVisualizer.initVisualizer({
  // Required
  apiHost: string;              // API endpoint URL
  config: {
    tourCode: string;           // Tour identifier
    language?: string;          // 'EN' | 'CN' | 'JP' | 'KR' | 'VI'
  };

  // Optional
  mobile?: boolean;             // Mobile mode
  onLoaded?: (tool) => void;    // Callback when loaded
  middleware?: (event) => void; // Analytics tracking
  listeners?: {                 // Event listeners (see table above)
    onPoiClicked?: (poi) => void;
    onSceneChanged?: (scene) => void;
    onStartScenario?: (scenarioCode) => void;
    onPinActionClicked?: (key) => void;
    onSceneCompleted?: (sceneCode, categoryCode) => void;
    // ... 16+ more listeners available
  };
});

Development

# Development with hot reload
yarn dev

# Production build
yarn build

# Linting
yarn lint
yarn lint:fix

# Code formatting
yarn prettier

# Serve built files locally
serve dist --cors

Documentation

Core Documentation

  • CLAUDE.md - Complete architecture overview and development guide
  • README.md - This file - Quick start and API reference

Analytics & Tracking

Planning & Specifications

License

Proprietary - Clik Vietnam