PhetUnit
PhetUnit (from scenerystack/scenery-phet) is a small class representing a unit of measurement — "m", "N", "°C" — as a first-class value that can be attached to a numeric Property via its units option, rather than baked into a hardcoded format string wherever that Property's value gets displayed. It implements the Unit interface defined in scenerystack/axon, and exists so that a value's units, and the translated strings for formatting "value + units" both visually and for accessibility, travel with the Property itself instead of being re-specified at every display site.
scenery-phet ships several dozen ready-made instances built on PhetUnit — metersUnit, newtonsUnit, centimetersUnit, kelvinUnit, and so on, under scenery-phet/js/units/ — but they are not re-exported from the library's public barrel, so application code that wants one either constructs its own PhetUnit (as below) or imports a specific unit file directly.
import { PhetUnit } from 'scenerystack/scenery-phet';
import { NumberProperty, StringProperty } from 'scenerystack/axon';A minimal example
const wattsUnit = new PhetUnit( 'W', {
visualStandaloneStringProperty: new StringProperty( 'watts' ),
visualPatternStringProperty: new StringProperty( '{{value}} W' )
} );
wattsUnit.getVisualStandaloneString(); // 'watts'
wattsUnit.getVisualString( 42 ); // '42 W'
// Attach it to a Property so downstream display components can find it:
const powerProperty = new NumberProperty( 0, {
units: wattsUnit
} );Constructor
new PhetUnit<InputPropertyType extends TReadOnlyProperty<string>>(
name: string, // backwards-compatible short name, e.g. 'm' or 'm/s^2'
options?: {
visualStandaloneStringProperty?: InputPropertyType; // e.g. 'meters', for units-with-no-value display
visualPatternStringProperty?: InputPropertyType; // e.g. '{{value}} m', filled in via a value
accessiblePattern?: AccessibleValuePattern; // a Fluent pattern for PDOM/voicing strings
}
)All three options are optional and independent — a PhetUnit can support none, some, or all of standalone/visual/accessible strings. hasVisualStandaloneString, hasVisualString, and hasAccessibleString (all public readonly booleans) reflect which were supplied.
Methods
| Method | Effect |
|---|---|
getVisualStandaloneString() | Current value of visualStandaloneStringProperty; throws if not configured |
getVisualString( value, options? ) | Fills value into visualPatternStringProperty's pattern via StringUtils.fillIn; throws if not configured |
getAccessibleString( value, options? ) | Formats value through accessiblePattern; throws if not configured |
getDualString( value, options? ) | { visualString, accessibleString } — convenience wrapper calling both of the above |
getVisualStringProperty( valueProperty, options? ) | A reactive ReadOnlyProperty<string> version of getVisualString, derived from valueProperty |
getAccessibleStringProperty( valueProperty, options? ) | Reactive version of getAccessibleString |
getDualStringProperty( valueProperty, options? ) | Reactive version of getDualString |
getDependentProperties() | The string Properties this unit's formatting depends on — used internally to build correct derivations |
getFallbackAccessibleUnitsStringProperty( valueProperty, options? ) is also exported alongside PhetUnit (not a method on the class): given any numeric Property, it returns that Property's unit's accessible string Property if units is a PhetUnit, or a plain formatted-number string Property otherwise — a convenient one-liner for accessibility code that doesn't want to branch on whether a units value happens to be rich.
Where this connects to NumberProperty and NumberDisplay
Any Property (including NumberProperty) accepts a units option typed Unit | string | null. When a PhetUnit instance is passed there, NumberDisplay automatically picks it up: if numberProperty.units is a PhetUnit (not a plain string) and both hasVisualString and hasAccessibleString are true, NumberDisplay uses unit.getDualString(...) as its default number formatter instead of the plain numeric formatter — meaning a well-configured PhetUnit gives you correctly-formatted, translated, accessible value-plus-units text with no valuePattern option needed. NumberControl inherits this automatically, since it composes a NumberDisplay internally via its numberDisplayOptions.
The automatic NumberDisplay formatter requires both visual and accessible support
NumberDisplay only switches to a unit's own formatter when unit.hasVisualString && unit.hasAccessibleString are both true. A PhetUnit built with only visualPatternStringProperty (as in the minimal example above, which omits accessiblePattern) will not be picked up automatically — NumberDisplay falls back to its default numeric formatter, and valuePattern/decimalPlaces still need to be set explicitly. Call unit.getVisualString(...) directly if you only need visual formatting without wiring up a full AccessibleValuePattern.
Distinct from UnitConversionProperty
UnitConversionProperty converts a numeric value between units (e.g. meters to centimeters, via a multiplicative factor) — it changes what number you're holding. PhetUnit doesn't convert anything; it labels a Property's existing numeric value with a unit for display purposes. The two compose naturally: convert with UnitConversionProperty, then tag the result's units option with the matching PhetUnit.