canvas-emulator 1.0.0

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.
Files changed (147) hide show
  1. package/.gitignore +233 -0
  2. package/CLAUDE.md +61 -0
  3. package/README.md +128 -0
  4. package/dist/cjs/playground.d.ts +2 -0
  5. package/dist/cjs/playground.d.ts.map +1 -0
  6. package/dist/cjs/playground.js +37 -0
  7. package/dist/cjs/playground.js.map +1 -0
  8. package/dist/cjs/src/canvas/canvas.d.ts +41 -0
  9. package/dist/cjs/src/canvas/canvas.d.ts.map +1 -0
  10. package/dist/cjs/src/canvas/canvas.js +83 -0
  11. package/dist/cjs/src/canvas/canvas.js.map +1 -0
  12. package/dist/cjs/src/canvas/context-2d.d.ts +37 -0
  13. package/dist/cjs/src/canvas/context-2d.d.ts.map +1 -0
  14. package/dist/cjs/src/canvas/context-2d.js +245 -0
  15. package/dist/cjs/src/canvas/context-2d.js.map +1 -0
  16. package/dist/cjs/src/canvas/index.d.ts +2 -0
  17. package/dist/cjs/src/canvas/index.d.ts.map +1 -0
  18. package/dist/cjs/src/canvas/index.js +18 -0
  19. package/dist/cjs/src/canvas/index.js.map +1 -0
  20. package/dist/cjs/src/common/array.d.ts +40 -0
  21. package/dist/cjs/src/common/array.d.ts.map +1 -0
  22. package/dist/cjs/src/common/array.js +99 -0
  23. package/dist/cjs/src/common/array.js.map +1 -0
  24. package/dist/cjs/src/common/colors.d.ts +62 -0
  25. package/dist/cjs/src/common/colors.d.ts.map +1 -0
  26. package/dist/cjs/src/common/colors.js +93 -0
  27. package/dist/cjs/src/common/colors.js.map +1 -0
  28. package/dist/cjs/src/common/hash.d.ts +3 -0
  29. package/dist/cjs/src/common/hash.d.ts.map +1 -0
  30. package/dist/cjs/src/common/hash.js +44 -0
  31. package/dist/cjs/src/common/hash.js.map +1 -0
  32. package/dist/cjs/src/common/index.d.ts +7 -0
  33. package/dist/cjs/src/common/index.d.ts.map +1 -0
  34. package/dist/cjs/src/common/index.js +23 -0
  35. package/dist/cjs/src/common/index.js.map +1 -0
  36. package/dist/cjs/src/common/ppm.d.ts +2 -0
  37. package/dist/cjs/src/common/ppm.d.ts.map +1 -0
  38. package/dist/cjs/src/common/ppm.js +21 -0
  39. package/dist/cjs/src/common/ppm.js.map +1 -0
  40. package/dist/cjs/src/common/scalar.d.ts +27 -0
  41. package/dist/cjs/src/common/scalar.d.ts.map +1 -0
  42. package/dist/cjs/src/common/scalar.js +65 -0
  43. package/dist/cjs/src/common/scalar.js.map +1 -0
  44. package/dist/cjs/src/common/types.d.ts +9 -0
  45. package/dist/cjs/src/common/types.d.ts.map +1 -0
  46. package/dist/cjs/src/common/types.js +3 -0
  47. package/dist/cjs/src/common/types.js.map +1 -0
  48. package/dist/cjs/src/data/font/index.d.ts +2 -0
  49. package/dist/cjs/src/data/font/index.d.ts.map +1 -0
  50. package/dist/cjs/src/data/font/index.js +18 -0
  51. package/dist/cjs/src/data/font/index.js.map +1 -0
  52. package/dist/cjs/src/data/font/noto-mono-regular-48.d.ts +747 -0
  53. package/dist/cjs/src/data/font/noto-mono-regular-48.d.ts.map +1 -0
  54. package/dist/cjs/src/data/font/noto-mono-regular-48.js +15544 -0
  55. package/dist/cjs/src/data/font/noto-mono-regular-48.js.map +1 -0
  56. package/dist/cjs/src/data/font/noto-mono-regular-48.json +15540 -0
  57. package/dist/cjs/src/data/index.d.ts +2 -0
  58. package/dist/cjs/src/data/index.d.ts.map +1 -0
  59. package/dist/cjs/src/data/index.js +18 -0
  60. package/dist/cjs/src/data/index.js.map +1 -0
  61. package/dist/cjs/src/index.d.ts +4 -0
  62. package/dist/cjs/src/index.d.ts.map +1 -0
  63. package/dist/cjs/src/index.js +20 -0
  64. package/dist/cjs/src/index.js.map +1 -0
  65. package/dist/esm/playground.d.ts +2 -0
  66. package/dist/esm/playground.d.ts.map +1 -0
  67. package/dist/esm/playground.js +37 -0
  68. package/dist/esm/playground.js.map +1 -0
  69. package/dist/esm/src/canvas/canvas.d.ts +41 -0
  70. package/dist/esm/src/canvas/canvas.d.ts.map +1 -0
  71. package/dist/esm/src/canvas/canvas.js +83 -0
  72. package/dist/esm/src/canvas/canvas.js.map +1 -0
  73. package/dist/esm/src/canvas/context-2d.d.ts +37 -0
  74. package/dist/esm/src/canvas/context-2d.d.ts.map +1 -0
  75. package/dist/esm/src/canvas/context-2d.js +245 -0
  76. package/dist/esm/src/canvas/context-2d.js.map +1 -0
  77. package/dist/esm/src/canvas/index.d.ts +2 -0
  78. package/dist/esm/src/canvas/index.d.ts.map +1 -0
  79. package/dist/esm/src/canvas/index.js +18 -0
  80. package/dist/esm/src/canvas/index.js.map +1 -0
  81. package/dist/esm/src/common/array.d.ts +40 -0
  82. package/dist/esm/src/common/array.d.ts.map +1 -0
  83. package/dist/esm/src/common/array.js +99 -0
  84. package/dist/esm/src/common/array.js.map +1 -0
  85. package/dist/esm/src/common/colors.d.ts +62 -0
  86. package/dist/esm/src/common/colors.d.ts.map +1 -0
  87. package/dist/esm/src/common/colors.js +93 -0
  88. package/dist/esm/src/common/colors.js.map +1 -0
  89. package/dist/esm/src/common/hash.d.ts +3 -0
  90. package/dist/esm/src/common/hash.d.ts.map +1 -0
  91. package/dist/esm/src/common/hash.js +44 -0
  92. package/dist/esm/src/common/hash.js.map +1 -0
  93. package/dist/esm/src/common/index.d.ts +7 -0
  94. package/dist/esm/src/common/index.d.ts.map +1 -0
  95. package/dist/esm/src/common/index.js +23 -0
  96. package/dist/esm/src/common/index.js.map +1 -0
  97. package/dist/esm/src/common/ppm.d.ts +2 -0
  98. package/dist/esm/src/common/ppm.d.ts.map +1 -0
  99. package/dist/esm/src/common/ppm.js +21 -0
  100. package/dist/esm/src/common/ppm.js.map +1 -0
  101. package/dist/esm/src/common/scalar.d.ts +27 -0
  102. package/dist/esm/src/common/scalar.d.ts.map +1 -0
  103. package/dist/esm/src/common/scalar.js +65 -0
  104. package/dist/esm/src/common/scalar.js.map +1 -0
  105. package/dist/esm/src/common/types.d.ts +9 -0
  106. package/dist/esm/src/common/types.d.ts.map +1 -0
  107. package/dist/esm/src/common/types.js +3 -0
  108. package/dist/esm/src/common/types.js.map +1 -0
  109. package/dist/esm/src/data/font/index.d.ts +2 -0
  110. package/dist/esm/src/data/font/index.d.ts.map +1 -0
  111. package/dist/esm/src/data/font/index.js +18 -0
  112. package/dist/esm/src/data/font/index.js.map +1 -0
  113. package/dist/esm/src/data/font/noto-mono-regular-48.d.ts +747 -0
  114. package/dist/esm/src/data/font/noto-mono-regular-48.d.ts.map +1 -0
  115. package/dist/esm/src/data/font/noto-mono-regular-48.js +15544 -0
  116. package/dist/esm/src/data/font/noto-mono-regular-48.js.map +1 -0
  117. package/dist/esm/src/data/font/noto-mono-regular-48.json +15540 -0
  118. package/dist/esm/src/data/index.d.ts +2 -0
  119. package/dist/esm/src/data/index.d.ts.map +1 -0
  120. package/dist/esm/src/data/index.js +18 -0
  121. package/dist/esm/src/data/index.js.map +1 -0
  122. package/dist/esm/src/index.d.ts +4 -0
  123. package/dist/esm/src/index.d.ts.map +1 -0
  124. package/dist/esm/src/index.js +20 -0
  125. package/dist/esm/src/index.js.map +1 -0
  126. package/package.json +43 -0
  127. package/playground.ts +41 -0
  128. package/pnpm-lock.yaml +352 -0
  129. package/render_font.py +98 -0
  130. package/src/canvas/canvas.ts +123 -0
  131. package/src/canvas/context-2d.ts +305 -0
  132. package/src/canvas/index.ts +1 -0
  133. package/src/common/array.ts +176 -0
  134. package/src/common/colors.ts +93 -0
  135. package/src/common/hash.ts +46 -0
  136. package/src/common/index.ts +6 -0
  137. package/src/common/ppm.ts +28 -0
  138. package/src/common/scalar.ts +72 -0
  139. package/src/common/types.ts +10 -0
  140. package/src/data/font/index.ts +1 -0
  141. package/src/data/font/noto-mono-regular-48.json +15540 -0
  142. package/src/data/font/noto-mono-regular-48.ts +15540 -0
  143. package/src/data/index.ts +1 -0
  144. package/src/index.ts +3 -0
  145. package/tsconfig.cjs.json +10 -0
  146. package/tsconfig.esm.json +10 -0
  147. package/tsconfig.json +23 -0
