@idle-screens/schema 3.8.0 → 3.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/FORMAT.md CHANGED
@@ -678,6 +678,9 @@ interpolation, and background drift is sampled at rest. These are documented
678
678
  trade-offs for a zero-dependency, renderer-free analysis tool.
679
679
 
680
680
  - `perceiveScene(spec, {t?, viewport?, seed?})` — one-call bundle: everything below.
681
+ **`t` is in milliseconds** (the MCP `previewScene` tool takes seconds and
682
+ converts; passing seconds here reads a self-typing block as one that never
683
+ finishes typing).
681
684
  - `perceiveSequenceFrame(seq, T, {viewport?, seed?, releasedBelow?})` — the
682
685
  same bundle for one frame of a **sequence** at global time `T`: resolves the
683
686
  segment (reported as `segment: {index, key, localT, held?}`) and, when the
package/dist/index.d.ts CHANGED
@@ -843,6 +843,13 @@ interface IdleSequence {
843
843
  }
844
844
 
845
845
  declare function validateSpec(spec: unknown): ValidationResult;
846
+ /**
847
+ * Dot-paths (numeric layer indices, as `steerablePaths` spells them) of every
848
+ * property the validator flags as unknown or misplaced — i.e. fields the
849
+ * renderer never reads, so steering them does nothing. Pure: unlike
850
+ * `validateSpec` it never normalises colours into the caller's spec.
851
+ */
852
+ declare function ignoredPropertyPaths(spec: unknown): string[];
846
853
  /** Narrowing helper: validate + cast. Throws with a joined message when invalid. */
847
854
  declare function assertValidSpec(spec: unknown): SaverSpec;
848
855
  /**
@@ -1235,6 +1242,12 @@ declare function morphNothingMorphable(a: SaverSpec, b: SaverSpec, opts?: {
1235
1242
  * (id, label, schemaVersion, seed, units, kind, type, key) are excluded —
1236
1243
  * they describe structure, not tuneable values.
1237
1244
  *
1245
+ * Properties the validator flags as unknown or misplaced (e.g. `angle` on a
1246
+ * gradient background, `blend` inside a sprite) are excluded too: the
1247
+ * renderer never reads them, so advertising them invites a steer that
1248
+ * silently does nothing. Same source of truth as validateSpec's
1249
+ * "will be ignored" warnings (`ignoredPropertyPaths`).
1250
+ *
1238
1251
  * Layer keys are NOT substituted: paths always use numeric indices.
1239
1252
  * Consumers can map to key-based paths via resolveSpecPath if needed.
1240
1253
  */
@@ -1894,6 +1907,14 @@ declare function segmentRenderSeed(seq: IdleSequence, index: number): number | u
1894
1907
  * `SpecInstance`. `undefined` when there's no bed or no derivable seed.
1895
1908
  */
1896
1909
  declare function bedRenderSeed(seq: IdleSequence): number | undefined;
1910
+ /**
1911
+ * Whether any scene in the sequence — the sequence itself or any segment —
1912
+ * declares a `finish`. Mirrors `SequenceInstance`'s construction-time check:
1913
+ * a finish anywhere allocates the presentation pass for the instance's whole
1914
+ * lifetime, so this is also what `sequenceSwapCompatible` must agree on
1915
+ * before and after a swap.
1916
+ */
1917
+ declare function sequenceWantsFinish(seq: IdleSequence): boolean;
1897
1918
  /**
1898
1919
  * Whether a republished sequence can be swapped into a live
1899
1920
  * `SequenceInstance` in place of `prev` without a remount
@@ -1909,6 +1930,19 @@ declare function bedRenderSeed(seq: IdleSequence): number | undefined;
1909
1930
  * the next boundary, leaving the room half-swapped;
1910
1931
  * - a `bed` on both sides or neither, structural twins with the same seed
1911
1932
  * when present;
1933
+ * - the same top-level `seq.seed`, compared normalized (like the mount-time
1934
+ * seed itself) so a change of an exact multiple of 2^32 isn't flagged —
1935
+ * but ONLY when either side has a sequence-level `finish`: that's the one
1936
+ * place `seq.seed` reaches rendering on its own (`frameFinishSeed` uses the
1937
+ * instance's mount-time seed for a sequence-level finish's grain, which a
1938
+ * swap cannot update). Without a sequence-level `finish`, every consumer of
1939
+ * `seq.seed` is a `segmentRenderSeed`/`bedRenderSeed` fallback, and those
1940
+ * are already compared per segment and for the bed below — so when every
1941
+ * segment and the bed carry their own seed, `seq.seed` is dead weight and
1942
+ * changing it is free;
1943
+ * - the same finish presence (`sequenceWantsFinish`) — the presentation
1944
+ * pass is allocated once at construction, so a swap that adds or removes
1945
+ * every `finish` in the sequence cannot (de)allocate it;
1912
1946
  * - the same `loop` and `sync` (absent `sync` is `'mount'`);
1913
1947
  * - the same `duration`, `advance` (absent is `'auto'`) and `transition`
1914
1948
  * (absent is `cut`; `text` on a morph defaults to `'step'`) on every
@@ -2114,6 +2148,164 @@ declare const WARP_TUNNEL_SPEC: SaverSpec;
2114
2148
  */
