@mentra/engine 3.3.0-dev.722 → 3.3.0-dev.730

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.
@@ -1,10 +1,10 @@
1
1
  export const ENGINE_RELEASE_METADATA = Object.freeze({
2
2
  "schemaVersion": 1,
3
3
  "familyBaseVersion": "3.3.0",
4
- "releaseIdentity": "3.3.0-dev.722",
5
- "releaseSetId": "mentra-3.3.0-dev.722",
6
- "sourceCommit": "b780c4d82e1a352ade975ea43477c45166977b29",
7
- "otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.722.json",
8
- "otaManifestSha256": "6d0e5485747d2fc134b04c38476d1b54a300d6a08c4710eb445256b1dbcaf836"
4
+ "releaseIdentity": "3.3.0-dev.730",
5
+ "releaseSetId": "mentra-3.3.0-dev.730",
6
+ "sourceCommit": "558bc769919e2f69bc863012bf439db8358fed17",
7
+ "otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.730.json",
8
+ "otaManifestSha256": "91ebac8ac498f211418df31d731c3bda065b2e145e1ec48980324303484886c8"
9
9
  });
10
10
  //# sourceMappingURL=releaseMetadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,iIAAiI;IACnJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.3.0\",\n \"releaseIdentity\": \"3.3.0-dev.722\",\n \"releaseSetId\": \"mentra-3.3.0-dev.722\",\n \"sourceCommit\": \"b780c4d82e1a352ade975ea43477c45166977b29\",\n \"otaManifestUrl\": \"https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.722.json\",\n \"otaManifestSha256\": \"6d0e5485747d2fc134b04c38476d1b54a300d6a08c4710eb445256b1dbcaf836\"\n})\n"]}
1
+ {"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,uBAAuB,GAAoC,MAAM,CAAC,MAAM,CAAC;IACpF,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,eAAe;IAClC,cAAc,EAAE,sBAAsB;IACtC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,iIAAiI;IACnJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface EngineReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.3.0\",\n \"releaseIdentity\": \"3.3.0-dev.730\",\n \"releaseSetId\": \"mentra-3.3.0-dev.730\",\n \"sourceCommit\": \"558bc769919e2f69bc863012bf439db8358fed17\",\n \"otaManifestUrl\": \"https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.730.json\",\n \"otaManifestSha256\": \"91ebac8ac498f211418df31d731c3bda065b2e145e1ec48980324303484886c8\"\n})\n"]}
@@ -1,5 +1,7 @@
1
1
  import type { DisplayProfile } from "./profiles/types";
2
2
  export declare function normalizeNimoDisplayText(text: string): string;
3
+ /** Preserve firmware-mapped G1 Latin clusters before measuring or encoding text. */
4
+ export declare function normalizeG1DisplayText(text: string): string;
3
5
  /** Keep feedback offsets in the miniapp's original UTF-16 source after glyph substitutions. */
