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

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,11 @@ 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
- Later undeclared catalog changes stay async and do not block.
56
- Translation is applied only when the result is `needed: true`. Without the
57
- injected SDK, the game stays on the source text.
55
+ If the host returns `needed: true` but a template is missing from
56
+ `translations`, the system merges all current texts and waits for one more
57
+ `requestI18n` before showing that label. Translation is applied only when
58
+ the result is `needed: true`. Without the injected SDK, the game stays on
59
+ the source text.
58
60
 
59
61
  ## License
60
62
 
package/agent-skill.md CHANGED
@@ -40,11 +40,15 @@ reuse that cache and do not flash the source language. You can also call
40
40
  The source template itself is the translation lookup key. After labels exist,
41
41
  the system checks that `window.combos.requestI18n` exists. The first
42
42
  `requestI18n({ sourceLocale, sourceTexts })` runs in `beforeReady` and holds
43
- game `ready` / `start` until the host replies. Later text that was not declared
44
- requests again without blocking. Apply the result only when `needed: true`. Do
45
- not post `i18n-ready` / `set-i18n` from this plugin. If no source locale or
46
- method is present, placeholder replacement still works and source text stays
47
- as-is.
43
+ game `ready` / `start` until the host replies. Apply the result only when
44
+ `needed: true`. If that reply is `needed: true` but a current template is
45
+ missing from `translations`, merge every seeded and mounted template and
46
+ `requestI18n` once more before `ready`. After ready, a new label whose
47
+ 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
50
+ this plugin. If no source locale or method is present, placeholder replacement
51
+ still works and source text stays as-is.
48
52
 
49
53
  ## Parameters
50
54
 
@@ -214,12 +214,42 @@ function interpolateText(template, replacements) {
214
214
  return String(replacements[name]);
215
215
  });
216
216
  }
217
+ function findTranslatedTemplate(sourceText, translations) {
218
+ if (Object.prototype.hasOwnProperty.call(translations, sourceText)) {
219
+ return translations[sourceText];
220
+ }
221
+ const trimmed = sourceText.trim();
222
+ if (trimmed &&
223
+ trimmed !== sourceText &&
224
+ Object.prototype.hasOwnProperty.call(translations, trimmed)) {
225
+ return translations[trimmed];
226
+ }
227
+ return undefined;
228
+ }
229
+ function hasSourceTranslation(sourceText, translations) {
230
+ return findTranslatedTemplate(sourceText, translations) !== undefined;
231
+ }
232
+ function hasMissingSourceTranslations(sourceTexts, translations) {
233
+ return sourceTexts.some((text) => !hasSourceTranslation(text, translations));
234
+ }
235
+ function shouldHoldForMissingTranslation(sourceText, translations, state) {
236
+ if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled)
237
+ return false;
238
+ if (state.sourceLocale.toLowerCase() === state.targetLocale.toLowerCase())
239
+ return false;
240
+ const trimmed = sourceText.trim();
241
+ if (!trimmed)
242
+ return false;
243
+ if (hasSourceTranslation(sourceText, translations))
244
+ return false;
245
+ return !state.resolvedSourceTexts.has(trimmed);
246
+ }
217
247
  function localizeText(sourceText, replacements, sourceLocale, targetLocale, translations) {
218
248
  const shouldTranslate = !!sourceLocale &&
219
249
  !!targetLocale &&
220
250
  sourceLocale.toLowerCase() !== targetLocale.toLowerCase();
221
- const template = shouldTranslate && Object.prototype.hasOwnProperty.call(translations, sourceText)
222
- ? translations[sourceText]
251
+ const template = shouldTranslate
252
+ ? findTranslatedTemplate(sourceText, translations) ?? sourceText
223
253
  : sourceText;
224
254
  return interpolateText(template, replacements);
225
255
  }
@@ -255,6 +285,8 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
255
285
  this.i18nRequestScheduled = false;
256
286
  this.i18nRequestId = 0;
257
287
  this.firstI18nSettled = false;
