# `@combos-fun/plugin-renderer-text` — Agent notes

Read only for 2D text labels. This is not bitmap-atlas text.

```ts
import {
  Text,
  TextSystem,
  type TextParams,
  type TextStyleInput,
  parseTextColor,
  splitTextStyle,
} from '@combos-fun/plugin-renderer-text';
```

`Text.componentName = 'Text'`; `TextSystem.systemName = 'Text'`.

`TextParams.text` is required. `style` is optional and starts with `{ fontSize: 20 }`; supplied fields merge into that object. `TextStyleInput` accepts Pixi v8 `TextStyle` fields plus Combos-only `backgroundColor`.

```ts
score.addComponent(new Text({
  text: 'Score: 0',
  style: { fontSize: 32, fill: 0xffffff },
}));
```

For dynamic, translatable text, keep values in named `replacements`; do not
concatenate them into `text` and do not invent translation IDs:

```ts
score.addComponent(new Text({
  text: '{player} scored {score} points',
  replacements: { player: 'Alice', score: 100 },
}));
```

**MUST** set `TextSystem` `sourceLocale` to the game's written language as a
BCP 47 tag (`en`, `en-US`, `zh-CN`, `ja-JP`, …). Match the `Text` literals,
not the player device locale. Omitting it disables host i18n.

```ts
new TextSystem({
  sourceLocale: 'zh-CN',
  sourceTexts: ['开始游戏', '下一关已解锁'],
});
```

Pass **every** later-screen template in `sourceTexts` so the first
`requestI18n` translates the full catalog before `ready`. The system keeps one
growing session catalog of source templates and translations: new labels are
added to it, and going back to earlier copy looks up that catalog instead of
rebuilding from the current screen. You can also call
`textSystem.declareSourceTexts([...])` during `onSystemsBootstrapComplete`.

`Text` is not a layout region. Tag the same GameObject with `LayoutRegion` (`role: "text"` or `"hud"`) so overlap / safe-area checks can see it. Do not invent a DOM label.

The source template itself is the translation lookup key. After labels exist,
the system checks that `window.combos.requestI18n` exists. The first
`requestI18n({ sourceLocale, sourceTexts })` runs in `beforeReady` and holds
game `ready` / `start` until the host replies. Labels stay empty until that
first reply so the source language does not flash on the canvas. Apply the
result only when `needed: true`. If that reply is `needed: true` but a current
template is missing from `translations`, send only the still-untranslated
templates and `requestI18n` once more before `ready`. After ready, a new label
whose translation is still missing stays empty, sends only those missing
templates, waits for one more `requestI18n`, then renders. Already-translated
templates are omitted from later `requestI18n` payloads and do not trigger
another call when the same labels go back to earlier copy. `needed: false` keeps source text and does not hold later labels. Do not
post `i18n-ready` / `set-i18n` from this plugin. If no source locale or method
is present, placeholder replacement still works and source text stays as-is.

Useful style fields include `fill`, font fields, `align`, wrapping fields, spacing, `stroke`, `dropShadow`, and `backgroundColor`; arbitrary CSS properties are not supported. Wrapping requires both `wordWrap: true` and `wordWrapWidth`.

Text or style changes update the Pixi object, and rendered bounds overwrite `Transform2D.size`. Load custom webfonts before adding the Component. `splitTextStyle` removes `backgroundColor` before Pixi construction; `parseTextColor` accepts numeric colors, `#rgb`, `#rrggbb`/`#rrggbbaa`, and `0x...` strings.
