Scale
Design-resolution-aware scaling for numbers, arrays, and AAs.
scale multiplies a numeric value by
(actual device display width) / (configured design-resolution width),
computed once at app boot — so a layout authored at one resolution renders proportionally correct at another.
Setup — config file and manifest, both required
flash-theater.config.json declares the baseline your pixel values were
authored against:
{
"designResolution": "hd"
}
The Roku manifest's ui_resolutions must declare
every tier you want scale to ever do
anything for — a single-tier manifest makes Roku's own OS-level auto-scaling absorb the difference first,
silently turning every scale call into a permanent no-op:
# manifest — MUST declare every resolution tier you want scale to act on
ui_resolutions=fhd,hdDeclaration form
scale field/state/derived/watch/read —
scales a number directly, or an array/assocarray element-wise, one level deep.
scale field cardWidth: integer = 300
scale field cardHeight: integer = 180
scale derived cardTranslation: object = [810, 450]Statement form
A template {expr} binding can't be scaled
directly — compute the scaled value once via scale <local> = <expr> and
store it on the data instead:
private function renumbered(days: object): object {
updated = []
for (i = 0 to days.Count() - 1) {
day = days[i]
scale y = i * 40
day.y = y
updated.Push(day)
}
return updated
}Reference implementation — every app, not just one
Unlike every other topic on this site, scale has no single dedicated chapter
app of its own — it's used pervasively across all 14 apps/* workspaces (every
rootWidth/rootHeight, every translation,
every chapter app's own layout), since a real device pass needs every screen scaled consistently, not just one
demo of the mechanism in isolation. apps/animation-demo's
BounceButtonDemo.thr and apps/sample-app's
ScheduleList.thr (the two files excerpted above) are two ordinary,
representative examples, not special cases. See findings/scale-config-and-codegen.md
for the compile-time design and findings/scale-device-verification.md for the
live-device lessons (manifest tiers, designResolution choice, partial-scale
focus breakage) — the closest thing this feature has to a "which chapter covers this" index, since the real
answer is "all of them."
⚠️ Not (yet) supported
- ○
node-typed fields are excluded from scaling entirely. - ○ Integer scaling truncates toward zero, never rounds —
10 * 0.667 = 6, not 7. - ○ Arrays/assocarrays scale one level deep only — a nested array's inner values pass through unscaled.
- ○ No compile-time type check on
scale derived/watch/read— ascaled non-numeric expression is a silent runtime no-op, not a diagnostic. - ○
scale watch/readhave an unresolved double-scaling risk if a store value was already scaled by whoever wrote it. - ○ Partial adoption across a screen with cross-component focus/LRUD dependencies can break directional navigation between a scaled and an unscaled sibling — treat
scaleadoption as closer to all-or-nothing per app.
Exact grammar: GRAMMAR.md. Full feature status: docs/features.md.