288
+ this.i18nNeeded = false;
289
+ this.resolvedSourceTexts = new Set();
258
290
  }
259
291
  static { this.systemName = 'Text3DSystem'; }
260
292
  init(params) {
@@ -278,6 +310,10 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
278
310
  return;
279
311
  }
280
312
  await this.requestI18nAndApply();
313
+ if (this.i18nNeeded &&
314
+ hasMissingSourceTranslations(this.collectSourceTexts(), this.translations)) {
315
+ await this.requestI18nAndApply();
316
+ }
281
317
  this.firstI18nSettled = true;
282
318
  }
283
319
  setI18n(locale, translations) {
@@ -371,12 +407,23 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
371
407
  onDestroy() {
372
408
  this.i18nRequestId += 1;
373
409
  this.firstI18nSettled = false;
410
+ this.i18nNeeded = false;
411
+ this.resolvedSourceTexts.clear();
374
412
  for (const [id] of this.texts) {
375
413
  this.handleRemove(id);
376
414
  }
377
415
  this.texts.clear();
378
416
  }
379
417
  resolveText(component) {
418
+ if (shouldHoldForMissingTranslation(component.text, this.translations, {
419
+ sourceLocale: this.sourceLocale,
420
+ targetLocale: this.targetLocale,
421
+ i18nNeeded: this.i18nNeeded,
422
+ firstI18nSettled: this.firstI18nSettled,
423
+ resolvedSourceTexts: this.resolvedSourceTexts,
424
+ })) {
425
+ return '';
426
+ }
380
427
  return localizeText(component.text, component.replacements, this.sourceLocale, this.targetLocale, this.translations);
381
428
  }
382
429
  collectSourceTexts() {
@@ -415,8 +462,12 @@ let Text3DSystem = class Text3DSystem extends pluginRenderer3d.Renderer3D {
415
462
  });
416
463
  if (requestId !== this.i18nRequestId)
417
464
  return;
418
- if (!result.needed)
465
+ addSourceTexts(this.resolvedSourceTexts, sourceTexts);
466
+ this.i18nNeeded = result.needed;
467
+ if (!result.needed) {
468
+ this.refreshAllText();
419
469
  return;
470
+ }
420
471
  this.setI18n(result.locale, result.translations);
421
472
  }
