@combos-fun/plugin-renderer-3d-text 0.1.7 → 0.1.8

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/README.md CHANGED
@@ -52,9 +52,13 @@ The host injects `window.combos` into the game HTML head. The first
52
52
  `requestI18n` runs in `beforeReady` and holds `combos-game:ready` / `start`
53
53
  until the host replies. Put every later-screen template in `sourceTexts` so
54
54
  those screens reuse the startup catalog instead of flashing source text.
55
+ The system keeps one growing session catalog of source templates and
56
+ translations; later `requestI18n` calls only run for templates still missing
57
+ from that catalog.
55
58
  If the host returns `needed: true` but a template is missing from
56
59
  `translations`, the system merges all current texts and waits for one more
57
- `requestI18n` before showing that label. Translation is applied only when
60
+ `requestI18n` before showing that label. Returning to copy that is already in
61
+ `translations` does not call `requestI18n` again. Translation is applied only when
58
62
  the result is `needed: true`. Without the injected SDK, the game stays on
59
63
  the source text.
60
64
 
package/agent-skill.md CHANGED
@@ -23,18 +23,22 @@ score.addComponent(new Text3D({
23
23
  }));
24
24
  ```
25
25
 
26
- Enable host-driven translation with:
26
+ **MUST** set `Text3DSystem` `sourceLocale` to the game's written language as a
27
+ BCP 47 tag (`en`, `en-US`, `zh-CN`, `ja-JP`, …). Match the `Text3D` literals,
28
+ not the player device locale. Omitting it disables host i18n.
27
29
 
28
30
  ```ts
29
31
  new Text3DSystem({
30
- sourceLocale: 'en-US',
31
- sourceTexts: ['Play', 'Next stage unlocked'],
32
+ sourceLocale: 'zh-CN',
33
+ sourceTexts: ['开始游戏', '下一关已解锁'],
32
34
  });
