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

cbm-calculator-lib

v0.0.3

Published

A modular Angular library for calculating **Cubic Meters (CBM)**, managing freight containers, and visualizing 3D cargo loading. Built with Angular Signals and fully tree-shakeable — **import only the components you need**.

Readme

cbm-calculator-lib

A modular Angular library for calculating Cubic Meters (CBM), managing freight containers, and visualizing 3D cargo loading. Built with Angular Signals and fully tree-shakeable — import only the components you need.

npm version


Installation

npm install cbm-calculator-lib

Optional: Only install three if you use the ContainerVisualizer component:

npm install three @types/three

Architecture Overview

All components share a single CalculatorState service (providedIn: 'root'). This means:

  • Components automatically stay in sync — changing the container type in ContainerUnit instantly updates Summary, VolumeWeightStatus, etc.
  • You can use any combination of components. No need to import all of them.
  • Each component is a separate secondary entry point — only the code you import gets bundled.
cbm-calculator-lib
├── /calculator-state      ← Shared reactive state service (core)
├── /container-unit        ← Container type, unit system, transport mode selector
├── /item-details          ← Cargo items table (add/edit/remove rows)
├── /summary               ← Totals: volume, weight, chargeable weight, pricing basis
├── /volume-weight-status  ← Visual progress bars for container utilization
├── /transport-comparison  ← Side-by-side Sea / Air / Road freight comparison
└── /container-visualizer  ← Interactive 3D container loading viewer (Three.js)

Components

1. CalculatorState — Core Service

Import path: cbm-calculator-lib/calculator-state

The reactive state engine. All UI components inject this service. You can also inject it directly to read or mutate state in your own components.

import { CalculatorState } from 'cbm-calculator-lib/calculator-state';

@Component({ ... })
export class MyComponent {
  state = inject(CalculatorState);

  // Read computed values
  totalVolume = this.state.totalItemsVolumeCbm;   // signal: number (m³)
  totalWeight = this.state.totalItemsWeightKg;    // signal: number (kg)
  utilization = this.state.volumeUtilization;     // signal: number (%)

  // Mutate state
  addItem()        { this.state.addItem(); }
  removeItem(id)   { this.state.removeItem(id); }
  updateItem(id, patch) { this.state.updateItem(id, patch); }
}

Exported types:

| Type / Constant | Description | |---|---| | CalculatorState | Injectable service class | | CargoItem | { id, width, length, height, quantity, weightPerUnit } | | UnitSystem | 'Metric' \| 'Imperial' | | ContainerType | '20DC' \| '40DC' \| '40HC' | | TransportMode | 'Sea' \| 'Air' \| 'Road' | | CONTAINERS | Array of container definitions with inner dimensions | | TRANSPORT_MODES | Array of transport mode definitions with volumetric factors |

Key computed signals on CalculatorState:

| Signal | Type | Description | |---|---|---| | unitSystem | Signal<UnitSystem> | Current unit system | | containerType | Signal<ContainerType> | Selected container | | transportMode | Signal<TransportMode> | Selected transport | | items | Signal<CargoItem[]> | List of cargo items | | activeContainer | Signal<ContainerDef> | Full spec of selected container | | containerVolumeM3 | Signal<number> | Container inner volume in m³ | | totalItemsVolumeCbm | Signal<number> | Sum of all items' volume in m³ | | totalItemsWeightKg | Signal<number> | Sum of all items' weight in kg | | volumetricWeightKg | Signal<number> | CBM × transport factor | | chargeableWeightKg | Signal<number> | max(actual, volumetric) | | pricingBasis | Signal<string> | 'Volume-Based' \| 'Weight-Based' \| 'Equal' | | volumeUtilization | Signal<number> | Volume used / container capacity × 100 | | weightUtilization | Signal<number> | Weight used / max payload × 100 |


2. ContainerUnit — Settings Panel

Import path: cbm-calculator-lib/container-unit Selector: <app-container-unit>

Renders dropdowns to select container type, unit system (Metric/Imperial), and transport mode. Also shows transport-specific pricing inputs and the selected container's spec summary.

import { ContainerUnit } from 'cbm-calculator-lib/container-unit';

@Component({
  imports: [ContainerUnit],
  template: `<app-container-unit />`
})
export class MyPage {}

Peer dependency required: @angular/common


3. ItemDetails — Cargo Items Table

Import path: cbm-calculator-lib/item-details Selector: <app-item-details>

An editable table where users enter cargo dimensions (W × L × H), quantity, and weight per unit. Each row shows the calculated CBM. Rows can be added or removed.

import { ItemDetails } from 'cbm-calculator-lib/item-details';

@Component({
  imports: [ItemDetails],
  template: `<app-item-details />`
})
export class MyPage {}

Peer dependency required: @angular/common, @angular/forms


4. Summary — Totals Card

Import path: cbm-calculator-lib/summary Selector: <app-summary>

Displays total volume, total weight, converted values, volumetric weight, chargeable weight, containers needed, and pricing basis.

import { Summary } from 'cbm-calculator-lib/summary';

@Component({
  imports: [Summary],
  template: `<app-summary />`
})
export class MyPage {}