422
473
  refreshAllText() {
@@ -443,10 +494,14 @@ exports.COMBOS_HOST_SDK = COMBOS_HOST_SDK;
443
494
  exports.Text3D = Text3D;
444
495
  exports.Text3DSystem = Text3DSystem_default;
445
496
  exports.addSourceTexts = addSourceTexts;
497
+ exports.findTranslatedTemplate = findTranslatedTemplate;
446
498
  exports.hasCombosRequestI18n = hasCombosRequestI18n;
499
+ exports.hasMissingSourceTranslations = hasMissingSourceTranslations;
500
+ exports.hasSourceTranslation = hasSourceTranslation;
447
501
  exports.interpolateText = interpolateText;
448
502
  exports.localizeText = localizeText;
449
503
  exports.mergeTranslations = mergeTranslations;
450
504
  exports.parseI18nResult = parseI18nResult;
451
505
  exports.requestHostI18n = requestHostI18n;
506
+ exports.shouldHoldForMissingTranslation = shouldHoldForMissingTranslation;
452
507
  //# 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 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 =\n shouldTranslate && Object.prototype.hasOwnProperty.call(translations, sourceText)\n ? 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 localizeText,\n mergeTranslations,\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\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 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 for (const [id] of this.texts) {\n this.handleRemove(id);\n }\n this.texts.clear();\n }\n\n private resolveText(component: Text3D): string {\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 if (!result.needed) return;\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 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 +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"),i=require("troika-three-text");class r 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"})],r.prototype,"text",void 0),e.__decorate([o.Field({type:"number",step:.01,group:"Text3D",label:"fontSize",description:"Font size.",editor:"number-stepper"})],r.prototype,"fontSize",void 0),e.__decorate([o.Field({type:"number",group:"Text3D",label:"color",description:"Color value.",editor:"number-stepper"})],r.prototype,"color",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"anchorX",description:"Horizontal text anchor.",editor:"text"})],r.prototype,"anchorX",void 0),e.__decorate([o.Field({type:"string",group:"Text3D",label:"anchorY",description:"Vertical text anchor.",editor:"text"})],r.prototype,"anchorY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"maxWidth",description:"Maximum text wrap width.",editor:"number-stepper"})],r.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"})],r.prototype,"font",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionX",description:"Local X position.",editor:"number-stepper"})],r.prototype,"positionX",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionY",description:"Local Y position.",editor:"number-stepper"})],r.prototype,"positionY",void 0),e.__decorate([o.Field({type:"number",step:.1,group:"Text3D",label:"positionZ",description:"Local Z position.",editor:"number-stepper"})],r.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"})],r.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"})],r.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"})],r.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,o,s,i){return p(!!o&&!!s&&o.toLowerCase()!==s.toLowerCase()&&Object.prototype.hasOwnProperty.call(i,e)?i[e]:e,t)}function h(e,t){if(t)for(const o of t){const t="string"==typeof o?o.trim():"";t&&e.add(t)}}function u(e,t){const o={...e};for(const[e,s]of Object.entries(t))"string"==typeof s&&(o[e]=s);return o}let x=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}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){h(this.seededSourceTexts,e),this.scheduleI18nRequest()}async beforeReady(){this.firstI18nSettled||(this.update(),this.sourceLocale?(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=u(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(r);if(!t)return;const o=this.texts.get(e.id);o&&this.applyPose(e,t,o.mesh)}handleAdd(e,t){const o=new i.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 i=this.poseBridges.get(e.id);i||(i=new s.VisualPoseBridge,this.poseBridges.set(e.id,i));const r=e.getComponent(s.Transform3D);if(!i.sync(t,r))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;for(const[e]of this.texts)this.handleRemove(e);this.texts.clear()}resolveText(e){return l(e.text,e.replacements,this.sourceLocale,this.targetLocale,this.translations)}collectSourceTexts(){const e=new Set(this.seededSourceTexts);for(const t of this.texts.values())h(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&&s.needed&&this.setI18n(s.locale,s.translations)}refreshAllText(){for(const e of this.texts.values())e.mesh.text=this.resolveText(e.component),e.mesh.sync()}};x=e.__decorate([t.decorators.componentObserver({Text3D:["text",{prop:["replacements"],deep:!0},"fontSize","color","anchorX","anchorY","maxWidth","font","positionX","positionY","positionZ","rotationX","rotationY","rotationZ"]})],x);var m=x;exports.COMBOS_HOST_SDK="combos",exports.Text3D=r,exports.Text3DSystem=m,exports.addSourceTexts=h,exports.hasCombosRequestI18n=n,exports.interpolateText=p,exports.localizeText=l,exports.mergeTranslations=u,exports.parseI18nResult=a,exports.requestHostI18n=c;
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;
@@ -6,6 +6,16 @@ type TextReplacementValue = string | number;
6
6
  type TextReplacements = Record<string, TextReplacementValue>;
7
7
  type TextTranslations = Record<string, string>;
8
8
  declare function interpolateText(template: string, replacements?: TextReplacements): string;
9
+ declare function findTranslatedTemplate(sourceText: string, translations: TextTranslations): string | undefined;
10
+ declare function hasSourceTranslation(sourceText: string, translations: TextTranslations): boolean;
11
+ declare function hasMissingSourceTranslations(sourceTexts: readonly string[], translations: TextTranslations): boolean;
12
+ declare function shouldHoldForMissingTranslation(sourceText: string, translations: TextTranslations, state: {
13
+ sourceLocale: string;
14
+ targetLocale: string;
15
+ i18nNeeded: boolean;
16
+ firstI18nSettled: boolean;
17
+ resolvedSourceTexts: ReadonlySet<string>;
18
+ }): boolean;
9
19
  declare function localizeText(sourceText: string, replacements: TextReplacements | undefined, sourceLocale: string, targetLocale: string, translations: TextTranslations): string;
10
20
  declare function addSourceTexts(target: Set<string>, texts?: Iterable<string | undefined | null>): void;
11
21
  declare function mergeTranslations(current: TextTranslations, incoming: Record<string, unknown>): TextTranslations;
@@ -69,6 +79,8 @@ declare class Text3DSystem extends Renderer3D<Text3DSystemParams> {
69
79
  private i18nRequestScheduled;
70
80
  private i18nRequestId;
71
81
  private firstI18nSettled;
82
+ private i18nNeeded;
83
+ private resolvedSourceTexts;
72
84
  init(params?: Text3DSystemParams): void;
73
85
  /** Register extra source templates before or after ready. First request includes these. */
74
86
  declareSourceTexts(texts?: string[]): void;
@@ -120,5 +132,5 @@ declare function parseI18nResult(data: unknown): CombosI18nResult;
120
132
  /** Ask the injected host SDK. Always resolves; missing method means no translation. */
121
133
  declare function requestHostI18n(request: CombosI18nRequest): Promise<CombosI18nResult>;
122
134
 
123
- export { COMBOS_HOST_SDK, Text3D, Text3DSystem, addSourceTexts, hasCombosRequestI18n, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n };
135
+ export { COMBOS_HOST_SDK, Text3D, Text3DSystem, addSourceTexts, findTranslatedTemplate, hasCombosRequestI18n, hasMissingSourceTranslations, hasSourceTranslation, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n, shouldHoldForMissingTranslation };
124
136
  export type { CombosHostSdk, CombosI18nRequest, CombosI18nResult, Text3DParams, Text3DSystemParams, TextReplacementValue, TextReplacements, TextTranslations };
@@ -212,12 +212,42 @@ function interpolateText(template, replacements) {
212
212
  return String(replacements[name]);
213
213
  });
214
214
  }