33
35
  ```
34
36
 
35
37
  Pass **every** later-screen template in `sourceTexts` so the first
36
- `requestI18n` translates the full catalog before `ready`. New labels then
37
- reuse that cache and do not flash the source language. You can also call
38
+ `requestI18n` translates the full catalog before `ready`. The system keeps one
39
+ growing session catalog of source templates and translations: new labels are
40
+ added to it, and going back to earlier copy looks up that catalog instead of
41
+ rebuilding from the current screen. You can also call
38
42
  `textSystem.declareSourceTexts([...])` during `onSystemsBootstrapComplete`.
39
43
 
40
44
  The source template itself is the translation lookup key. After labels exist,
@@ -45,8 +49,9 @@ game `ready` / `start` until the host replies. Apply the result only when
45
49
  missing from `translations`, merge every seeded and mounted template and
46
50
  `requestI18n` once more before `ready`. After ready, a new label whose
47
51
  translation is still missing stays empty, merges all current templates, waits
48
- for one more `requestI18n`, then renders. `needed: false` keeps source text
49
- and does not hold later labels. Do not post `i18n-ready` / `set-i18n` from
52
+ for one more `requestI18n`, then renders. Already-translated templates do not
53
+ trigger another `requestI18n` when the same labels go back to earlier copy.
54
+ `needed: false` keeps source text and does not hold later labels. Do not post `i18n-ready` / `set-i18n` from
50
55
  this plugin. If no source locale or method is present, placeholder replacement
51
56
  still works and source text stays as-is.
52
57
 
@@ -232,6 +232,17 @@ function hasSourceTranslation(sourceText, translations) {
232
232
  function hasMissingSourceTranslations(sourceTexts, translations) {
233
233
  return sourceTexts.some((text) => !hasSourceTranslation(text, translations));
234
234
  }
235
+ function sourceTextsSignature(sourceTexts) {
236
+ return [...sourceTexts].sort().join('\0');
237
+ }
238
+ /** After the first host reply, only request again for templates still missing. */
239
+ function shouldRequestI18nForSourceTexts(sourceTexts, translations, state) {
240
+ if (!state.i18nNeeded)
241
+ return false;
242
+ if (!hasMissingSourceTranslations(sourceTexts, translations))
243
+ return false;
244
+ return sourceTextsSignature(sourceTexts) !== state.lastRequestedSourceTexts;
245
+ }
235
246
  function shouldHoldForMissingTranslation(sourceText, translations, state) {
236
247
  if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled)
237
248
  return false;
@@ -280,7 +291,8 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
280
291
  this.sourceLocale = '';
281
292
  this.targetLocale = '';
282
293
  this.translations = {};
283
- this.seededSourceTexts = new Set();
294
+ /** Growing catalog of every source template seen this session. */
295
+ this.knownSourceTexts = new Set();
284
296
  this.lastRequestedSourceTexts = '';
285
297
  this.i18nRequestScheduled = false;
286
298
  this.i18nRequestId = 0;
@@ -298,7 +310,7 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
298
310
  }
299
311
  /** Register extra source templates before or after ready. First request includes these. */
300
312
  declareSourceTexts(texts) {
301
- addSourceTexts(this.seededSourceTexts, texts);
313
+ this.rememberSourceTexts(texts);
302
314
  this.scheduleI18nRequest();
303
315
  }
304
316
  async beforeReady() {
@@ -354,6 +366,7 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
354
366
  this.threeContext.attachVisual(gameObject.id, textMesh, gameObject);
355
367
  this.texts.set(gameObject.id, { mesh: textMesh, component });
356
368
  this.poseBridges.set(gameObject.id, new pluginRenderer3d.VisualPoseBridge());
369
+ this.rememberSourceTexts([component.text]);
357
370
  this.scheduleI18nRequest();
358
371
  }
359
372
  handleChange(changed) {
@@ -362,6 +375,8 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
362
375
  return;
363
376
  const component = changed.component;
364
377
  entry.component = component;
378
+ if (changed.prop.prop[0] === 'text')
379
+ this.rememberSourceTexts([component.text]);
365
380
  this.syncTextProps(entry.mesh, component);
366
381
  entry.mesh.sync();
367
382
  if (changed.prop.prop[0] === 'text')
@@ -426,12 +441,14 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
426
441
  }
427
442
  return localizeText(component.text, component.replacements, this.sourceLocale, this.targetLocale, this.translations);
428
443
  }
444
+ rememberSourceTexts(texts) {
445
+ addSourceTexts(this.knownSourceTexts, texts);
446
+ }
429
447
  collectSourceTexts() {
430
- const sourceTexts = new Set(this.seededSourceTexts);
431
448
  for (const entry of this.texts.values()) {
432
- addSourceTexts(sourceTexts, [entry.component.text]);
449
+ this.rememberSourceTexts([entry.component.text]);
433
450
  }
434
- return [...sourceTexts];
451
+ return [...this.knownSourceTexts];
435
452
  }
436
453
  scheduleI18nRequest() {
437
454
  if (!this.sourceLocale || !this.firstI18nSettled || this.i18nRequestScheduled)
@@ -446,15 +463,17 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
446
463
  if (!this.sourceLocale || !this.firstI18nSettled)
447
464
  return;
448
465
  const sourceTexts = this.collectSourceTexts();
449
- const signature = [...sourceTexts].sort().join('\0');
450
- if (signature === this.lastRequestedSourceTexts)
466
+ if (!shouldRequestI18nForSourceTexts(sourceTexts, this.translations, {
467
+ i18nNeeded: this.i18nNeeded,
468
+ lastRequestedSourceTexts: this.lastRequestedSourceTexts,
469
+ })) {
451
470
  return;
471
+ }
452
472
  void this.requestI18nAndApply();
453
473
  }
454
474
  async requestI18nAndApply() {
455
475
  const sourceTexts = this.collectSourceTexts();
456
- const signature = [...sourceTexts].sort().join('\0');
457
- this.lastRequestedSourceTexts = signature;
476
+ this.lastRequestedSourceTexts = sourceTextsSignature(sourceTexts);
458
477
  const requestId = ++this.i18nRequestId;
459
478
  const result = await requestHostI18n({
460
479
  sourceLocale: this.sourceLocale,
@@ -504,4 +523,6 @@ exports.mergeTranslations = mergeTranslations;
504
523
  exports.parseI18nResult = parseI18nResult;
505
524
  exports.requestHostI18n = requestHostI18n;
506
525
  exports.shouldHoldForMissingTranslation = shouldHoldForMissingTranslation;
526
+ exports.shouldRequestI18nForSourceTexts = shouldRequestI18nForSourceTexts;
527
+ exports.sourceTextsSignature = sourceTextsSignature;
507
528
  //# sourceMappingURL=plugin-renderer-3d-text.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-renderer-3d-text.cjs.js","sources":["../lib/component.ts","../lib/hostSdk.ts","../lib/localization.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\nimport type { TextReplacements } from './localization';\n\nexport type { TextReplacementValue, TextReplacements } from './localization';\n\nexport interface Text3DParams {\n text?: string;\n /** Values substituted into named placeholders such as `{score}`. */\n replacements?: TextReplacements;\n fontSize?: number;\n color?: number;\n anchorX?: string;\n anchorY?: string;\n maxWidth?: number;\n font?: string;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n}\n\nexport default class Text3D extends Component<Text3DParams> {\n static componentName: string = 'Text3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Text3D',\n\n label: 'text',\n\n description: 'Visible text content.',\n\n editor: 'text',\n\n })\n\n text: string = '';\n\n replacements: TextReplacements = {};\n\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'fontSize',\n description: 'Font size.',\n editor: 'number-stepper',\n })\n fontSize: number = 0.5;\n @Field({\n type: 'number',\n group: 'Text3D',\n label: 'color',\n description: 'Color value.',\n editor: 'number-stepper',\n })\n color: number = 0xffffff;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorX',\n description: 'Horizontal text anchor.',\n editor: 'text',\n })\n anchorX: string = 'center';\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorY',\n description: 'Vertical text anchor.',\n editor: 'text',\n })\n anchorY: string = 'middle';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'maxWidth',\n description: 'Maximum text wrap width.',\n editor: 'number-stepper',\n })\n maxWidth: number = 0;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'font',\n description: 'Font URL or path for troika-three-text (not an engine resource name).',\n editor: 'text',\n })\n font: string = '';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n\n init(obj?: Text3DParams) {\n if (!obj) return;\n const { replacements, ...rest } = obj;\n Object.assign(this, rest);\n if (replacements) this.replacements = { ...replacements };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` hostSdk. */\nimport type { TextTranslations } from './localization';\n\n/** Host-injected global. The SDK itself is not part of this repo. */\nexport const COMBOS_HOST_SDK = 'combos' as const;\n\nexport interface CombosI18nRequest {\n sourceLocale: string;\n sourceTexts: string[];\n}\n\nexport type CombosI18nResult =\n | { needed: false }\n | { needed: true; locale: string; translations: TextTranslations };\n\nexport interface CombosHostSdk {\n requestI18n?(request: CombosI18nRequest): Promise<CombosI18nResult>;\n}\n\ndeclare global {\n interface Window {\n combos?: CombosHostSdk;\n }\n}\n\nexport function hasCombosRequestI18n(\n sdk: CombosHostSdk | undefined | null = typeof window === 'undefined' ? undefined : window.combos,\n): sdk is CombosHostSdk & { requestI18n: NonNullable<CombosHostSdk['requestI18n']> } {\n return !!sdk && typeof sdk.requestI18n === 'function';\n}\n\nexport function parseI18nResult(data: unknown): CombosI18nResult {\n if (!data || typeof data !== 'object') return { needed: false };\n const input = data as {\n needed?: unknown;\n locale?: unknown;\n translations?: unknown;\n };\n if (input.needed !== true) return { needed: false };\n if (typeof input.locale !== 'string' || !input.locale.trim()) {\n return { needed: false };\n }\n if (\n !input.translations ||\n typeof input.translations !== 'object' ||\n Array.isArray(input.translations)\n ) {\n return { needed: false };\n }\n const entries = Object.entries(input.translations);\n if (entries.some(([, value]) => typeof value !== 'string')) {\n return { needed: false };\n }\n return {\n needed: true,\n locale: input.locale.trim(),\n translations: Object.fromEntries(entries) as TextTranslations,\n };\n}\n\n/** Ask the injected host SDK. Always resolves; missing method means no translation. */\nexport async function requestHostI18n(\n request: CombosI18nRequest,\n): Promise<CombosI18nResult> {\n if (typeof window === 'undefined' || !hasCombosRequestI18n(window.combos)) {\n return { needed: false };\n }\n try {\n return parseI18nResult(await window.combos.requestI18n(request));\n } catch {\n return { needed: false };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` localization. */\n\nexport type TextReplacementValue = string | number;\nexport type TextReplacements = Record<string, TextReplacementValue>;\nexport type TextTranslations = Record<string, string>;\n\nconst PLACEHOLDER_PATTERN = /\\{([A-Za-z_$][\\w$.-]*)\\}/g;\n\nexport function interpolateText(\n template: string,\n replacements?: TextReplacements,\n): string {\n if (!replacements) return template;\n return template.replace(PLACEHOLDER_PATTERN, (placeholder, name: string) => {\n if (!Object.prototype.hasOwnProperty.call(replacements, name)) {\n return placeholder;\n }\n return String(replacements[name]);\n });\n}\n\nexport function findTranslatedTemplate(\n sourceText: string,\n translations: TextTranslations,\n): string | undefined {\n if (Object.prototype.hasOwnProperty.call(translations, sourceText)) {\n return translations[sourceText];\n }\n const trimmed = sourceText.trim();\n if (\n trimmed &&\n trimmed !== sourceText &&\n Object.prototype.hasOwnProperty.call(translations, trimmed)\n ) {\n return translations[trimmed];\n }\n return undefined;\n}\n\nexport function hasSourceTranslation(\n sourceText: string,\n translations: TextTranslations,\n): boolean {\n return findTranslatedTemplate(sourceText, translations) !== undefined;\n}\n\nexport function hasMissingSourceTranslations(\n sourceTexts: readonly string[],\n translations: TextTranslations,\n): boolean {\n return sourceTexts.some((text) => !hasSourceTranslation(text, translations));\n}\n\nexport function shouldHoldForMissingTranslation(\n sourceText: string,\n translations: TextTranslations,\n state: {\n sourceLocale: string;\n targetLocale: string;\n i18nNeeded: boolean;\n firstI18nSettled: boolean;\n resolvedSourceTexts: ReadonlySet<string>;\n },\n): boolean {\n if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled) return false;\n if (state.sourceLocale.toLowerCase() === state.targetLocale.toLowerCase()) return false;\n const trimmed = sourceText.trim();\n if (!trimmed) return false;\n if (hasSourceTranslation(sourceText, translations)) return false;\n return !state.resolvedSourceTexts.has(trimmed);\n}\n\nexport function localizeText(\n sourceText: string,\n replacements: TextReplacements | undefined,\n sourceLocale: string,\n targetLocale: string,\n translations: TextTranslations,\n): string {\n const shouldTranslate =\n !!sourceLocale &&\n !!targetLocale &&\n sourceLocale.toLowerCase() !== targetLocale.toLowerCase();\n const template = shouldTranslate\n ? findTranslatedTemplate(sourceText, translations) ?? sourceText\n : sourceText;\n return interpolateText(template, replacements);\n}\n\nexport function addSourceTexts(\n target: Set<string>,\n texts?: Iterable<string | undefined | null>,\n) {\n if (!texts) return;\n for (const text of texts) {\n const source = typeof text === 'string' ? text.trim() : '';\n if (source) target.add(source);\n }\n}\n\nexport function mergeTranslations(\n current: TextTranslations,\n incoming: Record<string, unknown>,\n): TextTranslations {\n const next = { ...current };\n for (const [key, value] of Object.entries(incoming)) {\n if (typeof value === 'string') next[key] = value;\n }\n return next;\n}\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport { Renderer3D, Renderer3DSystem, tagObject3D, Transform3D, VisualPoseBridge } from '@combos-fun/plugin-renderer-3d';\nimport { Text as TroikaText } from 'troika-three-text';\nimport Text3D from './component';\nimport { requestHostI18n } from './hostSdk';\nimport {\n addSourceTexts,\n hasMissingSourceTranslations,\n localizeText,\n mergeTranslations,\n shouldHoldForMissingTranslation,\n type TextTranslations,\n} from './localization';\n\nexport interface Text3DSystemParams {\n /** BCP 47 locale of the source text, for example `zh-CN`. Omit to disable host-driven i18n. */\n sourceLocale?: string;\n /**\n * All source templates to translate on first `requestI18n`, including copy\n * for screens that are not mounted yet. Later `Text3D` nodes reuse this catalog\n * and will not flash the source language.\n */\n sourceTexts?: string[];\n}\n\n@decorators.componentObserver({\n Text3D: [\n 'text',\n { prop: ['replacements'], deep: true },\n 'fontSize', 'color', 'anchorX', 'anchorY', 'maxWidth', 'font',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n ],\n})\nexport default class Text3DSystem extends Renderer3D<Text3DSystemParams> {\n static systemName = 'Text3DSystem';\n name: string = 'Text3DSystem';\n\n private texts = new Map<number, { mesh: TroikaText; component: Text3D }>();\n private poseBridges = new Map<number, VisualPoseBridge>();\n private sourceLocale = '';\n private targetLocale = '';\n private translations: TextTranslations = {};\n private seededSourceTexts = new Set<string>();\n private lastRequestedSourceTexts = '';\n private i18nRequestScheduled = false;\n private i18nRequestId = 0;\n private firstI18nSettled = false;\n private i18nNeeded = false;\n private resolvedSourceTexts = new Set<string>();\n\n init(params?: Text3DSystemParams) {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n this.sourceLocale = params?.sourceLocale?.trim() ?? '';\n this.targetLocale = this.sourceLocale;\n this.declareSourceTexts(params?.sourceTexts);\n }\n\n /** Register extra source templates before or after ready. First request includes these. */\n declareSourceTexts(texts?: string[]) {\n addSourceTexts(this.seededSourceTexts, texts);\n this.scheduleI18nRequest();\n }\n\n async beforeReady() {\n if (this.firstI18nSettled) return;\n this.update();\n if (!this.sourceLocale) {\n this.firstI18nSettled = true;\n return;\n }\n await this.requestI18nAndApply();\n if (\n this.i18nNeeded &&\n hasMissingSourceTranslations(this.collectSourceTexts(), this.translations)\n ) {\n await this.requestI18nAndApply();\n }\n this.firstI18nSettled = true;\n }\n\n setI18n(locale: string, translations: TextTranslations) {\n const targetLocale = locale?.trim();\n if (!targetLocale || !translations || typeof translations !== 'object') return;\n this.targetLocale = targetLocale;\n this.translations = mergeTranslations(this.translations, translations);\n this.refreshAllText();\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Text3D') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, changed.component as Text3D);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.handleRemove(changed.gameObject.id);\n } else {\n this.handleChange(changed);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Text3D) as Text3D;\n if (!component) return;\n\n const entry = this.texts.get(gameObject.id);\n if (!entry) return;\n this.applyPose(gameObject, component, entry.mesh);\n }\n\n private handleAdd(gameObject: GameObject, component: Text3D) {\n const textMesh = new TroikaText();\n this.syncTextProps(textMesh, component);\n textMesh.sync();\n tagObject3D(textMesh, gameObject.id);\n\n this.threeContext.attachVisual(gameObject.id, textMesh, gameObject);\n this.texts.set(gameObject.id, { mesh: textMesh, component });\n this.poseBridges.set(gameObject.id, new VisualPoseBridge());\n this.scheduleI18nRequest();\n }\n\n private handleChange(changed: ComponentChanged) {\n const entry = this.texts.get(changed.gameObject.id);\n if (!entry) return;\n const component = changed.component as Text3D;\n entry.component = component;\n this.syncTextProps(entry.mesh, component);\n entry.mesh.sync();\n if (changed.prop.prop[0] === 'text') this.scheduleI18nRequest();\n }\n\n private handleRemove(id: number) {\n const entry = this.texts.get(id);\n if (!entry) return;\n\n this.threeContext.detachVisual(id, entry.mesh);\n entry.mesh.dispose();\n this.texts.delete(id);\n this.poseBridges.delete(id);\n }\n\n private syncTextProps(textMesh: TroikaText, component: Text3D) {\n textMesh.text = this.resolveText(component);\n textMesh.fontSize = component.fontSize;\n textMesh.color = component.color;\n textMesh.anchorX = component.anchorX;\n textMesh.anchorY = component.anchorY;\n if (component.maxWidth > 0) {\n textMesh.maxWidth = component.maxWidth;\n }\n if (component.font) {\n textMesh.font = component.font;\n }\n }\n\n private applyPose(gameObject: GameObject, component: Text3D, textMesh: TroikaText) {\n let bridge = this.poseBridges.get(gameObject.id);\n if (!bridge) {\n bridge = new VisualPoseBridge();\n this.poseBridges.set(gameObject.id, bridge);\n }\n const transform = gameObject.getComponent(Transform3D) as Transform3D | undefined;\n if (!bridge.sync(component, transform)) {\n textMesh.position.set(0, 0, 0);\n textMesh.rotation.set(0, 0, 0);\n return;\n }\n textMesh.position.set(component.positionX, component.positionY, component.positionZ);\n textMesh.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n }\n\n onDestroy() {\n this.i18nRequestId += 1;\n this.firstI18nSettled = false;\n this.i18nNeeded = false;\n this.resolvedSourceTexts.clear();\n for (const [id] of this.texts) {\n this.handleRemove(id);\n }\n this.texts.clear();\n }\n\n private resolveText(component: Text3D): string {\n if (\n shouldHoldForMissingTranslation(component.text, this.translations, {\n sourceLocale: this.sourceLocale,\n targetLocale: this.targetLocale,\n i18nNeeded: this.i18nNeeded,\n firstI18nSettled: this.firstI18nSettled,\n resolvedSourceTexts: this.resolvedSourceTexts,\n })\n ) {\n return '';\n }\n return localizeText(\n component.text,\n component.replacements,\n this.sourceLocale,\n this.targetLocale,\n this.translations,\n );\n }\n\n private collectSourceTexts(): string[] {\n const sourceTexts = new Set(this.seededSourceTexts);\n for (const entry of this.texts.values()) {\n addSourceTexts(sourceTexts, [entry.component.text]);\n }\n return [...sourceTexts];\n }\n\n private scheduleI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled || this.i18nRequestScheduled) return;\n this.i18nRequestScheduled = true;\n queueMicrotask(() => {\n this.i18nRequestScheduled = false;\n this.startI18nRequest();\n });\n }\n\n private startI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled) return;\n const sourceTexts = this.collectSourceTexts();\n const signature = [...sourceTexts].sort().join('\\0');\n if (signature === this.lastRequestedSourceTexts) return;\n void this.requestI18nAndApply();\n }\n\n private async requestI18nAndApply() {\n const sourceTexts = this.collectSourceTexts();\n const signature = [...sourceTexts].sort().join('\\0');\n this.lastRequestedSourceTexts = signature;\n const requestId = ++this.i18nRequestId;\n const result = await requestHostI18n({\n sourceLocale: this.sourceLocale,\n sourceTexts,\n });\n if (requestId !== this.i18nRequestId) return;\n addSourceTexts(this.resolvedSourceTexts, sourceTexts);\n this.i18nNeeded = result.needed;\n if (!result.needed) {\n this.refreshAllText();\n return;\n }\n this.setI18n(result.locale, result.translations);\n }\n\n private refreshAllText() {\n for (const entry of this.texts.values()) {\n entry.mesh.text = this.resolveText(entry.component);\n entry.mesh.sync();\n }\n }\n}\n"],"names":["Component","__decorate","Field","Renderer3D","Renderer3DSystem","OBSERVER_TYPE","TroikaText","tagObject3D","VisualPoseBridge","Transform3D","decorators"],"mappings":"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"}
1
+ {"version":3,"file":"plugin-renderer-3d-text.cjs.js","sources":["../lib/component.ts","../lib/hostSdk.ts","../lib/localization.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\nimport type { TextReplacements } from './localization';\n\nexport type { TextReplacementValue, TextReplacements } from './localization';\n\nexport interface Text3DParams {\n text?: string;\n /** Values substituted into named placeholders such as `{score}`. */\n replacements?: TextReplacements;\n fontSize?: number;\n color?: number;\n anchorX?: string;\n anchorY?: string;\n maxWidth?: number;\n font?: string;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n}\n\nexport default class Text3D extends Component<Text3DParams> {\n static componentName: string = 'Text3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Text3D',\n\n label: 'text',\n\n description: 'Visible text content.',\n\n editor: 'text',\n\n })\n\n text: string = '';\n\n replacements: TextReplacements = {};\n\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'fontSize',\n description: 'Font size.',\n editor: 'number-stepper',\n })\n fontSize: number = 0.5;\n @Field({\n type: 'number',\n group: 'Text3D',\n label: 'color',\n description: 'Color value.',\n editor: 'number-stepper',\n })\n color: number = 0xffffff;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorX',\n description: 'Horizontal text anchor.',\n editor: 'text',\n })\n anchorX: string = 'center';\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorY',\n description: 'Vertical text anchor.',\n editor: 'text',\n })\n anchorY: string = 'middle';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'maxWidth',\n description: 'Maximum text wrap width.',\n editor: 'number-stepper',\n })\n maxWidth: number = 0;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'font',\n description: 'Font URL or path for troika-three-text (not an engine resource name).',\n editor: 'text',\n })\n font: string = '';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n\n init(obj?: Text3DParams) {\n if (!obj) return;\n const { replacements, ...rest } = obj;\n Object.assign(this, rest);\n if (replacements) this.replacements = { ...replacements };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` hostSdk. */\nimport type { TextTranslations } from './localization';\n\n/** Host-injected global. The SDK itself is not part of this repo. */\nexport const COMBOS_HOST_SDK = 'combos' as const;\n\nexport interface CombosI18nRequest {\n sourceLocale: string;\n sourceTexts: string[];\n}\n\nexport type CombosI18nResult =\n | { needed: false }\n | { needed: true; locale: string; translations: TextTranslations };\n\nexport interface CombosHostSdk {\n requestI18n?(request: CombosI18nRequest): Promise<CombosI18nResult>;\n}\n\ndeclare global {\n interface Window {\n combos?: CombosHostSdk;\n }\n}\n\nexport function hasCombosRequestI18n(\n sdk: CombosHostSdk | undefined | null = typeof window === 'undefined' ? undefined : window.combos,\n): sdk is CombosHostSdk & { requestI18n: NonNullable<CombosHostSdk['requestI18n']> } {\n return !!sdk && typeof sdk.requestI18n === 'function';\n}\n\nexport function parseI18nResult(data: unknown): CombosI18nResult {\n if (!data || typeof data !== 'object') return { needed: false };\n const input = data as {\n needed?: unknown;\n locale?: unknown;\n translations?: unknown;\n };\n if (input.needed !== true) return { needed: false };\n if (typeof input.locale !== 'string' || !input.locale.trim()) {\n return { needed: false };\n }\n if (\n !input.translations ||\n typeof input.translations !== 'object' ||\n Array.isArray(input.translations)\n ) {\n return { needed: false };\n }\n const entries = Object.entries(input.translations);\n if (entries.some(([, value]) => typeof value !== 'string')) {\n return { needed: false };\n }\n return {\n needed: true,\n locale: input.locale.trim(),\n translations: Object.fromEntries(entries) as TextTranslations,\n };\n}\n\n/** Ask the injected host SDK. Always resolves; missing method means no translation. */\nexport async function requestHostI18n(\n request: CombosI18nRequest,\n): Promise<CombosI18nResult> {\n if (typeof window === 'undefined' || !hasCombosRequestI18n(window.combos)) {\n return { needed: false };\n }\n try {\n return parseI18nResult(await window.combos.requestI18n(request));\n } catch {\n return { needed: false };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` localization. */\n\nexport type TextReplacementValue = string | number;\nexport type TextReplacements = Record<string, TextReplacementValue>;\nexport type TextTranslations = Record<string, string>;\n\nconst PLACEHOLDER_PATTERN = /\\{([A-Za-z_$][\\w$.-]*)\\}/g;\n\nexport function interpolateText(\n template: string,\n replacements?: TextReplacements,\n): string {\n if (!replacements) return template;\n return template.replace(PLACEHOLDER_PATTERN, (placeholder, name: string) => {\n if (!Object.prototype.hasOwnProperty.call(replacements, name)) {\n return placeholder;\n }\n return String(replacements[name]);\n });\n}\n\nexport function findTranslatedTemplate(\n sourceText: string,\n translations: TextTranslations,\n): string | undefined {\n if (Object.prototype.hasOwnProperty.call(translations, sourceText)) {\n return translations[sourceText];\n }\n const trimmed = sourceText.trim();\n if (\n trimmed &&\n trimmed !== sourceText &&\n Object.prototype.hasOwnProperty.call(translations, trimmed)\n ) {\n return translations[trimmed];\n }\n return undefined;\n}\n\nexport function hasSourceTranslation(\n sourceText: string,\n translations: TextTranslations,\n): boolean {\n return findTranslatedTemplate(sourceText, translations) !== undefined;\n}\n\nexport function hasMissingSourceTranslations(\n sourceTexts: readonly string[],\n translations: TextTranslations,\n): boolean {\n return sourceTexts.some((text) => !hasSourceTranslation(text, translations));\n}\n\nexport function sourceTextsSignature(sourceTexts: readonly string[]): string {\n return [...sourceTexts].sort().join('\\0');\n}\n\n/** After the first host reply, only request again for templates still missing. */\nexport function shouldRequestI18nForSourceTexts(\n sourceTexts: readonly string[],\n translations: TextTranslations,\n state: {\n i18nNeeded: boolean;\n lastRequestedSourceTexts: string;\n },\n): boolean {\n if (!state.i18nNeeded) return false;\n if (!hasMissingSourceTranslations(sourceTexts, translations)) return false;\n return sourceTextsSignature(sourceTexts) !== state.lastRequestedSourceTexts;\n}\n\nexport function shouldHoldForMissingTranslation(\n sourceText: string,\n translations: TextTranslations,\n state: {\n sourceLocale: string;\n targetLocale: string;\n i18nNeeded: boolean;\n firstI18nSettled: boolean;\n resolvedSourceTexts: ReadonlySet<string>;\n },\n): boolean {\n if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled) return false;\n if (state.sourceLocale.toLowerCase() === state.targetLocale.toLowerCase()) return false;\n const trimmed = sourceText.trim();\n if (!trimmed) return false;\n if (hasSourceTranslation(sourceText, translations)) return false;\n return !state.resolvedSourceTexts.has(trimmed);\n}\n\nexport function localizeText(\n sourceText: string,\n replacements: TextReplacements | undefined,\n sourceLocale: string,\n targetLocale: string,\n translations: TextTranslations,\n): string {\n const shouldTranslate =\n !!sourceLocale &&\n !!targetLocale &&\n sourceLocale.toLowerCase() !== targetLocale.toLowerCase();\n const template = shouldTranslate\n ? findTranslatedTemplate(sourceText, translations) ?? sourceText\n : sourceText;\n return interpolateText(template, replacements);\n}\n\nexport function addSourceTexts(\n target: Set<string>,\n texts?: Iterable<string | undefined | null>,\n) {\n if (!texts) return;\n for (const text of texts) {\n const source = typeof text === 'string' ? text.trim() : '';\n if (source) target.add(source);\n }\n}\n\nexport function mergeTranslations(\n current: TextTranslations,\n incoming: Record<string, unknown>,\n): TextTranslations {\n const next = { ...current };\n for (const [key, value] of Object.entries(incoming)) {\n if (typeof value === 'string') next[key] = value;\n }\n return next;\n}\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport { Renderer3D, Renderer3DSystem, tagObject3D, Transform3D, VisualPoseBridge } from '@combos-fun/plugin-renderer-3d';\nimport { Text as TroikaText } from 'troika-three-text';\nimport Text3D from './component';\nimport { requestHostI18n } from './hostSdk';\nimport {\n addSourceTexts,\n hasMissingSourceTranslations,\n localizeText,\n mergeTranslations,\n shouldHoldForMissingTranslation,\n shouldRequestI18nForSourceTexts,\n sourceTextsSignature,\n type TextTranslations,\n} from './localization';\n\nexport interface Text3DSystemParams {\n /** BCP 47 locale of the source text, for example `zh-CN`. Omit to disable host-driven i18n. */\n sourceLocale?: string;\n /**\n * All source templates to translate on first `requestI18n`, including copy\n * for screens that are not mounted yet. The system also keeps a growing\n * session catalog of every later template it sees.\n */\n sourceTexts?: string[];\n}\n\n@decorators.componentObserver({\n Text3D: [\n 'text',\n { prop: ['replacements'], deep: true },\n 'fontSize', 'color', 'anchorX', 'anchorY', 'maxWidth', 'font',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n ],\n})\nexport default class Text3DSystem extends Renderer3D<Text3DSystemParams> {\n static systemName = 'Text3DSystem';\n name: string = 'Text3DSystem';\n\n private texts = new Map<number, { mesh: TroikaText; component: Text3D }>();\n private poseBridges = new Map<number, VisualPoseBridge>();\n private sourceLocale = '';\n private targetLocale = '';\n private translations: TextTranslations = {};\n /** Growing catalog of every source template seen this session. */\n private knownSourceTexts = new Set<string>();\n private lastRequestedSourceTexts = '';\n private i18nRequestScheduled = false;\n private i18nRequestId = 0;\n private firstI18nSettled = false;\n private i18nNeeded = false;\n private resolvedSourceTexts = new Set<string>();\n\n init(params?: Text3DSystemParams) {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n this.sourceLocale = params?.sourceLocale?.trim() ?? '';\n this.targetLocale = this.sourceLocale;\n this.declareSourceTexts(params?.sourceTexts);\n }\n\n /** Register extra source templates before or after ready. First request includes these. */\n declareSourceTexts(texts?: string[]) {\n this.rememberSourceTexts(texts);\n this.scheduleI18nRequest();\n }\n\n async beforeReady() {\n if (this.firstI18nSettled) return;\n this.update();\n if (!this.sourceLocale) {\n this.firstI18nSettled = true;\n return;\n }\n await this.requestI18nAndApply();\n if (\n this.i18nNeeded &&\n hasMissingSourceTranslations(this.collectSourceTexts(), this.translations)\n ) {\n await this.requestI18nAndApply();\n }\n this.firstI18nSettled = true;\n }\n\n setI18n(locale: string, translations: TextTranslations) {\n const targetLocale = locale?.trim();\n if (!targetLocale || !translations || typeof translations !== 'object') return;\n this.targetLocale = targetLocale;\n this.translations = mergeTranslations(this.translations, translations);\n this.refreshAllText();\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Text3D') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, changed.component as Text3D);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.handleRemove(changed.gameObject.id);\n } else {\n this.handleChange(changed);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Text3D) as Text3D;\n if (!component) return;\n\n const entry = this.texts.get(gameObject.id);\n if (!entry) return;\n this.applyPose(gameObject, component, entry.mesh);\n }\n\n private handleAdd(gameObject: GameObject, component: Text3D) {\n const textMesh = new TroikaText();\n this.syncTextProps(textMesh, component);\n textMesh.sync();\n tagObject3D(textMesh, gameObject.id);\n\n this.threeContext.attachVisual(gameObject.id, textMesh, gameObject);\n this.texts.set(gameObject.id, { mesh: textMesh, component });\n this.poseBridges.set(gameObject.id, new VisualPoseBridge());\n this.rememberSourceTexts([component.text]);\n this.scheduleI18nRequest();\n }\n\n private handleChange(changed: ComponentChanged) {\n const entry = this.texts.get(changed.gameObject.id);\n if (!entry) return;\n const component = changed.component as Text3D;\n entry.component = component;\n if (changed.prop.prop[0] === 'text') this.rememberSourceTexts([component.text]);\n this.syncTextProps(entry.mesh, component);\n entry.mesh.sync();\n if (changed.prop.prop[0] === 'text') this.scheduleI18nRequest();\n }\n\n private handleRemove(id: number) {\n const entry = this.texts.get(id);\n if (!entry) return;\n\n this.threeContext.detachVisual(id, entry.mesh);\n entry.mesh.dispose();\n this.texts.delete(id);\n this.poseBridges.delete(id);\n }\n\n private syncTextProps(textMesh: TroikaText, component: Text3D) {\n textMesh.text = this.resolveText(component);\n textMesh.fontSize = component.fontSize;\n textMesh.color = component.color;\n textMesh.anchorX = component.anchorX;\n textMesh.anchorY = component.anchorY;\n if (component.maxWidth > 0) {\n textMesh.maxWidth = component.maxWidth;\n }\n if (component.font) {\n textMesh.font = component.font;\n }\n }\n\n private applyPose(gameObject: GameObject, component: Text3D, textMesh: TroikaText) {\n let bridge = this.poseBridges.get(gameObject.id);\n if (!bridge) {\n bridge = new VisualPoseBridge();\n this.poseBridges.set(gameObject.id, bridge);\n }\n const transform = gameObject.getComponent(Transform3D) as Transform3D | undefined;\n if (!bridge.sync(component, transform)) {\n textMesh.position.set(0, 0, 0);\n textMesh.rotation.set(0, 0, 0);\n return;\n }\n textMesh.position.set(component.positionX, component.positionY, component.positionZ);\n textMesh.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n }\n\n onDestroy() {\n this.i18nRequestId += 1;\n this.firstI18nSettled = false;\n this.i18nNeeded = false;\n this.resolvedSourceTexts.clear();\n for (const [id] of this.texts) {\n this.handleRemove(id);\n }\n this.texts.clear();\n }\n\n private resolveText(component: Text3D): string {\n if (\n shouldHoldForMissingTranslation(component.text, this.translations, {\n sourceLocale: this.sourceLocale,\n targetLocale: this.targetLocale,\n i18nNeeded: this.i18nNeeded,\n firstI18nSettled: this.firstI18nSettled,\n resolvedSourceTexts: this.resolvedSourceTexts,\n })\n ) {\n return '';\n }\n return localizeText(\n component.text,\n component.replacements,\n this.sourceLocale,\n this.targetLocale,\n this.translations,\n );\n }\n\n private rememberSourceTexts(texts?: Iterable<string | undefined | null>) {\n addSourceTexts(this.knownSourceTexts, texts);\n }\n\n private collectSourceTexts(): string[] {\n for (const entry of this.texts.values()) {\n this.rememberSourceTexts([entry.component.text]);\n }\n return [...this.knownSourceTexts];\n }\n\n private scheduleI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled || this.i18nRequestScheduled) return;\n this.i18nRequestScheduled = true;\n queueMicrotask(() => {\n this.i18nRequestScheduled = false;\n this.startI18nRequest();\n });\n }\n\n private startI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled) return;\n const sourceTexts = this.collectSourceTexts();\n if (\n !shouldRequestI18nForSourceTexts(sourceTexts, this.translations, {\n i18nNeeded: this.i18nNeeded,\n lastRequestedSourceTexts: this.lastRequestedSourceTexts,\n })\n ) {\n return;\n }\n void this.requestI18nAndApply();\n }\n\n private async requestI18nAndApply() {\n const sourceTexts = this.collectSourceTexts();\n this.lastRequestedSourceTexts = sourceTextsSignature(sourceTexts);\n const requestId = ++this.i18nRequestId;\n const result = await requestHostI18n({\n sourceLocale: this.sourceLocale,\n sourceTexts,\n });\n if (requestId !== this.i18nRequestId) return;\n addSourceTexts(this.resolvedSourceTexts, sourceTexts);\n this.i18nNeeded = result.needed;\n if (!result.needed) {\n this.refreshAllText();\n return;\n }\n this.setI18n(result.locale, result.translations);\n }\n\n private refreshAllText() {\n for (const entry of this.texts.values()) {\n entry.mesh.text = this.resolveText(entry.component);\n entry.mesh.sync();\n }\n }\n}\n"],"names":["Component","__decorate","Field","Renderer3D","Renderer3DSystem","OBSERVER_TYPE","TroikaText","tagObject3D","VisualPoseBridge","Transform3D","decorators"],"mappings":"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"}
@@ -1 +1 @@
1
- "use strict";var e=require("tslib"),t=require("@combos-fun/engine"),o=require("@combos-fun/inspector-decorator"),s=require("@combos-fun/plugin-renderer-3d"),r=require("troika-three-text");class i extends t.Component{constructor(){super(...arguments),this.text="",this.replacements={},this.fontSize=.5,this.color=16777215,this.anchorX="center",this.anchorY="middle",this.maxWidth=0,this.font="",this.positionX=0,this.positionY=0,this.positionZ=0,this.rotationX=0,this.rotationY=0,this.rotationZ=0}static{this.componentName="Text3D"}init(e){if(!e)return;const{replacements:t,...o}=e;Object.assign(this,o),t&&(this.replacements={...t})}}e.__decorate([o.Field({type:"string",group:"Text3D",label:"text",description:"Visible text content.",editor:"text"})],i.prototype,"text",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"fontSize",description:"Font size.",editor:"number-stepper"})],i.prototype,"fontSize",void 0),e.__decorate([o.Field({type:"number",group:"Text3D",label:"color",description:"Color value.",editor:"number-stepper"})],i.prototype,"color",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"anchorX",description:"Horizontal text anchor.",editor:"text"})],i.prototype,"anchorX",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"anchorY",description:"Vertical text anchor.",editor:"text"})],i.prototype,"anchorY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"maxWidth",description:"Maximum text wrap width.",editor:"number-stepper"})],i.prototype,"maxWidth",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"font",description:"Font URL or path for troika-three-text (not an engine resource name).",editor:"text"})],i.prototype,"font",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionX",description:"Local X position.",editor:"number-stepper"})],i.prototype,"positionX",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionY",description:"Local Y position.",editor:"number-stepper"})],i.prototype,"positionY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionZ",description:"Local Z position.",editor:"number-stepper"})],i.prototype,"positionZ",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"rotationX",description:"Rotation around X in radians.",editor:"number-stepper"})],i.prototype,"rotationX",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"rotationY",description:"Rotation around Y in radians.",editor:"number-stepper"})],i.prototype,"rotationY",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"rotationZ",description:"Rotation around Z in radians.",editor:"number-stepper"})],i.prototype,"rotationZ",void 0);function n(e=("undefined"==typeof window?void 0:window.combos)){return!!e&&"function"==typeof e.requestI18n}function a(e){if(!e||"object"!=typeof e)return{needed:!1};const t=e;if(!0!==t.needed)return{needed:!1};if("string"!=typeof t.locale||!t.locale.trim())return{needed:!1};if(!t.translations||"object"!=typeof t.translations||Array.isArray(t.translations))return{needed:!1};const o=Object.entries(t.translations);return o.some(([,e])=>"string"!=typeof e)?{needed:!1}:{needed:!0,locale:t.locale.trim(),translations:Object.fromEntries(o)}}async function c(e){if("undefined"==typeof window||!n(window.combos))return{needed:!1};try{return a(await window.combos.requestI18n(e))}catch{return{needed:!1}}}const d=/\{([A-Za-z_$][\w$.-]*)\}/g;function p(e,t){return t?e.replace(d,(e,o)=>Object.prototype.hasOwnProperty.call(t,o)?String(t[o]):e):e}function l(e,t){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];const o=e.trim();return o&&o!==e&&Object.prototype.hasOwnProperty.call(t,o)?t[o]:void 0}function h(e,t){return void 0!==l(e,t)}function u(e,t){return e.some(e=>!h(e,t))}function x(e,t,o){if(!o.sourceLocale||!o.i18nNeeded||!o.firstI18nSettled)return!1;if(o.sourceLocale.toLowerCase()===o.targetLocale.toLowerCase())return!1;const s=e.trim();return!!s&&(!h(e,t)&&!o.resolvedSourceTexts.has(s))}function m(e,t,o,s,r){return p(!!o&&!!s&&o.toLowerCase()!==s.toLowerCase()?l(e,r)??e:e,t)}function f(e,t){if(t)for(const o of t){const t="string"==typeof o?o.trim():"";t&&e.add(t)}}function y(e,t){const o={...e};for(const[e,s]of Object.entries(t))"string"==typeof s&&(o[e]=s);return o}let T=class extends s.Renderer3D{constructor(){super(...arguments),this.name="Text3DSystem",this.texts=new Map,this.poseBridges=new Map,this.sourceLocale="",this.targetLocale="",this.translations={},this.seededSourceTexts=new Set,this.lastRequestedSourceTexts="",this.i18nRequestScheduled=!1,this.i18nRequestId=0,this.firstI18nSettled=!1,this.i18nNeeded=!1,this.resolvedSourceTexts=new Set}static{this.systemName="Text3DSystem"}init(e){this.game.getSystem(s.Renderer3DSystem).rendererManager.register(this),this.sourceLocale=e?.sourceLocale?.trim()??"",this.targetLocale=this.sourceLocale,this.declareSourceTexts(e?.sourceTexts)}declareSourceTexts(e){f(this.seededSourceTexts,e),this.scheduleI18nRequest()}async beforeReady(){this.firstI18nSettled||(this.update(),this.sourceLocale?(await this.requestI18nAndApply(),this.i18nNeeded&&u(this.collectSourceTexts(),this.translations)&&await this.requestI18nAndApply(),this.firstI18nSettled=!0):this.firstI18nSettled=!0)}setI18n(e,t){const o=e?.trim();o&&t&&"object"==typeof t&&(this.targetLocale=o,this.translations=y(this.translations,t),this.refreshAllText())}componentChanged(e){"Text3D"===e.componentName&&(e.type===t.OBSERVER_TYPE.ADD?this.handleAdd(e.gameObject,e.component):e.type===t.OBSERVER_TYPE.REMOVE?this.handleRemove(e.gameObject.id):this.handleChange(e))}rendererUpdate(e){const t=e.getComponent(i);if(!t)return;const o=this.texts.get(e.id);o&&this.applyPose(e,t,o.mesh)}handleAdd(e,t){const o=new r.Text;this.syncTextProps(o,t),o.sync(),s.tagObject3D(o,e.id),this.threeContext.attachVisual(e.id,o,e),this.texts.set(e.id,{mesh:o,component:t}),this.poseBridges.set(e.id,new s.VisualPoseBridge),this.scheduleI18nRequest()}handleChange(e){const t=this.texts.get(e.gameObject.id);if(!t)return;const o=e.component;t.component=o,this.syncTextProps(t.mesh,o),t.mesh.sync(),"text"===e.prop.prop[0]&&this.scheduleI18nRequest()}handleRemove(e){const t=this.texts.get(e);t&&(this.threeContext.detachVisual(e,t.mesh),t.mesh.dispose(),this.texts.delete(e),this.poseBridges.delete(e))}syncTextProps(e,t){e.text=this.resolveText(t),e.fontSize=t.fontSize,e.color=t.color,e.anchorX=t.anchorX,e.anchorY=t.anchorY,t.maxWidth>0&&(e.maxWidth=t.maxWidth),t.font&&(e.font=t.font)}applyPose(e,t,o){let r=this.poseBridges.get(e.id);r||(r=new s.VisualPoseBridge,this.poseBridges.set(e.id,r));const i=e.getComponent(s.Transform3D);if(!r.sync(t,i))return o.position.set(0,0,0),void o.rotation.set(0,0,0);o.position.set(t.positionX,t.positionY,t.positionZ),o.rotation.set(t.rotationX,t.rotationY,t.rotationZ)}onDestroy(){this.i18nRequestId+=1,this.firstI18nSettled=!1,this.i18nNeeded=!1,this.resolvedSourceTexts.clear();for(const[e]of this.texts)this.handleRemove(e);this.texts.clear()}resolveText(e){return x(e.text,this.translations,{sourceLocale:this.sourceLocale,targetLocale:this.targetLocale,i18nNeeded:this.i18nNeeded,firstI18nSettled:this.firstI18nSettled,resolvedSourceTexts:this.resolvedSourceTexts})?"":m(e.text,e.replacements,this.sourceLocale,this.targetLocale,this.translations)}collectSourceTexts(){const e=new Set(this.seededSourceTexts);for(const t of this.texts.values())f(e,[t.component.text]);return[...e]}scheduleI18nRequest(){this.sourceLocale&&this.firstI18nSettled&&!this.i18nRequestScheduled&&(this.i18nRequestScheduled=!0,queueMicrotask(()=>{this.i18nRequestScheduled=!1,this.startI18nRequest()}))}startI18nRequest(){if(!this.sourceLocale||!this.firstI18nSettled)return;[...this.collectSourceTexts()].sort().join("\0")!==this.lastRequestedSourceTexts&&this.requestI18nAndApply()}async requestI18nAndApply(){const e=this.collectSourceTexts(),t=[...e].sort().join("\0");this.lastRequestedSourceTexts=t;const o=++this.i18nRequestId,s=await c({sourceLocale:this.sourceLocale,sourceTexts:e});o===this.i18nRequestId&&(f(this.resolvedSourceTexts,e),this.i18nNeeded=s.needed,s.needed?this.setI18n(s.locale,s.translations):this.refreshAllText())}refreshAllText(){for(const e of this.texts.values())e.mesh.text=this.resolveText(e.component),e.mesh.sync()}};T=e.__decorate([t.decorators.componentObserver({Text3D:["text",{prop:["replacements"],deep:!0},"fontSize","color","anchorX","anchorY","maxWidth","font","positionX","positionY","positionZ","rotationX","rotationY","rotationZ"]})],T);var g=T;exports.COMBOS_HOST_SDK="combos",exports.Text3D=i,exports.Text3DSystem=g,exports.addSourceTexts=f,exports.findTranslatedTemplate=l,exports.hasCombosRequestI18n=n,exports.hasMissingSourceTranslations=u,exports.hasSourceTranslation=h,exports.interpolateText=p,exports.localizeText=m,exports.mergeTranslations=y,exports.parseI18nResult=a,exports.requestHostI18n=c,exports.shouldHoldForMissingTranslation=x;
1
+ "use strict";var e=require("tslib"),t=require("@combos-fun/engine"),o=require("@combos-fun/inspector-decorator"),s=require("@combos-fun/plugin-renderer-3d"),r=require("troika-three-text");class i extends t.Component{constructor(){super(...arguments),this.text="",this.replacements={},this.fontSize=.5,this.color=16777215,this.anchorX="center",this.anchorY="middle",this.maxWidth=0,this.font="",this.positionX=0,this.positionY=0,this.positionZ=0,this.rotationX=0,this.rotationY=0,this.rotationZ=0}static{this.componentName="Text3D"}init(e){if(!e)return;const{replacements:t,...o}=e;Object.assign(this,o),t&&(this.replacements={...t})}}e.__decorate([o.Field({type:"string",group:"Text3D",label:"text",description:"Visible text content.",editor:"text"})],i.prototype,"text",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"fontSize",description:"Font size.",editor:"number-stepper"})],i.prototype,"fontSize",void 0),e.__decorate([o.Field({type:"number",group:"Text3D",label:"color",description:"Color value.",editor:"number-stepper"})],i.prototype,"color",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"anchorX",description:"Horizontal text anchor.",editor:"text"})],i.prototype,"anchorX",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"anchorY",description:"Vertical text anchor.",editor:"text"})],i.prototype,"anchorY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"maxWidth",description:"Maximum text wrap width.",editor:"number-stepper"})],i.prototype,"maxWidth",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"font",description:"Font URL or path for troika-three-text (not an engine resource name).",editor:"text"})],i.prototype,"font",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionX",description:"Local X position.",editor:"number-stepper"})],i.prototype,"positionX",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionY",description:"Local Y position.",editor:"number-stepper"})],i.prototype,"positionY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionZ",description:"Local Z position.",editor:"number-stepper"})],i.prototype,"positionZ",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"rotationX",description:"Rotation around X in radians.",editor:"number-stepper"})],i.prototype,"rotationX",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"rotationY",description:"Rotation around Y in radians.",editor:"number-stepper"})],i.prototype,"rotationY",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"rotationZ",description:"Rotation around Z in radians.",editor:"number-stepper"})],i.prototype,"rotationZ",void 0);function n(e=("undefined"==typeof window?void 0:window.combos)){return!!e&&"function"==typeof e.requestI18n}function a(e){if(!e||"object"!=typeof e)return{needed:!1};const t=e;if(!0!==t.needed)return{needed:!1};if("string"!=typeof t.locale||!t.locale.trim())return{needed:!1};if(!t.translations||"object"!=typeof t.translations||Array.isArray(t.translations))return{needed:!1};const o=Object.entries(t.translations);return o.some(([,e])=>"string"!=typeof e)?{needed:!1}:{needed:!0,locale:t.locale.trim(),translations:Object.fromEntries(o)}}async function c(e){if("undefined"==typeof window||!n(window.combos))return{needed:!1};try{return a(await window.combos.requestI18n(e))}catch{return{needed:!1}}}const d=/\{([A-Za-z_$][\w$.-]*)\}/g;function p(e,t){return t?e.replace(d,(e,o)=>Object.prototype.hasOwnProperty.call(t,o)?String(t[o]):e):e}function l(e,t){if(Object.prototype.hasOwnProperty.call(t,e))return t[e];const o=e.trim();return o&&o!==e&&Object.prototype.hasOwnProperty.call(t,o)?t[o]:void 0}function u(e,t){return void 0!==l(e,t)}function h(e,t){return e.some(e=>!u(e,t))}function x(e){return[...e].sort().join("\0")}function m(e,t,o){return!!o.i18nNeeded&&(!!h(e,t)&&x(e)!==o.lastRequestedSourceTexts)}function f(e,t,o){if(!o.sourceLocale||!o.i18nNeeded||!o.firstI18nSettled)return!1;if(o.sourceLocale.toLowerCase()===o.targetLocale.toLowerCase())return!1;const s=e.trim();return!!s&&(!u(e,t)&&!o.resolvedSourceTexts.has(s))}function T(e,t,o,s,r){return p(!!o&&!!s&&o.toLowerCase()!==s.toLowerCase()?l(e,r)??e:e,t)}function y(e,t){if(t)for(const o of t){const t="string"==typeof o?o.trim():"";t&&e.add(t)}}function S(e,t){const o={...e};for(const[e,s]of Object.entries(t))"string"==typeof s&&(o[e]=s);return o}let b=class extends s.Renderer3D{constructor(){super(...arguments),this.name="Text3DSystem",this.texts=new Map,this.poseBridges=new Map,this.sourceLocale="",this.targetLocale="",this.translations={},this.knownSourceTexts=new Set,this.lastRequestedSourceTexts="",this.i18nRequestScheduled=!1,this.i18nRequestId=0,this.firstI18nSettled=!1,this.i18nNeeded=!1,this.resolvedSourceTexts=new Set}static{this.systemName="Text3DSystem"}init(e){this.game.getSystem(s.Renderer3DSystem).rendererManager.register(this),this.sourceLocale=e?.sourceLocale?.trim()??"",this.targetLocale=this.sourceLocale,this.declareSourceTexts(e?.sourceTexts)}declareSourceTexts(e){this.rememberSourceTexts(e),this.scheduleI18nRequest()}async beforeReady(){this.firstI18nSettled||(this.update(),this.sourceLocale?(await this.requestI18nAndApply(),this.i18nNeeded&&h(this.collectSourceTexts(),this.translations)&&await this.requestI18nAndApply(),this.firstI18nSettled=!0):this.firstI18nSettled=!0)}setI18n(e,t){const o=e?.trim();o&&t&&"object"==typeof t&&(this.targetLocale=o,this.translations=S(this.translations,t),this.refreshAllText())}componentChanged(e){"Text3D"===e.componentName&&(e.type===t.OBSERVER_TYPE.ADD?this.handleAdd(e.gameObject,e.component):e.type===t.OBSERVER_TYPE.REMOVE?this.handleRemove(e.gameObject.id):this.handleChange(e))}rendererUpdate(e){const t=e.getComponent(i);if(!t)return;const o=this.texts.get(e.id);o&&this.applyPose(e,t,o.mesh)}handleAdd(e,t){const o=new r.Text;this.syncTextProps(o,t),o.sync(),s.tagObject3D(o,e.id),this.threeContext.attachVisual(e.id,o,e),this.texts.set(e.id,{mesh:o,component:t}),this.poseBridges.set(e.id,new s.VisualPoseBridge),this.rememberSourceTexts([t.text]),this.scheduleI18nRequest()}handleChange(e){const t=this.texts.get(e.gameObject.id);if(!t)return;const o=e.component;t.component=o,"text"===e.prop.prop[0]&&this.rememberSourceTexts([o.text]),this.syncTextProps(t.mesh,o),t.mesh.sync(),"text"===e.prop.prop[0]&&this.scheduleI18nRequest()}handleRemove(e){const t=this.texts.get(e);t&&(this.threeContext.detachVisual(e,t.mesh),t.mesh.dispose(),this.texts.delete(e),this.poseBridges.delete(e))}syncTextProps(e,t){e.text=this.resolveText(t),e.fontSize=t.fontSize,e.color=t.color,e.anchorX=t.anchorX,e.anchorY=t.anchorY,t.maxWidth>0&&(e.maxWidth=t.maxWidth),t.font&&(e.font=t.font)}applyPose(e,t,o){let r=this.poseBridges.get(e.id);r||(r=new s.VisualPoseBridge,this.poseBridges.set(e.id,r));const i=e.getComponent(s.Transform3D);if(!r.sync(t,i))return o.position.set(0,0,0),void o.rotation.set(0,0,0);o.position.set(t.positionX,t.positionY,t.positionZ),o.rotation.set(t.rotationX,t.rotationY,t.rotationZ)}onDestroy(){this.i18nRequestId+=1,this.firstI18nSettled=!1,this.i18nNeeded=!1,this.resolvedSourceTexts.clear();for(const[e]of this.texts)this.handleRemove(e);this.texts.clear()}resolveText(e){return f(e.text,this.translations,{sourceLocale:this.sourceLocale,targetLocale:this.targetLocale,i18nNeeded:this.i18nNeeded,firstI18nSettled:this.firstI18nSettled,resolvedSourceTexts:this.resolvedSourceTexts})?"":T(e.text,e.replacements,this.sourceLocale,this.targetLocale,this.translations)}rememberSourceTexts(e){y(this.knownSourceTexts,e)}collectSourceTexts(){for(const e of this.texts.values())this.rememberSourceTexts([e.component.text]);return[...this.knownSourceTexts]}scheduleI18nRequest(){this.sourceLocale&&this.firstI18nSettled&&!this.i18nRequestScheduled&&(this.i18nRequestScheduled=!0,queueMicrotask(()=>{this.i18nRequestScheduled=!1,this.startI18nRequest()}))}startI18nRequest(){if(!this.sourceLocale||!this.firstI18nSettled)return;m(this.collectSourceTexts(),this.translations,{i18nNeeded:this.i18nNeeded,lastRequestedSourceTexts:this.lastRequestedSourceTexts})&&this.requestI18nAndApply()}async requestI18nAndApply(){const e=this.collectSourceTexts();this.lastRequestedSourceTexts=x(e);const t=++this.i18nRequestId,o=await c({sourceLocale:this.sourceLocale,sourceTexts:e});t===this.i18nRequestId&&(y(this.resolvedSourceTexts,e),this.i18nNeeded=o.needed,o.needed?this.setI18n(o.locale,o.translations):this.refreshAllText())}refreshAllText(){for(const e of this.texts.values())e.mesh.text=this.resolveText(e.component),e.mesh.sync()}};b=e.__decorate([t.decorators.componentObserver({Text3D:["text",{prop:["replacements"],deep:!0},"fontSize","color","anchorX","anchorY","maxWidth","font","positionX","positionY","positionZ","rotationX","rotationY","rotationZ"]})],b);var g=b;exports.COMBOS_HOST_SDK="combos",exports.Text3D=i,exports.Text3DSystem=g,exports.addSourceTexts=y,exports.findTranslatedTemplate=l,exports.hasCombosRequestI18n=n,exports.hasMissingSourceTranslations=h,exports.hasSourceTranslation=u,exports.interpolateText=p,exports.localizeText=T,exports.mergeTranslations=S,exports.parseI18nResult=a,exports.requestHostI18n=c,exports.shouldHoldForMissingTranslation=f,exports.shouldRequestI18nForSourceTexts=m,exports.sourceTextsSignature=x;
@@ -9,6 +9,12 @@ declare function interpolateText(template: string, replacements?: TextReplacemen
9
9
  declare function findTranslatedTemplate(sourceText: string, translations: TextTranslations): string | undefined;
10
10
  declare function hasSourceTranslation(sourceText: string, translations: TextTranslations): boolean;
11
11
  declare function hasMissingSourceTranslations(sourceTexts: readonly string[], translations: TextTranslations): boolean;
12
+ declare function sourceTextsSignature(sourceTexts: readonly string[]): string;
13
+ /** After the first host reply, only request again for templates still missing. */
14
+ declare function shouldRequestI18nForSourceTexts(sourceTexts: readonly string[], translations: TextTranslations, state: {
15
+ i18nNeeded: boolean;
16
+ lastRequestedSourceTexts: string;
17
+ }): boolean;
12
18
  declare function shouldHoldForMissingTranslation(sourceText: string, translations: TextTranslations, state: {
13
19
  sourceLocale: string;
14
20
  targetLocale: string;
@@ -61,8 +67,8 @@ interface Text3DSystemParams {
61
67
  sourceLocale?: string;
62
68
  /**
63
69
  * All source templates to translate on first `requestI18n`, including copy
64
- * for screens that are not mounted yet. Later `Text3D` nodes reuse this catalog
65
- * and will not flash the source language.
70
+ * for screens that are not mounted yet. The system also keeps a growing
71
+ * session catalog of every later template it sees.
66
72
  */
67
73
  sourceTexts?: string[];
68
74
  }
@@ -74,7 +80,8 @@ declare class Text3DSystem extends Renderer3D<Text3DSystemParams> {
74
80
  private sourceLocale;
75
81
  private targetLocale;
76
82
  private translations;
77
- private seededSourceTexts;
83
+ /** Growing catalog of every source template seen this session. */
84
+ private knownSourceTexts;
78
85
  private lastRequestedSourceTexts;
79
86
  private i18nRequestScheduled;
80
87
  private i18nRequestId;
@@ -95,6 +102,7 @@ declare class Text3DSystem extends Renderer3D<Text3DSystemParams> {
95
102
  private applyPose;
96
103
  onDestroy(): void;
97
104
  private resolveText;
105
+ private rememberSourceTexts;
98
106
  private collectSourceTexts;
99
107
  private scheduleI18nRequest;
100
108
  private startI18nRequest;
@@ -132,5 +140,5 @@ declare function parseI18nResult(data: unknown): CombosI18nResult;
132
140
  /** Ask the injected host SDK. Always resolves; missing method means no translation. */
133
141
  declare function requestHostI18n(request: CombosI18nRequest): Promise<CombosI18nResult>;
134
142
 
135
- export { COMBOS_HOST_SDK, Text3D, Text3DSystem, addSourceTexts, findTranslatedTemplate, hasCombosRequestI18n, hasMissingSourceTranslations, hasSourceTranslation, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n, shouldHoldForMissingTranslation };
143
+ export { COMBOS_HOST_SDK, Text3D, Text3DSystem, addSourceTexts, findTranslatedTemplate, hasCombosRequestI18n, hasMissingSourceTranslations, hasSourceTranslation, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n, shouldHoldForMissingTranslation, shouldRequestI18nForSourceTexts, sourceTextsSignature };
136
144
  export type { CombosHostSdk, CombosI18nRequest, CombosI18nResult, Text3DParams, Text3DSystemParams, TextReplacementValue, TextReplacements, TextTranslations };
@@ -230,6 +230,17 @@ function hasSourceTranslation(sourceText, translations) {
230
230
  function hasMissingSourceTranslations(sourceTexts, translations) {
231
231
  return sourceTexts.some((text) => !hasSourceTranslation(text, translations));
232
232
  }
233
+ function sourceTextsSignature(sourceTexts) {
234
+ return [...sourceTexts].sort().join('\0');
235
+ }
236
+ /** After the first host reply, only request again for templates still missing. */
237
+ function shouldRequestI18nForSourceTexts(sourceTexts, translations, state) {
238
+ if (!state.i18nNeeded)
239
+ return false;
240
+ if (!hasMissingSourceTranslations(sourceTexts, translations))
241
+ return false;
242
+ return sourceTextsSignature(sourceTexts) !== state.lastRequestedSourceTexts;
243
+ }
233
244
  function shouldHoldForMissingTranslation(sourceText, translations, state) {
234
245
  if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled)
235
246
  return false;
@@ -278,7 +289,8 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
278
289
  this.sourceLocale = '';
279
290
  this.targetLocale = '';
280
291
  this.translations = {};
281
- this.seededSourceTexts = new Set();
292
+ /** Growing catalog of every source template seen this session. */
293
+ this.knownSourceTexts = new Set();
282
294
  this.lastRequestedSourceTexts = '';
283
295
  this.i18nRequestScheduled = false;
284
296
  this.i18nRequestId = 0;
@@ -296,7 +308,7 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
296
308
  }
297
309
  /** Register extra source templates before or after ready. First request includes these. */
298
310
  declareSourceTexts(texts) {
299
- addSourceTexts(this.seededSourceTexts, texts);
311
+ this.rememberSourceTexts(texts);
300
312
  this.scheduleI18nRequest();
301
313
  }
302
314
  async beforeReady() {
@@ -352,6 +364,7 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
352
364
  this.threeContext.attachVisual(gameObject.id, textMesh, gameObject);
353
365
  this.texts.set(gameObject.id, { mesh: textMesh, component });
354
366
  this.poseBridges.set(gameObject.id, new VisualPoseBridge());
367
+ this.rememberSourceTexts([component.text]);
355
368
  this.scheduleI18nRequest();
356
369
  }
357
370
  handleChange(changed) {
@@ -360,6 +373,8 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
360
373
  return;
361
374
  const component = changed.component;
362
375
  entry.component = component;
376
+ if (changed.prop.prop[0] === 'text')
377
+ this.rememberSourceTexts([component.text]);
363
378
  this.syncTextProps(entry.mesh, component);
364
379
  entry.mesh.sync();
365
380
  if (changed.prop.prop[0] === 'text')
@@ -424,12 +439,14 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
424
439
  }
425
440
  return localizeText(component.text, component.replacements, this.sourceLocale, this.targetLocale, this.translations);
426
441
  }
442
+ rememberSourceTexts(texts) {
443
+ addSourceTexts(this.knownSourceTexts, texts);
444
+ }
427
445
  collectSourceTexts() {
428
- const sourceTexts = new Set(this.seededSourceTexts);
429
446
  for (const entry of this.texts.values()) {
430
- addSourceTexts(sourceTexts, [entry.component.text]);
447
+ this.rememberSourceTexts([entry.component.text]);
431
448
  }
432
- return [...sourceTexts];
449
+ return [...this.knownSourceTexts];
433
450
  }
434
451
  scheduleI18nRequest() {
435
452
  if (!this.sourceLocale || !this.firstI18nSettled || this.i18nRequestScheduled)
@@ -444,15 +461,17 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
444
461
  if (!this.sourceLocale || !this.firstI18nSettled)
445
462
  return;
446
463
  const sourceTexts = this.collectSourceTexts();
447
- const signature = [...sourceTexts].sort().join('\0');
448
- if (signature === this.lastRequestedSourceTexts)
464
+ if (!shouldRequestI18nForSourceTexts(sourceTexts, this.translations, {
465
+ i18nNeeded: this.i18nNeeded,
466
+ lastRequestedSourceTexts: this.lastRequestedSourceTexts,
467
+ })) {
449
468
  return;
469
+ }
450
470
  void this.requestI18nAndApply();
451
471
  }
452
472
  async requestI18nAndApply() {
453
473
  const sourceTexts = this.collectSourceTexts();
454
- const signature = [...sourceTexts].sort().join('\0');
455
- this.lastRequestedSourceTexts = signature;
474
+ this.lastRequestedSourceTexts = sourceTextsSignature(sourceTexts);
456
475
  const requestId = ++this.i18nRequestId;
457
476
  const result = await requestHostI18n({
458
477
  sourceLocale: this.sourceLocale,
@@ -488,5 +507,5 @@ Text3DSystem = __decorate([
488
507
  ], Text3DSystem);
489
508
  var Text3DSystem_default = Text3DSystem;
490
509
 
491
- export { COMBOS_HOST_SDK, Text3D, Text3DSystem_default as Text3DSystem, addSourceTexts, findTranslatedTemplate, hasCombosRequestI18n, hasMissingSourceTranslations, hasSourceTranslation, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n, shouldHoldForMissingTranslation };
510
+ export { COMBOS_HOST_SDK, Text3D, Text3DSystem_default as Text3DSystem, addSourceTexts, findTranslatedTemplate, hasCombosRequestI18n, hasMissingSourceTranslations, hasSourceTranslation, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n, shouldHoldForMissingTranslation, shouldRequestI18nForSourceTexts, sourceTextsSignature };
492
511
  //# sourceMappingURL=plugin-renderer-3d-text.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-renderer-3d-text.esm.js","sources":["../lib/component.ts","../lib/hostSdk.ts","../lib/localization.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\nimport type { TextReplacements } from './localization';\n\nexport type { TextReplacementValue, TextReplacements } from './localization';\n\nexport interface Text3DParams {\n text?: string;\n /** Values substituted into named placeholders such as `{score}`. */\n replacements?: TextReplacements;\n fontSize?: number;\n color?: number;\n anchorX?: string;\n anchorY?: string;\n maxWidth?: number;\n font?: string;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n}\n\nexport default class Text3D extends Component<Text3DParams> {\n static componentName: string = 'Text3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Text3D',\n\n label: 'text',\n\n description: 'Visible text content.',\n\n editor: 'text',\n\n })\n\n text: string = '';\n\n replacements: TextReplacements = {};\n\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'fontSize',\n description: 'Font size.',\n editor: 'number-stepper',\n })\n fontSize: number = 0.5;\n @Field({\n type: 'number',\n group: 'Text3D',\n label: 'color',\n description: 'Color value.',\n editor: 'number-stepper',\n })\n color: number = 0xffffff;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorX',\n description: 'Horizontal text anchor.',\n editor: 'text',\n })\n anchorX: string = 'center';\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorY',\n description: 'Vertical text anchor.',\n editor: 'text',\n })\n anchorY: string = 'middle';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'maxWidth',\n description: 'Maximum text wrap width.',\n editor: 'number-stepper',\n })\n maxWidth: number = 0;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'font',\n description: 'Font URL or path for troika-three-text (not an engine resource name).',\n editor: 'text',\n })\n font: string = '';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n\n init(obj?: Text3DParams) {\n if (!obj) return;\n const { replacements, ...rest } = obj;\n Object.assign(this, rest);\n if (replacements) this.replacements = { ...replacements };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` hostSdk. */\nimport type { TextTranslations } from './localization';\n\n/** Host-injected global. The SDK itself is not part of this repo. */\nexport const COMBOS_HOST_SDK = 'combos' as const;\n\nexport interface CombosI18nRequest {\n sourceLocale: string;\n sourceTexts: string[];\n}\n\nexport type CombosI18nResult =\n | { needed: false }\n | { needed: true; locale: string; translations: TextTranslations };\n\nexport interface CombosHostSdk {\n requestI18n?(request: CombosI18nRequest): Promise<CombosI18nResult>;\n}\n\ndeclare global {\n interface Window {\n combos?: CombosHostSdk;\n }\n}\n\nexport function hasCombosRequestI18n(\n sdk: CombosHostSdk | undefined | null = typeof window === 'undefined' ? undefined : window.combos,\n): sdk is CombosHostSdk & { requestI18n: NonNullable<CombosHostSdk['requestI18n']> } {\n return !!sdk && typeof sdk.requestI18n === 'function';\n}\n\nexport function parseI18nResult(data: unknown): CombosI18nResult {\n if (!data || typeof data !== 'object') return { needed: false };\n const input = data as {\n needed?: unknown;\n locale?: unknown;\n translations?: unknown;\n };\n if (input.needed !== true) return { needed: false };\n if (typeof input.locale !== 'string' || !input.locale.trim()) {\n return { needed: false };\n }\n if (\n !input.translations ||\n typeof input.translations !== 'object' ||\n Array.isArray(input.translations)\n ) {\n return { needed: false };\n }\n const entries = Object.entries(input.translations);\n if (entries.some(([, value]) => typeof value !== 'string')) {\n return { needed: false };\n }\n return {\n needed: true,\n locale: input.locale.trim(),\n translations: Object.fromEntries(entries) as TextTranslations,\n };\n}\n\n/** Ask the injected host SDK. Always resolves; missing method means no translation. */\nexport async function requestHostI18n(\n request: CombosI18nRequest,\n): Promise<CombosI18nResult> {\n if (typeof window === 'undefined' || !hasCombosRequestI18n(window.combos)) {\n return { needed: false };\n }\n try {\n return parseI18nResult(await window.combos.requestI18n(request));\n } catch {\n return { needed: false };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` localization. */\n\nexport type TextReplacementValue = string | number;\nexport type TextReplacements = Record<string, TextReplacementValue>;\nexport type TextTranslations = Record<string, string>;\n\nconst PLACEHOLDER_PATTERN = /\\{([A-Za-z_$][\\w$.-]*)\\}/g;\n\nexport function interpolateText(\n template: string,\n replacements?: TextReplacements,\n): string {\n if (!replacements) return template;\n return template.replace(PLACEHOLDER_PATTERN, (placeholder, name: string) => {\n if (!Object.prototype.hasOwnProperty.call(replacements, name)) {\n return placeholder;\n }\n return String(replacements[name]);\n });\n}\n\nexport function findTranslatedTemplate(\n sourceText: string,\n translations: TextTranslations,\n): string | undefined {\n if (Object.prototype.hasOwnProperty.call(translations, sourceText)) {\n return translations[sourceText];\n }\n const trimmed = sourceText.trim();\n if (\n trimmed &&\n trimmed !== sourceText &&\n Object.prototype.hasOwnProperty.call(translations, trimmed)\n ) {\n return translations[trimmed];\n }\n return undefined;\n}\n\nexport function hasSourceTranslation(\n sourceText: string,\n translations: TextTranslations,\n): boolean {\n return findTranslatedTemplate(sourceText, translations) !== undefined;\n}\n\nexport function hasMissingSourceTranslations(\n sourceTexts: readonly string[],\n translations: TextTranslations,\n): boolean {\n return sourceTexts.some((text) => !hasSourceTranslation(text, translations));\n}\n\nexport function shouldHoldForMissingTranslation(\n sourceText: string,\n translations: TextTranslations,\n state: {\n sourceLocale: string;\n targetLocale: string;\n i18nNeeded: boolean;\n firstI18nSettled: boolean;\n resolvedSourceTexts: ReadonlySet<string>;\n },\n): boolean {\n if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled) return false;\n if (state.sourceLocale.toLowerCase() === state.targetLocale.toLowerCase()) return false;\n const trimmed = sourceText.trim();\n if (!trimmed) return false;\n if (hasSourceTranslation(sourceText, translations)) return false;\n return !state.resolvedSourceTexts.has(trimmed);\n}\n\nexport function localizeText(\n sourceText: string,\n replacements: TextReplacements | undefined,\n sourceLocale: string,\n targetLocale: string,\n translations: TextTranslations,\n): string {\n const shouldTranslate =\n !!sourceLocale &&\n !!targetLocale &&\n sourceLocale.toLowerCase() !== targetLocale.toLowerCase();\n const template = shouldTranslate\n ? findTranslatedTemplate(sourceText, translations) ?? sourceText\n : sourceText;\n return interpolateText(template, replacements);\n}\n\nexport function addSourceTexts(\n target: Set<string>,\n texts?: Iterable<string | undefined | null>,\n) {\n if (!texts) return;\n for (const text of texts) {\n const source = typeof text === 'string' ? text.trim() : '';\n if (source) target.add(source);\n }\n}\n\nexport function mergeTranslations(\n current: TextTranslations,\n incoming: Record<string, unknown>,\n): TextTranslations {\n const next = { ...current };\n for (const [key, value] of Object.entries(incoming)) {\n if (typeof value === 'string') next[key] = value;\n }\n return next;\n}\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport { Renderer3D, Renderer3DSystem, tagObject3D, Transform3D, VisualPoseBridge } from '@combos-fun/plugin-renderer-3d';\nimport { Text as TroikaText } from 'troika-three-text';\nimport Text3D from './component';\nimport { requestHostI18n } from './hostSdk';\nimport {\n addSourceTexts,\n hasMissingSourceTranslations,\n localizeText,\n mergeTranslations,\n shouldHoldForMissingTranslation,\n type TextTranslations,\n} from './localization';\n\nexport interface Text3DSystemParams {\n /** BCP 47 locale of the source text, for example `zh-CN`. Omit to disable host-driven i18n. */\n sourceLocale?: string;\n /**\n * All source templates to translate on first `requestI18n`, including copy\n * for screens that are not mounted yet. Later `Text3D` nodes reuse this catalog\n * and will not flash the source language.\n */\n sourceTexts?: string[];\n}\n\n@decorators.componentObserver({\n Text3D: [\n 'text',\n { prop: ['replacements'], deep: true },\n 'fontSize', 'color', 'anchorX', 'anchorY', 'maxWidth', 'font',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n ],\n})\nexport default class Text3DSystem extends Renderer3D<Text3DSystemParams> {\n static systemName = 'Text3DSystem';\n name: string = 'Text3DSystem';\n\n private texts = new Map<number, { mesh: TroikaText; component: Text3D }>();\n private poseBridges = new Map<number, VisualPoseBridge>();\n private sourceLocale = '';\n private targetLocale = '';\n private translations: TextTranslations = {};\n private seededSourceTexts = new Set<string>();\n private lastRequestedSourceTexts = '';\n private i18nRequestScheduled = false;\n private i18nRequestId = 0;\n private firstI18nSettled = false;\n private i18nNeeded = false;\n private resolvedSourceTexts = new Set<string>();\n\n init(params?: Text3DSystemParams) {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n this.sourceLocale = params?.sourceLocale?.trim() ?? '';\n this.targetLocale = this.sourceLocale;\n this.declareSourceTexts(params?.sourceTexts);\n }\n\n /** Register extra source templates before or after ready. First request includes these. */\n declareSourceTexts(texts?: string[]) {\n addSourceTexts(this.seededSourceTexts, texts);\n this.scheduleI18nRequest();\n }\n\n async beforeReady() {\n if (this.firstI18nSettled) return;\n this.update();\n if (!this.sourceLocale) {\n this.firstI18nSettled = true;\n return;\n }\n await this.requestI18nAndApply();\n if (\n this.i18nNeeded &&\n hasMissingSourceTranslations(this.collectSourceTexts(), this.translations)\n ) {\n await this.requestI18nAndApply();\n }\n this.firstI18nSettled = true;\n }\n\n setI18n(locale: string, translations: TextTranslations) {\n const targetLocale = locale?.trim();\n if (!targetLocale || !translations || typeof translations !== 'object') return;\n this.targetLocale = targetLocale;\n this.translations = mergeTranslations(this.translations, translations);\n this.refreshAllText();\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Text3D') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, changed.component as Text3D);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.handleRemove(changed.gameObject.id);\n } else {\n this.handleChange(changed);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Text3D) as Text3D;\n if (!component) return;\n\n const entry = this.texts.get(gameObject.id);\n if (!entry) return;\n this.applyPose(gameObject, component, entry.mesh);\n }\n\n private handleAdd(gameObject: GameObject, component: Text3D) {\n const textMesh = new TroikaText();\n this.syncTextProps(textMesh, component);\n textMesh.sync();\n tagObject3D(textMesh, gameObject.id);\n\n this.threeContext.attachVisual(gameObject.id, textMesh, gameObject);\n this.texts.set(gameObject.id, { mesh: textMesh, component });\n this.poseBridges.set(gameObject.id, new VisualPoseBridge());\n this.scheduleI18nRequest();\n }\n\n private handleChange(changed: ComponentChanged) {\n const entry = this.texts.get(changed.gameObject.id);\n if (!entry) return;\n const component = changed.component as Text3D;\n entry.component = component;\n this.syncTextProps(entry.mesh, component);\n entry.mesh.sync();\n if (changed.prop.prop[0] === 'text') this.scheduleI18nRequest();\n }\n\n private handleRemove(id: number) {\n const entry = this.texts.get(id);\n if (!entry) return;\n\n this.threeContext.detachVisual(id, entry.mesh);\n entry.mesh.dispose();\n this.texts.delete(id);\n this.poseBridges.delete(id);\n }\n\n private syncTextProps(textMesh: TroikaText, component: Text3D) {\n textMesh.text = this.resolveText(component);\n textMesh.fontSize = component.fontSize;\n textMesh.color = component.color;\n textMesh.anchorX = component.anchorX;\n textMesh.anchorY = component.anchorY;\n if (component.maxWidth > 0) {\n textMesh.maxWidth = component.maxWidth;\n }\n if (component.font) {\n textMesh.font = component.font;\n }\n }\n\n private applyPose(gameObject: GameObject, component: Text3D, textMesh: TroikaText) {\n let bridge = this.poseBridges.get(gameObject.id);\n if (!bridge) {\n bridge = new VisualPoseBridge();\n this.poseBridges.set(gameObject.id, bridge);\n }\n const transform = gameObject.getComponent(Transform3D) as Transform3D | undefined;\n if (!bridge.sync(component, transform)) {\n textMesh.position.set(0, 0, 0);\n textMesh.rotation.set(0, 0, 0);\n return;\n }\n textMesh.position.set(component.positionX, component.positionY, component.positionZ);\n textMesh.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n }\n\n onDestroy() {\n this.i18nRequestId += 1;\n this.firstI18nSettled = false;\n this.i18nNeeded = false;\n this.resolvedSourceTexts.clear();\n for (const [id] of this.texts) {\n this.handleRemove(id);\n }\n this.texts.clear();\n }\n\n private resolveText(component: Text3D): string {\n if (\n shouldHoldForMissingTranslation(component.text, this.translations, {\n sourceLocale: this.sourceLocale,\n targetLocale: this.targetLocale,\n i18nNeeded: this.i18nNeeded,\n firstI18nSettled: this.firstI18nSettled,\n resolvedSourceTexts: this.resolvedSourceTexts,\n })\n ) {\n return '';\n }\n return localizeText(\n component.text,\n component.replacements,\n this.sourceLocale,\n this.targetLocale,\n this.translations,\n );\n }\n\n private collectSourceTexts(): string[] {\n const sourceTexts = new Set(this.seededSourceTexts);\n for (const entry of this.texts.values()) {\n addSourceTexts(sourceTexts, [entry.component.text]);\n }\n return [...sourceTexts];\n }\n\n private scheduleI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled || this.i18nRequestScheduled) return;\n this.i18nRequestScheduled = true;\n queueMicrotask(() => {\n this.i18nRequestScheduled = false;\n this.startI18nRequest();\n });\n }\n\n private startI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled) return;\n const sourceTexts = this.collectSourceTexts();\n const signature = [...sourceTexts].sort().join('\\0');\n if (signature === this.lastRequestedSourceTexts) return;\n void this.requestI18nAndApply();\n }\n\n private async requestI18nAndApply() {\n const sourceTexts = this.collectSourceTexts();\n const signature = [...sourceTexts].sort().join('\\0');\n this.lastRequestedSourceTexts = signature;\n const requestId = ++this.i18nRequestId;\n const result = await requestHostI18n({\n sourceLocale: this.sourceLocale,\n sourceTexts,\n });\n if (requestId !== this.i18nRequestId) return;\n addSourceTexts(this.resolvedSourceTexts, sourceTexts);\n this.i18nNeeded = result.needed;\n if (!result.needed) {\n this.refreshAllText();\n return;\n }\n this.setI18n(result.locale, result.translations);\n }\n\n private refreshAllText() {\n for (const entry of this.texts.values()) {\n entry.mesh.text = this.resolveText(entry.component);\n entry.mesh.sync();\n }\n }\n}\n"],"names":["TroikaText"],"mappings":"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"}
1
+ {"version":3,"file":"plugin-renderer-3d-text.esm.js","sources":["../lib/component.ts","../lib/hostSdk.ts","../lib/localization.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\nimport type { TextReplacements } from './localization';\n\nexport type { TextReplacementValue, TextReplacements } from './localization';\n\nexport interface Text3DParams {\n text?: string;\n /** Values substituted into named placeholders such as `{score}`. */\n replacements?: TextReplacements;\n fontSize?: number;\n color?: number;\n anchorX?: string;\n anchorY?: string;\n maxWidth?: number;\n font?: string;\n positionX?: number;\n positionY?: number;\n positionZ?: number;\n rotationX?: number;\n rotationY?: number;\n rotationZ?: number;\n}\n\nexport default class Text3D extends Component<Text3DParams> {\n static componentName: string = 'Text3D';\n\n @Field({\n\n type: 'string',\n\n group: 'Text3D',\n\n label: 'text',\n\n description: 'Visible text content.',\n\n editor: 'text',\n\n })\n\n text: string = '';\n\n replacements: TextReplacements = {};\n\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'fontSize',\n description: 'Font size.',\n editor: 'number-stepper',\n })\n fontSize: number = 0.5;\n @Field({\n type: 'number',\n group: 'Text3D',\n label: 'color',\n description: 'Color value.',\n editor: 'number-stepper',\n })\n color: number = 0xffffff;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorX',\n description: 'Horizontal text anchor.',\n editor: 'text',\n })\n anchorX: string = 'center';\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'anchorY',\n description: 'Vertical text anchor.',\n editor: 'text',\n })\n anchorY: string = 'middle';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'maxWidth',\n description: 'Maximum text wrap width.',\n editor: 'number-stepper',\n })\n maxWidth: number = 0;\n @Field({\n type: 'string',\n group: 'Text3D',\n label: 'font',\n description: 'Font URL or path for troika-three-text (not an engine resource name).',\n editor: 'text',\n })\n font: string = '';\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionX',\n description: 'Local X position.',\n editor: 'number-stepper',\n })\n positionX: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionY',\n description: 'Local Y position.',\n editor: 'number-stepper',\n })\n positionY: number = 0;\n @Field({\n type: 'number',\n step: 0.1,\n group: 'Text3D',\n label: 'positionZ',\n description: 'Local Z position.',\n editor: 'number-stepper',\n })\n positionZ: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationX',\n description: 'Rotation around X in radians.',\n editor: 'number-stepper',\n })\n rotationX: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationY',\n description: 'Rotation around Y in radians.',\n editor: 'number-stepper',\n })\n rotationY: number = 0;\n @Field({\n type: 'number',\n step: 0.01,\n group: 'Text3D',\n label: 'rotationZ',\n description: 'Rotation around Z in radians.',\n editor: 'number-stepper',\n })\n rotationZ: number = 0;\n\n init(obj?: Text3DParams) {\n if (!obj) return;\n const { replacements, ...rest } = obj;\n Object.assign(this, rest);\n if (replacements) this.replacements = { ...replacements };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` hostSdk. */\nimport type { TextTranslations } from './localization';\n\n/** Host-injected global. The SDK itself is not part of this repo. */\nexport const COMBOS_HOST_SDK = 'combos' as const;\n\nexport interface CombosI18nRequest {\n sourceLocale: string;\n sourceTexts: string[];\n}\n\nexport type CombosI18nResult =\n | { needed: false }\n | { needed: true; locale: string; translations: TextTranslations };\n\nexport interface CombosHostSdk {\n requestI18n?(request: CombosI18nRequest): Promise<CombosI18nResult>;\n}\n\ndeclare global {\n interface Window {\n combos?: CombosHostSdk;\n }\n}\n\nexport function hasCombosRequestI18n(\n sdk: CombosHostSdk | undefined | null = typeof window === 'undefined' ? undefined : window.combos,\n): sdk is CombosHostSdk & { requestI18n: NonNullable<CombosHostSdk['requestI18n']> } {\n return !!sdk && typeof sdk.requestI18n === 'function';\n}\n\nexport function parseI18nResult(data: unknown): CombosI18nResult {\n if (!data || typeof data !== 'object') return { needed: false };\n const input = data as {\n needed?: unknown;\n locale?: unknown;\n translations?: unknown;\n };\n if (input.needed !== true) return { needed: false };\n if (typeof input.locale !== 'string' || !input.locale.trim()) {\n return { needed: false };\n }\n if (\n !input.translations ||\n typeof input.translations !== 'object' ||\n Array.isArray(input.translations)\n ) {\n return { needed: false };\n }\n const entries = Object.entries(input.translations);\n if (entries.some(([, value]) => typeof value !== 'string')) {\n return { needed: false };\n }\n return {\n needed: true,\n locale: input.locale.trim(),\n translations: Object.fromEntries(entries) as TextTranslations,\n };\n}\n\n/** Ask the injected host SDK. Always resolves; missing method means no translation. */\nexport async function requestHostI18n(\n request: CombosI18nRequest,\n): Promise<CombosI18nResult> {\n if (typeof window === 'undefined' || !hasCombosRequestI18n(window.combos)) {\n return { needed: false };\n }\n try {\n return parseI18nResult(await window.combos.requestI18n(request));\n } catch {\n return { needed: false };\n }\n}\n","/** Keep identical to `@combos-fun/plugin-renderer-text` localization. */\n\nexport type TextReplacementValue = string | number;\nexport type TextReplacements = Record<string, TextReplacementValue>;\nexport type TextTranslations = Record<string, string>;\n\nconst PLACEHOLDER_PATTERN = /\\{([A-Za-z_$][\\w$.-]*)\\}/g;\n\nexport function interpolateText(\n template: string,\n replacements?: TextReplacements,\n): string {\n if (!replacements) return template;\n return template.replace(PLACEHOLDER_PATTERN, (placeholder, name: string) => {\n if (!Object.prototype.hasOwnProperty.call(replacements, name)) {\n return placeholder;\n }\n return String(replacements[name]);\n });\n}\n\nexport function findTranslatedTemplate(\n sourceText: string,\n translations: TextTranslations,\n): string | undefined {\n if (Object.prototype.hasOwnProperty.call(translations, sourceText)) {\n return translations[sourceText];\n }\n const trimmed = sourceText.trim();\n if (\n trimmed &&\n trimmed !== sourceText &&\n Object.prototype.hasOwnProperty.call(translations, trimmed)\n ) {\n return translations[trimmed];\n }\n return undefined;\n}\n\nexport function hasSourceTranslation(\n sourceText: string,\n translations: TextTranslations,\n): boolean {\n return findTranslatedTemplate(sourceText, translations) !== undefined;\n}\n\nexport function hasMissingSourceTranslations(\n sourceTexts: readonly string[],\n translations: TextTranslations,\n): boolean {\n return sourceTexts.some((text) => !hasSourceTranslation(text, translations));\n}\n\nexport function sourceTextsSignature(sourceTexts: readonly string[]): string {\n return [...sourceTexts].sort().join('\\0');\n}\n\n/** After the first host reply, only request again for templates still missing. */\nexport function shouldRequestI18nForSourceTexts(\n sourceTexts: readonly string[],\n translations: TextTranslations,\n state: {\n i18nNeeded: boolean;\n lastRequestedSourceTexts: string;\n },\n): boolean {\n if (!state.i18nNeeded) return false;\n if (!hasMissingSourceTranslations(sourceTexts, translations)) return false;\n return sourceTextsSignature(sourceTexts) !== state.lastRequestedSourceTexts;\n}\n\nexport function shouldHoldForMissingTranslation(\n sourceText: string,\n translations: TextTranslations,\n state: {\n sourceLocale: string;\n targetLocale: string;\n i18nNeeded: boolean;\n firstI18nSettled: boolean;\n resolvedSourceTexts: ReadonlySet<string>;\n },\n): boolean {\n if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled) return false;\n if (state.sourceLocale.toLowerCase() === state.targetLocale.toLowerCase()) return false;\n const trimmed = sourceText.trim();\n if (!trimmed) return false;\n if (hasSourceTranslation(sourceText, translations)) return false;\n return !state.resolvedSourceTexts.has(trimmed);\n}\n\nexport function localizeText(\n sourceText: string,\n replacements: TextReplacements | undefined,\n sourceLocale: string,\n targetLocale: string,\n translations: TextTranslations,\n): string {\n const shouldTranslate =\n !!sourceLocale &&\n !!targetLocale &&\n sourceLocale.toLowerCase() !== targetLocale.toLowerCase();\n const template = shouldTranslate\n ? findTranslatedTemplate(sourceText, translations) ?? sourceText\n : sourceText;\n return interpolateText(template, replacements);\n}\n\nexport function addSourceTexts(\n target: Set<string>,\n texts?: Iterable<string | undefined | null>,\n) {\n if (!texts) return;\n for (const text of texts) {\n const source = typeof text === 'string' ? text.trim() : '';\n if (source) target.add(source);\n }\n}\n\nexport function mergeTranslations(\n current: TextTranslations,\n incoming: Record<string, unknown>,\n): TextTranslations {\n const next = { ...current };\n for (const [key, value] of Object.entries(incoming)) {\n if (typeof value === 'string') next[key] = value;\n }\n return next;\n}\n","import { decorators, ComponentChanged, OBSERVER_TYPE, GameObject } from '@combos-fun/engine';\nimport { Renderer3D, Renderer3DSystem, tagObject3D, Transform3D, VisualPoseBridge } from '@combos-fun/plugin-renderer-3d';\nimport { Text as TroikaText } from 'troika-three-text';\nimport Text3D from './component';\nimport { requestHostI18n } from './hostSdk';\nimport {\n addSourceTexts,\n hasMissingSourceTranslations,\n localizeText,\n mergeTranslations,\n shouldHoldForMissingTranslation,\n shouldRequestI18nForSourceTexts,\n sourceTextsSignature,\n type TextTranslations,\n} from './localization';\n\nexport interface Text3DSystemParams {\n /** BCP 47 locale of the source text, for example `zh-CN`. Omit to disable host-driven i18n. */\n sourceLocale?: string;\n /**\n * All source templates to translate on first `requestI18n`, including copy\n * for screens that are not mounted yet. The system also keeps a growing\n * session catalog of every later template it sees.\n */\n sourceTexts?: string[];\n}\n\n@decorators.componentObserver({\n Text3D: [\n 'text',\n { prop: ['replacements'], deep: true },\n 'fontSize', 'color', 'anchorX', 'anchorY', 'maxWidth', 'font',\n 'positionX', 'positionY', 'positionZ',\n 'rotationX', 'rotationY', 'rotationZ',\n ],\n})\nexport default class Text3DSystem extends Renderer3D<Text3DSystemParams> {\n static systemName = 'Text3DSystem';\n name: string = 'Text3DSystem';\n\n private texts = new Map<number, { mesh: TroikaText; component: Text3D }>();\n private poseBridges = new Map<number, VisualPoseBridge>();\n private sourceLocale = '';\n private targetLocale = '';\n private translations: TextTranslations = {};\n /** Growing catalog of every source template seen this session. */\n private knownSourceTexts = new Set<string>();\n private lastRequestedSourceTexts = '';\n private i18nRequestScheduled = false;\n private i18nRequestId = 0;\n private firstI18nSettled = false;\n private i18nNeeded = false;\n private resolvedSourceTexts = new Set<string>();\n\n init(params?: Text3DSystemParams) {\n const renderer3DSystem = this.game.getSystem(Renderer3DSystem) as Renderer3DSystem;\n renderer3DSystem.rendererManager.register(this);\n this.sourceLocale = params?.sourceLocale?.trim() ?? '';\n this.targetLocale = this.sourceLocale;\n this.declareSourceTexts(params?.sourceTexts);\n }\n\n /** Register extra source templates before or after ready. First request includes these. */\n declareSourceTexts(texts?: string[]) {\n this.rememberSourceTexts(texts);\n this.scheduleI18nRequest();\n }\n\n async beforeReady() {\n if (this.firstI18nSettled) return;\n this.update();\n if (!this.sourceLocale) {\n this.firstI18nSettled = true;\n return;\n }\n await this.requestI18nAndApply();\n if (\n this.i18nNeeded &&\n hasMissingSourceTranslations(this.collectSourceTexts(), this.translations)\n ) {\n await this.requestI18nAndApply();\n }\n this.firstI18nSettled = true;\n }\n\n setI18n(locale: string, translations: TextTranslations) {\n const targetLocale = locale?.trim();\n if (!targetLocale || !translations || typeof translations !== 'object') return;\n this.targetLocale = targetLocale;\n this.translations = mergeTranslations(this.translations, translations);\n this.refreshAllText();\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Text3D') return;\n\n if (changed.type === OBSERVER_TYPE.ADD) {\n this.handleAdd(changed.gameObject, changed.component as Text3D);\n } else if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.handleRemove(changed.gameObject.id);\n } else {\n this.handleChange(changed);\n }\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(Text3D) as Text3D;\n if (!component) return;\n\n const entry = this.texts.get(gameObject.id);\n if (!entry) return;\n this.applyPose(gameObject, component, entry.mesh);\n }\n\n private handleAdd(gameObject: GameObject, component: Text3D) {\n const textMesh = new TroikaText();\n this.syncTextProps(textMesh, component);\n textMesh.sync();\n tagObject3D(textMesh, gameObject.id);\n\n this.threeContext.attachVisual(gameObject.id, textMesh, gameObject);\n this.texts.set(gameObject.id, { mesh: textMesh, component });\n this.poseBridges.set(gameObject.id, new VisualPoseBridge());\n this.rememberSourceTexts([component.text]);\n this.scheduleI18nRequest();\n }\n\n private handleChange(changed: ComponentChanged) {\n const entry = this.texts.get(changed.gameObject.id);\n if (!entry) return;\n const component = changed.component as Text3D;\n entry.component = component;\n if (changed.prop.prop[0] === 'text') this.rememberSourceTexts([component.text]);\n this.syncTextProps(entry.mesh, component);\n entry.mesh.sync();\n if (changed.prop.prop[0] === 'text') this.scheduleI18nRequest();\n }\n\n private handleRemove(id: number) {\n const entry = this.texts.get(id);\n if (!entry) return;\n\n this.threeContext.detachVisual(id, entry.mesh);\n entry.mesh.dispose();\n this.texts.delete(id);\n this.poseBridges.delete(id);\n }\n\n private syncTextProps(textMesh: TroikaText, component: Text3D) {\n textMesh.text = this.resolveText(component);\n textMesh.fontSize = component.fontSize;\n textMesh.color = component.color;\n textMesh.anchorX = component.anchorX;\n textMesh.anchorY = component.anchorY;\n if (component.maxWidth > 0) {\n textMesh.maxWidth = component.maxWidth;\n }\n if (component.font) {\n textMesh.font = component.font;\n }\n }\n\n private applyPose(gameObject: GameObject, component: Text3D, textMesh: TroikaText) {\n let bridge = this.poseBridges.get(gameObject.id);\n if (!bridge) {\n bridge = new VisualPoseBridge();\n this.poseBridges.set(gameObject.id, bridge);\n }\n const transform = gameObject.getComponent(Transform3D) as Transform3D | undefined;\n if (!bridge.sync(component, transform)) {\n textMesh.position.set(0, 0, 0);\n textMesh.rotation.set(0, 0, 0);\n return;\n }\n textMesh.position.set(component.positionX, component.positionY, component.positionZ);\n textMesh.rotation.set(component.rotationX, component.rotationY, component.rotationZ);\n }\n\n onDestroy() {\n this.i18nRequestId += 1;\n this.firstI18nSettled = false;\n this.i18nNeeded = false;\n this.resolvedSourceTexts.clear();\n for (const [id] of this.texts) {\n this.handleRemove(id);\n }\n this.texts.clear();\n }\n\n private resolveText(component: Text3D): string {\n if (\n shouldHoldForMissingTranslation(component.text, this.translations, {\n sourceLocale: this.sourceLocale,\n targetLocale: this.targetLocale,\n i18nNeeded: this.i18nNeeded,\n firstI18nSettled: this.firstI18nSettled,\n resolvedSourceTexts: this.resolvedSourceTexts,\n })\n ) {\n return '';\n }\n return localizeText(\n component.text,\n component.replacements,\n this.sourceLocale,\n this.targetLocale,\n this.translations,\n );\n }\n\n private rememberSourceTexts(texts?: Iterable<string | undefined | null>) {\n addSourceTexts(this.knownSourceTexts, texts);\n }\n\n private collectSourceTexts(): string[] {\n for (const entry of this.texts.values()) {\n this.rememberSourceTexts([entry.component.text]);\n }\n return [...this.knownSourceTexts];\n }\n\n private scheduleI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled || this.i18nRequestScheduled) return;\n this.i18nRequestScheduled = true;\n queueMicrotask(() => {\n this.i18nRequestScheduled = false;\n this.startI18nRequest();\n });\n }\n\n private startI18nRequest() {\n if (!this.sourceLocale || !this.firstI18nSettled) return;\n const sourceTexts = this.collectSourceTexts();\n if (\n !shouldRequestI18nForSourceTexts(sourceTexts, this.translations, {\n i18nNeeded: this.i18nNeeded,\n lastRequestedSourceTexts: this.lastRequestedSourceTexts,\n })\n ) {\n return;\n }\n void this.requestI18nAndApply();\n }\n\n private async requestI18nAndApply() {\n const sourceTexts = this.collectSourceTexts();\n this.lastRequestedSourceTexts = sourceTextsSignature(sourceTexts);\n const requestId = ++this.i18nRequestId;\n const result = await requestHostI18n({\n sourceLocale: this.sourceLocale,\n sourceTexts,\n });\n if (requestId !== this.i18nRequestId) return;\n addSourceTexts(this.resolvedSourceTexts, sourceTexts);\n this.i18nNeeded = result.needed;\n if (!result.needed) {\n this.refreshAllText();\n return;\n }\n this.setI18n(result.locale, result.translations);\n }\n\n private refreshAllText() {\n for (const entry of this.texts.values()) {\n entry.mesh.text = this.resolveText(entry.component);\n entry.mesh.sync();\n }\n }\n}\n"],"names":["TroikaText"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combos-fun/plugin-renderer-3d-text",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "3D text rendering, backed by troika-three-text",
5
5
  "main": "index.js",
6
6
  "module": "dist/plugin-renderer-3d-text.esm.js",
@@ -28,9 +28,9 @@
28
28
  "dependencies": {
29
29
  "three": "^0.172.0",
30
30
  "troika-three-text": "^0.52.3",
31
- "@combos-fun/plugin-renderer-3d": "0.1.7",
32
- "@combos-fun/engine": "0.1.7",
33
- "@combos-fun/inspector-decorator": "0.1.7"
31
+ "@combos-fun/engine": "0.1.8",
32
+ "@combos-fun/inspector-decorator": "0.1.8",
33
+ "@combos-fun/plugin-renderer-3d": "0.1.8"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsx": "^4.20.3"