piximps 0.1.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 (40) hide show
  1. package/.github/workflows/ci.yml +20 -0
  2. package/.github/workflows/demo.yml +22 -0
  3. package/.github/workflows/release.yml +22 -0
  4. package/README.md +110 -0
  5. package/docs/browser.global.js +1539 -0
  6. package/docs/index.html +442 -0
  7. package/package.json +42 -0
  8. package/src/piximps/browser.ts +114 -0
  9. package/src/piximps/common/templates/accessories.ts +174 -0
  10. package/src/piximps/common/templates/body.ts +390 -0
  11. package/src/piximps/common/templates/eyes.ts +95 -0
  12. package/src/piximps/common/templates/horns.ts +152 -0
  13. package/src/piximps/common/templates/mouth.ts +96 -0
  14. package/src/piximps/common/templates/types.ts +4 -0
  15. package/src/piximps/domain/color-palette.ts +22 -0
  16. package/src/piximps/domain/imp-traits.ts +35 -0
  17. package/src/piximps/domain/template.ts +35 -0
  18. package/src/piximps/domain/types.ts +34 -0
  19. package/src/piximps/entrypoints/renderers/to-png-binary.ts +13 -0
  20. package/src/piximps/entrypoints/renderers/to-rgba-buffer.ts +26 -0
  21. package/src/piximps/entrypoints/renderers/to-svg-string.ts +28 -0
  22. package/src/piximps/index.ts +117 -0
  23. package/src/piximps/services/edge-detector.ts +60 -0
  24. package/src/piximps/services/hash-to-byte-sequence.ts +75 -0
  25. package/src/piximps/services/layer-compositor.ts +157 -0
  26. package/src/piximps/services/palette-deriver.ts +75 -0
  27. package/src/piximps/services/trait-extractor.ts +88 -0
  28. package/tests/functional/test-domain-models.test.ts +136 -0
  29. package/tests/functional/test-edge-detector.test.ts +64 -0
  30. package/tests/functional/test-hash-to-byte-sequence.test.ts +39 -0
  31. package/tests/functional/test-layer-compositor.test.ts +107 -0
  32. package/tests/functional/test-palette-deriver.test.ts +43 -0
  33. package/tests/functional/test-renderers.test.ts +105 -0
  34. package/tests/functional/test-trait-extractor.test.ts +50 -0
  35. package/tests/integration/test-determinism.test.ts +40 -0
  36. package/tests/integration/test-generator-builder.test.ts +56 -0
  37. package/tests/integration/test-output-formats.test.ts +47 -0
  38. package/tsconfig.json +24 -0
  39. package/tsup.config.ts +11 -0
  40. package/vitest.config.ts +18 -0