215
+ function findTranslatedTemplate(sourceText, translations) {
216
+ if (Object.prototype.hasOwnProperty.call(translations, sourceText)) {
217
+ return translations[sourceText];
218
+ }
219
+ const trimmed = sourceText.trim();
220
+ if (trimmed &&
221
+ trimmed !== sourceText &&
222
+ Object.prototype.hasOwnProperty.call(translations, trimmed)) {
223
+ return translations[trimmed];
224
+ }
225
+ return undefined;
226
+ }
227
+ function hasSourceTranslation(sourceText, translations) {
228
+ return findTranslatedTemplate(sourceText, translations) !== undefined;
229
+ }
230
+ function hasMissingSourceTranslations(sourceTexts, translations) {
231
+ return sourceTexts.some((text) => !hasSourceTranslation(text, translations));
232
+ }
233
+ function shouldHoldForMissingTranslation(sourceText, translations, state) {
234
+ if (!state.sourceLocale || !state.i18nNeeded || !state.firstI18nSettled)
235
+ return false;
236
+ if (state.sourceLocale.toLowerCase() === state.targetLocale.toLowerCase())
237
+ return false;
238
+ const trimmed = sourceText.trim();
239
+ if (!trimmed)
240
+ return false;
241
+ if (hasSourceTranslation(sourceText, translations))
242
+ return false;
243
+ return !state.resolvedSourceTexts.has(trimmed);
244
+ }
215
245
  function localizeText(sourceText, replacements, sourceLocale, targetLocale, translations) {
216
246
  const shouldTranslate = !!sourceLocale &&
217
247
  !!targetLocale &&
218
248
  sourceLocale.toLowerCase() !== targetLocale.toLowerCase();
219
- const template = shouldTranslate && Object.prototype.hasOwnProperty.call(translations, sourceText)
220
- ? translations[sourceText]
249
+ const template = shouldTranslate
250
+ ? findTranslatedTemplate(sourceText, translations) ?? sourceText
221
251
  : sourceText;
222
252
  return interpolateText(template, replacements);
223
253
  }
@@ -253,6 +283,8 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
253
283
  this.i18nRequestScheduled = false;