@@ -0,0 +1,2 @@
1
+ export * from './font';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/data/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./font"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/data/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB"}
@@ -0,0 +1,4 @@
1
+ export * from "./canvas";
2
+ export * from "./common";
3
+ export * from './data';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./canvas"), exports);
18
+ __exportStar(require("./common"), exports);
19
+ __exportStar(require("./data"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,2CAAyB;AACzB,yCAAuB"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "canvas-emulator",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "./dist/cjs/index.js",
6
+ "types": "./dist/cjs/index.d.ts",
7
+ "typings": "./dist/cjs/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/esm/index.d.ts",
12
+ "default": "./dist/esm/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/cjs/index.d.ts",
16
+ "default": "./dist/cjs/index.js"
17
+ },
18
+ "default": {
19
+ "types": "./dist/cjs/index.d.ts",
20
+ "default": "./dist/cjs/index.js"
21
+ }
22
+ }
23
+ },
24
+ "files": [
25
+ "*",
26
+ "./dist/*"
27
+ ],
28
+ "keywords": [],
29
+ "author": "",
30
+ "license": "ISC",
31
+ "devDependencies": {
32
+ "@types/node": "^25.3.3",
33
+ "prettier": "^3.8.1",
34
+ "tsx": "^4.21.0",
35
+ "typescript": "^5.9.3"
36
+ },
37
+ "scripts": {
38
+ "test": "vitest",
39
+ "build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json",
40
+ "check": "tsc -p ./tsconfig.json --noEmit",
41
+ "format": "prettier --experimental-ternaries ./src --write"
42
+ }
43
+ }
package/playground.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { createPPM } from './src';
2
+ import { createCanvas } from './src/canvas/canvas';
3
+ import fs from 'fs';
4
+
5
+ const canvas = createCanvas({
6
+ width: 512,
7
+ height: 512
8
+ });
9
+
10
+ const ctx = canvas.getContext2D();
11
+
12
+
13
+ //ctx.save();
14
+ //ctx.beginPath();
15
+ //ctx.lineTo(canvas.width, canvas.height);
16
+ //ctx.closePath();
17
+ //ctx.stroke();
18
+ //ctx.restore();
19
+
20
+
21
+
22
+ //ctx.save();
23
+ //ctx.beginPath();
24
+ //ctx.arc(512/2, 512/2, 64, 0);
25
+ //ctx.closePath();
26
+ //ctx.fillStyle = 'purple';
27
+ //ctx.fill();
28
+ //ctx.restore();
29
+ //
30
+ //ctx.save();
31
+ //ctx.beginPath();
32
+ //ctx.rect((512/2)-16, (512/2)-16, 32, 32);
33
+ //ctx.closePath();
34
+ //ctx.fill();
35
+ //ctx.restore();
36
+
37
+ ctx.fillText('hello', 0, 512/4, 128);
38
+
39
+ const ppm = createPPM(canvas.width, canvas.height, canvas.renderRGB());
40
+
41
+ fs.writeFileSync('image.ppm', ppm, { encoding: 'utf-8' });
package/pnpm-lock.yaml ADDED
@@ -0,0 +1,352 @@
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+
9
+ .:
10
+ devDependencies:
11
+ '@types/node':
12
+ specifier: ^25.3.3
13
+ version: 25.3.3
14
+ prettier:
15
+ specifier: ^3.8.1
16
+ version: 3.8.1
17
+ tsx:
18
+ specifier: ^4.21.0
19
+ version: 4.21.0
20
+ typescript:
21
+ specifier: ^5.9.3
22
+ version: 5.9.3
23
+
24
+ packages:
25
+
26
+ '@esbuild/aix-ppc64@0.27.3':
27
+ resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
28
+ engines: {node: '>=18'}
29
+ cpu: [ppc64]
30
+ os: [aix]
31
+
32
+ '@esbuild/android-arm64@0.27.3':
33
+ resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==}
34
+ engines: {node: '>=18'}
35
+ cpu: [arm64]
36
+ os: [android]
37
+
38
+ '@esbuild/android-arm@0.27.3':
39
+ resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==}
40
+ engines: {node: '>=18'}
41
+ cpu: [arm]
42
+ os: [android]
43
+
44
+ '@esbuild/android-x64@0.27.3':
45
+ resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==}
46
+ engines: {node: '>=18'}
47
+ cpu: [x64]
48
+ os: [android]
49
+
50
+ '@esbuild/darwin-arm64@0.27.3':
51
+ resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==}
52
+ engines: {node: '>=18'}
53
+ cpu: [arm64]
54
+ os: [darwin]
55
+
56
+ '@esbuild/darwin-x64@0.27.3':
57
+ resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==}
58
+ engines: {node: '>=18'}
59
+ cpu: [x64]
60
+ os: [darwin]
61
+
62
+ '@esbuild/freebsd-arm64@0.27.3':
63
+ resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==}
64
+ engines: {node: '>=18'}
65
+ cpu: [arm64]
66
+ os: [freebsd]
67
+
68
+ '@esbuild/freebsd-x64@0.27.3':
69
+ resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==}
70
+ engines: {node: '>=18'}
71
+ cpu: [x64]
72
+ os: [freebsd]
73
+
74
+ '@esbuild/linux-arm64@0.27.3':
75
+ resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==}
76
+ engines: {node: '>=18'}
77
+ cpu: [arm64]
78
+ os: [linux]
79
+
80
+ '@esbuild/linux-arm@0.27.3':
81
+ resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==}
82
+ engines: {node: '>=18'}
83
+ cpu: [arm]
84
+ os: [linux]
85
+
86
+ '@esbuild/linux-ia32@0.27.3':
87
+ resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==}
88
+ engines: {node: '>=18'}
89
+ cpu: [ia32]
90
+ os: [linux]
91
+
92
+ '@esbuild/linux-loong64@0.27.3':
93
+ resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==}
94
+ engines: {node: '>=18'}
95
+ cpu: [loong64]
96
+ os: [linux]
97
+
98
+ '@esbuild/linux-mips64el@0.27.3':
99
+ resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==}
100
+ engines: {node: '>=18'}
101
+ cpu: [mips64el]
102
+ os: [linux]
103
+
104
+ '@esbuild/linux-ppc64@0.27.3':
105
+ resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==}
106
+ engines: {node: '>=18'}
107
+ cpu: [ppc64]
108
+ os: [linux]
109
+
110
+ '@esbuild/linux-riscv64@0.27.3':
111
+ resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==}
112
+ engines: {node: '>=18'}
113
+ cpu: [riscv64]
114
+ os: [linux]
115
+
116
+ '@esbuild/linux-s390x@0.27.3':
117
+ resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==}
118
+ engines: {node: '>=18'}
119
+ cpu: [s390x]
120
+ os: [linux]
121
+
122
+ '@esbuild/linux-x64@0.27.3':
123
+ resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==}
124
+ engines: {node: '>=18'}
125
+ cpu: [x64]
126
+ os: [linux]
127
+
128
+ '@esbuild/netbsd-arm64@0.27.3':
129
+ resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==}
130
+ engines: {node: '>=18'}
131
+ cpu: [arm64]
132
+ os: [netbsd]
133
+
134
+ '@esbuild/netbsd-x64@0.27.3':
135
+ resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==}
136
+ engines: {node: '>=18'}
137
+ cpu: [x64]
138
+ os: [netbsd]
139
+
140
+ '@esbuild/openbsd-arm64@0.27.3':
141
+ resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==}
142
+ engines: {node: '>=18'}
143
+ cpu: [arm64]
144
+ os: [openbsd]
145
+
146
+ '@esbuild/openbsd-x64@0.27.3':
147
+ resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==}
148
+ engines: {node: '>=18'}
149
+ cpu: [x64]
150
+ os: [openbsd]
151
+
152
+ '@esbuild/openharmony-arm64@0.27.3':
153
+ resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
154
+ engines: {node: '>=18'}
155
+ cpu: [arm64]
156
+ os: [openharmony]
157
+
158
+ '@esbuild/sunos-x64@0.27.3':
159
+ resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==}
160
+ engines: {node: '>=18'}
161
+ cpu: [x64]
162
+ os: [sunos]
163
+
164
+ '@esbuild/win32-arm64@0.27.3':
165
+ resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==}
166
+ engines: {node: '>=18'}
167
+ cpu: [arm64]
168
+ os: [win32]
169
+
170
+ '@esbuild/win32-ia32@0.27.3':
171
+ resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==}
172
+ engines: {node: '>=18'}
173
+ cpu: [ia32]
174
+ os: [win32]
175
+
176
+ '@esbuild/win32-x64@0.27.3':
177
+ resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==}
178
+ engines: {node: '>=18'}
179
+ cpu: [x64]
180
+ os: [win32]
181
+
182
+ '@types/node@25.3.3':
183
+ resolution: {integrity: sha512-DpzbrH7wIcBaJibpKo9nnSQL0MTRdnWttGyE5haGwK86xgMOkFLp7vEyfQPGLOJh5wNYiJ3V9PmUMDhV9u8kkQ==}
184
+
185
+ esbuild@0.27.3:
186
+ resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==}
187
+ engines: {node: '>=18'}
188
+ hasBin: true
189
+
190
+ fsevents@2.3.3:
191
+ resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
192
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
193
+ os: [darwin]
194
+
195
+ get-tsconfig@4.13.6:
196
+ resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==}
197
+
198
+ prettier@3.8.1:
199
+ resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
200
+ engines: {node: '>=14'}
201
+ hasBin: true
202
+
203
+ resolve-pkg-maps@1.0.0:
204
+ resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
205
+
206
+ tsx@4.21.0:
207
+ resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==}
208
+ engines: {node: '>=18.0.0'}
209
+ hasBin: true
210
+
211
+ typescript@5.9.3:
212
+ resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
213
+ engines: {node: '>=14.17'}
214
+ hasBin: true
215
+
216
+ undici-types@7.18.2:
217
+ resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
218
+
219
+ snapshots:
220
+
221
+ '@esbuild/aix-ppc64@0.27.3':
222
+ optional: true
223
+
224
+ '@esbuild/android-arm64@0.27.3':
225
+ optional: true
226
+
227
+ '@esbuild/android-arm@0.27.3':
228
+ optional: true
229
+
230
+ '@esbuild/android-x64@0.27.3':
231
+ optional: true
232
+
233
+ '@esbuild/darwin-arm64@0.27.3':
234
+ optional: true
235
+
236
+ '@esbuild/darwin-x64@0.27.3':
237
+ optional: true
238
+
239
+ '@esbuild/freebsd-arm64@0.27.3':
240
+ optional: true
241
+
242
+ '@esbuild/freebsd-x64@0.27.3':
243
+ optional: true
244
+
245
+ '@esbuild/linux-arm64@0.27.3':
246
+ optional: true
247
+
248
+ '@esbuild/linux-arm@0.27.3':
249
+ optional: true
250
+
251
+ '@esbuild/linux-ia32@0.27.3':
252
+ optional: true
253
+
254
+ '@esbuild/linux-loong64@0.27.3':
255
+ optional: true
256
+
257
+ '@esbuild/linux-mips64el@0.27.3':
258
+ optional: true
259
+
260
+ '@esbuild/linux-ppc64@0.27.3':
261
+ optional: true
262
+
263
+ '@esbuild/linux-riscv64@0.27.3':
264
+ optional: true
265
+
266
+ '@esbuild/linux-s390x@0.27.3':
267
+ optional: true
268
+
269
+ '@esbuild/linux-x64@0.27.3':
270
+ optional: true
271
+
272
+ '@esbuild/netbsd-arm64@0.27.3':
273
+ optional: true
274
+
275
+ '@esbuild/netbsd-x64@0.27.3':
276
+ optional: true
277
+
278
+ '@esbuild/openbsd-arm64@0.27.3':
279
+ optional: true
280
+
281
+ '@esbuild/openbsd-x64@0.27.3':
282
+ optional: true
283
+
284
+ '@esbuild/openharmony-arm64@0.27.3':
285
+ optional: true
286
+
287
+ '@esbuild/sunos-x64@0.27.3':
288
+ optional: true
289
+
290
+ '@esbuild/win32-arm64@0.27.3':
291
+ optional: true
292
+
293
+ '@esbuild/win32-ia32@0.27.3':
294
+ optional: true
295
+
296
+ '@esbuild/win32-x64@0.27.3':
297
+ optional: true
298
+
299
+ '@types/node@25.3.3':
300
+ dependencies:
301
+ undici-types: 7.18.2
302
+
303
+ esbuild@0.27.3:
304
+ optionalDependencies:
305
+ '@esbuild/aix-ppc64': 0.27.3
306
+ '@esbuild/android-arm': 0.27.3
307
+ '@esbuild/android-arm64': 0.27.3
308
+ '@esbuild/android-x64': 0.27.3
309
+ '@esbuild/darwin-arm64': 0.27.3
310
+ '@esbuild/darwin-x64': 0.27.3
311
+ '@esbuild/freebsd-arm64': 0.27.3
312
+ '@esbuild/freebsd-x64': 0.27.3
313
+ '@esbuild/linux-arm': 0.27.3
314
+ '@esbuild/linux-arm64': 0.27.3
315
+ '@esbuild/linux-ia32': 0.27.3
316
+ '@esbuild/linux-loong64': 0.27.3
317
+ '@esbuild/linux-mips64el': 0.27.3
318
+ '@esbuild/linux-ppc64': 0.27.3
319
+ '@esbuild/linux-riscv64': 0.27.3
320
+ '@esbuild/linux-s390x': 0.27.3
321
+ '@esbuild/linux-x64': 0.27.3
322
+ '@esbuild/netbsd-arm64': 0.27.3
323
+ '@esbuild/netbsd-x64': 0.27.3
324
+ '@esbuild/openbsd-arm64': 0.27.3
325
+ '@esbuild/openbsd-x64': 0.27.3
326
+ '@esbuild/openharmony-arm64': 0.27.3
327
+ '@esbuild/sunos-x64': 0.27.3
328
+ '@esbuild/win32-arm64': 0.27.3
329
+ '@esbuild/win32-ia32': 0.27.3
330
+ '@esbuild/win32-x64': 0.27.3
331
+
332
+ fsevents@2.3.3:
333
+ optional: true
334
+
335
+ get-tsconfig@4.13.6:
336
+ dependencies:
337
+ resolve-pkg-maps: 1.0.0
338
+
339
+ prettier@3.8.1: {}
340
+
341
+ resolve-pkg-maps@1.0.0: {}
342
+
343
+ tsx@4.21.0:
344
+ dependencies:
345
+ esbuild: 0.27.3
346
+ get-tsconfig: 4.13.6
347
+ optionalDependencies:
348
+ fsevents: 2.3.3
349
+
350
+ typescript@5.9.3: {}
351
+
352
+ undici-types@7.18.2: {}
package/render_font.py ADDED
@@ -0,0 +1,98 @@
1
+ import sys
2
+ import argparse
3
+ import string
4
+ from PIL import Image, ImageFont, ImageDraw
5
+
6
+ def get_glyph_data(font_path, char, size):
7
+ try:
8
+ # Use the specific size for rendering
9
+ font = ImageFont.truetype(font_path, size)
10
+ except Exception as e:
11
+ return None
12
+
13
+ # Get metrics
14
+ # glyph_metrics: (ascent, descent)
15
+ ascent, descent = font.getmetrics()
16
+
17
+ # getmask gives us the actual alpha buffer and its offset/size
18
+ mask = font.getmask(char)
19
+ mask_width, mask_height = mask.size
20
+
21
+ # getbbox: (left, top, right, bottom)
22
+ bbox = font.getbbox(char)
23
+ if not bbox:
24
+ # For spaces or empty glyphs
25
+ return {
26
+ "metrics": {"width": 0, "height": 0, "offset_x": 0, "offset_y": 0, "advance": font.getlength(char)},
27
+ "data": [0.0] * (size * size)
28
+ }
29
+
30
+ # Create the square canvas
31
+ image = Image.new("L", (size, size), 0)
32
+ draw = ImageDraw.Draw(image)
33
+
34
+ # Calculate centering for the VISUAL 1D array
35
+ # This keeps the JSON scanable while providing the math for real rendering
36
+ text_w = bbox[2] - bbox[0]
37
+ text_h = bbox[3] - bbox[1]
38
+
39
+ draw_x = (size - text_w) // 2 - bbox[0]
40
+ draw_y = (size - text_h) // 2 - bbox[1]
41
+
42
+ draw.text((draw_x, draw_y), char, font=font, fill=255)
43
+
44
+ # Flatten the 1:1 square data
45
+ flat_data = []
46
+ for y in range(size):
47
+ for x in range(size):
48
+ flat_data.append(round(image.getpixel((x, y)) / 255.0, 2))
49
+
50
+ return {
51
+ "metrics": {
52
+ "width": text_w,
53
+ "height": text_h,
54
+ "offset_x": bbox[0],
55
+ "offset_y": bbox[1],
56
+ "advance": round(font.getlength(char), 2)
57
+ },
58
+ "data": flat_data
59
+ }
60
+
61
+ def main():
62
+ parser = argparse.ArgumentParser()
63
+ parser.add_argument("font", help="Path to font file")
64
+ parser.add_argument("--size", type=int, default=16, help="Target square dimension")
65
+ args = parser.parse_args()
66
+
67
+ symbols = r"!@#$%^&*()_+-=[]{}|;':\",./<>? "
68
+ char_set = string.ascii_letters + string.digits + symbols
69
+ unique_chars = sorted(list(set(char_set)), key=ord)
70
+
71
+ print("{")
72
+ for i, char in enumerate(unique_chars):
73
+ ascii_key = str(ord(char))
74
+ result = get_glyph_data(args.font, char, args.size)
75
+
76
+ if result:
77
+ m = result["metrics"]
78
+ print(f' "{ascii_key}": {{')
79
+ print(f' "width": {m["width"]}, "height": {m["height"]},')
80
+ print(f' "offset_x": {m["offset_x"]}, "offset_y": {m["offset_y"]},')
81
+ print(f' "advance": {m["advance"]},')
82
+ print(f' "data": [')
83
+
84
+ # Print data rows for visual alignment
85
+ for row_idx in range(args.size):
86
+ start = row_idx * args.size
87
+ end = start + args.size
88
+ row_slice = result["data"][start:end]
89
+ formatted_row = ", ".join(f"{v:4.2f}" for v in row_slice)
90
+ row_comma = "," if row_idx < args.size - 1 else ""
91
+ print(f" {formatted_row}{row_comma}")
92
+
93
+ print(f' ]')
94
+ print(f' }}{"," if i < len(unique_chars) - 1 else ""}')
95
+ print("}")
96
+
97
+ if __name__ == "__main__":
98
+ main()