Peer dependency required: @angular/common


5. VolumeWeightStatus — Utilization Bars

Import path: cbm-calculator-lib/volume-weight-status Selector: <app-volume-weight-status>

Shows animated progress bars for volume utilization and weight utilization of the selected container. The weight bar turns red when utilization exceeds 90%.

import { VolumeWeightStatus } from 'cbm-calculator-lib/volume-weight-status';

@Component({
  imports: [VolumeWeightStatus],
  template: `<app-volume-weight-status />`
})
export class MyPage {}

Peer dependency required: @angular/common


6. TransportComparison — Freight Mode Comparison

Import path: cbm-calculator-lib/transport-comparison Selector: <app-transport-comparison>

Side-by-side cards comparing Sea Freight, Air Freight, and Road Freight. Shows the volumetric weight, chargeable weight, and smart insights for each mode based on the current cargo.

| Mode | Volumetric factor | |---|---| | Sea Freight | 1 m³ = 1,000 kg | | Air Freight (IATA) | 1 m³ = 167 kg | | Road Freight | 1 m³ = 333 kg |

import { TransportComparison } from 'cbm-calculator-lib/transport-comparison';

@Component({
  imports: [TransportComparison],
  template: `<app-transport-comparison />`
})
export class MyPage {}

Peer dependency required: @angular/common


7. ContainerVisualizer — 3D Viewer

Import path: cbm-calculator-lib/container-visualizer Selector: <app-container-visualizer>

An interactive 3D visualization of cargo items packed inside the selected container. Uses Three.js with OrbitControls — users can rotate, zoom, and pan the scene. The 3D scene is loaded on demand (click "Load 3D Container") to avoid unnecessary GPU usage.

import { ContainerVisualizer } from 'cbm-calculator-lib/container-visualizer';

@Component({
  imports: [ContainerVisualizer],
  template: `<app-container-visualizer />`
})
export class MyPage {}

Peer dependency required: @angular/common, three (must be installed separately)

npm install three @types/three

Usage Examples

Minimal setup — Summary + Item entry only

No visualizer, no transport comparison. Only the components you need:

import { Component } from '@angular/core';
import { ItemDetails } from 'cbm-calculator-lib/item-details';
import { Summary } from 'cbm-calculator-lib/summary';

@Component({
  selector: 'app-root',
  imports: [ItemDetails, Summary],
  template: `
    <app-item-details />
    <app-summary />
  `
})
export class AppComponent {}

three is not needed here. The ContainerVisualizer is never imported, so it is never bundled.


Full setup — all components

import { Component } from '@angular/core';
import { ContainerUnit }       from 'cbm-calculator-lib/container-unit';
import { ItemDetails }         from 'cbm-calculator-lib/item-details';
import { Summary }             from 'cbm-calculator-lib/summary';
import { VolumeWeightStatus }  from 'cbm-calculator-lib/volume-weight-status';
import { TransportComparison } from 'cbm-calculator-lib/transport-comparison';
import { ContainerVisualizer } from 'cbm-calculator-lib/container-visualizer';

@Component({
  selector: 'app-root',
  imports: [
    ContainerUnit,
    ItemDetails,
    Summary,
    VolumeWeightStatus,
    TransportComparison,
    ContainerVisualizer,
  ],
  template: `
    <div class="layout">
      <app-container-unit />
      <app-summary />
    </div>
    <app-item-details />
    <app-volume-weight-status />
    <app-transport-comparison />
    <app-container-visualizer />
  `
})
export class AppComponent {}

Reading state in your own component

Inject CalculatorState directly to access computed values or trigger actions:

import { Component, inject } from '@angular/core';
import { CalculatorState } from 'cbm-calculator-lib/calculator-state';

@Component({
  selector: 'app-my-widget',
  template: `
    <p>Total CBM: {{ state.totalItemsVolumeCbm() | number:'1.3-3' }}</p>
    <p>Chargeable weight: {{ state.chargeableWeightKg() | number:'1.1-1' }} kg</p>
    <p>Pricing basis: {{ state.pricingBasis() }}</p>
  `
})
export class MyWidget {
  state = inject(CalculatorState);
}

Peer Dependencies Summary

| Package | Required by | Optional? | |---|---|---| | @angular/core | All components | No | | @angular/common | All UI components | No | | @angular/forms | ItemDetails only | Yes | | three | ContainerVisualizer only | Yes |


Container Specifications

| Container | Inner L × W × H (mm) | Volume | Max Payload | |---|---|---|---| | 20' Dry Container (20DC) | 5898 × 2352 × 2393 | ~33.2 m³ | 28,000 kg | | 40' Dry Container (40DC) | 12025 × 2352 × 2393 | ~67.7 m³ | 28,800 kg | | 40' High Cube (40HC) | 12025 × 2352 × 2698 | ~76.3 m³ | 28,600 kg |


Development

# Clone and install
git clone <repo-url>
cd "cbm calculator"
npm install

# Run the demo app
npm start

# Build the library only
npm run build:lib

# Pack for local testing
npm run package:lib

# Publish to npm
npm run publish:npm