2115
2149
  declare const THERMAL_FIELD_SPEC: SaverSpec;
2116
2150
 
2151
+ /**
2152
+ * Sparse Night — emptiness, declared as intent.
2153
+ * A star-grain field (radius under 0.001 — the rung FORMAT.md's ladder calls
2154
+ * texture, never the subject) over near-black, one faint linked pentagon as
2155
+ * the only figure, and a single satellite that flares for three seconds out of
2156
+ * every eighteen. Measured coverage sits around one percent, which `adviseSpec`
2157
+ * would flag as `sparse-scene` at every legal count — the spec's
2158
+ * `density: 'sparse'` declaration is the point of this example: it withholds
2159
+ * that advisory AND opts the scene into `density-mismatch` instead, so the
2160
+ * emptiness is a claim the perception API checks rather than a gap it nags
2161
+ * about. Before `density` shipped, restraint like this could not pass advise
2162
+ * clean; the one-mark house style sat at the suite floor for exactly this
2163
+ * reason.
2164
+ */
2165
+ declare const SPARSE_NIGHT_SPEC: SaverSpec;
2166
+
2167
+ /**
2168
+ * Typed Cue — textBlock.reveal, both moods.
2169
+ * Two self-typing captions over near-black. The upper one types at ten
2170
+ * graphemes a second with a blinking caret (`mode: 'typewriter'` — the classic
2171
+ * terminal reveal; `speed` makes progress a pure function of scene time, so
2172
+ * every viewer types the same line on the same clock from its own mount). The
2173
+ * lower one arrives as a wave of overlapping fades (`mode: 'glyphFade'`,
2174
+ * `fade: 0.4` — each glyph ramps in over 40% of the progress window, which
2175
+ * reads as a soft dissolve rather than typing) and carries no caret. Both
2176
+ * blocks declare `opacity` so the path is steerable, and layout always runs on
2177
+ * the FULL text — reveal only masks glyphs, so lines never reflow mid-type.
2178
+ *
2179
+ * Trap, documented in the playbook and true here too: at t = 0 a self-typing
2180
+ * block has typed nothing, so `previewScene` at the default instant looks
2181
+ * empty — preview at t ≥ 10 s to see the words. To swap the line live, glide
2182
+ * `reveal.progress` to 0, step the `text`, glide back (one `setTrack` call).
2183
+ *
2184
+ * The scan band is the one non-text layer, and it is load-bearing twice over:
2185
+ * a screensaver of two static text blocks is a document, not a screensaver
2186
+ * (`text-heavy`), and the band gives the words something to sit on — a slow
2187
+ * refresh sweep passing under the type. Note the units: `perceiveScene` takes
2188
+ * `t` in MILLISECONDS while the MCP `previewScene` tool takes seconds (the
2189
+ * worker converts); passing seconds to the library reads as a block that
2190
+ * never finishes typing.
2191
+ */
2192
+ declare const TYPED_CUE_SPEC: SaverSpec;
2193
+
2194
+ /**
2195
+ * Signal Board — the instrument panel, laid out by the format.
2196
+ * A 3×3 table of data bars with their labels in a matching table, one
2197
+ * monospace caption, and a phosphor sweep crossing the frame every ~90
2198
+ * seconds. The teaching layer is `layout: { type: 'table', columns: 3 }`:
2199
+ * nine bars and nine labels are TWO layers, not eighteen positioned blocks —
2200
+ * entity i reads `values[i]` / `strings[i]` in reading order, and each bar
2201
+ * draws `length × values[i] / max` from its cell. `values` are paint, so
2202
+ * `setParam("readout.sprite.values", [...])` glides every bar at once, which
2203
+ * is the whole point of the shape: a live readout that never re-publishes.
2204
+ */
2205
+ declare const SIGNAL_BOARD_SPEC: SaverSpec;
2206
+
2207
+ /**
2208
+ * Phase Duet — three layers on one clock.
2209
+ * A grid of sixty dots ripples as a traveling wave (`pulse.wave`), three rings
2210
+ * swell, and one soft heart breathes — and none of them drift apart, because
2211
+ * all three declare the same `clock`. `clock` is the format's answer to
2212
+ * coincidence: without it, `pulse`, `grow` and `cycle` run on per-entity
2213
+ * seeded phases, so two layers with the same period never line up (they are
2214
+ * a room full of people, not a duet). With one shared `clock: { phase: 0,
2215
+ * rate: 1 }` they breathe in step and stay there — period ÷ rate must stay
2216
+ * ≥ 1000 ms, which is why every layer here runs a 6000 ms cycle.
2217
+ */
2218
+ declare const PHASE_DUET_SPEC: SaverSpec;
2219
+
2220
+ /**
2221
+ * Web Work — a randomised graph that fades with distance.
2222
+ * Forty-four drifting nodes wired `mode: 'random'` (a fixed deterministic
2223
+ * wiring, not k-nearest — the difference is topology: nearest gives
2224
+ * crystalline clusters, random gives a web that crosses itself) with
2225
+ * `falloff: true`, so an edge's alpha fades toward `maxDist` instead of
2226
+ * popping in at the cutoff. The second layer is a row of `orient: true`
2227
+ * strokes: the mark's +x axis turns to follow the entity's heading, so each
2228
+ * one reads as a wind tick rather than a stamp. Both are the difference
2229
+ * between "lines between dots" and a drawing.
2230
+ */
2231
+ declare const WEB_WORK_SPEC: SaverSpec;
2232
+
2233
+ /**
2234
+ * Shard Fall — tumbling shapes and a passing shadow.
2235
+ * Two features nothing else here uses. `rotate` is STATIC per-entity rotation
2236
+ * (a range seeded per entity), which is not the same as `spin: [0, 0]` — a
2237
+ * zero spin speed renders the seeded start angle as 0, so "tilted but not
2238
+ * turning" was previously inexpressible; here the shards are thrown at
2239
+ * `rotate: [-180, 180]` AND tumbling on their own `spin` range, so no two
2240
+ * facets agree on an angle. The shadow layer demonstrates `blend:
2241
+ * 'multiply'`: two large soft discs darkening a pale plate as they wander,
2242
+ * which is how the format does shadow and silhouette — `lighter` adds light,
2243
+ * `multiply` removes it, and neither needs a sprite that looks like darkness.
2244
+ * The polygons use `points` (unit coordinates scaled by `radius`), which are
2245
+ * paint, so two shards with the same point count will morph into each other.
2246
+ */
2247
+ declare const SHARD_FALL_SPEC: SaverSpec;
2248
+
2249
+ /**
2250
+ * Murmur — a flock with no birds in it.
2251
+ * Six hundred and twenty entities: two registers of streaks (260 each) on
2252
+ * harmonic `wander` with `coherence` near 1, so each layer folds and wheels as
2253
+ * one body, and a static grain layer behind them. Nothing here
2254
+ * interacts — no entity reads another's position — which is the trick the
2255
+ * format is built on: a shared harmonic set plus a wide speed range reads as
2256
+ * a murmuration while staying a pure function of (seed, t), so it replays
2257
+ * identically and seeks instantly. `density: 'dense'` is doing real work:
2258
+ * past 500 entities `adviseSpec` raises `dense-scene`, and the declaration
2259
+ * says the crowding is the subject rather than a mistake — while still opting
2260
+ * into `density-mismatch` if the scene ever measures as empty instead.
2261
+ */
2262
+ declare const MURMUR_SPEC: SaverSpec;
2263
+
2264
+ /**
2265
+ * Three Movements — one ground, three scenes, two kinds of transition.
2266
+ *
2267
+ * The sequence envelope, exercised end to end:
2268
+ *
2269
+ * - **bed.** A drifting field with a few motes, drawn under every segment on
2270
+ * the SEQUENCE clock — it does not reset at a boundary and a
2271
+ * `sequence.segment` steer cannot rewind it. That is the fix for the
2272
+ * boundary rewind every ambient sequence suffers: put the motion that must
2273
+ * be continuous in the bed, the slide content in the segments. (Segments
2274
+ * deliberately declare no `background`: over a bed it is never painted on
2275
+ * the web, and the validator warns `bed-hides-segment-background` — the
2276
+ * native tvOS player, which ignores the bed, will show them over black
2277
+ * until it learns the field. Prefer a bed the piece can survive without.)
2278
+ * - **morph + text crossfade.** Segments 1 → 2 are structural twins differing
2279
+ * only in colour and words, so the transition can MORPH: every numeric and
2280
+ * hex value glides over 2500 ms, and because the words differ and the
2281
+ * transition declares `text: 'crossfade'`, the outgoing caption fades under
2282
+ * the incoming one instead of switching whole-frame. Without the crossfade
2283
+ * declaration the morph would still glide — colour alone gives it a
2284
+ * `hasGlide` — just with the caption stepping on the first frame instead of
2285
+ * fading; the validator only says `morph-nothing-morphable` for a pair
2286
+ * whose differences are all values morph cannot glide — strings
2287
+ * (`textBlock.text` above all), booleans, mismatched arrays — which this
2288
+ * one isn't.
2289
+ * - **fade.** Segments 2 → 3 have nothing structurally in common, so a morph
2290
+ * is impossible and a `fade` is the honest transition: the outgoing scene
2291
+ * keeps animating on its own canvas for 3000 ms while the incoming one
2292
+ * fades up. The cost is two live segments during the window, which is why
2293
+ * the lowest capability tier degrades a fade to a cut
2294
+ * (`fade-degrades-on-low-tier` — informational, and this sequence keeps the
2295
+ * fade because the web and native players both honour it).
2296
+ * - **finish.** One grain-and-dither pass over the composed frame — bed,
2297
+ * segment and any fade together — the sequence-level screen no segment can
2298
+ * override.
2299
+ *
2300
+ * The final segment carries no duration, so it holds indefinitely; `loop` is
2301
+ * therefore false (`loop: true` is incompatible with a durationless segment).
2302
+ * `sync: 'mount'` is the default and the reason a joiner always sees movement
2303
+ * one: pre-roll semantics. An `epoch` sequence would instead start every
2304
+ * viewer at the room's shared clock — right for a wall of screens, wrong for
2305
+ * a piece that should start when you look at it.
2306
+ */
2307
+ declare const THREE_MOVEMENTS_SEQUENCE: IdleSequence;
2308
+
2117
2309
  /** Catalog entry for a bundled schema example. */