254
284
  this.i18nRequestId = 0;
255
285
  this.firstI18nSettled = false;
286
+ this.i18nNeeded = false;
287
+ this.resolvedSourceTexts = new Set();
256
288
  }
257
289
  static { this.systemName = 'Text3DSystem'; }
258
290
  init(params) {
@@ -276,6 +308,10 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
276
308
  return;
277
309
  }
278
310
  await this.requestI18nAndApply();
311
+ if (this.i18nNeeded &&
312
+ hasMissingSourceTranslations(this.collectSourceTexts(), this.translations)) {
313
+ await this.requestI18nAndApply();
314
+ }
279
315
  this.firstI18nSettled = true;
280
316
  }
281
317
  setI18n(locale, translations) {
@@ -369,12 +405,23 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
369
405
  onDestroy() {
370
406
  this.i18nRequestId += 1;
371
407
  this.firstI18nSettled = false;
408
+ this.i18nNeeded = false;
409
+ this.resolvedSourceTexts.clear();
372
410
  for (const [id] of this.texts) {
373
411
  this.handleRemove(id);
374
412
  }
375
413
  this.texts.clear();
376
414
  }
377
415
  resolveText(component) {
416
+ if (shouldHoldForMissingTranslation(component.text, this.translations, {
417
+ sourceLocale: this.sourceLocale,
418
+ targetLocale: this.targetLocale,
419
+ i18nNeeded: this.i18nNeeded,
420
+ firstI18nSettled: this.firstI18nSettled,
421
+ resolvedSourceTexts: this.resolvedSourceTexts,
422
+ })) {
423
+ return '';
424
+ }
378
425
  return localizeText(component.text, component.replacements, this.sourceLocale, this.targetLocale, this.translations);
379
426
  }
380
427
  collectSourceTexts() {
@@ -413,8 +460,12 @@ let Text3DSystem = class Text3DSystem extends Renderer3D {
413
460
  });
414
461
  if (requestId !== this.i18nRequestId)
415
462
  return;
416
- if (!result.needed)
463
+ addSourceTexts(this.resolvedSourceTexts, sourceTexts);
464
+ this.i18nNeeded = result.needed;
465
+ if (!result.needed) {
466
+ this.refreshAllText();
417
467
  return;
468
+ }
418
469
  this.setI18n(result.locale, result.translations);
419
470
  }
420
471
  refreshAllText() {
@@ -437,5 +488,5 @@ Text3DSystem = __decorate([
437
488
  ], Text3DSystem);
438
489
  var Text3DSystem_default = Text3DSystem;
439
490
 
440
- export { COMBOS_HOST_SDK, Text3D, Text3DSystem_default as Text3DSystem, addSourceTexts, hasCombosRequestI18n, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n };
491
+ export { COMBOS_HOST_SDK, Text3D, Text3DSystem_default as Text3DSystem, addSourceTexts, findTranslatedTemplate, hasCombosRequestI18n, hasMissingSourceTranslations, hasSourceTranslation, interpolateText, localizeText, mergeTranslations, parseI18nResult, requestHostI18n, shouldHoldForMissingTranslation };
441
492
  //# 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 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 =\n shouldTranslate && Object.prototype.hasOwnProperty.call(translations, sourceText)\n ? 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 localizeText,\n mergeTranslations,\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\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 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 for (const [id] of this.texts) {\n this.handleRemove(id);\n }\n this.texts.clear();\n }\n\n private resolveText(component: Text3D): string {\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 if (!result.needed) return;\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 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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@combos-fun/plugin-renderer-3d-text",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
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.5",
32
- "@combos-fun/inspector-decorator": "0.1.5",
33
- "@combos-fun/engine": "0.1.5"
31
+ "@combos-fun/plugin-renderer-3d": "0.1.7",
32
+ "@combos-fun/engine": "0.1.7",
33
+ "@combos-fun/inspector-decorator": "0.1.7"
34
34
  },
35
35
  "devDependencies": {
36
36
  "tsx": "^4.20.3"