4
6
  export declare function normalizeTextWithSource(text: string, profile: DisplayProfile): {
5
7
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"normalization.d.ts","sourceRoot":"","sources":["../../../src/utils/display/normalization.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAsBpD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED,+FAA+F;AAC/F,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;;yBACZ,MAAM,OAAO,MAAM;;;;EAqBnF"}
1
+ {"version":3,"file":"normalization.d.ts","sourceRoot":"","sources":["../../../src/utils/display/normalization.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAsBpD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK7D;AAED,oFAAoF;AACpF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED,+FAA+F;AAC/F,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;;yBACZ,MAAM,OAAO,MAAM;;;;EAqBnF"}
@@ -1,4 +1,5 @@
1
- // Mirrors the native LatinTextSanitizer used by G1 and NIMO.
1
+ import { G1_LATIN_GLYPH_WIDTHS } from "./profiles/g1LatinGlyphs";
2
+ // Mirrors the native fallback for unmapped G1 Latin glyphs and all NIMO Latin text.
2
3
  const LATIN_REPLACEMENTS = {
3
4
  Đ: "D",
4
5
  Ð: "D",
@@ -23,6 +24,17 @@ export function normalizeNimoDisplayText(text) {
23
24
  .replace(/\p{Script=Latin}\p{M}*/gu, (cluster) => cluster.normalize("NFD").replace(/\p{M}+/gu, ""))
24
25
  .replace(/—/g, "-");
25
26
  }
27
+ /** Preserve firmware-mapped G1 Latin clusters before measuring or encoding text. */
28
+ export function normalizeG1DisplayText(text) {
29
+ return text.replace(/\p{Script=Latin}\p{M}*/gu, (cluster) => {
30
+ const composed = cluster.normalize("NFC");
31
+ if (composed.length === 1 &&
32
+ (composed.charCodeAt(0) <= 0x7e || Object.prototype.hasOwnProperty.call(G1_LATIN_GLYPH_WIDTHS, composed))) {
33
+ return composed;
34
+ }
35
+ return normalizeNimoDisplayText(cluster);
36
+ });
37
+ }
26
38
  /** Keep feedback offsets in the miniapp's original UTF-16 source after glyph substitutions. */
27
39
  export function normalizeTextWithSource(text, profile) {
28
40
  if (!profile.normalizeText)
@@ -43,7 +55,7 @@ export function normalizeTextWithSource(text, profile) {
43
55
  text: normalized,
44
56
  sourceRange: (start, end) => ({
45
57
  start: starts[start] ?? text.length,
46
- end: end > start ? ends[end - 1] : starts[start] ?? text.length,
58
+ end: end > start ? ends[end - 1] : (starts[start] ?? text.length),
47
59
  }),
48
60
  };
49
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"normalization.js","sourceRoot":"","sources":["../../../src/utils/display/normalization.ts"],"names":[],"mappings":"AAEA,6DAA6D;AAC7D,MAAM,kBAAkB,GAA2B;IACjD,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,GAAG;IACN,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;IACP,CAAC,EAAE,IAAI;CACR,CAAA;AAED,MAAM,UAAU,wBAAwB,CAAC,IAAY;IACnD,OAAO,IAAI;SACR,OAAO,CAAC,qBAAqB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;SAC5E,OAAO,CAAC,0BAA0B,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;SAClG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;AACvB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,OAAuB;IAC3E,IAAI,CAAC,OAAO,CAAC,aAAa;QAAE,OAAO,EAAC,IAAI,EAAE,WAAW,EAAE,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC,EAAC,KAAK,EAAE,GAAG,EAAC,CAAC,EAAC,CAAA;IAEtG,IAAI,UAAU,GAAG,EAAE,CAAA;IACnB,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,IAAI,GAAa,EAAE,CAAA;IACzB,+FAA+F;IAC/F,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QACnD,UAAU,IAAI,WAAW,CAAA;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YACxB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;QAC1C,CAAC;IACH,CAAC;IACD,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,WAAW,EAAE,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC;YAC5C,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM;YACnC,GAAG,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM;SAChE,CAAC;KACH,CAAA;AACH,CAAC","sourcesContent":["import type {DisplayProfile} from \"./profiles/types\"\n\n// Mirrors the native LatinTextSanitizer used by G1 and NIMO.\nconst LATIN_REPLACEMENTS: Record<string, string> = {\n Đ: \"D\",\n Ð: \"D\",\n đ: \"d\",\n ð: \"d\",\n Ł: \"L\",\n ł: \"l\",\n Ø: \"O\",\n ø: \"o\",\n Æ: \"AE\",\n æ: \"ae\",\n Œ: \"OE\",\n œ: \"oe\",\n ẞ: \"SS\",\n ß: \"ss\",\n Þ: \"TH\",\n þ: \"th\",\n}\n\nexport function normalizeNimoDisplayText(text: string): string {\n return text\n .replace(/[ĐÐđðŁłØøÆæŒœẞßÞþ]/g, (character) => LATIN_REPLACEMENTS[character])\n .replace(/\\p{Script=Latin}\\p{M}*/gu, (cluster) => cluster.normalize(\"NFD\").replace(/\\p{M}+/gu, \"\"))\n .replace(/—/g, \"-\")\n}\n\n/** Keep feedback offsets in the miniapp's original UTF-16 source after glyph substitutions. */\nexport function normalizeTextWithSource(text: string, profile: DisplayProfile) {\n if (!profile.normalizeText) return {text, sourceRange: (start: number, end: number) => ({start, end})}\n\n let normalized = \"\"\n const starts: number[] = []\n const ends: number[] = []\n // Include combining marks with their base so a removed accent remains inside its source range.\n for (const match of text.matchAll(/\\P{M}\\p{M}*|\\p{M}+/gu)) {\n const replacement = profile.normalizeText(match[0])\n normalized += replacement\n for (let i = 0; i < replacement.length; i++) {\n starts.push(match.index)\n ends.push(match.index + match[0].length)\n }\n }\n return {\n text: normalized,\n sourceRange: (start: number, end: number) => ({\n start: starts[start] ?? text.length,\n end: end > start ? ends[end - 1] : starts[start] ?? text.length,\n }),\n }\n}\n"]}
1
+ {"version":3,"file":"normalization.js","sourceRoot":"","sources":["../../../src/utils/display/normalization.ts"],"names":[],"mappings":"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","sourcesContent":["import {G1_LATIN_GLYPH_WIDTHS} from \"./profiles/g1LatinGlyphs\"\nimport type {DisplayProfile} from \"./profiles/types\"\n\n// Mirrors the native fallback for unmapped G1 Latin glyphs and all NIMO Latin text.\nconst LATIN_REPLACEMENTS: Record<string, string> = {\n Đ: \"D\",\n Ð: \"D\",\n đ: \"d\",\n ð: \"d\",\n Ł: \"L\",\n ł: \"l\",\n Ø: \"O\",\n ø: \"o\",\n Æ: \"AE\",\n æ: \"ae\",\n Œ: \"OE\",\n œ: \"oe\",\n ẞ: \"SS\",\n ß: \"ss\",\n Þ: \"TH\",\n þ: \"th\",\n}\n\nexport function normalizeNimoDisplayText(text: string): string {\n return text\n .replace(/[ĐÐđðŁłØøÆæŒœẞßÞþ]/g, (character) => LATIN_REPLACEMENTS[character])\n .replace(/\\p{Script=Latin}\\p{M}*/gu, (cluster) => cluster.normalize(\"NFD\").replace(/\\p{M}+/gu, \"\"))\n .replace(/—/g, \"-\")\n}\n\n/** Preserve firmware-mapped G1 Latin clusters before measuring or encoding text. */\nexport function normalizeG1DisplayText(text: string): string {\n return text.replace(/\\p{Script=Latin}\\p{M}*/gu, (cluster) => {\n const composed = cluster.normalize(\"NFC\")\n if (\n composed.length === 1 &&\n (composed.charCodeAt(0) <= 0x7e || Object.prototype.hasOwnProperty.call(G1_LATIN_GLYPH_WIDTHS, composed))\n ) {\n return composed\n }\n return normalizeNimoDisplayText(cluster)\n })\n}\n\n/** Keep feedback offsets in the miniapp's original UTF-16 source after glyph substitutions. */\nexport function normalizeTextWithSource(text: string, profile: DisplayProfile) {\n if (!profile.normalizeText) return {text, sourceRange: (start: number, end: number) => ({start, end})}\n\n let normalized = \"\"\n const starts: number[] = []\n const ends: number[] = []\n // Include combining marks with their base so a removed accent remains inside its source range.\n for (const match of text.matchAll(/\\P{M}\\p{M}*|\\p{M}+/gu)) {\n const replacement = profile.normalizeText(match[0])\n normalized += replacement\n for (let i = 0; i < replacement.length; i++) {\n starts.push(match.index)\n ends.push(match.index + match[0].length)\n }\n }\n return {\n text: normalized,\n sourceRange: (start: number, end: number) => ({\n start: starts[start] ?? text.length,\n end: end > start ? ends[end - 1] : (starts[start] ?? text.length),\n }),\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"g1.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g1.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAsHtC;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,cAgDxB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAoC/B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA"}
1
+ {"version":3,"file":"g1.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g1.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAwHtC;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,cAkDxB,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,iBAAiB,EAAE,cAsC/B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA"}
@@ -1,9 +1,12 @@
1
+ import { normalizeG1DisplayText } from "../normalization";
2
+ import { G1_LATIN_GLYPH_WIDTHS } from "./g1LatinGlyphs";
1
3
  /**
2
- * Complete G1 glyph widths from G1FontLoaderKt
4
+ * ASCII widths from G1FontLoaderKt and embedded G1 1.5.6 Latin glyphs.
3
5
  * These are GLYPH widths - multiply using renderFormula to get rendered pixels.
4
6
  * Rendered width = (glyphWidth + 1) * 2
5
7
  */
6
8
  const G1_GLYPH_WIDTHS = {
9
+ ...G1_LATIN_GLYPH_WIDTHS,
7
10
  // Punctuation & Symbols
8
11
  " ": 2,
9
12
  "!": 1,
@@ -116,6 +119,7 @@ const G1_GLYPH_WIDTHS = {
116
119
  export const G1_PROFILE = {
117
120
  id: "even-realities-g1",
118
121
  name: "Even Realities G1",
122
+ normalizeText: normalizeG1DisplayText,
119
123
  // Display dimensions
120
124
  displayWidthPx: 576,
121
125
  maxLines: 5,
@@ -170,6 +174,7 @@ export const G1_PROFILE = {
170
174
  export const G1_PROFILE_LEGACY = {
171
175
  id: "even-realities-g1-legacy",
172
176
  name: "Even Realities G1 (Legacy Client Compatibility)",
177
+ normalizeText: normalizeG1DisplayText,
173
178
  // Reduced display width to prevent double-wrapping overflow
174
179
  // Old mobile client wraps at ~90% of true width
175
180
  displayWidthPx: 420,
@@ -1 +1 @@
1
- {"version":3,"file":"g1.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g1.ts"],"names":[],"mappings":"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","sourcesContent":["import {DisplayProfile} from \"./types\"\n\n/**\n * Complete G1 glyph widths from G1FontLoaderKt\n * These are GLYPH widths - multiply using renderFormula to get rendered pixels.\n * Rendered width = (glyphWidth + 1) * 2\n */\nconst G1_GLYPH_WIDTHS: Record<string, number> = {\n // Punctuation & Symbols\n \" \": 2,\n \"!\": 1,\n '\"': 2,\n \"#\": 6,\n \"$\": 5,\n \"%\": 6,\n \"&\": 7,\n \"'\": 1,\n \"(\": 2,\n \")\": 2,\n \"*\": 3,\n \"+\": 4,\n \",\": 1,\n \"-\": 4, // Hyphen: 4px glyph → 10px rendered (CRITICAL for breaking!)\n \".\": 1,\n \"/\": 3,\n\n // Numbers\n \"0\": 5,\n \"1\": 3,\n \"2\": 5,\n \"3\": 5,\n \"4\": 5,\n \"5\": 5,\n \"6\": 5,\n \"7\": 5,\n \"8\": 5,\n \"9\": 5,\n\n // More punctuation\n \":\": 1,\n \";\": 1,\n \"<\": 4,\n \"=\": 4,\n \">\": 4,\n \"?\": 5,\n \"@\": 7,\n\n // Uppercase\n \"A\": 6,\n \"B\": 5,\n \"C\": 5,\n \"D\": 5,\n \"E\": 4,\n \"F\": 4,\n \"G\": 5,\n \"H\": 5,\n \"I\": 2,\n \"J\": 3,\n \"K\": 5,\n \"L\": 4,\n \"M\": 7,\n \"N\": 5,\n \"O\": 5,\n \"P\": 5,\n \"Q\": 5,\n \"R\": 5,\n \"S\": 5,\n \"T\": 5,\n \"U\": 5,\n \"V\": 6,\n \"W\": 7,\n \"X\": 6,\n \"Y\": 6,\n \"Z\": 5,\n\n // Brackets & special\n \"[\": 2,\n \"\\\\\": 3,\n \"]\": 2,\n \"^\": 4,\n \"_\": 3,\n \"`\": 2,\n\n // Lowercase\n \"a\": 5,\n \"b\": 4,\n \"c\": 4,\n \"d\": 4,\n \"e\": 4,\n \"f\": 4,\n \"g\": 4,\n \"h\": 4,\n \"i\": 1,\n \"j\": 2,\n \"k\": 4,\n \"l\": 1,\n \"m\": 7,\n \"n\": 4,\n \"o\": 4,\n \"p\": 4,\n \"q\": 4,\n \"r\": 3,\n \"s\": 4,\n \"t\": 3,\n \"u\": 5,\n \"v\": 5,\n \"w\": 7,\n \"x\": 5,\n \"y\": 5,\n \"z\": 4,\n\n // More special\n \"{\": 3,\n \"|\": 1,\n \"}\": 3,\n \"~\": 7,\n}\n\n/**\n * Even Realities G1 Smart Glasses Display Profile\n *\n * Verified through empirical testing with actual hardware.\n * See: line-width-debug-tool/line-width-spec.md\n */\nexport const G1_PROFILE: DisplayProfile = {\n id: \"even-realities-g1\",\n name: \"Even Realities G1\",\n\n // Display dimensions\n displayWidthPx: 576,\n maxLines: 5,\n\n // BLE constraints\n maxPayloadBytes: 390,\n bleChunkSize: 176,\n\n // Font metrics\n fontMetrics: {\n // Glyph widths from G1FontLoaderKt\n glyphWidths: new Map(Object.entries(G1_GLYPH_WIDTHS)),\n\n // Default glyph width for unmapped Latin characters (use max to be safe)\n defaultGlyphWidth: 7,\n\n // Rendered width = (glyphWidth + 1) * 2\n renderFormula: (glyphWidth: number) => (glyphWidth + 1) * 2,\n\n // Uniform-width scripts - ALL characters in these scripts render at this exact width\n // These are verified values in RENDERED pixels, NOT averages\n uniformScripts: {\n cjk: 18, // ALL Chinese/Japanese Kanji chars = 18px (verified)\n hiragana: 18, // ALL Hiragana chars = 18px (verified)\n katakana: 18, // ALL Katakana chars = 18px (verified)\n korean: 24, // ALL Korean Hangul chars = 24px (verified)\n cyrillic: 18, // ALL Cyrillic chars = 18px (verified)\n },\n\n // Fallback for unmapped Latin characters\n // Uses MAX width to guarantee no overflow (safe under-utilization)\n fallback: {\n latinMaxWidth: 16, // Max Latin = 'm', 'w' at (7+1)*2 = 16px\n unknownBehavior: \"useLatinMax\",\n },\n },\n\n constraints: {\n minCharsBeforeHyphen: 3,\n // Kinsoku: Characters that should not appear at start of line\n noStartChars: [\".\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"]\", \"}\", \"。\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"】\", \"」\"],\n // Kinsoku: Characters that should not appear at end of line\n noEndChars: [\"(\", \"[\", \"{\", \"(\", \"【\", \"「\"],\n },\n}\n\n/**\n * G1 Profile for LEGACY mobile clients that have their own wrapping logic.\n *\n * Old mobile clients re-wrap text received from the cloud, causing double-wrapping.\n * This profile uses a reduced display width (~522px instead of 576px) so that\n * when the mobile client re-wraps, the result still fits within 5 lines.\n *\n * Use this profile when:\n * - Mobile client version < X.X.X (has old wrapping logic)\n * - You see text getting cut off or exceeding 5 lines\n *\n * Once all clients are updated, this can be deprecated.\n */\nexport const G1_PROFILE_LEGACY: DisplayProfile = {\n id: \"even-realities-g1-legacy\",\n name: \"Even Realities G1 (Legacy Client Compatibility)\",\n\n // Reduced display width to prevent double-wrapping overflow\n // Old mobile client wraps at ~90% of true width\n displayWidthPx: 420,\n maxLines: 5,\n\n // BLE constraints (same as standard)\n maxPayloadBytes: 390,\n bleChunkSize: 176,\n\n // Font metrics (same as standard)\n fontMetrics: {\n glyphWidths: new Map(Object.entries(G1_GLYPH_WIDTHS)),\n defaultGlyphWidth: 7,\n renderFormula: (glyphWidth: number) => (glyphWidth + 1) * 2,\n uniformScripts: {\n cjk: 18,\n hiragana: 18,\n katakana: 18,\n korean: 24,\n cyrillic: 18,\n },\n fallback: {\n latinMaxWidth: 16,\n unknownBehavior: \"useLatinMax\",\n },\n },\n\n constraints: {\n minCharsBeforeHyphen: 3,\n noStartChars: [\".\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"]\", \"}\", \"。\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"】\", \"」\"],\n noEndChars: [\"(\", \"[\", \"{\", \"(\", \"【\", \"「\"],\n },\n}\n\n/**\n * Get the hyphen width for G1 in rendered pixels.\n * Hyphen glyph = 4px → rendered = (4+1)*2 = 10px\n */\nexport const G1_HYPHEN_WIDTH_PX = 10\n\n/**\n * Get the space width for G1 in rendered pixels.\n * Space glyph = 2px → rendered = (2+1)*2 = 6px\n */\nexport const G1_SPACE_WIDTH_PX = 6\n"]}
1
+ {"version":3,"file":"g1.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g1.ts"],"names":[],"mappings":"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","sourcesContent":["import {normalizeG1DisplayText} from \"../normalization\"\nimport {G1_LATIN_GLYPH_WIDTHS} from \"./g1LatinGlyphs\"\nimport {DisplayProfile} from \"./types\"\n\n/**\n * ASCII widths from G1FontLoaderKt and embedded G1 1.5.6 Latin glyphs.\n * These are GLYPH widths - multiply using renderFormula to get rendered pixels.\n * Rendered width = (glyphWidth + 1) * 2\n */\nconst G1_GLYPH_WIDTHS: Record<string, number> = {\n ...G1_LATIN_GLYPH_WIDTHS,\n\n // Punctuation & Symbols\n \" \": 2,\n \"!\": 1,\n '\"': 2,\n \"#\": 6,\n \"$\": 5,\n \"%\": 6,\n \"&\": 7,\n \"'\": 1,\n \"(\": 2,\n \")\": 2,\n \"*\": 3,\n \"+\": 4,\n \",\": 1,\n \"-\": 4, // Hyphen: 4px glyph → 10px rendered (CRITICAL for breaking!)\n \".\": 1,\n \"/\": 3,\n\n // Numbers\n \"0\": 5,\n \"1\": 3,\n \"2\": 5,\n \"3\": 5,\n \"4\": 5,\n \"5\": 5,\n \"6\": 5,\n \"7\": 5,\n \"8\": 5,\n \"9\": 5,\n\n // More punctuation\n \":\": 1,\n \";\": 1,\n \"<\": 4,\n \"=\": 4,\n \">\": 4,\n \"?\": 5,\n \"@\": 7,\n\n // Uppercase\n \"A\": 6,\n \"B\": 5,\n \"C\": 5,\n \"D\": 5,\n \"E\": 4,\n \"F\": 4,\n \"G\": 5,\n \"H\": 5,\n \"I\": 2,\n \"J\": 3,\n \"K\": 5,\n \"L\": 4,\n \"M\": 7,\n \"N\": 5,\n \"O\": 5,\n \"P\": 5,\n \"Q\": 5,\n \"R\": 5,\n \"S\": 5,\n \"T\": 5,\n \"U\": 5,\n \"V\": 6,\n \"W\": 7,\n \"X\": 6,\n \"Y\": 6,\n \"Z\": 5,\n\n // Brackets & special\n \"[\": 2,\n \"\\\\\": 3,\n \"]\": 2,\n \"^\": 4,\n \"_\": 3,\n \"`\": 2,\n\n // Lowercase\n \"a\": 5,\n \"b\": 4,\n \"c\": 4,\n \"d\": 4,\n \"e\": 4,\n \"f\": 4,\n \"g\": 4,\n \"h\": 4,\n \"i\": 1,\n \"j\": 2,\n \"k\": 4,\n \"l\": 1,\n \"m\": 7,\n \"n\": 4,\n \"o\": 4,\n \"p\": 4,\n \"q\": 4,\n \"r\": 3,\n \"s\": 4,\n \"t\": 3,\n \"u\": 5,\n \"v\": 5,\n \"w\": 7,\n \"x\": 5,\n \"y\": 5,\n \"z\": 4,\n\n // More special\n \"{\": 3,\n \"|\": 1,\n \"}\": 3,\n \"~\": 7,\n}\n\n/**\n * Even Realities G1 Smart Glasses Display Profile\n *\n * Verified through empirical testing with actual hardware.\n * See: line-width-debug-tool/line-width-spec.md\n */\nexport const G1_PROFILE: DisplayProfile = {\n id: \"even-realities-g1\",\n name: \"Even Realities G1\",\n\n normalizeText: normalizeG1DisplayText,\n\n // Display dimensions\n displayWidthPx: 576,\n maxLines: 5,\n\n // BLE constraints\n maxPayloadBytes: 390,\n bleChunkSize: 176,\n\n // Font metrics\n fontMetrics: {\n // Glyph widths from G1FontLoaderKt\n glyphWidths: new Map(Object.entries(G1_GLYPH_WIDTHS)),\n\n // Default glyph width for unmapped Latin characters (use max to be safe)\n defaultGlyphWidth: 7,\n\n // Rendered width = (glyphWidth + 1) * 2\n renderFormula: (glyphWidth: number) => (glyphWidth + 1) * 2,\n\n // Uniform-width scripts - ALL characters in these scripts render at this exact width\n // These are verified values in RENDERED pixels, NOT averages\n uniformScripts: {\n cjk: 18, // ALL Chinese/Japanese Kanji chars = 18px (verified)\n hiragana: 18, // ALL Hiragana chars = 18px (verified)\n katakana: 18, // ALL Katakana chars = 18px (verified)\n korean: 24, // ALL Korean Hangul chars = 24px (verified)\n cyrillic: 18, // ALL Cyrillic chars = 18px (verified)\n },\n\n // Fallback for unmapped Latin characters\n // Uses MAX width to guarantee no overflow (safe under-utilization)\n fallback: {\n latinMaxWidth: 16, // Max Latin = 'm', 'w' at (7+1)*2 = 16px\n unknownBehavior: \"useLatinMax\",\n },\n },\n\n constraints: {\n minCharsBeforeHyphen: 3,\n // Kinsoku: Characters that should not appear at start of line\n noStartChars: [\".\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"]\", \"}\", \"。\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"】\", \"」\"],\n // Kinsoku: Characters that should not appear at end of line\n noEndChars: [\"(\", \"[\", \"{\", \"(\", \"【\", \"「\"],\n },\n}\n\n/**\n * G1 Profile for LEGACY mobile clients that have their own wrapping logic.\n *\n * Old mobile clients re-wrap text received from the cloud, causing double-wrapping.\n * This profile uses a reduced display width (~522px instead of 576px) so that\n * when the mobile client re-wraps, the result still fits within 5 lines.\n *\n * Use this profile when:\n * - Mobile client version < X.X.X (has old wrapping logic)\n * - You see text getting cut off or exceeding 5 lines\n *\n * Once all clients are updated, this can be deprecated.\n */\nexport const G1_PROFILE_LEGACY: DisplayProfile = {\n id: \"even-realities-g1-legacy\",\n name: \"Even Realities G1 (Legacy Client Compatibility)\",\n\n normalizeText: normalizeG1DisplayText,\n\n // Reduced display width to prevent double-wrapping overflow\n // Old mobile client wraps at ~90% of true width\n displayWidthPx: 420,\n maxLines: 5,\n\n // BLE constraints (same as standard)\n maxPayloadBytes: 390,\n bleChunkSize: 176,\n\n // Font metrics (same as standard)\n fontMetrics: {\n glyphWidths: new Map(Object.entries(G1_GLYPH_WIDTHS)),\n defaultGlyphWidth: 7,\n renderFormula: (glyphWidth: number) => (glyphWidth + 1) * 2,\n uniformScripts: {\n cjk: 18,\n hiragana: 18,\n katakana: 18,\n korean: 24,\n cyrillic: 18,\n },\n fallback: {\n latinMaxWidth: 16,\n unknownBehavior: \"useLatinMax\",\n },\n },\n\n constraints: {\n minCharsBeforeHyphen: 3,\n noStartChars: [\".\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"]\", \"}\", \"。\", \",\", \"!\", \"?\", \":\", \";\", \")\", \"】\", \"」\"],\n noEndChars: [\"(\", \"[\", \"{\", \"(\", \"【\", \"「\"],\n },\n}\n\n/**\n * Get the hyphen width for G1 in rendered pixels.\n * Hyphen glyph = 4px → rendered = (4+1)*2 = 10px\n */\nexport const G1_HYPHEN_WIDTH_PX = 10\n\n/**\n * Get the space width for G1 in rendered pixels.\n * Space glyph = 2px → rendered = (2+1)*2 = 6px\n */\nexport const G1_SPACE_WIDTH_PX = 6\n"]}
@@ -0,0 +1,2 @@
1
+ export declare const G1_LATIN_GLYPH_WIDTHS: Record<string, number>;
2
+ //# sourceMappingURL=g1LatinGlyphs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"g1LatinGlyphs.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g1LatinGlyphs.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA6HxD,CAAA"}
@@ -0,0 +1,128 @@
1
+ // Embedded G1 1.5.6 Latin glyphs. See notes/g1-character-support.md.
2
+ export const G1_LATIN_GLYPH_WIDTHS = {
3
+ À: 6,
4
+ Â: 6,
5
+ Ç: 5,
6
+ È: 4,
7
+ É: 4,
8
+ Ê: 4,
9
+ Ë: 4,
10
+ Î: 3,
11
+ Ï: 3,
12
+ Ô: 5,
13
+ Ù: 5,
14
+ Û: 5,
15
+ Ü: 5,
16
+ à: 5,
17
+ ç: 4,
18
+ è: 4,
19
+ é: 4,
20
+ ê: 4,
21
+ ë: 4,
22
+ î: 3,
23
+ ï: 3,
24
+ ô: 4,
25
+ ù: 5,
26
+ û: 5,
27
+ ü: 5,
28
+ ÿ: 5,
29
+ Ÿ: 6,
30
+ Ä: 6,
31
+ ä: 5,
32
+ Ö: 5,
33
+ ö: 4,
34
+ ß: 4,
35
+ ẞ: 5,
36
+ â: 5,
37
+ Á: 6,
38
+ á: 5,
39
+ Í: 2,
40
+ í: 2,
41
+ Ñ: 5,
42
+ ñ: 4,
43
+ ú: 5,
44
+ Ó: 5,
45
+ ó: 4,
46
+ Ú: 5,
47
+ ⁱ: 6,
48
+ IJ: 4,
49
+ ij: 2,
50
+ Š: 5,
51
+ š: 4,
52
+ Ž: 5,
53
+ ž: 4,
54
+ Ã: 6,
55
+ Å: 6,
56
+ Æ: 8,
57
+ Ì: 2,
58
+ Ð: 5,
59
+ Ò: 5,
60
+ Õ: 5,
61
+ Ø: 6,
62
+ Ý: 6,
63
+ Þ: 5,
64
+ ã: 5,
65
+ å: 5,
66
+ æ: 8,
67
+ ì: 2,
68
+ ð: 5,
69
+ ò: 4,
70
+ õ: 4,
71
+ ø: 5,
72
+ ý: 5,
73
+ þ: 4,
74
+ Ą: 6,
75
+ ą: 5,
76
+ Ć: 5,
77
+ ć: 4,
78
+ Č: 5,
79
+ č: 4,
80
+ Ď: 5,
81
+ ď: 6,
82
+ Ę: 4,
83
+ ę: 4,
84
+ Ě: 4,
85
+ ě: 4,
86
+ Ğ: 5,
87
+ ğ: 4,
88
+ Ł: 5,
89
+ ł: 3,
90
+ Ń: 5,
91
+ ń: 4,
92
+ Ň: 5,
93
+ ň: 4,
94
+ Ř: 5,
95
+ ř: 3,
96
+ Ś: 5,
97
+ ś: 4,
98
+ Ş: 5,
99
+ ş: 4,
100
+ Ť: 5,
101
+ ť: 3,
102
+ Ů: 5,
103
+ ů: 5,
104
+ Ź: 5,
105
+ ź: 4,
106
+ Ż: 5,
107
+ ż: 4,
108
+ Ă: 6,
109
+ ă: 5,
110
+ ı: 1,
111
+ Ș: 5,
112
+ ș: 4,
113
+ Ț: 5,
114
+ ț: 3,
115
+ ǖ: 5,
116
+ ǘ: 5,
117
+ ǚ: 5,
118
+ ǜ: 5,
119
+ ǎ: 5,
120
+ ǐ: 3,
121
+ ǒ: 4,
122
+ ǔ: 5,
123
+ Ő: 5,
124
+ ő: 4,
125
+ Ű: 5,
126
+ ű: 5,
127
+ };
128
+ //# sourceMappingURL=g1LatinGlyphs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"g1LatinGlyphs.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g1LatinGlyphs.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;CACL,CAAA","sourcesContent":["// Embedded G1 1.5.6 Latin glyphs. See notes/g1-character-support.md.\nexport const G1_LATIN_GLYPH_WIDTHS: Record<string, number> = {\n À: 6,\n Â: 6,\n Ç: 5,\n È: 4,\n É: 4,\n Ê: 4,\n Ë: 4,\n Î: 3,\n Ï: 3,\n Ô: 5,\n Ù: 5,\n Û: 5,\n Ü: 5,\n à: 5,\n ç: 4,\n è: 4,\n é: 4,\n ê: 4,\n ë: 4,\n î: 3,\n ï: 3,\n ô: 4,\n ù: 5,\n û: 5,\n ü: 5,\n ÿ: 5,\n Ÿ: 6,\n Ä: 6,\n ä: 5,\n Ö: 5,\n ö: 4,\n ß: 4,\n ẞ: 5,\n â: 5,\n Á: 6,\n á: 5,\n Í: 2,\n í: 2,\n Ñ: 5,\n ñ: 4,\n ú: 5,\n Ó: 5,\n ó: 4,\n Ú: 5,\n ⁱ: 6,\n IJ: 4,\n ij: 2,\n Š: 5,\n š: 4,\n Ž: 5,\n ž: 4,\n Ã: 6,\n Å: 6,\n Æ: 8,\n Ì: 2,\n Ð: 5,\n Ò: 5,\n Õ: 5,\n Ø: 6,\n Ý: 6,\n Þ: 5,\n ã: 5,\n å: 5,\n æ: 8,\n ì: 2,\n ð: 5,\n ò: 4,\n õ: 4,\n ø: 5,\n ý: 5,\n þ: 4,\n Ą: 6,\n ą: 5,\n Ć: 5,\n ć: 4,\n Č: 5,\n č: 4,\n Ď: 5,\n ď: 6,\n Ę: 4,\n ę: 4,\n Ě: 4,\n ě: 4,\n Ğ: 5,\n ğ: 4,\n Ł: 5,\n ł: 3,\n Ń: 5,\n ń: 4,\n Ň: 5,\n ň: 4,\n Ř: 5,\n ř: 3,\n Ś: 5,\n ś: 4,\n Ş: 5,\n ş: 4,\n Ť: 5,\n ť: 3,\n Ů: 5,\n ů: 5,\n Ź: 5,\n ź: 4,\n Ż: 5,\n ż: 4,\n Ă: 6,\n ă: 5,\n ı: 1,\n Ș: 5,\n ș: 4,\n Ț: 5,\n ț: 3,\n ǖ: 5,\n ǘ: 5,\n ǚ: 5,\n ǜ: 5,\n ǎ: 5,\n ǐ: 3,\n ǒ: 4,\n ǔ: 5,\n Ő: 5,\n ő: 4,\n Ű: 5,\n ű: 5,\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"g2.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAsF3C,eAAO,MAAM,UAAU,EAAE,cAwBxB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA"}
1
+ {"version":3,"file":"g2.d.ts","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,SAAS,CAAA;AAsF3C,eAAO,MAAM,UAAU,EAAE,cAyBxB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,IAAI,CAAA"}
@@ -83,6 +83,7 @@ const G2_CYRILLIC_RENDERED_PX = {
83
83
  };
84
84
  export const G2_PROFILE = {
85
85
  ...G1_PROFILE,
86
+ normalizeText: undefined, // G2 sends Unicode without the G1 Latin fallback.
86
87
  id: "even-realities-g2",
87
88
  name: "Even Realities G2",
88
89
  // G2 fits more vertical text than G1 — allow up to 8 lines before the
@@ -1 +1 @@
1
- {"version":3,"file":"g2.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g2.ts"],"names":[],"mappings":"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","sourcesContent":["import {G1_PROFILE} from \"./g1\"\nimport type {DisplayProfile} from \"./types\"\n\n/**\n * Even Realities G2 display profile. Reuse G1's baseline metrics with\n * G2-specific line limits and proportional Russian Cyrillic advances.\n */\n\n/**\n * Russian Cyrillic advance widths in rendered pixels. Independently reproduced\n * with @evenrealities/evenhub-simulator 0.9.5: render each glyph 8 and 16 times,\n * subtract the alpha-bounds widths, then divide by 8 to cancel glyph bearings\n * and container padding. Simulator font rendering can differ from hardware.\n * Other Cyrillic characters retain the inherited 18px fallback.\n *\n * Values below are converted to raw glyph units for (g + 1) * 2. Half-unit\n * raw values preserve odd rendered advances exactly.\n */\nconst G2_CYRILLIC_RENDERED_PX: Record<string, number> = {\n а: 12,\n б: 12,\n в: 12,\n г: 9,\n д: 12,\n е: 11,\n ё: 11,\n ж: 13,\n з: 11,\n и: 12,\n й: 12,\n к: 10,\n л: 12,\n м: 14,\n н: 12,\n о: 11,\n п: 11,\n р: 12,\n с: 11,\n т: 11,\n у: 11,\n ф: 13,\n х: 11,\n ц: 12,\n ч: 12,\n ш: 14,\n щ: 15,\n ъ: 13,\n ы: 14,\n ь: 12,\n э: 11,\n ю: 14,\n я: 11,\n А: 13,\n Б: 13,\n В: 13,\n Г: 10,\n Д: 15,\n Е: 12,\n Ё: 12,\n Ж: 17,\n З: 12,\n И: 14,\n Й: 14,\n К: 13,\n Л: 14,\n М: 16,\n Н: 13,\n О: 14,\n П: 13,\n Р: 13,\n С: 13,\n Т: 12,\n У: 13,\n Ф: 16,\n Х: 13,\n Ц: 13,\n Ч: 12,\n Ш: 16,\n Щ: 17,\n Ъ: 15,\n Ы: 16,\n Ь: 13,\n Э: 13,\n Ю: 17,\n Я: 13,\n}\n\nexport const G2_PROFILE: DisplayProfile = {\n ...G1_PROFILE,\n id: \"even-realities-g2\",\n name: \"Even Realities G2\",\n // G2 fits more vertical text than G1 — allow up to 8 lines before the\n // wrapper truncates (G1 stays at its inherited 5).\n maxLines: 8,\n // Hardware-calibrated 2026-07-03: a 28px container overflowed one line of\n // the firmware font (triggering the fw's overflow indicator tick); 40px is\n // clean. With this set, the scene pipeline height-clips text so a box is\n // never handed more lines than fit.\n lineHeightPx: 40,\n fontMetrics: {\n ...G1_PROFILE.fontMetrics,\n // Glyph map takes priority over uniformScripts in TextMeasurer, so the\n // Cyrillic table overrides the uniform width for G2 only —\n // G1 keeps its verified uniform 18px untouched.\n glyphWidths: new Map<string, number>([\n ...G1_PROFILE.fontMetrics.glyphWidths,\n ...Object.entries(G2_CYRILLIC_RENDERED_PX).map(\n ([char, renderedPx]) => [char, renderedPx / 2 - 1] as [string, number],\n ),\n ]),\n },\n}\n\n/**\n * Get the hyphen width for G2 in rendered pixels.\n * Same as G1: Hyphen glyph = 4px → rendered = (4+1)*2 = 10px\n */\nexport const G2_HYPHEN_WIDTH_PX = 10\n\n/**\n * Get the space width for G2 in rendered pixels.\n * Same as G1: Space glyph = 2px → rendered = (2+1)*2 = 6px\n */\nexport const G2_SPACE_WIDTH_PX = 6\n"]}
1
+ {"version":3,"file":"g2.js","sourceRoot":"","sources":["../../../../src/utils/display/profiles/g2.ts"],"names":[],"mappings":"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","sourcesContent":["import {G1_PROFILE} from \"./g1\"\nimport type {DisplayProfile} from \"./types\"\n\n/**\n * Even Realities G2 display profile. Reuse G1's baseline metrics with\n * G2-specific line limits and proportional Russian Cyrillic advances.\n */\n\n/**\n * Russian Cyrillic advance widths in rendered pixels. Independently reproduced\n * with @evenrealities/evenhub-simulator 0.9.5: render each glyph 8 and 16 times,\n * subtract the alpha-bounds widths, then divide by 8 to cancel glyph bearings\n * and container padding. Simulator font rendering can differ from hardware.\n * Other Cyrillic characters retain the inherited 18px fallback.\n *\n * Values below are converted to raw glyph units for (g + 1) * 2. Half-unit\n * raw values preserve odd rendered advances exactly.\n */\nconst G2_CYRILLIC_RENDERED_PX: Record<string, number> = {\n а: 12,\n б: 12,\n в: 12,\n г: 9,\n д: 12,\n е: 11,\n ё: 11,\n ж: 13,\n з: 11,\n и: 12,\n й: 12,\n к: 10,\n л: 12,\n м: 14,\n н: 12,\n о: 11,\n п: 11,\n р: 12,\n с: 11,\n т: 11,\n у: 11,\n ф: 13,\n х: 11,\n ц: 12,\n ч: 12,\n ш: 14,\n щ: 15,\n ъ: 13,\n ы: 14,\n ь: 12,\n э: 11,\n ю: 14,\n я: 11,\n А: 13,\n Б: 13,\n В: 13,\n Г: 10,\n Д: 15,\n Е: 12,\n Ё: 12,\n Ж: 17,\n З: 12,\n И: 14,\n Й: 14,\n К: 13,\n Л: 14,\n М: 16,\n Н: 13,\n О: 14,\n П: 13,\n Р: 13,\n С: 13,\n Т: 12,\n У: 13,\n Ф: 16,\n Х: 13,\n Ц: 13,\n Ч: 12,\n Ш: 16,\n Щ: 17,\n Ъ: 15,\n Ы: 16,\n Ь: 13,\n Э: 13,\n Ю: 17,\n Я: 13,\n}\n\nexport const G2_PROFILE: DisplayProfile = {\n ...G1_PROFILE,\n normalizeText: undefined, // G2 sends Unicode without the G1 Latin fallback.\n id: \"even-realities-g2\",\n name: \"Even Realities G2\",\n // G2 fits more vertical text than G1 — allow up to 8 lines before the\n // wrapper truncates (G1 stays at its inherited 5).\n maxLines: 8,\n // Hardware-calibrated 2026-07-03: a 28px container overflowed one line of\n // the firmware font (triggering the fw's overflow indicator tick); 40px is\n // clean. With this set, the scene pipeline height-clips text so a box is\n // never handed more lines than fit.\n lineHeightPx: 40,\n fontMetrics: {\n ...G1_PROFILE.fontMetrics,\n // Glyph map takes priority over uniformScripts in TextMeasurer, so the\n // Cyrillic table overrides the uniform width for G2 only —\n // G1 keeps its verified uniform 18px untouched.\n glyphWidths: new Map<string, number>([\n ...G1_PROFILE.fontMetrics.glyphWidths,\n ...Object.entries(G2_CYRILLIC_RENDERED_PX).map(\n ([char, renderedPx]) => [char, renderedPx / 2 - 1] as [string, number],\n ),\n ]),\n },\n}\n\n/**\n * Get the hyphen width for G2 in rendered pixels.\n * Same as G1: Hyphen glyph = 4px → rendered = (4+1)*2 = 10px\n */\nexport const G2_HYPHEN_WIDTH_PX = 10\n\n/**\n * Get the space width for G2 in rendered pixels.\n * Same as G1: Space glyph = 2px → rendered = (2+1)*2 = 6px\n */\nexport const G2_SPACE_WIDTH_PX = 6\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentra/engine",
3
- "version": "3.3.0-dev.722",
3
+ "version": "3.3.0-dev.730",
4
4
  "description": "Mentra Engine — miniapp registry, WebView bridge, and miniapp store",
5
5
  "main": "build/index.js",
6
6
  "react-native": "src/index.ts",
@@ -97,13 +97,13 @@
97
97
  "registry": "https://registry.npmjs.org/"
98
98
  },
99
99
  "dependencies": {
100
- "@mentra/acs-meeting": "3.3.0-dev.722",
101
- "@mentra/glasses-media": "3.3.0-dev.722",
102
- "@mentra/bluetooth-sdk": "3.3.0-dev.722",
103
- "@mentra/cloud-client": "3.3.0-dev.722",
104
- "@mentra/cloud-protocol": "3.3.0-dev.722",
105
- "@mentra/crust": "3.3.0-dev.722",
106
- "@mentra/miniapp": "3.3.0-dev.722",
100
+ "@mentra/acs-meeting": "3.3.0-dev.730",
101
+ "@mentra/glasses-media": "3.3.0-dev.730",
102
+ "@mentra/bluetooth-sdk": "3.3.0-dev.730",
103
+ "@mentra/cloud-client": "3.3.0-dev.730",
104
+ "@mentra/cloud-protocol": "3.3.0-dev.730",
105
+ "@mentra/crust": "3.3.0-dev.730",
106
+ "@mentra/miniapp": "3.3.0-dev.730",
107
107
  "buffer": "^6.0.3",
108
108
  "events": "^3.3.0",
109
109
  "react-native-marked": "8.1.1",
@@ -12,9 +12,9 @@ export interface EngineReleaseMetadata {
12
12
  export const ENGINE_RELEASE_METADATA: Readonly<EngineReleaseMetadata> = Object.freeze({
13
13
  "schemaVersion": 1,
14
14
  "familyBaseVersion": "3.3.0",
15
- "releaseIdentity": "3.3.0-dev.722",
16
- "releaseSetId": "mentra-3.3.0-dev.722",
17
- "sourceCommit": "b780c4d82e1a352ade975ea43477c45166977b29",
18
- "otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.722.json",
19
- "otaManifestSha256": "6d0e5485747d2fc134b04c38476d1b54a300d6a08c4710eb445256b1dbcaf836"
15
+ "releaseIdentity": "3.3.0-dev.730",
16
+ "releaseSetId": "mentra-3.3.0-dev.730",
17
+ "sourceCommit": "558bc769919e2f69bc863012bf439db8358fed17",
18
+ "otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.3.0/mentra-live-ota-3.3.0-dev.730.json",
19
+ "otaManifestSha256": "91ebac8ac498f211418df31d731c3bda065b2e145e1ec48980324303484886c8"
20
20
  })
@@ -1,6 +1,7 @@
1
+ import {G1_LATIN_GLYPH_WIDTHS} from "./profiles/g1LatinGlyphs"
1
2
  import type {DisplayProfile} from "./profiles/types"
2
3
 
3
- // Mirrors the native LatinTextSanitizer used by G1 and NIMO.
4
+ // Mirrors the native fallback for unmapped G1 Latin glyphs and all NIMO Latin text.
4
5
  const LATIN_REPLACEMENTS: Record<string, string> = {
5
6
  Đ: "D",
6
7
  Ð: "D",
@@ -27,6 +28,20 @@ export function normalizeNimoDisplayText(text: string): string {
27
28
  .replace(/—/g, "-")
28
29
  }
29
30
 
31
+ /** Preserve firmware-mapped G1 Latin clusters before measuring or encoding text. */
32
+ export function normalizeG1DisplayText(text: string): string {
33
+ return text.replace(/\p{Script=Latin}\p{M}*/gu, (cluster) => {
34
+ const composed = cluster.normalize("NFC")
35
+ if (
36
+ composed.length === 1 &&
37
+ (composed.charCodeAt(0) <= 0x7e || Object.prototype.hasOwnProperty.call(G1_LATIN_GLYPH_WIDTHS, composed))
38
+ ) {
39
+ return composed
40
+ }
41
+ return normalizeNimoDisplayText(cluster)
42
+ })
43
+ }
44
+
30
45
  /** Keep feedback offsets in the miniapp's original UTF-16 source after glyph substitutions. */
31
46
  export function normalizeTextWithSource(text: string, profile: DisplayProfile) {
32
47
  if (!profile.normalizeText) return {text, sourceRange: (start: number, end: number) => ({start, end})}
@@ -47,7 +62,7 @@ export function normalizeTextWithSource(text: string, profile: DisplayProfile) {
47
62
  text: normalized,
48
63
  sourceRange: (start: number, end: number) => ({
49
64
  start: starts[start] ?? text.length,
50
- end: end > start ? ends[end - 1] : starts[start] ?? text.length,
65
+ end: end > start ? ends[end - 1] : (starts[start] ?? text.length),
51
66
  }),
52
67
  }
53
68
  }
@@ -1,11 +1,15 @@
1
+ import {normalizeG1DisplayText} from "../normalization"
2
+ import {G1_LATIN_GLYPH_WIDTHS} from "./g1LatinGlyphs"
1
3
  import {DisplayProfile} from "./types"
2
4
 
3
5
  /**
4
- * Complete G1 glyph widths from G1FontLoaderKt
6
+ * ASCII widths from G1FontLoaderKt and embedded G1 1.5.6 Latin glyphs.
5
7
  * These are GLYPH widths - multiply using renderFormula to get rendered pixels.
6
8
  * Rendered width = (glyphWidth + 1) * 2
7
9
  */
8
10
  const G1_GLYPH_WIDTHS: Record<string, number> = {
11
+ ...G1_LATIN_GLYPH_WIDTHS,
12
+
9
13
  // Punctuation & Symbols
10
14
  " ": 2,
11
15
  "!": 1,
@@ -126,6 +130,8 @@ export const G1_PROFILE: DisplayProfile = {
126
130
  id: "even-realities-g1",
127
131
  name: "Even Realities G1",
128
132
 
133
+ normalizeText: normalizeG1DisplayText,
134
+
129
135
  // Display dimensions
130
136
  displayWidthPx: 576,
131
137
  maxLines: 5,
@@ -189,6 +195,8 @@ export const G1_PROFILE_LEGACY: DisplayProfile = {
189
195
  id: "even-realities-g1-legacy",
190
196
  name: "Even Realities G1 (Legacy Client Compatibility)",
191
197
 
198
+ normalizeText: normalizeG1DisplayText,
199
+
192
200
  // Reduced display width to prevent double-wrapping overflow
193
201
  // Old mobile client wraps at ~90% of true width
194
202
  displayWidthPx: 420,
@@ -0,0 +1,127 @@
1
+ // Embedded G1 1.5.6 Latin glyphs. See notes/g1-character-support.md.
2
+ export const G1_LATIN_GLYPH_WIDTHS: Record<string, number> = {
3
+ À: 6,
4
+ Â: 6,
5
+ Ç: 5,
6
+ È: 4,
7
+ É: 4,
8
+ Ê: 4,
9
+ Ë: 4,
10
+ Î: 3,
11
+ Ï: 3,
12
+ Ô: 5,
13
+ Ù: 5,
14
+ Û: 5,
15
+ Ü: 5,
16
+ à: 5,
17
+ ç: 4,
18
+ è: 4,
19
+ é: 4,
20
+ ê: 4,
21
+ ë: 4,
22
+ î: 3,
23
+ ï: 3,
24
+ ô: 4,
25
+ ù: 5,
26
+ û: 5,
27
+ ü: 5,
28
+ ÿ: 5,
29
+ Ÿ: 6,
30
+ Ä: 6,
31
+ ä: 5,
32
+ Ö: 5,
33
+ ö: 4,
34
+ ß: 4,
35
+ ẞ: 5,
36
+ â: 5,
37
+ Á: 6,
38
+ á: 5,
39
+ Í: 2,
40
+ í: 2,
41
+ Ñ: 5,
42
+ ñ: 4,
43
+ ú: 5,
44
+ Ó: 5,
45
+ ó: 4,
46
+ Ú: 5,
47
+ ⁱ: 6,
48
+ IJ: 4,
49
+ ij: 2,
50
+ Š: 5,
51
+ š: 4,
52
+ Ž: 5,
53
+ ž: 4,
54
+ Ã: 6,
55
+ Å: 6,
56
+ Æ: 8,
57
+ Ì: 2,
58
+ Ð: 5,
59
+ Ò: 5,
60
+ Õ: 5,
61
+ Ø: 6,
62
+ Ý: 6,
63
+ Þ: 5,
64
+ ã: 5,
65
+ å: 5,
66
+ æ: 8,
67
+ ì: 2,
68
+ ð: 5,
69
+ ò: 4,
70
+ õ: 4,
71
+ ø: 5,
72
+ ý: 5,
73
+ þ: 4,
74
+ Ą: 6,
75
+ ą: 5,
76
+ Ć: 5,
77
+ ć: 4,
78
+ Č: 5,
79
+ č: 4,
80
+ Ď: 5,
81
+ ď: 6,
82
+ Ę: 4,
83
+ ę: 4,
84
+ Ě: 4,
85
+ ě: 4,
86
+ Ğ: 5,
87
+ ğ: 4,
88
+ Ł: 5,
89
+ ł: 3,
90
+ Ń: 5,
91
+ ń: 4,
92
+ Ň: 5,
93
+ ň: 4,
94
+ Ř: 5,
95
+ ř: 3,
96
+ Ś: 5,
97
+ ś: 4,
98
+ Ş: 5,
99
+ ş: 4,
100
+ Ť: 5,
101
+ ť: 3,
102
+ Ů: 5,
103
+ ů: 5,
104
+ Ź: 5,
105
+ ź: 4,
106
+ Ż: 5,
107
+ ż: 4,
108
+ Ă: 6,
109
+ ă: 5,
110
+ ı: 1,
111
+ Ș: 5,
112
+ ș: 4,
113
+ Ț: 5,
114
+ ț: 3,
115
+ ǖ: 5,
116
+ ǘ: 5,
117
+ ǚ: 5,
118
+ ǜ: 5,
119
+ ǎ: 5,
120
+ ǐ: 3,
121
+ ǒ: 4,
122
+ ǔ: 5,
123
+ Ő: 5,
124
+ ő: 4,
125
+ Ű: 5,
126
+ ű: 5,
127
+ }
@@ -87,6 +87,7 @@ const G2_CYRILLIC_RENDERED_PX: Record<string, number> = {
87
87
 
88
88
  export const G2_PROFILE: DisplayProfile = {
89
89
  ...G1_PROFILE,
90
+ normalizeText: undefined, // G2 sends Unicode without the G1 Latin fallback.
90
91
  id: "even-realities-g2",
91
92
  name: "Even Realities G2",
92
93
  // G2 fits more vertical text than G1 — allow up to 8 lines before the