2118
2310
  interface SchemaExample {
2119
2311
  id: string;
@@ -2122,9 +2314,24 @@ interface SchemaExample {
2122
2314
  }
2123
2315
  /** Ordered catalog of bundled schema examples. Add new specs as standalone files, then register here. */
2124
2316
  declare const SCHEMA_EXAMPLES: readonly SchemaExample[];
2317
+ /** Catalog entry for a bundled idle-sequence example. */
2318
+ interface SequenceExample {
2319
+ id: string;
2320
+ label: string;
2321
+ sequence: IdleSequence;
2322
+ }
2323
+ /**
2324
+ * Ordered catalog of bundled idle-sequence examples.
2325
+ *
2326
+ * Deliberately separate from SCHEMA_EXAMPLES: that catalog is typed
2327
+ * `SaverSpec[]` and its consumers (manifests, batch compile, the MCP examples
2328
+ * resource) rely on that. A sequence is a different top-level format, so it
2329
+ * gets its own list rather than widening theirs.
2330
+ */
2331
+ declare const EXAMPLE_SEQUENCES: readonly SequenceExample[];
2125
2332
  /** All example specs in catalog order (tests, batch compile). */
2126
2333
  declare const EXAMPLE_SPECS: SaverSpec[];
2127
2334
  /** Lookup by saver id. */
2128
2335
  declare const EXAMPLE_BY_ID: Readonly<Record<string, SaverSpec>>;
2129
2336
 
2130
- export { AQUARIUM_SPEC, AURORA_SPEC, type BackgroundDrift, type BackgroundSpec, type BandSpec, COHESION_T, COMETS_SPEC, CONSTELLATION_SPEC, type CapabilityTier, type CohesionRead, type CycleSpec, DASHBOARD_SPEC, DITHER_ALPHA, DITHER_TILE, type DominanceEntry, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, FACETS_SPEC, FIELD_BUCKET_MS, FIELD_DRIFT_DEFAULT_AMOUNT, FIELD_RASTER_SHORT_SIDE, FIELD_RASTER_SHORT_SIDE_LOW, FINISH_ANIMATE_HZ, type FieldBackground, type FieldDrift, type FinishPass, type FinishSpec, GRAIN_ALPHA, GRAIN_TILE, type GradientStop, HAIKU_SPEC, type IdleSequence, LANTERNS_SPEC, LIMITS, LOBBY_TALK_SPEC, type LayerCohesion, type LayerMotionStats, type LayerSnapshot, type LayerSpec, type LinkEdge, type LuminanceGrid, type LuminanceGridOptions, MATRIX_RAIN_SPEC, type MotionEase, type MotionSpec, NOSTALGHIA_CANDLE_SPEC, ORRERY_SPEC, PINGS_SPEC, POLYGONS_SPEC, PROCESSION_SPEC, type PerceiveOptions, type PerceiveSequenceOptions, type Placed, RAIN_SPEC, RELAY_BOARD_SPEC, type ResolveOptions, type ResolvedSegment, type RevealState, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SceneDescription, type SceneDiff, type ScenePerception, type SceneSnapshot, type SchemaExample, type ScreenOp, type SequenceFramePerception, type SequenceMountContext, type SequenceSaverInstance, type SequenceSaverPlugin, type SequenceSegment, type SequenceTransition, type SpecError, type SpecMountContext, type SpecWarning, type SpriteSpec, type SteerDelta, THERMAL_FIELD_SPEC, type TextBlockAnchor, type TextBlockLine, type TextMetricsClass, type TextRevealInput, type TextRevealSpec, type TextRole, type TextSpriteInfo, type ValidationResult, WARP_MAX_SCALE, WARP_NEAR, WARP_TUNNEL_SPEC, type WanderOsc, type WarningBox, adviseSequence, adviseSpec, alphaAt, applyDeltasToSpec, assertValidSequence, assertValidSpec, bayerMatrix, bayerTilePixels, bedRenderSeed, breakTextBlock, buildEntities, canMorph, cohesionOf, compileSaver, compileSequence, createFinishPass, createSceneCanvas, describeScene, diffScenes, dominanceRanking, easeSmooth, emitEnvelope, emitWindow, fieldAt, fieldOctaves, fieldRgb, fieldRgbAt, fieldSampleTime, finishStrength, grainOffset, grainTilePixels, graphemeClusters, hasHotSwapSequence, headingAt, hexToRgb255, latticeHash, layerCohesion, lerpSpec, lifeAlphaAt, linkEdges, linkPairs, luminanceGrid, manifestFor, morphChainRoot, morphNothingMorphable, motionStats, normalizeSeed, perceiveScene, perceiveSequenceFrame, pickScreenOp, positionAt, presentWithFinish, renderBrailleMap, renderDensityMap, resolveSegment, resolveSpecPath, revealState, rgb255Luma, rotationAt, seamCauseOf, seamsWorthWarning, segmentRenderSeed, segmentStart, sequenceSteerablePaths, sequenceSwapCompatible, sizeAt, spriteIndexAt, spriteVariants, steerablePaths, structuralSignature, textBlockAnchorOffset, textMetricsClassFor, textSprites, textStringsDiffer, textStringsOf, textWidthEm, validateSequence, validateSpec };
2337
+ export { AQUARIUM_SPEC, AURORA_SPEC, type BackgroundDrift, type BackgroundSpec, type BandSpec, COHESION_T, COMETS_SPEC, CONSTELLATION_SPEC, type CapabilityTier, type CohesionRead, type CycleSpec, DASHBOARD_SPEC, DITHER_ALPHA, DITHER_TILE, type DominanceEntry, EXAMPLE_BY_ID, EXAMPLE_SEQUENCES, EXAMPLE_SPECS, type Entity, FACETS_SPEC, FIELD_BUCKET_MS, FIELD_DRIFT_DEFAULT_AMOUNT, FIELD_RASTER_SHORT_SIDE, FIELD_RASTER_SHORT_SIDE_LOW, FINISH_ANIMATE_HZ, type FieldBackground, type FieldDrift, type FinishPass, type FinishSpec, GRAIN_ALPHA, GRAIN_TILE, type GradientStop, HAIKU_SPEC, type IdleSequence, LANTERNS_SPEC, LIMITS, LOBBY_TALK_SPEC, type LayerCohesion, type LayerMotionStats, type LayerSnapshot, type LayerSpec, type LinkEdge, type LuminanceGrid, type LuminanceGridOptions, MATRIX_RAIN_SPEC, MURMUR_SPEC, type MotionEase, type MotionSpec, NOSTALGHIA_CANDLE_SPEC, ORRERY_SPEC, PHASE_DUET_SPEC, PINGS_SPEC, POLYGONS_SPEC, PROCESSION_SPEC, type PerceiveOptions, type PerceiveSequenceOptions, type Placed, RAIN_SPEC, RELAY_BOARD_SPEC, type ResolveOptions, type ResolvedSegment, type RevealState, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SHARD_FALL_SPEC, SIGNAL_BOARD_SPEC, SNOWFALL_SPEC, SPARSE_NIGHT_SPEC, type SaverSpec, type SceneDescription, type SceneDiff, type ScenePerception, type SceneSnapshot, type SchemaExample, type ScreenOp, type SequenceExample, type SequenceFramePerception, type SequenceMountContext, type SequenceSaverInstance, type SequenceSaverPlugin, type SequenceSegment, type SequenceTransition, type SpecError, type SpecMountContext, type SpecWarning, type SpriteSpec, type SteerDelta, THERMAL_FIELD_SPEC, THREE_MOVEMENTS_SEQUENCE, TYPED_CUE_SPEC, type TextBlockAnchor, type TextBlockLine, type TextMetricsClass, type TextRevealInput, type TextRevealSpec, type TextRole, type TextSpriteInfo, type ValidationResult, WARP_MAX_SCALE, WARP_NEAR, WARP_TUNNEL_SPEC, WEB_WORK_SPEC, type WanderOsc, type WarningBox, adviseSequence, adviseSpec, alphaAt, applyDeltasToSpec, assertValidSequence, assertValidSpec, bayerMatrix, bayerTilePixels, bedRenderSeed, breakTextBlock, buildEntities, canMorph, cohesionOf, compileSaver, compileSequence, createFinishPass, createSceneCanvas, describeScene, diffScenes, dominanceRanking, easeSmooth, emitEnvelope, emitWindow, fieldAt, fieldOctaves, fieldRgb, fieldRgbAt, fieldSampleTime, finishStrength, grainOffset, grainTilePixels, graphemeClusters, hasHotSwapSequence, headingAt, hexToRgb255, ignoredPropertyPaths, latticeHash, layerCohesion, lerpSpec, lifeAlphaAt, linkEdges, linkPairs, luminanceGrid, manifestFor, morphChainRoot, morphNothingMorphable, motionStats, normalizeSeed, perceiveScene, perceiveSequenceFrame, pickScreenOp, positionAt, presentWithFinish, renderBrailleMap, renderDensityMap, resolveSegment, resolveSpecPath, revealState, rgb255Luma, rotationAt, seamCauseOf, seamsWorthWarning, segmentRenderSeed, segmentStart, sequenceSteerablePaths, sequenceSwapCompatible, sequenceWantsFinish, sizeAt, spriteIndexAt, spriteVariants, steerablePaths, structuralSignature, textBlockAnchorOffset, textMetricsClassFor, textSprites, textStringsDiffer, textStringsOf, textWidthEm, validateSequence, validateSpec };