@@ -0,0 +1,174 @@
1
+ import { CellType as C } from '@piximps/domain/types'
2
+ import { Template } from '@piximps/domain/template'
3
+ import { type TemplateRegistry } from './types'
4
+
5
+ const _ = C.AlwaysEmpty
6
+ const F = C.AlwaysFilled
7
+ const P = C.Probabilistic
8
+
9
+ const tail8 = new Template({
10
+ grid: [
11
+ [_, _, _, _],
12
+ [_, _, _, _],
13
+ [_, _, _, _],
14
+ [_, _, _, _],
15
+ [_, _, _, _],
16
+ [_, _, _, _],
17
+ [F, _, _, _],
18
+ [_, F, _, _],
19
+ ],
20
+ anchors: {},
21
+ compatibleWith: [],
22
+ symmetric: false,
23
+ })
24
+
25
+ const wings8 = new Template({
26
+ grid: [
27
+ [_, _, _, _],
28
+ [_, _, _, _],
29
+ [_, _, _, _],
30
+ [F, P, _, _],
31
+ [F, F, _, _],
32
+ [_, _, _, _],
33
+ [_, _, _, _],
34
+ [_, _, _, _],
35
+ ],
36
+ anchors: {},
37
+ compatibleWith: [],
38
+ symmetric: false,
39
+ })
40
+
41
+ const tail16 = new Template({
42
+ grid: [
43
+ [_, _, _, _, _, _, _, _],
44
+ [_, _, _, _, _, _, _, _],
45
+ [_, _, _, _, _, _, _, _],
46
+ [_, _, _, _, _, _, _, _],
47
+ [_, _, _, _, _, _, _, _],
48
+ [_, _, _, _, _, _, _, _],
49
+ [_, _, _, _, _, _, _, _],
50
+ [_, _, _, _, _, _, _, _],
51
+ [_, _, _, _, _, _, _, _],
52
+ [_, _, _, _, _, _, _, _],
53
+ [_, _, _, _, _, _, _, _],
54
+ [F, _, _, _, _, _, _, _],
55
+ [_, F, _, _, _, _, _, _],
56
+ [_, _, F, _, _, _, _, _],
57
+ [_, _, F, _, _, _, _, _],
58
+ [_, F, P, _, _, _, _, _],
59
+ ],
60
+ anchors: {},
61
+ compatibleWith: [],
62
+ symmetric: false,
63
+ })
64
+
65
+ const wings16 = new Template({
66
+ grid: [
67
+ [_, _, _, _, _, _, _, _],
68
+ [_, _, _, _, _, _, _, _],
69
+ [_, _, _, _, _, _, _, _],
70
+ [_, _, _, _, _, _, _, _],
71
+ [_, _, _, _, _, _, _, _],
72
+ [_, _, _, _, _, _, _, _],
73
+ [F, _, _, _, _, _, _, _],
74
+ [F, F, _, _, _, _, _, _],
75
+ [F, F, P, _, _, _, _, _],
76
+ [F, F, F, _, _, _, _, _],
77
+ [_, F, F, _, _, _, _, _],
78
+ [_, _, F, _, _, _, _, _],
79
+ [_, _, _, _, _, _, _, _],
80
+ [_, _, _, _, _, _, _, _],
81
+ [_, _, _, _, _, _, _, _],
82
+ [_, _, _, _, _, _, _, _],
83
+ ],
84
+ anchors: {},
85
+ compatibleWith: [],
86
+ symmetric: false,
87
+ })
88
+
89
+ const tail32 = new Template({
90
+ grid: [
91
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
92
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
93
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
94
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
95
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
96
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
97
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
98
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
99
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
100
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
101
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
102
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
103
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
104
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
105
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
106
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
107
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
108
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
109
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
110
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
111
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
112
+ [F, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
113
+ [_, F, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
114
+ [_, _, F, _, _, _, _, _, _, _, _, _, _, _, _, _],
115
+ [_, _, _, F, _, _, _, _, _, _, _, _, _, _, _, _],
116
+ [_, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _],
117
+ [_, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _],
118
+ [_, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _],
119
+ [_, _, _, F, F, _, _, _, _, _, _, _, _, _, _, _],
120
+ [_, _, F, P, _, _, _, _, _, _, _, _, _, _, _, _],
121
+ [_, F, F, _, _, _, _, _, _, _, _, _, _, _, _, _],
122
+ [P, F, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
123
+ ],
124
+ anchors: {},
125
+ compatibleWith: [],
126
+ symmetric: false,
127
+ })
128
+
129
+ const wings32 = new Template({
130
+ grid: [
131
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
132
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
133
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
134
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
135
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
136
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
137
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
138
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
139
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
140
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
141
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
142
+ [F, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
143
+ [F, F, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
144
+ [F, F, F, _, _, _, _, _, _, _, _, _, _, _, _, _],
145
+ [F, F, F, F, _, _, _, _, _, _, _, _, _, _, _, _],
146
+ [F, F, P, F, F, _, _, _, _, _, _, _, _, _, _, _],
147
+ [F, F, P, P, F, F, _, _, _, _, _, _, _, _, _, _],
148
+ [F, P, F, P, F, F, _, _, _, _, _, _, _, _, _, _],
149
+ [_, F, F, F, F, F, _, _, _, _, _, _, _, _, _, _],
150
+ [_, _, F, F, F, _, _, _, _, _, _, _, _, _, _, _],
151
+ [_, _, _, F, F, _, _, _, _, _, _, _, _, _, _, _],
152
+ [_, _, _, _, F, _, _, _, _, _, _, _, _, _, _, _],
153
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
154
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
155
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
156
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
157
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
158
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
159
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
160
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
161
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
162
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _],
163
+ ],
164
+ anchors: {},
165
+ compatibleWith: [],
166
+ symmetric: false,
167
+ })
168
+
169
+ export const accessoryTemplates: Record<string, TemplateRegistry> = {
170
+ tail: { 8: [tail8], 16: [tail16], 32: [tail32] },
171
+ wings: { 8: [wings8], 16: [wings16], 32: [wings32] },
172
+ weapon: { 8: [], 16: [], 32: [] },
173
+ hat: { 8: [], 16: [], 32: [] },
174
+ }
@@ -0,0 +1,390 @@
1
+ import { CellType as C } from '@piximps/domain/types'
2
+ import { Template } from '@piximps/domain/template'
3
+ import { type TemplateRegistry } from './types'
4
+
5
+ const _ = C.AlwaysEmpty
6
+ const P = C.Probabilistic
7
+ const F = C.AlwaysFilled
8
+ const B = C.InnerBody
9
+
10
+ // ============================================================
11
+ // 8x8 bodies (half-width = 4 cols, mirrored width = 7)
12
+ // These are small so anatomy is simplified but should
13
+ // read as upright humanoid imps, not blobs.
14
+ // ============================================================
15
+
16
+ // Stocky imp: wide shoulders, short legs
17
+ const stocky8 = new Template({
18
+ grid: [
19
+ [_, _, F, F], // pointed head top
20
+ [_, _, B, B], // head
21
+ [_, F, B, B], // shoulders (wide)
22
+ [_, P, F, B], // arms out + torso
23
+ [_, _, F, B], // waist
24
+ [_, _, B, B], // hips
25
+ [_, _, F, F], // upper legs
26
+ [_, _, F, _], // feet apart
27
+ ],
28
+ anchors: {
29
+ horns: { row: 0, columnStart: 2, columnEnd: 3 },
30
+ eyes: { row: 1, columnStart: 2, columnEnd: 3 },
31
+ mouth: { row: 2, columnStart: 2, columnEnd: 3 },
32
+ },
33
+ compatibleWith: ['wide-horns', 'small-horns', 'single-eye', 'double-eye', 'fangs', 'grin'],
34
+ symmetric: true,
35
+ })
36
+
37
+ // Lanky imp: tall, thin, long legs
38
+ const lanky8 = new Template({
39
+ grid: [
40
+ [_, _, F, F], // pointed head
41
+ [_, _, B, B], // head
42
+ [_, _, F, B], // narrow shoulders
43
+ [_, P, F, B], // arm + torso
44
+ [_, _, F, B], // waist
45
+ [_, _, F, F], // hips
46
+ [_, _, F, _], // legs
47
+ [_, _, F, _], // feet
48
+ ],
49
+ anchors: {
50
+ horns: { row: 0, columnStart: 2, columnEnd: 3 },
51
+ eyes: { row: 1, columnStart: 2, columnEnd: 3 },
52
+ mouth: { row: 2, columnStart: 2, columnEnd: 3 },
53
+ },
54
+ compatibleWith: ['tall-horns', 'small-horns', 'single-eye', 'double-eye', 'fangs', 'smirk'],
55
+ symmetric: true,
56
+ })
57
+
58
+ // Brawler imp: very wide shoulders, thick arms, sturdy
59
+ const brawler8 = new Template({
60
+ grid: [
61
+ [_, _, F, F], // head top
62
+ [_, F, B, B], // head (wider)
63
+ [F, F, B, B], // big shoulders
64
+ [F, P, F, B], // arms out wide
65
+ [_, _, F, B], // narrow waist
66
+ [_, _, B, B], // hips
67
+ [_, _, F, F], // legs
68
+ [_, F, _, F], // wide stance
69
+ ],
70
+ anchors: {
71
+ horns: { row: 0, columnStart: 2, columnEnd: 3 },
72
+ eyes: { row: 1, columnStart: 1, columnEnd: 3 },
73
+ mouth: { row: 2, columnStart: 1, columnEnd: 3 },
74
+ },
75
+ compatibleWith: ['wide-horns', 'small-horns', 'triple-eye', 'double-eye', 'fangs', 'grin'],
76
+ symmetric: true,
77
+ })
78
+
79
+ // ============================================================
80
+ // 16x16 bodies (half-width = 8 cols, mirrored width = 15)
81
+ // More room for distinct head, neck, torso, arms, legs.
82
+ // ============================================================
83
+
84
+ // Classic imp: balanced proportions, arms out, digitigrade legs
85
+ const classic16 = new Template({
86
+ grid: [
87
+ [_, _, _, _, _, _, _, _], // row 0
88
+ [_, _, _, _, _, _, _, _], // row 1
89
+ [_, _, _, _, _, _, F, F], // row 2: head top (pointed)
90
+ [_, _, _, _, _, F, B, B], // row 3: head
91
+ [_, _, _, _, _, F, B, B], // row 4: head
92
+ [_, _, _, _, _, F, B, B], // row 5: lower head
93
+ [_, _, _, _, _, _, F, F], // row 6: neck
94
+ [_, _, _, _, F, F, B, F], // row 7: shoulders
95
+ [_, _, _, P, F, B, B, F], // row 8: arms + upper torso
96
+ [_, _, _, _, F, B, B, F], // row 9: torso
97
+ [_, _, _, _, _, F, B, F], // row 10: waist (narrow)
98
+ [_, _, _, _, _, F, B, F], // row 11: hips
99
+ [_, _, _, _, _, F, F, F], // row 12: upper legs
100
+ [_, _, _, _, _, F, _, F], // row 13: legs apart
101
+ [_, _, _, _, _, F, _, F], // row 14: lower legs
102
+ [_, _, _, _, F, F, _, _], // row 15: feet (digitigrade)
103
+ ],
104
+ anchors: {
105
+ horns: { row: 2, columnStart: 6, columnEnd: 7 },
106
+ eyes: { row: 4, columnStart: 5, columnEnd: 7 },
107
+ mouth: { row: 5, columnStart: 5, columnEnd: 7 },
108
+ },
109
+ compatibleWith: ['wide-horns', 'small-horns', 'single-eye', 'double-eye', 'fangs', 'grin'],
110
+ symmetric: true,
111
+ })
112
+
113
+ // Lanky imp: tall narrow head, long thin body, very long legs
114
+ const lanky16 = new Template({
115
+ grid: [
116
+ [_, _, _, _, _, _, _, _], // row 0
117
+ [_, _, _, _, _, _, F, F], // row 1: head top
118
+ [_, _, _, _, _, _, B, B], // row 2: head
119
+ [_, _, _, _, _, F, B, B], // row 3: head
120
+ [_, _, _, _, _, F, B, B], // row 4: lower head
121
+ [_, _, _, _, _, _, F, F], // row 5: neck
122
+ [_, _, _, _, _, F, B, F], // row 6: shoulders
123
+ [_, _, _, _, P, F, B, F], // row 7: arm + torso
124
+ [_, _, _, _, _, F, B, F], // row 8: torso
125
+ [_, _, _, _, _, F, B, F], // row 9: torso
126
+ [_, _, _, _, _, _, F, F], // row 10: waist
127
+ [_, _, _, _, _, _, F, F], // row 11: hips
128
+ [_, _, _, _, _, _, F, _], // row 12: legs
129
+ [_, _, _, _, _, _, F, _], // row 13: legs
130
+ [_, _, _, _, _, _, F, _], // row 14: lower legs
131
+ [_, _, _, _, _, F, F, _], // row 15: feet
132
+ ],
133
+ anchors: {
134
+ horns: { row: 1, columnStart: 6, columnEnd: 7 },
135
+ eyes: { row: 3, columnStart: 5, columnEnd: 7 },
136
+ mouth: { row: 4, columnStart: 5, columnEnd: 7 },
137
+ },
138
+ compatibleWith: ['tall-horns', 'small-horns', 'single-eye', 'double-eye', 'fangs', 'smirk'],
139
+ symmetric: true,
140
+ })
141
+
142
+ // Brute imp: wide shoulders, thick arms, powerful build
143
+ const brute16 = new Template({
144
+ grid: [
145
+ [_, _, _, _, _, _, _, _], // row 0
146
+ [_, _, _, _, _, _, _, _], // row 1
147
+ [_, _, _, _, _, _, F, F], // row 2: head top
148
+ [_, _, _, _, _, F, B, B], // row 3: head
149
+ [_, _, _, _, _, F, B, B], // row 4: head
150
+ [_, _, _, _, _, F, B, B], // row 5: jaw
151
+ [_, _, _, _, _, _, F, F], // row 6: neck
152
+ [_, _, _, _, F, F, B, F], // row 7: shoulders
153
+ [_, _, _, F, F, B, B, F], // row 8: big arms
154
+ [_, _, P, F, F, B, B, F], // row 9: forearms
155
+ [_, _, _, _, F, B, B, F], // row 10: torso
156
+ [_, _, _, _, _, F, B, F], // row 11: waist
157
+ [_, _, _, _, _, F, B, F], // row 12: hips
158
+ [_, _, _, _, _, F, F, F], // row 13: upper legs
159
+ [_, _, _, _, F, F, _, F], // row 14: legs apart
160
+ [_, _, _, _, F, _, _, F], // row 15: wide stance
161
+ ],
162
+ anchors: {
163
+ horns: { row: 2, columnStart: 6, columnEnd: 7 },
164
+ eyes: { row: 4, columnStart: 5, columnEnd: 7 },
165
+ mouth: { row: 5, columnStart: 5, columnEnd: 7 },
166
+ },
167
+ compatibleWith: ['wide-horns', 'small-horns', 'triple-eye', 'double-eye', 'fangs', 'grin'],
168
+ symmetric: true,
169
+ })
170
+
171
+ // Hunched imp: head jutting forward, bent posture, long arms
172
+ const hunched16 = new Template({
173
+ grid: [
174
+ [_, _, _, _, _, _, _, _], // row 0
175
+ [_, _, _, _, _, _, _, _], // row 1
176
+ [_, _, _, _, _, _, _, _], // row 2
177
+ [_, _, _, _, _, _, F, F], // row 3: head top
178
+ [_, _, _, _, _, F, B, B], // row 4: head
179
+ [_, _, _, _, _, F, B, B], // row 5: head
180
+ [_, _, _, _, _, F, F, F], // row 6: neck (forward)
181
+ [_, _, _, _, F, F, B, F], // row 7: hunched shoulders
182
+ [_, _, _, P, F, B, B, F], // row 8: long arms
183
+ [_, _, P, F, F, B, B, F], // row 9: arms reaching down
184
+ [_, _, _, _, F, F, B, F], // row 10: torso
185
+ [_, _, _, _, _, F, B, F], // row 11: waist
186
+ [_, _, _, _, _, F, F, F], // row 12: hips
187
+ [_, _, _, _, _, F, _, F], // row 13: legs
188
+ [_, _, _, _, _, F, _, F], // row 14: lower legs
189
+ [_, _, _, _, F, F, _, _], // row 15: feet
190
+ ],
191
+ anchors: {
192
+ horns: { row: 3, columnStart: 6, columnEnd: 7 },
193
+ eyes: { row: 4, columnStart: 5, columnEnd: 7 },
194
+ mouth: { row: 5, columnStart: 5, columnEnd: 7 },
195
+ },
196
+ compatibleWith: ['wide-horns', 'tall-horns', 'single-eye', 'double-eye', 'fangs', 'smirk'],
197
+ symmetric: true,
198
+ })
199
+
200
+ // ============================================================
201
+ // 32x32 bodies (half-width = 16 cols, mirrored width = 31)
202
+ // Full detail: distinct head shape, neck, shoulders, arms
203
+ // with claws, defined torso, narrow waist, digitigrade legs.
204
+ // ============================================================
205
+
206
+ // Classic imp 32: balanced proportions
207
+ const classic32 = new Template({
208
+ grid: [
209
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 0
210
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 1
211
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 2
212
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 3
213
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, F], // 4: head top
214
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, B, B], // 5: head
215
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 6: head wide
216
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 7: head
217
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 8: lower head
218
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 9: jaw
219
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, F, F, F], // 10: chin
220
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, _], // 11: neck
221
+ [_, _, _, _, _, _, _, _, _, _, F, F, F, B, F, _], // 12: shoulders
222
+ [_, _, _, _, _, _, _, _, _, F, F, B, B, B, F, _], // 13: upper torso
223
+ [_, _, _, _, _, _, _, _, P, F, B, B, B, B, F, _], // 14: arms out
224
+ [_, _, _, _, _, _, _, P, F, F, B, B, B, B, F, _], // 15: forearms
225
+ [_, _, _, _, _, _, _, _, _, F, F, B, B, B, F, _], // 16: torso
226
+ [_, _, _, _, _, _, _, _, _, _, F, B, B, B, F, _], // 17: torso
227
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 18: waist
228
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 19: waist
229
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 20: hips
230
+ [_, _, _, _, _, _, _, _, _, _, _, F, F, F, F, _], // 21: upper legs
231
+ [_, _, _, _, _, _, _, _, _, _, _, F, F, _, F, _], // 22: legs split
232
+ [_, _, _, _, _, _, _, _, _, _, _, F, _, _, F, _], // 23: legs
233
+ [_, _, _, _, _, _, _, _, _, _, _, F, _, _, F, _], // 24: legs
234
+ [_, _, _, _, _, _, _, _, _, _, _, F, _, _, F, _], // 25: lower legs
235
+ [_, _, _, _, _, _, _, _, _, _, F, F, _, _, F, _], // 26: ankles
236
+ [_, _, _, _, _, _, _, _, _, _, F, _, _, F, F, _], // 27: digitigrade feet
237
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 28
238
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 29
239
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 30
240
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 31
241
+ ],
242
+ anchors: {
243
+ horns: { row: 4, columnStart: 13, columnEnd: 15 },
244
+ eyes: { row: 7, columnStart: 11, columnEnd: 15 },
245
+ mouth: { row: 9, columnStart: 11, columnEnd: 15 },
246
+ },
247
+ compatibleWith: ['wide-horns', 'small-horns', 'single-eye', 'double-eye', 'fangs', 'grin'],
248
+ symmetric: true,
249
+ })
250
+
251
+ // Lanky imp 32: very tall and thin, long limbs
252
+ const lanky32 = new Template({
253
+ grid: [
254
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 0
255
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 1
256
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 2
257
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, F, F], // 3: head top
258
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, B, B], // 4: head
259
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, B, B], // 5: head
260
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, B, B], // 6: head
261
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, B, B], // 7: lower head
262
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, F], // 8: chin
263
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, F, _], // 9: thin neck
264
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, F, F, _], // 10: shoulders
265
+ [_, _, _, _, _, _, _, _, _, _, _, P, F, B, F, _], // 11: arms
266
+ [_, _, _, _, _, _, _, _, _, _, P, F, F, B, F, _], // 12: forearms
267
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, F, _], // 13: torso
268
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, F, _], // 14: torso
269
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, F, _], // 15: torso
270
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, _], // 16: waist
271
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, _], // 17: hips
272
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, _], // 18: upper legs
273
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, _, _], // 19: legs
274
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, _, _], // 20: legs
275
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, _, _], // 21: legs
276
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, _, _], // 22: legs
277
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, _, _], // 23: legs
278
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, _, _], // 24: legs
279
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, F, _, _], // 25: ankles
280
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, _, _, _], // 26: feet
281
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 27
282
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 28
283
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 29
284
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 30
285
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 31
286
+ ],
287
+ anchors: {
288
+ horns: { row: 3, columnStart: 14, columnEnd: 15 },
289
+ eyes: { row: 5, columnStart: 12, columnEnd: 15 },
290
+ mouth: { row: 7, columnStart: 12, columnEnd: 15 },
291
+ },
292
+ compatibleWith: ['tall-horns', 'small-horns', 'single-eye', 'double-eye', 'fangs', 'smirk'],
293
+ symmetric: true,
294
+ })
295
+
296
+ // Brute imp 32: massive shoulders, thick arms
297
+ const brute32 = new Template({
298
+ grid: [
299
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 0
300
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 1
301
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 2
302
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 3
303
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, F], // 4: head top
304
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, B, B], // 5: head
305
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 6: head
306
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 7: head
307
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 8: lower head
308
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, F, F, F], // 9: chin
309
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, _], // 10: neck
310
+ [_, _, _, _, _, _, _, _, _, F, F, F, F, B, F, _], // 11: wide shoulders
311
+ [_, _, _, _, _, _, _, _, F, F, B, B, B, B, F, _], // 12: big arms
312
+ [_, _, _, _, _, _, _, F, F, B, B, B, B, B, F, _], // 13: arms
313
+ [_, _, _, _, _, _, P, F, F, B, B, B, B, B, F, _], // 14: forearms + claws
314
+ [_, _, _, _, _, _, _, F, F, F, B, B, B, B, F, _], // 15: forearms
315
+ [_, _, _, _, _, _, _, _, _, F, F, B, B, B, F, _], // 16: torso
316
+ [_, _, _, _, _, _, _, _, _, _, F, B, B, B, F, _], // 17: torso
317
+ [_, _, _, _, _, _, _, _, _, _, F, B, B, B, F, _], // 18: torso
318
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 19: waist
319
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 20: hips
320
+ [_, _, _, _, _, _, _, _, _, _, _, F, F, F, F, _], // 21: upper legs
321
+ [_, _, _, _, _, _, _, _, _, _, F, F, _, _, F, F], // 22: legs wide
322
+ [_, _, _, _, _, _, _, _, _, _, F, _, _, _, _, F], // 23: legs
323
+ [_, _, _, _, _, _, _, _, _, _, F, _, _, _, _, F], // 24: legs
324
+ [_, _, _, _, _, _, _, _, _, F, F, _, _, _, F, F], // 25: ankles
325
+ [_, _, _, _, _, _, _, _, _, F, _, _, _, _, F, _], // 26: feet
326
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 27
327
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 28
328
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 29
329
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 30
330
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 31
331
+ ],
332
+ anchors: {
333
+ horns: { row: 4, columnStart: 13, columnEnd: 15 },
334
+ eyes: { row: 7, columnStart: 11, columnEnd: 15 },
335
+ mouth: { row: 8, columnStart: 11, columnEnd: 15 },
336
+ },
337
+ compatibleWith: ['wide-horns', 'small-horns', 'triple-eye', 'double-eye', 'fangs', 'grin'],
338
+ symmetric: true,
339
+ })
340
+
341
+ // Hunched imp 32: stooped posture, long dangling arms
342
+ const hunched32 = new Template({
343
+ grid: [
344
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 0
345
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 1
346
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 2
347
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 3
348
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 4
349
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, F, F, F], // 5: head top
350
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, B, B, B], // 6: head
351
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 7: head
352
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, B, B], // 8: head
353
+ [_, _, _, _, _, _, _, _, _, _, _, _, F, F, F, F], // 9: chin
354
+ [_, _, _, _, _, _, _, _, _, _, _, F, F, B, F, _], // 10: hunched neck
355
+ [_, _, _, _, _, _, _, _, _, _, F, F, B, B, F, _], // 11: shoulders
356
+ [_, _, _, _, _, _, _, _, _, F, F, B, B, B, F, _], // 12: torso
357
+ [_, _, _, _, _, _, _, _, P, F, B, B, B, B, F, _], // 13: long arms
358
+ [_, _, _, _, _, _, _, P, F, F, B, B, B, B, F, _], // 14: arms reaching
359
+ [_, _, _, _, _, _, P, F, F, _, F, B, B, B, F, _], // 15: claws dangling
360
+ [_, _, _, _, _, _, _, _, _, _, F, B, B, B, F, _], // 16: torso
361
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 17: waist
362
+ [_, _, _, _, _, _, _, _, _, _, _, F, B, B, F, _], // 18: hips
363
+ [_, _, _, _, _, _, _, _, _, _, _, F, F, F, F, _], // 19: upper legs
364
+ [_, _, _, _, _, _, _, _, _, _, _, F, _, _, F, _], // 20: legs
365
+ [_, _, _, _, _, _, _, _, _, _, _, F, _, _, F, _], // 21: legs
366
+ [_, _, _, _, _, _, _, _, _, _, _, F, _, _, F, _], // 22: legs
367
+ [_, _, _, _, _, _, _, _, _, _, F, F, _, _, F, _], // 23: ankles
368
+ [_, _, _, _, _, _, _, _, _, _, F, _, _, F, F, _], // 24: feet
369
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 25
370
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 26
371
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 27
372
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 28
373
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 29
374
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 30
375
+ [_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _], // 31
376
+ ],
377
+ anchors: {
378
+ horns: { row: 5, columnStart: 13, columnEnd: 15 },
379
+ eyes: { row: 7, columnStart: 11, columnEnd: 15 },
380
+ mouth: { row: 8, columnStart: 11, columnEnd: 15 },
381
+ },
382
+ compatibleWith: ['wide-horns', 'tall-horns', 'single-eye', 'double-eye', 'fangs', 'smirk'],
383
+ symmetric: true,
384
+ })
385
+
386
+ export const bodyTemplates: TemplateRegistry = {
387
+ 8: [stocky8, lanky8, brawler8],
388
+ 16: [classic16, lanky16, brute16, hunched16],
389
+ 32: [classic32, lanky32, brute32, hunched32],
390
+ }
@@ -0,0 +1,95 @@
1
+ import { CellType as C } from '@piximps/domain/types'
2
+ import { Template } from '@piximps/domain/template'
3
+ import { type TemplateRegistry } from './types'
4
+
5
+ const _ = C.AlwaysEmpty
6
+ const F = C.AlwaysFilled
7
+
8
+ const singleEye8 = new Template({
9
+ grid: [[_, _, _, F]],
10
+ anchors: {},
11
+ compatibleWith: ['single-eye'],
12
+ symmetric: true,
13
+ })
14
+
15
+ const doubleEye8 = new Template({
16
+ grid: [[_, F, _, _]],
17
+ anchors: {},
18
+ compatibleWith: ['double-eye'],
19
+ symmetric: true,
20
+ })
21
+
22
+ const tripleEye8 = new Template({
23
+ grid: [[_, F, _, F]],
24
+ anchors: {},
25
+ compatibleWith: ['triple-eye'],
26
+ symmetric: true,
27
+ })
28
+
29
+ const singleEye16 = new Template({
30
+ grid: [
31
+ [_, _, _, F, F],
32
+ [_, _, _, F, F],
33
+ ],
34
+ anchors: {},
35
+ compatibleWith: ['single-eye'],
36
+ symmetric: true,
37
+ })
38
+
39
+ const doubleEye16 = new Template({
40
+ grid: [
41
+ [_, F, F, _, _],
42
+ [_, F, F, _, _],
43
+ ],
44
+ anchors: {},
45
+ compatibleWith: ['double-eye'],
46
+ symmetric: true,
47
+ })
48
+
49
+ const tripleEye16 = new Template({
50
+ grid: [
51
+ [_, F, _, F, F],
52
+ [_, F, _, F, F],
53
+ ],
54
+ anchors: {},
55
+ compatibleWith: ['triple-eye'],
56
+ symmetric: true,
57
+ })
58
+
59
+ const singleEye32 = new Template({
60
+ grid: [
61
+ [_, _, _, _, _, _, F, F, F],
62
+ [_, _, _, _, _, _, F, F, F],
63
+ [_, _, _, _, _, _, F, F, F],
64
+ ],
65
+ anchors: {},
66
+ compatibleWith: ['single-eye'],
67
+ symmetric: true,
68
+ })
69
+
70
+ const doubleEye32 = new Template({
71
+ grid: [
72
+ [_, _, F, F, _, _, _, _],
73
+ [_, _, F, F, _, _, _, _],
74
+ ],
75
+ anchors: {},
76
+ compatibleWith: ['double-eye'],
77
+ symmetric: true,
78
+ })
79
+
80
+ const tripleEye32 = new Template({
81
+ grid: [
82
+ [_, _, F, F, _, _, F, F, F],
83
+ [_, _, F, F, _, _, F, F, F],
84
+ [_, _, _, _, _, _, _, _, _],
85
+ ],
86
+ anchors: {},
87
+ compatibleWith: ['triple-eye'],
88
+ symmetric: true,
89
+ })
90
+
91
+ export const eyeTemplates: TemplateRegistry = {
92
+ 8: [singleEye8, doubleEye8, tripleEye8],
93
+ 16: [singleEye16, doubleEye16, tripleEye16],
94
+ 32: [singleEye32, doubleEye32, tripleEye32],
95
+ }