diff --git a/packages/dim-si/README.md b/packages/dim-si/README.md
index 3370c65..5b64961 100644
--- a/packages/dim-si/README.md
+++ b/packages/dim-si/README.md
@@ -133,30 +133,52 @@ bun add @isentropic/dim-si
### Derived
-| Quantity | Units |
-| --------------------- | ------------------------------------------------------------------- |
-| Area | `squareMeter`, `hectare` |
-| Volume | `cubicMeter`, `liter`, `milliliter`, `microliter` |
-| Velocity | `meterPerSecond` |
-| Acceleration | `meterPerSecondSquared` |
-| Force | `newton` |
-| Pressure | `pascal`, `bar`, `millibar` |
-| Energy | `joule`, `kilojoule`, `megajoule`, `kilowattHour` |
-| Power | `watt`, `milliwatt`, `kilowatt`, `megawatt`, `gigawatt`, `terawatt` |
-| Frequency | `hertz`, `kilohertz`, `megahertz`, `gigahertz`, `becquerel` |
-| Voltage | `volt`, `millivolt`, `kilovolt` |
-| Resistance | `ohm`, `milliohm`, `kilohm`, `megohm` |
-| Capacitance | `farad`, `microfarad`, `nanofarad`, `picofarad` |
-| Inductance | `henry`, `millihenry`, `microhenry` |
-| Charge | `coulomb` |
-| Magnetic Flux | `weber` |
-| Magnetic Flux Density | `tesla` |
-| Conductance | `siemens` |
-| Illuminance | `lux` |
-| Luminous Flux | `lumen` |
-| Catalytic Activity | `katal` |
-| Thermal Conductance | `wattPerKelvin`, `milliwattPerKelvin`, `kilowattPerKelvin` |
-| Absorbed Dose | `gray`, `sievert` |
+| Quantity | Units |
+| ----------------------- | ------------------------------------------------------------------- |
+| Area | `squareMeter`, `squareKilometer`, `squareCentimeter`, `hectare` |
+| Volume | `cubicMeter`, `liter`, `milliliter`, `microliter` |
+| Velocity | `meterPerSecond`, `kilometerPerHour` |
+| Acceleration | `meterPerSecondSquared` |
+| Force | `newton` |
+| Pressure | `pascal`, `bar`, `millibar`, `atmosphere` |
+| Energy | `joule`, `kilojoule`, `megajoule`, `kilowattHour` |
+| Power | `watt`, `milliwatt`, `kilowatt`, `megawatt`, `gigawatt`, `terawatt` |
+| Frequency | `hertz`, `kilohertz`, `megahertz`, `gigahertz`, `becquerel` |
+| Density | `kilogramPerCubicMeter`, `gramPerLiter`, `gramPerCubicCentimeter` |
+| Specific Volume | `cubicMeterPerKilogram` |
+| Momentum | `newtonSecond` |
+| Angular Velocity | `radianPerSecond`, `revolutionPerMinute` |
+| Angular Acceleration | `radianPerSecondSquared` |
+| Torque | `newtonMeter` |
+| Dynamic Viscosity | `pascalSecond` |
+| Kinematic Viscosity | `squareMeterPerSecond` |
+| Surface Tension | `newtonPerMeter` |
+| Wavenumber | `reciprocalMeter` |
+| Voltage | `volt`, `millivolt`, `kilovolt` |
+| Resistance | `ohm`, `milliohm`, `kilohm`, `megohm` |
+| Capacitance | `farad`, `microfarad`, `nanofarad`, `picofarad` |
+| Inductance | `henry`, `millihenry`, `microhenry` |
+| Charge | `coulomb`, `ampereHour`, `milliampereHour` |
+| Magnetic Flux | `weber` |
+| Magnetic Flux Density | `tesla` |
+| Conductance | `siemens` |
+| Electric Field Strength | `voltPerMeter` |
+| Permittivity | `faradPerMeter` |
+| Permeability | `henryPerMeter` |
+| Current Density | `amperePerSquareMeter` |
+| Illuminance | `lux` |
+| Luminous Flux | `lumen` |
+| Catalytic Activity | `katal` |
+| Thermal Conductance | `wattPerKelvin`, `milliwattPerKelvin`, `kilowattPerKelvin` |
+| Heat Capacity | `joulePerKelvin` |
+| Specific Heat Capacity | `joulePerKilogramKelvin` |
+| Specific Energy | `joulePerKilogram` |
+| Thermal Conductivity | `wattPerMeterKelvin` |
+| Absorbed Dose | `gray`, `sievert` |
+| Volumetric Flow Rate | `cubicMeterPerSecond`, `literPerSecond`, `literPerMinute` |
+| Mass Flow Rate | `kilogramPerSecond` |
+| Concentration | `molePerCubicMeter`, `molePerLiter` |
+| Molar Mass | `kilogramPerMole`, `gramPerMole` |
_\*
[Affine quantity](https://github.com/isentropic-dev/dim/blob/main/packages/dim-unit/README.md#affine-units)
diff --git a/packages/dim-si/deno.json b/packages/dim-si/deno.json
index 51e9078..453c9c6 100644
--- a/packages/dim-si/deno.json
+++ b/packages/dim-si/deno.json
@@ -48,7 +48,29 @@
"./illuminance": "./src/illuminance.ts",
"./absorbed-dose": "./src/absorbed-dose.ts",
"./catalytic-activity": "./src/catalytic-activity.ts",
- "./thermal-conductance": "./src/thermal-conductance.ts"
+ "./thermal-conductance": "./src/thermal-conductance.ts",
+ "./density": "./src/density.ts",
+ "./specific-volume": "./src/specific-volume.ts",
+ "./momentum": "./src/momentum.ts",
+ "./angular-velocity": "./src/angular-velocity.ts",
+ "./angular-acceleration": "./src/angular-acceleration.ts",
+ "./torque": "./src/torque.ts",
+ "./dynamic-viscosity": "./src/dynamic-viscosity.ts",
+ "./kinematic-viscosity": "./src/kinematic-viscosity.ts",
+ "./surface-tension": "./src/surface-tension.ts",
+ "./wavenumber": "./src/wavenumber.ts",
+ "./heat-capacity": "./src/heat-capacity.ts",
+ "./specific-heat-capacity": "./src/specific-heat-capacity.ts",
+ "./specific-energy": "./src/specific-energy.ts",
+ "./thermal-conductivity": "./src/thermal-conductivity.ts",
+ "./electric-field-strength": "./src/electric-field-strength.ts",
+ "./permittivity": "./src/permittivity.ts",
+ "./permeability": "./src/permeability.ts",
+ "./current-density": "./src/current-density.ts",
+ "./volumetric-flow-rate": "./src/volumetric-flow-rate.ts",
+ "./mass-flow-rate": "./src/mass-flow-rate.ts",
+ "./concentration": "./src/concentration.ts",
+ "./molar-mass": "./src/molar-mass.ts"
},
"version": "0.4.3"
}
diff --git a/packages/dim-si/src/absorbed-dose.ts b/packages/dim-si/src/absorbed-dose.ts
index 9825997..8a24aef 100644
--- a/packages/dim-si/src/absorbed-dose.ts
+++ b/packages/dim-si/src/absorbed-dose.ts
@@ -4,7 +4,8 @@
* SI unit: gray (Gy).
*
* Note: gray (absorbed radiation dose) and sievert (equivalent dose)
- * share this dimension. This is intentional per SI.
+ * share this dimension. This is intentional per SI — the type system
+ * cannot distinguish them.
*
* @example Creating dose quantities
* ```ts
diff --git a/packages/dim-si/src/angular-acceleration.ts b/packages/dim-si/src/angular-acceleration.ts
new file mode 100644
index 0000000..0c01c3b
--- /dev/null
+++ b/packages/dim-si/src/angular-acceleration.ts
@@ -0,0 +1,29 @@
+/**
+ * Angular acceleration units (T⁻²).
+ *
+ * SI unit: radian per second squared (rad/s²).
+ *
+ * @example Creating an angular acceleration
+ * ```ts
+ * import { radianPerSecondSquared } from "@isentropic/dim-si/angular-acceleration";
+ *
+ * const alpha = radianPerSecondSquared(5);
+ * ```
+ *
+ * @module
+ */
+
+import type { AngularAcceleration as AngularAccelerationDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { angularAcceleration } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI angular acceleration quantity. */
+export type AngularAcceleration = Linear;
+
+/** Radian per second squared (rad/s²) — SI unit of angular acceleration. */
+export const radianPerSecondSquared: BaseUnit = si.unit(
+ angularAcceleration,
+);
diff --git a/packages/dim-si/src/angular-velocity.ts b/packages/dim-si/src/angular-velocity.ts
new file mode 100644
index 0000000..efcdfa5
--- /dev/null
+++ b/packages/dim-si/src/angular-velocity.ts
@@ -0,0 +1,39 @@
+/**
+ * Angular velocity units (T⁻¹).
+ *
+ * SI unit: radian per second (rad/s).
+ *
+ * Note: angular velocity shares this dimension with frequency
+ * (hertz). This is intentional per SI — the type system cannot
+ * distinguish them.
+ *
+ * @example Converting RPM to radians per second
+ * ```ts
+ * import { radianPerSecond, revolutionPerMinute } from "@isentropic/dim-si/angular-velocity";
+ * import { valueIn } from "@isentropic/dim-si/ops";
+ *
+ * const engine = revolutionPerMinute(3000);
+ * valueIn(engine, radianPerSecond); // ~314.16
+ * ```
+ *
+ * @module
+ */
+
+import type { AngularVelocity as AngularVelocityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { angularVelocity } from "@isentropic/dim-isq";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI angular velocity quantity. */
+export type AngularVelocity = Linear;
+
+/** Radian per second (rad/s) — SI unit of angular velocity. */
+export const radianPerSecond: BaseUnit = si.unit(
+ angularVelocity,
+);
+
+/** Revolution per minute (rpm) — 2π/60 rad/s. */
+export const revolutionPerMinute: ScaledUnit =
+ radianPerSecond.scaled(2 * Math.PI / 60);
diff --git a/packages/dim-si/src/area.ts b/packages/dim-si/src/area.ts
index ecee908..517dd90 100644
--- a/packages/dim-si/src/area.ts
+++ b/packages/dim-si/src/area.ts
@@ -21,6 +21,7 @@ import { area } from "@isentropic/dim-isq";
import type { BaseUnit, ScaledUnit } from "./types.ts";
import type { Si } from "./system.ts";
import { si } from "./system.ts";
+import { centimeter, kilometer } from "./length.ts";
/** An SI area quantity. */
export type Area = Linear;
@@ -28,5 +29,15 @@ export type Area = Linear;
/** Square meter (m²) — SI unit of area. */
export const squareMeter: BaseUnit = si.unit(area);
+/** Square kilometer (km²) — 10⁶ square meters. */
+export const squareKilometer: ScaledUnit = squareMeter.scaled(
+ kilometer.scale ** 2,
+);
+
+/** Square centimeter (cm²) — 10⁻⁴ square meters. */
+export const squareCentimeter: ScaledUnit = squareMeter.scaled(
+ centimeter.scale ** 2,
+);
+
/** Hectare (ha) — 10000 square meters. */
export const hectare: ScaledUnit = squareMeter.scaled(10000);
diff --git a/packages/dim-si/src/charge.ts b/packages/dim-si/src/charge.ts
index fc88adc..61026ad 100644
--- a/packages/dim-si/src/charge.ts
+++ b/packages/dim-si/src/charge.ts
@@ -20,12 +20,24 @@
import type { Charge as ChargeDim } from "@isentropic/dim-isq";
import type { Linear } from "@isentropic/dim-unit";
import { charge } from "@isentropic/dim-isq";
-import type { BaseUnit } from "./types.ts";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
import type { Si } from "./system.ts";
import { si } from "./system.ts";
+import { ampere, milliampere } from "./current.ts";
+import { hour } from "./time.ts";
/** An SI charge quantity. */
export type Charge = Linear;
/** Coulomb (C) — SI unit of electric charge. */
export const coulomb: BaseUnit = si.unit(charge);
+
+/** Ampere-hour (Ah) — 3600 coulombs. */
+export const ampereHour: ScaledUnit = coulomb.scaled(
+ ampere.scale * hour.scale,
+);
+
+/** Milliampere-hour (mAh) — 3.6 coulombs. */
+export const milliampereHour: ScaledUnit = coulomb.scaled(
+ milliampere.scale * hour.scale,
+);
diff --git a/packages/dim-si/src/concentration.ts b/packages/dim-si/src/concentration.ts
new file mode 100644
index 0000000..10342f2
--- /dev/null
+++ b/packages/dim-si/src/concentration.ts
@@ -0,0 +1,36 @@
+/**
+ * Concentration units (N·L⁻³).
+ *
+ * SI unit: mole per cubic meter (mol/m³).
+ *
+ * @example Converting between concentration units
+ * ```ts
+ * import { molePerCubicMeter, molePerLiter } from "@isentropic/dim-si/concentration";
+ * import { valueIn } from "@isentropic/dim-si/ops";
+ *
+ * const c = molePerLiter(1);
+ * valueIn(c, molePerCubicMeter); // 1000
+ * ```
+ *
+ * @module
+ */
+
+import type { Concentration as ConcentrationDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { concentration } from "@isentropic/dim-isq";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+import { KILO } from "./prefixes.ts";
+
+/** An SI concentration quantity. */
+export type Concentration = Linear;
+
+/** Mole per cubic meter (mol/m³) — SI unit of concentration. */
+export const molePerCubicMeter: BaseUnit = si.unit(
+ concentration,
+);
+
+/** Mole per liter (mol/L) — 1000 mol/m³. */
+export const molePerLiter: ScaledUnit = molePerCubicMeter
+ .scaled(KILO);
diff --git a/packages/dim-si/src/current-density.ts b/packages/dim-si/src/current-density.ts
new file mode 100644
index 0000000..6468f62
--- /dev/null
+++ b/packages/dim-si/src/current-density.ts
@@ -0,0 +1,29 @@
+/**
+ * Current density units (I·L⁻²).
+ *
+ * SI unit: ampere per square meter (A/m²).
+ *
+ * @example Creating a current density
+ * ```ts
+ * import { amperePerSquareMeter } from "@isentropic/dim-si/current-density";
+ *
+ * const j = amperePerSquareMeter(1e6);
+ * ```
+ *
+ * @module
+ */
+
+import type { CurrentDensity as CurrentDensityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { currentDensity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI current density quantity. */
+export type CurrentDensity = Linear;
+
+/** Ampere per square meter (A/m²) — SI unit of current density. */
+export const amperePerSquareMeter: BaseUnit = si.unit(
+ currentDensity,
+);
diff --git a/packages/dim-si/src/density.ts b/packages/dim-si/src/density.ts
new file mode 100644
index 0000000..f9c7389
--- /dev/null
+++ b/packages/dim-si/src/density.ts
@@ -0,0 +1,44 @@
+/**
+ * Density units (M·L⁻³).
+ *
+ * SI unit: kilogram per cubic meter (kg/m³).
+ *
+ * @example Converting between density units
+ * ```ts
+ * import { gramPerCubicCentimeter, gramPerLiter, kilogramPerCubicMeter } from "@isentropic/dim-si/density";
+ * import { valueIn } from "@isentropic/dim-si/ops";
+ *
+ * const water = kilogramPerCubicMeter(1000);
+ * valueIn(water, gramPerLiter); // 1000
+ * valueIn(water, gramPerCubicCentimeter); // 1
+ * ```
+ *
+ * @module
+ */
+
+import type { Density as DensityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { density } from "@isentropic/dim-isq";
+import { roundScale } from "@isentropic/dim-unit";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+import { gram } from "./mass.ts";
+import { centimeter } from "./length.ts";
+import { liter } from "./volume.ts";
+
+/** An SI density quantity. */
+export type Density = Linear;
+
+/** Kilogram per cubic meter (kg/m³) — SI unit of density. */
+export const kilogramPerCubicMeter: BaseUnit = si.unit(density);
+
+/** Gram per liter (g/L) — numerically equivalent to kg/m³. */
+export const gramPerLiter: ScaledUnit = kilogramPerCubicMeter
+ .scaled(gram.scale / liter.scale);
+
+/** Gram per cubic centimeter (g/cm³) — 1000 kg/m³. */
+export const gramPerCubicCentimeter: ScaledUnit =
+ kilogramPerCubicMeter.scaled(
+ roundScale(gram.scale / centimeter.scale ** 3),
+ );
diff --git a/packages/dim-si/src/dynamic-viscosity.ts b/packages/dim-si/src/dynamic-viscosity.ts
new file mode 100644
index 0000000..358dea6
--- /dev/null
+++ b/packages/dim-si/src/dynamic-viscosity.ts
@@ -0,0 +1,29 @@
+/**
+ * Dynamic viscosity units (M·L⁻¹·T⁻¹).
+ *
+ * SI unit: pascal second (Pa·s).
+ *
+ * @example Creating a dynamic viscosity
+ * ```ts
+ * import { pascalSecond } from "@isentropic/dim-si/dynamic-viscosity";
+ *
+ * const water = pascalSecond(0.001);
+ * ```
+ *
+ * @module
+ */
+
+import type { DynamicViscosity as DynamicViscosityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { dynamicViscosity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI dynamic viscosity quantity. */
+export type DynamicViscosity = Linear;
+
+/** Pascal second (Pa·s) — SI unit of dynamic viscosity. */
+export const pascalSecond: BaseUnit = si.unit(
+ dynamicViscosity,
+);
diff --git a/packages/dim-si/src/electric-field-strength.ts b/packages/dim-si/src/electric-field-strength.ts
new file mode 100644
index 0000000..5f47dac
--- /dev/null
+++ b/packages/dim-si/src/electric-field-strength.ts
@@ -0,0 +1,29 @@
+/**
+ * Electric field strength units (M·L·T⁻³·I⁻¹).
+ *
+ * SI unit: volt per meter (V/m).
+ *
+ * @example Creating an electric field strength
+ * ```ts
+ * import { voltPerMeter } from "@isentropic/dim-si/electric-field-strength";
+ *
+ * const field = voltPerMeter(1000);
+ * ```
+ *
+ * @module
+ */
+
+import type { ElectricFieldStrength as ElectricFieldStrengthDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { electricFieldStrength } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI electric field strength quantity. */
+export type ElectricFieldStrength = Linear;
+
+/** Volt per meter (V/m) — SI unit of electric field strength. */
+export const voltPerMeter: BaseUnit = si.unit(
+ electricFieldStrength,
+);
diff --git a/packages/dim-si/src/frequency.ts b/packages/dim-si/src/frequency.ts
index 8a203fe..e76c601 100644
--- a/packages/dim-si/src/frequency.ts
+++ b/packages/dim-si/src/frequency.ts
@@ -4,7 +4,8 @@
* SI unit: hertz (Hz).
*
* Note: becquerel (radioactive decay rate) shares this dimension
- * with hertz (cycles per second). This is intentional per SI.
+ * with hertz (cycles per second). This is intentional per SI — the
+ * type system cannot distinguish them.
*
* @example Converting between frequency units
* ```ts
diff --git a/packages/dim-si/src/heat-capacity.ts b/packages/dim-si/src/heat-capacity.ts
new file mode 100644
index 0000000..b5fe0f8
--- /dev/null
+++ b/packages/dim-si/src/heat-capacity.ts
@@ -0,0 +1,27 @@
+/**
+ * Heat capacity units (M·L²·T⁻²·Θ⁻¹).
+ *
+ * SI unit: joule per kelvin (J/K).
+ *
+ * @example Creating a heat capacity
+ * ```ts
+ * import { joulePerKelvin } from "@isentropic/dim-si/heat-capacity";
+ *
+ * const capacity = joulePerKelvin(4186);
+ * ```
+ *
+ * @module
+ */
+
+import type { HeatCapacity as HeatCapacityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { heatCapacity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI heat capacity quantity. */
+export type HeatCapacity = Linear;
+
+/** Joule per kelvin (J/K) — SI unit of heat capacity. */
+export const joulePerKelvin: BaseUnit = si.unit(heatCapacity);
diff --git a/packages/dim-si/src/kinematic-viscosity.ts b/packages/dim-si/src/kinematic-viscosity.ts
new file mode 100644
index 0000000..1af308c
--- /dev/null
+++ b/packages/dim-si/src/kinematic-viscosity.ts
@@ -0,0 +1,29 @@
+/**
+ * Kinematic viscosity units (L²·T⁻¹).
+ *
+ * SI unit: square meter per second (m²/s).
+ *
+ * @example Creating a kinematic viscosity
+ * ```ts
+ * import { squareMeterPerSecond } from "@isentropic/dim-si/kinematic-viscosity";
+ *
+ * const water = squareMeterPerSecond(1e-6);
+ * ```
+ *
+ * @module
+ */
+
+import type { KinematicViscosity as KinematicViscosityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { kinematicViscosity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI kinematic viscosity quantity. */
+export type KinematicViscosity = Linear;
+
+/** Square meter per second (m²/s) — SI unit of kinematic viscosity. */
+export const squareMeterPerSecond: BaseUnit = si.unit(
+ kinematicViscosity,
+);
diff --git a/packages/dim-si/src/mass-flow-rate.ts b/packages/dim-si/src/mass-flow-rate.ts
new file mode 100644
index 0000000..766c8f5
--- /dev/null
+++ b/packages/dim-si/src/mass-flow-rate.ts
@@ -0,0 +1,29 @@
+/**
+ * Mass flow rate units (M·T⁻¹).
+ *
+ * SI unit: kilogram per second (kg/s).
+ *
+ * @example Creating a mass flow rate
+ * ```ts
+ * import { kilogramPerSecond } from "@isentropic/dim-si/mass-flow-rate";
+ *
+ * const flow = kilogramPerSecond(0.5);
+ * ```
+ *
+ * @module
+ */
+
+import type { MassFlowRate as MassFlowRateDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { massFlowRate } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI mass flow rate quantity. */
+export type MassFlowRate = Linear;
+
+/** Kilogram per second (kg/s) — SI unit of mass flow rate. */
+export const kilogramPerSecond: BaseUnit = si.unit(
+ massFlowRate,
+);
diff --git a/packages/dim-si/src/molar-mass.ts b/packages/dim-si/src/molar-mass.ts
new file mode 100644
index 0000000..a02cd30
--- /dev/null
+++ b/packages/dim-si/src/molar-mass.ts
@@ -0,0 +1,35 @@
+/**
+ * Molar mass units (M·N⁻¹).
+ *
+ * SI unit: kilogram per mole (kg/mol).
+ *
+ * @example Converting between molar mass units
+ * ```ts
+ * import { gramPerMole, kilogramPerMole } from "@isentropic/dim-si/molar-mass";
+ * import { valueIn } from "@isentropic/dim-si/ops";
+ *
+ * const water = gramPerMole(18.015);
+ * valueIn(water, kilogramPerMole); // 0.018015
+ * ```
+ *
+ * @module
+ */
+
+import type { MolarMass as MolarMassDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { molarMass } from "@isentropic/dim-isq";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+import { MILLI } from "./prefixes.ts";
+
+/** An SI molar mass quantity. */
+export type MolarMass = Linear;
+
+/** Kilogram per mole (kg/mol) — SI unit of molar mass. */
+export const kilogramPerMole: BaseUnit = si.unit(molarMass);
+
+/** Gram per mole (g/mol) — 10⁻³ kg/mol. */
+export const gramPerMole: ScaledUnit = kilogramPerMole.scaled(
+ MILLI,
+);
diff --git a/packages/dim-si/src/momentum.ts b/packages/dim-si/src/momentum.ts
new file mode 100644
index 0000000..b19d602
--- /dev/null
+++ b/packages/dim-si/src/momentum.ts
@@ -0,0 +1,27 @@
+/**
+ * Momentum units (M·L·T⁻¹).
+ *
+ * SI unit: newton second (N·s).
+ *
+ * @example Creating a momentum
+ * ```ts
+ * import { newtonSecond } from "@isentropic/dim-si/momentum";
+ *
+ * const impulse = newtonSecond(50);
+ * ```
+ *
+ * @module
+ */
+
+import type { Momentum as MomentumDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { momentum } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI momentum quantity. */
+export type Momentum = Linear;
+
+/** Newton second (N·s) — SI unit of momentum. */
+export const newtonSecond: BaseUnit = si.unit(momentum);
diff --git a/packages/dim-si/src/permeability.ts b/packages/dim-si/src/permeability.ts
new file mode 100644
index 0000000..961834d
--- /dev/null
+++ b/packages/dim-si/src/permeability.ts
@@ -0,0 +1,27 @@
+/**
+ * Permeability units (M·L·T⁻²·I⁻²).
+ *
+ * SI unit: henry per meter (H/m).
+ *
+ * @example Creating a permeability
+ * ```ts
+ * import { henryPerMeter } from "@isentropic/dim-si/permeability";
+ *
+ * const vacuum = henryPerMeter(1.2566e-6);
+ * ```
+ *
+ * @module
+ */
+
+import type { Permeability as PermeabilityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { permeability } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI permeability quantity. */
+export type Permeability = Linear;
+
+/** Henry per meter (H/m) — SI unit of permeability. */
+export const henryPerMeter: BaseUnit = si.unit(permeability);
diff --git a/packages/dim-si/src/permittivity.ts b/packages/dim-si/src/permittivity.ts
new file mode 100644
index 0000000..fe07f33
--- /dev/null
+++ b/packages/dim-si/src/permittivity.ts
@@ -0,0 +1,27 @@
+/**
+ * Permittivity units (M⁻¹·L⁻³·T⁴·I²).
+ *
+ * SI unit: farad per meter (F/m).
+ *
+ * @example Creating a permittivity
+ * ```ts
+ * import { faradPerMeter } from "@isentropic/dim-si/permittivity";
+ *
+ * const vacuum = faradPerMeter(8.854e-12);
+ * ```
+ *
+ * @module
+ */
+
+import type { Permittivity as PermittivityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { permittivity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI permittivity quantity. */
+export type Permittivity = Linear;
+
+/** Farad per meter (F/m) — SI unit of permittivity. */
+export const faradPerMeter: BaseUnit = si.unit(permittivity);
diff --git a/packages/dim-si/src/pressure.ts b/packages/dim-si/src/pressure.ts
index 5e954b8..e4d926a 100644
--- a/packages/dim-si/src/pressure.ts
+++ b/packages/dim-si/src/pressure.ts
@@ -35,3 +35,6 @@ export const bar: ScaledUnit = pascal.scaled(100000);
/** Millibar (mbar) — 100 pascals. */
export const millibar: ScaledUnit = bar.scaled(MILLI);
+
+/** Standard atmosphere (atm) — 101325 pascals. */
+export const atmosphere: ScaledUnit = pascal.scaled(101325);
diff --git a/packages/dim-si/src/specific-energy.ts b/packages/dim-si/src/specific-energy.ts
new file mode 100644
index 0000000..a3b4e29
--- /dev/null
+++ b/packages/dim-si/src/specific-energy.ts
@@ -0,0 +1,33 @@
+/**
+ * Specific energy units (L²·T⁻²).
+ *
+ * SI unit: joule per kilogram (J/kg).
+ *
+ * Note: specific energy shares this dimension with absorbed dose
+ * (gray/sievert). This is intentional per SI — the type system
+ * cannot distinguish them.
+ *
+ * @example Creating a specific energy
+ * ```ts
+ * import { joulePerKilogram } from "@isentropic/dim-si/specific-energy";
+ *
+ * const lhv = joulePerKilogram(43e6);
+ * ```
+ *
+ * @module
+ */
+
+import type { SpecificEnergy as SpecificEnergyDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { specificEnergy } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI specific energy quantity. */
+export type SpecificEnergy = Linear;
+
+/** Joule per kilogram (J/kg) — SI unit of specific energy. */
+export const joulePerKilogram: BaseUnit = si.unit(
+ specificEnergy,
+);
diff --git a/packages/dim-si/src/specific-heat-capacity.ts b/packages/dim-si/src/specific-heat-capacity.ts
new file mode 100644
index 0000000..7a9d7aa
--- /dev/null
+++ b/packages/dim-si/src/specific-heat-capacity.ts
@@ -0,0 +1,28 @@
+/**
+ * Specific heat capacity units (L²·T⁻²·Θ⁻¹).
+ *
+ * SI unit: joule per kilogram kelvin (J/(kg·K)).
+ *
+ * @example Creating a specific heat capacity
+ * ```ts
+ * import { joulePerKilogramKelvin } from "@isentropic/dim-si/specific-heat-capacity";
+ *
+ * const water = joulePerKilogramKelvin(4186);
+ * ```
+ *
+ * @module
+ */
+
+import type { SpecificHeatCapacity as SpecificHeatCapacityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { specificHeatCapacity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI specific heat capacity quantity. */
+export type SpecificHeatCapacity = Linear;
+
+/** Joule per kilogram kelvin (J/(kg·K)) — SI unit of specific heat capacity. */
+export const joulePerKilogramKelvin: BaseUnit = si
+ .unit(specificHeatCapacity);
diff --git a/packages/dim-si/src/specific-volume.ts b/packages/dim-si/src/specific-volume.ts
new file mode 100644
index 0000000..c11d673
--- /dev/null
+++ b/packages/dim-si/src/specific-volume.ts
@@ -0,0 +1,29 @@
+/**
+ * Specific volume units (M⁻¹·L³).
+ *
+ * SI unit: cubic meter per kilogram (m³/kg).
+ *
+ * @example Creating a specific volume
+ * ```ts
+ * import { cubicMeterPerKilogram } from "@isentropic/dim-si/specific-volume";
+ *
+ * const sv = cubicMeterPerKilogram(0.001);
+ * ```
+ *
+ * @module
+ */
+
+import type { SpecificVolume as SpecificVolumeDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { specificVolume } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI specific volume quantity. */
+export type SpecificVolume = Linear;
+
+/** Cubic meter per kilogram (m³/kg) — SI unit of specific volume. */
+export const cubicMeterPerKilogram: BaseUnit = si.unit(
+ specificVolume,
+);
diff --git a/packages/dim-si/src/surface-tension.ts b/packages/dim-si/src/surface-tension.ts
new file mode 100644
index 0000000..f070053
--- /dev/null
+++ b/packages/dim-si/src/surface-tension.ts
@@ -0,0 +1,29 @@
+/**
+ * Surface tension units (M·T⁻²).
+ *
+ * SI unit: newton per meter (N/m).
+ *
+ * @example Creating a surface tension
+ * ```ts
+ * import { newtonPerMeter } from "@isentropic/dim-si/surface-tension";
+ *
+ * const water = newtonPerMeter(0.0728);
+ * ```
+ *
+ * @module
+ */
+
+import type { SurfaceTension as SurfaceTensionDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { surfaceTension } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI surface tension quantity. */
+export type SurfaceTension = Linear;
+
+/** Newton per meter (N/m) — SI unit of surface tension. */
+export const newtonPerMeter: BaseUnit = si.unit(
+ surfaceTension,
+);
diff --git a/packages/dim-si/src/thermal-conductivity.ts b/packages/dim-si/src/thermal-conductivity.ts
new file mode 100644
index 0000000..64463a2
--- /dev/null
+++ b/packages/dim-si/src/thermal-conductivity.ts
@@ -0,0 +1,29 @@
+/**
+ * Thermal conductivity units (M·L·T⁻³·Θ⁻¹).
+ *
+ * SI unit: watt per meter kelvin (W/(m·K)).
+ *
+ * @example Creating a thermal conductivity
+ * ```ts
+ * import { wattPerMeterKelvin } from "@isentropic/dim-si/thermal-conductivity";
+ *
+ * const copper = wattPerMeterKelvin(385);
+ * ```
+ *
+ * @module
+ */
+
+import type { ThermalConductivity as ThermalConductivityDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { thermalConductivity } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI thermal conductivity quantity. */
+export type ThermalConductivity = Linear;
+
+/** Watt per meter kelvin (W/(m·K)) — SI unit of thermal conductivity. */
+export const wattPerMeterKelvin: BaseUnit = si.unit(
+ thermalConductivity,
+);
diff --git a/packages/dim-si/src/torque.ts b/packages/dim-si/src/torque.ts
new file mode 100644
index 0000000..d2ae598
--- /dev/null
+++ b/packages/dim-si/src/torque.ts
@@ -0,0 +1,30 @@
+/**
+ * Torque units (M·L²·T⁻²).
+ *
+ * SI unit: newton meter (N·m).
+ *
+ * Note: torque shares this dimension with energy (joule). This is
+ * intentional per SI — the type system cannot distinguish them.
+ *
+ * @example Creating a torque
+ * ```ts
+ * import { newtonMeter } from "@isentropic/dim-si/torque";
+ *
+ * const tau = newtonMeter(50);
+ * ```
+ *
+ * @module
+ */
+
+import type { Torque as TorqueDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { torque } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI torque quantity. */
+export type Torque = Linear;
+
+/** Newton meter (N·m) — SI unit of torque. */
+export const newtonMeter: BaseUnit = si.unit(torque);
diff --git a/packages/dim-si/src/velocity.ts b/packages/dim-si/src/velocity.ts
index 67b42d1..776061b 100644
--- a/packages/dim-si/src/velocity.ts
+++ b/packages/dim-si/src/velocity.ts
@@ -20,12 +20,19 @@
import type { Velocity as VelocityDim } from "@isentropic/dim-isq";
import type { Linear } from "@isentropic/dim-unit";
import { velocity } from "@isentropic/dim-isq";
-import type { BaseUnit } from "./types.ts";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
import type { Si } from "./system.ts";
import { si } from "./system.ts";
+import { kilometer } from "./length.ts";
+import { hour } from "./time.ts";
/** An SI velocity quantity. */
export type Velocity = Linear;
/** Meter per second (m/s) — SI unit of velocity. */
export const meterPerSecond: BaseUnit = si.unit(velocity);
+
+/** Kilometer per hour (km/h) — 1/3.6 m/s. */
+export const kilometerPerHour: ScaledUnit = meterPerSecond.scaled(
+ kilometer.scale / hour.scale,
+);
diff --git a/packages/dim-si/src/volumetric-flow-rate.ts b/packages/dim-si/src/volumetric-flow-rate.ts
new file mode 100644
index 0000000..6478f00
--- /dev/null
+++ b/packages/dim-si/src/volumetric-flow-rate.ts
@@ -0,0 +1,42 @@
+/**
+ * Volumetric flow rate units (L³·T⁻¹).
+ *
+ * SI unit: cubic meter per second (m³/s).
+ *
+ * @example Converting between flow rate units
+ * ```ts
+ * import { cubicMeterPerSecond, literPerMinute, literPerSecond } from "@isentropic/dim-si/volumetric-flow-rate";
+ * import { valueIn } from "@isentropic/dim-si/ops";
+ *
+ * const flow = cubicMeterPerSecond(1);
+ * valueIn(flow, literPerSecond); // 1000
+ * valueIn(flow, literPerMinute); // 60000
+ * ```
+ *
+ * @module
+ */
+
+import type { VolumetricFlowRate as VolumetricFlowRateDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { volumetricFlowRate } from "@isentropic/dim-isq";
+import type { BaseUnit, ScaledUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+import { liter } from "./volume.ts";
+import { minute } from "./time.ts";
+
+/** An SI volumetric flow rate quantity. */
+export type VolumetricFlowRate = Linear;
+
+/** Cubic meter per second (m³/s) — SI unit of volumetric flow rate. */
+export const cubicMeterPerSecond: BaseUnit = si.unit(
+ volumetricFlowRate,
+);
+
+/** Liter per second (L/s) — 10⁻³ m³/s. */
+export const literPerSecond: ScaledUnit =
+ cubicMeterPerSecond.scaled(liter.scale);
+
+/** Liter per minute (L/min) — 10⁻³/60 m³/s. */
+export const literPerMinute: ScaledUnit =
+ cubicMeterPerSecond.scaled(liter.scale / minute.scale);
diff --git a/packages/dim-si/src/wavenumber.ts b/packages/dim-si/src/wavenumber.ts
new file mode 100644
index 0000000..cf0079e
--- /dev/null
+++ b/packages/dim-si/src/wavenumber.ts
@@ -0,0 +1,27 @@
+/**
+ * Wavenumber units (L⁻¹).
+ *
+ * SI unit: reciprocal meter (m⁻¹).
+ *
+ * @example Creating a wavenumber
+ * ```ts
+ * import { reciprocalMeter } from "@isentropic/dim-si/wavenumber";
+ *
+ * const k = reciprocalMeter(100);
+ * ```
+ *
+ * @module
+ */
+
+import type { Wavenumber as WavenumberDim } from "@isentropic/dim-isq";
+import type { Linear } from "@isentropic/dim-unit";
+import { wavenumber } from "@isentropic/dim-isq";
+import type { BaseUnit } from "./types.ts";
+import type { Si } from "./system.ts";
+import { si } from "./system.ts";
+
+/** An SI wavenumber quantity. */
+export type Wavenumber = Linear;
+
+/** Reciprocal meter (m⁻¹) — SI unit of wavenumber. */
+export const reciprocalMeter: BaseUnit = si.unit(wavenumber);
diff --git a/packages/dim-unit/README.md b/packages/dim-unit/README.md
index c8d5d12..d67b670 100644
--- a/packages/dim-unit/README.md
+++ b/packages/dim-unit/README.md
@@ -178,6 +178,27 @@ The full set of linear/affine interactions:
| Affine + Affine | Error | — |
| scale/multiply/divide(Affine) | Error | — |
+## Floating-Point Scale Composition
+
+When computing scale factors from other unit scales — especially with
+exponentiation — IEEE 754 arithmetic can introduce small errors. For example,
+`centimeter.scale ** 3` produces `1.0000000000000002e-6` instead of `1e-6`.
+
+The `roundScale` utility rounds a computed scale factor to 15 significant
+digits, eliminating these artifacts while preserving all meaningful precision:
+
+```ts
+import { roundScale } from "@isentropic/dim-unit";
+
+// Without roundScale: gram.scale / centimeter.scale ** 3 = 999.9999999999999
+// With roundScale: 1000
+const gcm3 = kgPerM3.scaled(roundScale(gram.scale / centimeter.scale ** 3));
+```
+
+Use `roundScale` only when the factor is computed from other scales and the
+result has visible noise. Do not use it on direct expressions like `1000 / 3600`
+that are already the best float64 approximation of the intended value.
+
## Fluent API
The `q()` chain tracks linear/affine state at the type level. `QLinear` supports
diff --git a/packages/dim-unit/src/mod.ts b/packages/dim-unit/src/mod.ts
index 49d022d..1e57093 100644
--- a/packages/dim-unit/src/mod.ts
+++ b/packages/dim-unit/src/mod.ts
@@ -19,6 +19,7 @@
*/
export { defineUnitSystem } from "./system.ts";
+export { roundScale } from "./round-scale.ts";
export type {
AffineUnit,
BaseUnit,
diff --git a/packages/dim-unit/src/round-scale.ts b/packages/dim-unit/src/round-scale.ts
new file mode 100644
index 0000000..f70d7fa
--- /dev/null
+++ b/packages/dim-unit/src/round-scale.ts
@@ -0,0 +1,31 @@
+/**
+ * Round a computed scale factor to eliminate IEEE 754 composition noise.
+ *
+ * When composing scale factors from unit properties (e.g.,
+ * `gram.scale / centimeter.scale ** 3`), floating-point arithmetic can
+ * introduce small errors — `0.01 ** 3` produces `1.0000000000000002e-6`
+ * instead of `1e-6`. This function rounds to 15 significant digits,
+ * which preserves all meaningful precision while eliminating these
+ * artifacts.
+ *
+ * Use this when passing a computed expression to `.scaled()`. Do not
+ * use it on values that are already the best float64 approximation of
+ * the intended number (e.g., `1000 / 3600` for km/h) — rounding can
+ * make those less accurate.
+ *
+ * @param scale - The computed scale factor to round
+ * @returns The rounded scale factor
+ *
+ * @example Cleaning up composition noise
+ * ```ts
+ * import { roundScale } from "@isentropic/dim-unit";
+ *
+ * // Without roundScale: 0.01 ** 3 = 1.0000000000000002e-6
+ * // With roundScale: exactly 1e-6
+ * const factor = roundScale(gram.scale / centimeter.scale ** 3); // 1000
+ * const unit = baseUnit.scaled(factor);
+ * ```
+ */
+export function roundScale(scale: number): number {
+ return parseFloat(scale.toPrecision(15));
+}