diff --git a/examples/avatar-prototype/README.md b/examples/avatar-prototype/README.md new file mode 100644 index 00000000..dccd183f --- /dev/null +++ b/examples/avatar-prototype/README.md @@ -0,0 +1,5 @@ +# Skull reference + +`reference-skull.jpg` is the reference for the shaded, three-quarter skull. +The replacement native sources, rendered stills, talking animation, and +side-by-side comparison live in [`../skull/`](../skull/). diff --git a/examples/avatar-prototype/skull-outline.pxl b/examples/avatar-prototype/skull-outline.pxl deleted file mode 100644 index 96afd2d8..00000000 --- a/examples/avatar-prototype/skull-outline.pxl +++ /dev/null @@ -1,397 +0,0 @@ -// ============================================================================ -// SKULL OUTLINE - 3/4 View Silhouette Study -// ============================================================================ -// Reference: reference-skull.jpg -// Goal: Nail the silhouette before adding internal detail -// Canvas: 32x40 -// ============================================================================ - -{ - "type": "palette", - "name": "outline_pal", - "colors": { - "_": "transparent", - "outline": "#302828", - "fill": "#e8e0d8", - "fill2": "#e8e0d8", - "fill3": "#e8e0d8", - "fill4": "#e8e0d8", - "fill5": "#e8e0d8", - "fill6": "#e8e0d8" - } -} - -// V1: Build from simple shapes -{ - "type": "sprite", - "name": "skull_outline_v1", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { - "union": [ - { "ellipse": [14, 12, 13, 11] }, - { "rect": [5, 18, 22, 20] } - ], - "z": 0 - } - } -} - -// V2: Capture 3/4 view asymmetry -{ - "type": "sprite", - "name": "skull_outline_v2", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { - "union": [ - { "ellipse": [13, 11, 12, 10] }, - { "ellipse": [6, 13, 5, 8] }, - { "ellipse": [24, 20, 5, 6] }, - { "rect": [6, 18, 20, 8] }, - { "rect": [8, 26, 16, 8] }, - { "ellipse": [10, 34, 4, 5] }, - { "ellipse": [22, 34, 4, 5] } - ], - "z": 0 - } - } -} - -// V3: Refined proportions (has gap bug) -{ - "type": "sprite", - "name": "skull_outline_v3", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { - "union": [ - { "ellipse": [14, 10, 13, 10] }, - { "ellipse": [5, 12, 4, 6] }, - { "rect": [5, 16, 22, 10] }, - { "ellipse": [25, 22, 4, 4] }, - { "ellipse": [15, 32, 9, 7] } - ], - "z": 0 - } - } -} - -// V4: Simpler approach - just 3 main shapes with guaranteed overlap -{ - "type": "sprite", - "name": "skull_outline_v4", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - // Cranium - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - // Mid-face + jaw as one tall rect (will trim later) - "fill2": { "rect": [6, 18, 20, 20], "z": 0 } - } -} - -// V5: Separate regions - same z (has overlap bug) -{ - "type": "sprite", - "name": "skull_outline_v5", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill3": { "ellipse": [6, 14, 5, 7], "z": 0 }, - "fill4": { "rect": [6, 18, 21, 12], "z": 0 }, - "fill5": { "ellipse": [25, 23, 4, 5], "z": 0 }, - "fill6": { "ellipse": [16, 34, 8, 5], "z": 0 } - } -} - -// V6: Different z-levels (still has bug) -{ - "type": "sprite", - "name": "skull_outline_v6", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill2": { "ellipse": [6, 14, 5, 7], "z": 1 }, - "fill3": { "rect": [6, 18, 21, 12], "z": 2 }, - "fill4": { "ellipse": [25, 23, 4, 5], "z": 3 }, - "fill5": { "ellipse": [16, 34, 8, 5], "z": 4 } - } -} - -// V7: 3 shapes - works -{ - "type": "sprite", - "name": "skull_outline_v7", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 20], "z": 0 }, - "fill3": { "ellipse": [25, 23, 4, 5], "z": 0 } - } -} - -// V8: 4 shapes - works -{ - "type": "sprite", - "name": "skull_outline_v8", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 20], "z": 0 }, - "fill3": { "ellipse": [25, 23, 4, 5], "z": 0 }, - "fill4": { "ellipse": [5, 14, 4, 6], "z": 0 } - } -} - -// V9: 5 shapes - has bug (5 region limit) -{ - "type": "sprite", - "name": "skull_outline_v9", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - "fill3": { "ellipse": [25, 23, 4, 5], "z": 0 }, - "fill4": { "ellipse": [5, 14, 4, 6], "z": 0 }, - "fill5": { "ellipse": [16, 34, 8, 6], "z": 0 } - } -} - -// V10: 4 regions using union (has bug - 5 total shapes) -{ - "type": "sprite", - "name": "skull_outline_v10", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill2": { - "union": [ - { "rect": [6, 18, 20, 10] }, - { "ellipse": [16, 34, 8, 6] } - ], - "z": 0 - }, - "fill3": { "ellipse": [25, 23, 4, 5], "z": 0 }, - "fill4": { "ellipse": [5, 14, 4, 6], "z": 0 } - } -} - -// V11: 4 shapes - has gap between cranium and jaw -{ - "type": "sprite", - "name": "skull_outline_v11", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 10, 13, 10], "z": 0 }, - "fill2": { "ellipse": [15, 28, 11, 12], "z": 0 }, - "fill3": { "ellipse": [26, 22, 4, 5], "z": 0 }, - "fill4": { "ellipse": [4, 13, 4, 7], "z": 0 } - } -} - -// V12: Overlaps well but jaw too long -{ - "type": "sprite", - "name": "skull_outline_v12", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 14, 12], "z": 0 }, - "fill2": { "ellipse": [15, 26, 11, 14], "z": 0 }, - "fill3": { "ellipse": [26, 22, 4, 6], "z": 0 }, - "fill4": { "ellipse": [4, 14, 4, 7], "z": 0 } - } -} - -// V13: Better proportions - has gap -{ - "type": "sprite", - "name": "skull_outline_v13", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 12, 14, 12], "z": 0 }, - "fill2": { "ellipse": [15, 28, 10, 10], "z": 0 }, - "fill3": { "ellipse": [25, 24, 4, 5], "z": 0 }, - "fill4": { "ellipse": [4, 14, 3, 6], "z": 0 } - } -} - -// V14: Good baseline -{ - "type": "sprite", - "name": "skull_outline_v14", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 12, 14, 12], "z": 0 }, - "fill2": { "ellipse": [15, 26, 10, 12], "z": 0 }, - "fill3": { "ellipse": [26, 23, 4, 5], "z": 0 }, - "fill4": { "ellipse": [4, 14, 3, 6], "z": 0 } - } -} - -// V15: Has gap - shapes taper at overlap zone -{ - "type": "sprite", - "name": "skull_outline_v15", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 11, 13, 11], "z": 0 }, - "fill2": { "ellipse": [15, 27, 9, 11], "z": 0 }, - "fill3": { "ellipse": [26, 21, 4, 6], "z": 0 }, - "fill4": { "ellipse": [4, 13, 3, 6], "z": 0 } - } -} - -// V16: 4 ellipses - works but overly complex -{ - "type": "sprite", - "name": "skull_outline_v16", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "ellipse": [14, 13, 13, 13], "z": 0 }, - "fill2": { "ellipse": [15, 29, 10, 10], "z": 0 }, - "fill3": { "ellipse": [26, 22, 4, 6], "z": 0 }, - "fill4": { "ellipse": [4, 14, 3, 7], "z": 0 } - } -} - -// ============================================================================ -// SIMPLE APPROACH: Circle + Rect + Triangle (mushroom shape) -// ============================================================================ - -// V17: Simple mushroom - symmetric front view -{ - "type": "sprite", - "name": "skull_outline_v17", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [16, 12, 12], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - "fill3": { "polygon": [[6, 28], [26, 28], [16, 38]], "z": 0 } - } -} - -// V18: 3/4 view - shapes shifted left -{ - "type": "sprite", - "name": "skull_outline_v18", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [4, 18, 22, 10], "z": 0 }, - "fill3": { "polygon": [[4, 28], [26, 28], [14, 38]], "z": 0 } - } -} - -// V19: Has gap - triangle not connected -{ - "type": "sprite", - "name": "skull_outline_v19", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [8, 18, 20, 10], "z": 0 }, - "fill3": { "polygon": [[8, 28], [8, 38], [26, 33]], "z": 0 } - } -} - -// V20: Triangle too narrow -{ - "type": "sprite", - "name": "skull_outline_v20", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - "fill3": { "polygon": [[6, 28], [6, 38], [28, 33]], "z": 0 } - } -} - -// V21: Sharp triangle chin -{ - "type": "sprite", - "name": "skull_outline_v21", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - "fill3": { "polygon": [[6, 28], [26, 28], [28, 36]], "z": 0 } - } -} - -// V22: 6-vertex polygon has fill bug -{ - "type": "sprite", - "name": "skull_outline_v22", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - "fill3": { - "polygon": [ - [6, 28], [26, 28], [20, 32], [24, 36], [20, 38], [6, 38] - ], - "z": 0 - } - } -} - -// V23: 4-vertex trapezoid - works but straight hypotenuse -{ - "type": "sprite", - "name": "skull_outline_v23", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - "fill3": { - "polygon": [[6, 28], [26, 28], [24, 38], [6, 38]], - "z": 0 - } - } -} - -// V24: 5-vertex polygon - bowed hypotenuse -{ - "type": "sprite", - "name": "skull_outline_v24", - "size": [32, 40], - "palette": "outline_pal", - "regions": { - "fill": { "circle": [14, 12, 12], "z": 0 }, - "fill2": { "rect": [6, 18, 20, 10], "z": 0 }, - // 5 vertices: add midpoint on hypotenuse that bows inward - "fill3": { - "polygon": [ - [6, 28], // top-left - [26, 28], // top-right - [20, 33], // midpoint bows inward (was ~25,33 on straight line) - [24, 38], // chin right - [6, 38] // chin left - ], - "z": 0 - } - } -} diff --git a/examples/avatar-prototype/skull-outline_skull_outline_v23.png b/examples/avatar-prototype/skull-outline_skull_outline_v23.png deleted file mode 100644 index ae043ea3..00000000 Binary files a/examples/avatar-prototype/skull-outline_skull_outline_v23.png and /dev/null differ diff --git a/examples/avatar-prototype/skull-outline_skull_outline_v24.png b/examples/avatar-prototype/skull-outline_skull_outline_v24.png deleted file mode 100644 index 4207a084..00000000 Binary files a/examples/avatar-prototype/skull-outline_skull_outline_v24.png and /dev/null differ diff --git a/examples/avatar-prototype/skull.png b/examples/avatar-prototype/skull.png deleted file mode 100644 index 563198bd..00000000 Binary files a/examples/avatar-prototype/skull.png and /dev/null differ diff --git a/examples/avatar-prototype/skull.pxl b/examples/avatar-prototype/skull.pxl deleted file mode 100644 index 6dfb2378..00000000 --- a/examples/avatar-prototype/skull.pxl +++ /dev/null @@ -1,720 +0,0 @@ -// ============================================================================ -// SKULL HEAD - Artisan Workflow Test -// ============================================================================ -// Reference: examples/iso-prototype/reference-skull.jpg -// Target: 32x40 isometric skull with 3-surface shading -// -// Components: -// - cranium (dome shape) -// - eye_sockets (dark recessed areas) -// - nose (triangular cavity) -// - jaw (teeth, lower structure) -// - shading (lit/shadow overlays) -// ============================================================================ - -// Bone palette - derived from reference skull colors -{ - "type": "palette", - "name": "skull_pal", - "colors": { - "_": "transparent", - - // Bone ramp (5 levels) - "bone_hi": "#f8f4f0", - "bone_lit": "#e8e0d8", - "bone": "#d8d0c8", - "bone_shd": "#b8b0a8", - "bone_dark": "#989088", - - // Cavities (eye sockets, nose) - "cavity": "#484040", - "cavity_deep": "#302828", - - // Teeth - "tooth": "#e0d8d0", - "tooth_shd": "#c8c0b8", - "tooth_gap": "#686060", - - // Multiple regions with same color - "cavity_l": "#484040", - "cavity_r": "#484040", - "cavity_nose": "#484040", - "bone_jaw": "#d8d0c8", - "bone_lit_jaw": "#e8e0d8", - "bone_shd_jaw": "#b8b0a8", - "bone_shd_nose": "#b8b0a8", - "bone_dark_l": "#989088", - "bone_dark_r": "#989088" - } -} - -// V0: Initial skull draft -{ - "type": "sprite", - "name": "skull_v0", - "size": [32, 40], - "palette": "skull_pal", - "regions": { - // CRANIUM - main dome shape - "bone": { "ellipse": [16, 14, 13, 12], "z": 0 }, - - // Cranium shading - lit side (right) - "bone_lit": { - "polygon": [ - [18, 4], [24, 6], [27, 10], [28, 16], [27, 22], [24, 24], [18, 24], - [20, 20], [22, 16], [22, 10], [20, 6] - ], - "z": 1 - }, - - // Cranium shading - shadow side (left) - "bone_shd": { - "polygon": [ - [14, 4], [8, 6], [5, 10], [4, 16], [5, 22], [8, 24], [14, 24], - [12, 20], [10, 16], [10, 10], [12, 6] - ], - "z": 1 - }, - - // Highlight on dome - "bone_hi": { - "polygon": [[20, 6], [24, 8], [25, 12], [23, 14], [20, 12], [19, 8]], - "z": 2 - }, - - // EYE SOCKETS - dark recessed areas - "cavity_l": { - "ellipse": [11, 16, 4, 3], - "z": 3 - }, - "cavity_r": { - "ellipse": [21, 16, 4, 3], - "z": 3 - }, - - // Deeper eye shadows - "cavity_deep": { - "points": [[10, 16], [11, 17], [20, 16], [21, 17]], - "z": 4 - }, - - // NOSE - triangular cavity - "cavity_nose": { - "polygon": [[14, 20], [18, 20], [16, 26]], - "z": 3 - }, - - // Nose bone ridge - "bone_shd_nose": { - "line": [[16, 14], [16, 20]], - "z": 2 - }, - - // JAW - lower face structure - "bone_jaw": { - "polygon": [ - [8, 26], [24, 26], [26, 28], [26, 34], [24, 38], [8, 38], [6, 34], [6, 28] - ], - "z": 0 - }, - - // Jaw shading - "bone_lit_jaw": { - "polygon": [[20, 26], [24, 26], [26, 28], [26, 34], [24, 36], [20, 36]], - "z": 1 - }, - "bone_shd_jaw": { - "polygon": [[8, 26], [12, 26], [12, 36], [8, 38], [6, 34], [6, 28]], - "z": 1 - }, - - // TEETH - horizontal lines - "tooth": { - "rect": [10, 28, 12, 6], - "z": 2 - }, - "tooth_gap": { - "union": [ - { "line": [[10, 30], [22, 30]] }, - { "line": [[10, 32], [22, 32]] }, - { "points": [[12, 28], [14, 28], [16, 28], [18, 28], [20, 28]] }, - { "points": [[12, 34], [14, 34], [16, 34], [18, 34], [20, 34]] } - ], - "z": 3 - }, - - // Cheekbone structure - "bone_dark_l": { - "polygon": [[6, 22], [8, 20], [10, 22], [10, 26], [6, 26]], - "z": 1 - }, - "bone_dark_r": { - "polygon": [[26, 22], [24, 20], [22, 22], [22, 26], [26, 26]], - "z": 1 - } - } -} - -// ============================================================================ -// CRANIUM ITERATION - Round 1 -// ============================================================================ - -// FINAL: Iteration Round 2 - 3/4 view (front-left) perspective -// Reference: skull faces viewer's left. Right side = near (more visible), -// Left side = far (foreshortened). Light from upper-right. -// Round 2 changes: brow ridge, angular eye sockets, narrower jaw, teeth character -{ - "type": "sprite", - "name": "skull", - "size": [32, 40], - "palette": "skull_pal", - "regions": { - // CRANIUM - off-center ellipse shifted right (near side extends further right) - "bone": { "ellipse": [18, 12, 13, 11], "z": 0 }, - - // Cranium shading - lit/near side (right) - wide, visible curve - "bone_lit": { - "polygon": [ - [19, 2], [26, 4], [29, 8], [30, 14], [29, 20], [25, 23], [19, 23], - [22, 20], [25, 15], [25, 10], [22, 5] - ], - "z": 1 - }, - - // Cranium shading - shadow/far side (left) - narrow, foreshortened - "bone_shd": { - "polygon": [ - [16, 2], [12, 4], [9, 8], [7, 14], [8, 20], [11, 23], [16, 23], - [14, 20], [12, 15], [12, 10], [14, 5] - ], - "z": 1 - }, - - // Deep shadow on far left edge + brow ridge overhang (1px line) - "bone_dark": { - "union": [ - { "polygon": [[7, 6], [5, 10], [5, 16], [7, 22], [9, 20], [8, 14], [9, 8]] }, - { "polygon": [[7, 13], [17, 12], [28, 13], [28, 14], [7, 14]] } - ], - "z": 2 - }, - - // Highlight on dome - prominent specular on near/right side - "bone_hi": { - "polygon": [[23, 4], [28, 6], [29, 11], [27, 14], [24, 12], [23, 7]], - "z": 2 - }, - - // EYE SOCKETS - angular trapezoids (wider at brow, narrow toward cheek) - // Left (far) - smaller, foreshortened - "cavity_l": { - "polygon": [[8, 15], [15, 14], [14, 20], [9, 21]], - "z": 3 - }, - // Right (near) - larger, angular trapezoid converging downward - "cavity_r": { - "polygon": [[18, 14], [27, 14], [26, 21], [19, 21]], - "z": 3 - }, - - // Deeper eye shadows - concentrated at inner/lower areas - "cavity_deep": { - "union": [ - { "polygon": [[9, 16], [13, 15], [13, 19], [10, 20]] }, - { "polygon": [[20, 15], [25, 15], [25, 19], [21, 20]] } - ], - "z": 4 - }, - - // NOSE - narrower, offset right for 3/4 perspective - "cavity_nose": { - "polygon": [[15, 22], [19, 22], [18, 25], [17, 27], [15, 25]], - "z": 3 - }, - - // Nose bone ridge - offset right, starts below brow - "bone_shd_nose": { - "line": [[17, 15], [17, 22]], - "z": 2 - }, - - // CHEEKBONES - pronounced, left (far) narrower, right (near) wider - "bone_dark_l": { - "polygon": [[5, 18], [8, 15], [9, 18], [9, 24], [5, 25]], - "z": 1 - }, - "bone_dark_r": { - "polygon": [[29, 17], [27, 14], [26, 18], [26, 24], [29, 25]], - "z": 1 - }, - - // JAW - narrower than cranium, asymmetric 3/4 - "bone_jaw": { - "polygon": [ - [8, 24], [26, 24], [28, 26], [28, 33], [24, 37], [11, 37], [7, 33], [6, 26] - ], - "z": 0 - }, - - // Jaw shading - lit/near side (right) - "bone_lit_jaw": { - "polygon": [[20, 24], [26, 24], [28, 26], [28, 33], [24, 35], [20, 35]], - "z": 1 - }, - // Jaw shading - shadow/far side (left) - "bone_shd_jaw": { - "polygon": [[8, 24], [13, 24], [13, 35], [11, 37], [7, 33], [6, 26]], - "z": 1 - }, - - // TEETH - narrower to match jaw, with character - "tooth": { - "rect": [10, 26, 16, 7], - "z": 2 - }, - // Teeth gaps - clean bite line with varied vertical dividers - "tooth_gap": { - "union": [ - // Bite line (main horizontal gap between upper and lower teeth) - { "line": [[10, 29], [26, 29]] }, - // Upper teeth vertical dividers - varied widths for character - { "points": [[13, 26], [16, 26], [18, 26], [21, 26], [24, 26]] }, - { "points": [[13, 27], [16, 27], [18, 27], [21, 27], [24, 27]] }, - { "points": [[13, 28], [16, 28], [18, 28], [21, 28], [24, 28]] }, - // Lower teeth vertical dividers - offset for character - { "points": [[12, 30], [15, 30], [19, 30], [22, 30]] }, - { "points": [[12, 31], [15, 31], [19, 31], [22, 31]] }, - { "points": [[12, 32], [15, 32], [19, 32], [22, 32]] } - ], - "z": 3 - }, - // Tooth shading for depth on far/left side - "tooth_shd": { - "union": [ - { "line": [[10, 26], [10, 33]] }, - { "line": [[11, 26], [11, 33]] }, - { "line": [[10, 33], [26, 33]] } - ], - "z": 3 - } - } -} - -// V1B: Taller dome, more pronounced brow ridge -{ - "type": "sprite", - "name": "skull_v1b", - "size": [32, 40], - "palette": "skull_pal", - "regions": { - // CRANIUM - taller dome - "bone": { "ellipse": [16, 12, 13, 12], "z": 0 }, - - // Brow ridge - prominent overhang - "bone_shd": { - "polygon": [ - [5, 12], [8, 10], [16, 9], [24, 10], [27, 12], [27, 15], [5, 15] - ], - "z": 1 - }, - - // Cranium shading - lit side - "bone_lit": { - "polygon": [ - [18, 2], [24, 4], [27, 8], [28, 12], [27, 10], [24, 6], [18, 4], - [20, 6], [22, 9], [23, 12] - ], - "z": 1 - }, - - // Highlight - "bone_hi": { - "polygon": [[19, 3], [23, 5], [24, 8], [22, 10], [19, 8]], - "z": 2 - }, - - // EYE SOCKETS - recessed under brow - "cavity_l": { - "polygon": [[7, 15], [13, 15], [13, 19], [7, 19]], - "z": 3 - }, - "cavity_r": { - "polygon": [[19, 15], [25, 15], [25, 19], [19, 19]], - "z": 3 - }, - - // Deeper shadows - "cavity_deep": { - "points": [[9, 17], [10, 17], [11, 17], [21, 17], [22, 17], [23, 17]], - "z": 4 - }, - - // NOSE - "cavity_nose": { - "polygon": [[14, 20], [18, 20], [17, 23], [16, 26], [15, 23]], - "z": 3 - }, - - "bone_shd_nose": { - "line": [[16, 15], [16, 20]], - "z": 2 - }, - - // JAW - "bone_jaw": { - "polygon": [ - [7, 26], [25, 26], [27, 28], [26, 34], [23, 38], [9, 38], [6, 34], [5, 28] - ], - "z": 0 - }, - - "bone_lit_jaw": { - "polygon": [[20, 26], [25, 26], [27, 28], [26, 34], [23, 36], [20, 36]], - "z": 1 - }, - "bone_shd_jaw": { - "polygon": [[7, 26], [12, 26], [12, 36], [9, 38], [6, 34], [5, 28]], - "z": 1 - }, - - // TEETH - "tooth": { - "rect": [9, 28, 14, 6], - "z": 2 - }, - "tooth_gap": { - "union": [ - { "line": [[9, 30], [23, 30]] }, - { "line": [[9, 32], [23, 32]] }, - { "points": [[11, 28], [13, 28], [15, 28], [17, 28], [19, 28], [21, 28]] }, - { "points": [[11, 34], [13, 34], [15, 34], [17, 34], [19, 34], [21, 34]] } - ], - "z": 3 - }, - - // Cheekbones - "bone_dark_l": { - "polygon": [[5, 19], [7, 17], [8, 19], [8, 26], [5, 26]], - "z": 1 - }, - "bone_dark_r": { - "polygon": [[27, 19], [25, 17], [24, 19], [24, 26], [27, 26]], - "z": 1 - } - } -} - -// ============================================================================ -// TALKING ANIMATION - Mouth State Overlays -// ============================================================================ -// Skull mouth positions for dialogue: -// - mouth_closed: jaw in neutral position (default skull) -// - mouth_small: slight jaw drop, gap between teeth rows -// - mouth_wide: full jaw drop, more teeth visible -// ============================================================================ - -// MOUTH CLOSED - neutral position, covers base and redraws at same position -// Use this to ensure consistent overlay behavior in compositions -{ - "type": "sprite", - "name": "skull_mouth_closed", - "size": [32, 40], - "palette": "skull_pal", - "regions": { - // Cover existing jaw area completely - "bone": { "rect": [2, 23, 28, 17], "z": 10 }, - - // JAW - matches base skull narrower 3/4 perspective - "bone_jaw": { - "polygon": [ - [8, 24], [26, 24], [28, 26], [28, 33], [24, 37], [11, 37], [7, 33], [6, 26] - ], - "z": 11 - }, - - // Jaw shading - "bone_lit_jaw": { - "polygon": [[20, 24], [26, 24], [28, 26], [28, 33], [24, 35], [20, 35]], - "z": 12 - }, - "bone_shd_jaw": { - "polygon": [[8, 24], [13, 24], [13, 35], [11, 37], [7, 33], [6, 26]], - "z": 12 - }, - - // TEETH - narrower, with character - "tooth": { - "rect": [10, 26, 16, 7], - "z": 13 - }, - "tooth_gap": { - "union": [ - { "line": [[10, 29], [26, 29]] }, - { "points": [[13, 26], [16, 26], [18, 26], [21, 26], [24, 26]] }, - { "points": [[13, 27], [16, 27], [18, 27], [21, 27], [24, 27]] }, - { "points": [[13, 28], [16, 28], [18, 28], [21, 28], [24, 28]] }, - { "points": [[12, 30], [15, 30], [19, 30], [22, 30]] }, - { "points": [[12, 31], [15, 31], [19, 31], [22, 31]] }, - { "points": [[12, 32], [15, 32], [19, 32], [22, 32]] } - ], - "z": 14 - }, - "tooth_shd": { - "union": [ - { "line": [[10, 26], [10, 33]] }, - { "line": [[11, 26], [11, 33]] }, - { "line": [[10, 33], [26, 33]] } - ], - "z": 14 - }, - - // Cheekbone structure - matches base skull 3/4 - "bone_dark_l": { - "polygon": [[5, 18], [8, 15], [9, 18], [9, 24], [5, 25]], - "z": 12 - }, - "bone_dark_r": { - "polygon": [[29, 17], [27, 14], [26, 18], [26, 24], [29, 25]], - "z": 12 - } - } -} - -// MOUTH SMALL OPEN - slight jaw drop (3px), gap between upper and lower teeth -{ - "type": "sprite", - "name": "skull_mouth_small", - "size": [32, 40], - "palette": "skull_pal", - "regions": { - // Cover existing jaw area completely - "bone": { "rect": [2, 23, 28, 17], "z": 10 }, - - // Dark cavity behind teeth (mouth interior) - "cavity": { - "rect": [10, 30, 16, 3], - "z": 11 - }, - - // UPPER JAW - stays in place, narrower 3/4 perspective - "bone_jaw": { - "polygon": [ - [8, 24], [26, 24], [28, 26], [28, 30], [6, 30], [6, 26] - ], - "z": 12 - }, - - // Upper jaw shading - "bone_lit_jaw": { - "polygon": [[20, 24], [26, 24], [28, 26], [28, 30], [20, 30]], - "z": 13 - }, - "bone_shd_jaw": { - "polygon": [[8, 24], [13, 24], [13, 30], [6, 30], [6, 26]], - "z": 13 - }, - - // UPPER TEETH - narrower, with character - "tooth": { - "rect": [10, 26, 16, 3], - "z": 14 - }, - "tooth_gap": { - "union": [ - { "points": [[13, 26], [16, 26], [18, 26], [21, 26], [24, 26]] }, - { "points": [[13, 27], [16, 27], [18, 27], [21, 27], [24, 27]] }, - { "points": [[13, 28], [16, 28], [18, 28], [21, 28], [24, 28]] } - ], - "z": 15 - }, - - // LOWER JAW - dropped 3px, narrower 3/4 perspective - "bone_dark": { - "polygon": [ - [8, 33], [26, 33], [28, 35], [24, 39], [11, 39], [7, 35] - ], - "z": 12 - }, - - // Lower jaw shading - "bone_lit": { - "polygon": [[20, 33], [26, 33], [28, 35], [24, 37], [20, 37]], - "z": 13 - }, - "bone_shd": { - "polygon": [[8, 33], [13, 33], [13, 37], [11, 39], [7, 35]], - "z": 13 - }, - - // LOWER TEETH - dropped, with character - "tooth_shd": { - "rect": [10, 33, 16, 4], - "z": 14 - }, - "cavity_deep": { - "union": [ - { "line": [[10, 35], [26, 35]] }, - { "points": [[12, 33], [15, 33], [19, 33], [22, 33]] }, - { "points": [[12, 34], [15, 34], [19, 34], [22, 34]] }, - { "points": [[12, 35], [15, 35], [19, 35], [22, 35]] }, - { "points": [[12, 36], [15, 36], [19, 36], [22, 36]] } - ], - "z": 15 - }, - - // Cheekbones - matches base skull - "bone_dark_l": { - "polygon": [[5, 18], [8, 15], [9, 18], [9, 24], [5, 25]], - "z": 13 - }, - "bone_dark_r": { - "polygon": [[29, 17], [27, 14], [26, 18], [26, 24], [29, 25]], - "z": 13 - } - } -} - -// MOUTH WIDE OPEN - full jaw drop (5px), maximum teeth exposure -{ - "type": "sprite", - "name": "skull_mouth_wide", - "size": [32, 40], - "palette": "skull_pal", - "regions": { - // Cover existing jaw area completely - "bone": { "rect": [2, 23, 28, 17], "z": 10 }, - - // Dark cavity behind teeth (larger mouth interior) - "cavity": { - "rect": [9, 30, 18, 6], - "z": 11 - }, - "cavity_deep": { - "rect": [11, 31, 14, 4], - "z": 12 - }, - - // UPPER JAW - stays in place, narrower 3/4 perspective - "bone_jaw": { - "polygon": [ - [8, 24], [26, 24], [28, 26], [28, 30], [6, 30], [6, 26] - ], - "z": 13 - }, - - // Upper jaw shading - "bone_lit_jaw": { - "polygon": [[20, 24], [26, 24], [28, 26], [28, 30], [20, 30]], - "z": 14 - }, - "bone_shd_jaw": { - "polygon": [[8, 24], [13, 24], [13, 30], [6, 30], [6, 26]], - "z": 14 - }, - - // UPPER TEETH - narrower, with character - "tooth": { - "rect": [10, 26, 16, 3], - "z": 15 - }, - "tooth_gap": { - "union": [ - { "points": [[13, 26], [16, 26], [18, 26], [21, 26], [24, 26]] }, - { "points": [[13, 27], [16, 27], [18, 27], [21, 27], [24, 27]] }, - { "points": [[13, 28], [16, 28], [18, 28], [21, 28], [24, 28]] } - ], - "z": 16 - }, - - // LOWER JAW - dropped 5px, narrower 3/4 perspective - "bone_dark": { - "polygon": [ - [8, 36], [26, 36], [28, 38], [24, 42], [11, 42], [7, 38] - ], - "z": 13 - }, - - // Lower jaw shading - "bone_lit": { - "polygon": [[20, 36], [26, 36], [28, 38], [24, 40], [20, 40]], - "z": 14 - }, - "bone_shd": { - "polygon": [[8, 36], [13, 36], [13, 40], [11, 42], [7, 38]], - "z": 14 - }, - - // LOWER TEETH - dropped further, with character - "tooth_shd": { - "rect": [10, 36, 16, 4], - "z": 15 - }, - "bone_shd_nose": { - "union": [ - { "line": [[10, 38], [26, 38]] }, - { "points": [[12, 36], [15, 36], [19, 36], [22, 36]] }, - { "points": [[12, 37], [15, 37], [19, 37], [22, 37]] }, - { "points": [[12, 38], [15, 38], [19, 38], [22, 38]] }, - { "points": [[12, 39], [15, 39], [19, 39], [22, 39]] } - ], - "z": 16 - }, - - // Cheekbones - matches base skull - "bone_dark_l": { - "polygon": [[5, 18], [8, 15], [9, 18], [9, 24], [5, 25]], - "z": 14 - }, - "bone_dark_r": { - "polygon": [[29, 17], [27, 14], [26, 18], [26, 24], [29, 25]], - "z": 14 - } - } -} - -// ============================================================================ -// TALKING COMPOSITIONS - Layer mouth states on skull base -// ============================================================================ - -{ - "type": "composition", - "name": "skull_talk_closed", - "size": [32, 40], - "cell_size": [32, 40], - "sprites": { "S": "skull", "M": "skull_mouth_closed" }, - "layers": [{ "map": ["S"] }, { "map": ["M"] }] -} - -{ - "type": "composition", - "name": "skull_talk_small", - "size": [32, 40], - "cell_size": [32, 40], - "sprites": { "S": "skull", "M": "skull_mouth_small" }, - "layers": [{ "map": ["S"] }, { "map": ["M"] }] -} - -{ - "type": "composition", - "name": "skull_talk_wide", - "size": [32, 40], - "cell_size": [32, 40], - "sprites": { "S": "skull", "M": "skull_mouth_wide" }, - "layers": [{ "map": ["S"] }, { "map": ["M"] }] -} - -// ============================================================================ -// TALKING ANIMATION - Frame sequence for dialogue -// ============================================================================ - -{ - "type": "animation", - "name": "skull_talking", - "frames": [ - "skull_talk_closed", "skull_talk_small", "skull_talk_wide", "skull_talk_small", - "skull_talk_closed", "skull_talk_small", "skull_talk_wide", "skull_talk_wide", - "skull_talk_small", "skull_talk_closed", "skull_talk_closed", "skull_talk_small" - ], - "duration": 80, - "loop": true -} diff --git a/examples/avatar-prototype/skull_4x.png b/examples/avatar-prototype/skull_4x.png deleted file mode 100644 index 1dcf3c16..00000000 Binary files a/examples/avatar-prototype/skull_4x.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_talk_closed.png b/examples/avatar-prototype/skull_talk_closed.png deleted file mode 100644 index 1666254b..00000000 Binary files a/examples/avatar-prototype/skull_talk_closed.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_talk_small.png b/examples/avatar-prototype/skull_talk_small.png deleted file mode 100644 index 9489343f..00000000 Binary files a/examples/avatar-prototype/skull_talk_small.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_talk_wide.png b/examples/avatar-prototype/skull_talk_wide.png deleted file mode 100644 index 6bfc6028..00000000 Binary files a/examples/avatar-prototype/skull_talk_wide.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_talking.gif b/examples/avatar-prototype/skull_talking.gif deleted file mode 100644 index 39df6433..00000000 Binary files a/examples/avatar-prototype/skull_talking.gif and /dev/null differ diff --git a/examples/avatar-prototype/skull_talking_4x.gif b/examples/avatar-prototype/skull_talking_4x.gif deleted file mode 100644 index 115cc6b7..00000000 Binary files a/examples/avatar-prototype/skull_talking_4x.gif and /dev/null differ diff --git a/examples/avatar-prototype/skull_v0.png b/examples/avatar-prototype/skull_v0.png deleted file mode 100644 index 1b7d7f34..00000000 Binary files a/examples/avatar-prototype/skull_v0.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_v0_4x.png b/examples/avatar-prototype/skull_v0_4x.png deleted file mode 100644 index 04f297e7..00000000 Binary files a/examples/avatar-prototype/skull_v0_4x.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_v1a_4x.png b/examples/avatar-prototype/skull_v1a_4x.png deleted file mode 100644 index 4c930056..00000000 Binary files a/examples/avatar-prototype/skull_v1a_4x.png and /dev/null differ diff --git a/examples/avatar-prototype/skull_v1b_4x.png b/examples/avatar-prototype/skull_v1b_4x.png deleted file mode 100644 index 8875d940..00000000 Binary files a/examples/avatar-prototype/skull_v1b_4x.png and /dev/null differ diff --git a/examples/skull/README.md b/examples/skull/README.md new file mode 100644 index 00000000..b872f7e5 --- /dev/null +++ b/examples/skull/README.md @@ -0,0 +1,73 @@ +# Three-quarter skull + +A 48 × 48 skull facing right, drawn in native Pixelsrc regions with a warm bone +ramp, angular recessed sockets, a notched nose, cheekbone and separate mandible. +The source reference remains in +[`../avatar-prototype/reference-skull.jpg`](../avatar-prototype/reference-skull.jpg). + +![Reference at left, Pixelsrc at right](comparison.png) + +![Talking skull](skull_talking.gif) + +## Render + +From the repository root, build `pxl` with `cargo build --bin pxl`, then use that +binary (or an installed `pxl`) for these commands: + +```sh +pxl validate --strict examples/skull/skull.pxl +pxl validate --strict examples/skull/skull_talking.pxl +pxl render examples/skull/skull.pxl --composition skull --strict -o examples/skull/skull.png +pxl render examples/skull/skull.pxl --composition skull --strict --scale 4 -o examples/skull/skull_4x.png +pxl render examples/skull/skull.pxl --composition skull --strict --scale 8 -o examples/skull/skull_8x.png +pxl render examples/skull/skull_talking.pxl --animation skull_talking --gif --strict --scale 4 -o examples/skull/skull_talking.gif +pxl render examples/skull/skull_talking.pxl --animation skull_talking --spritesheet --strict --scale 4 -o examples/skull/skull_poses.png +``` + +Every sprite PNG and the GIF are direct `pxl` output; no painted raster assets +or post-render retouching. The background is transparent. The GIF loops through +closed → small → wide → small at 120 ms per frame. The cranium stays fixed; +the mandible drops by one or three logical pixels with a dark cavity behind it. + +Both `.pxl` files are standalone examples. The still's palette and components +are repeated verbatim at the beginning of `skull_talking.pxl`; keep that prefix +in sync when changing the design. Validate the two files separately, since +validating them together treats their intentionally shared names as duplicates. + +The talking file uses explicit jaw-pose regions. In the current renderer, +composition-layer `shift` and source-sprite `shift` inside compositions silently +render the unshifted pose, even though direct rendering of the shifted sprite +works. This compiler limitation is tracked separately with an 8 × 8 reproducer; +the example does not rely on those transforms. + +## Comparison and visual checks + +`comparison.png` is a presentation image only: the existing reference enlarged +with nearest-neighbor sampling beside the unmodified 8× Pixelsrc render on white. +Regenerate it with ImageMagick: + +```sh +magick \ + \( examples/avatar-prototype/reference-skull.jpg -filter point -resize 384x384 \ + -background white -gravity south -splice 0x24 -font DejaVu-Sans \ + -pointsize 14 -annotate 0 'Reference' \) \ + \( examples/skull/skull_8x.png -background white -alpha remove -alpha off \ + -gravity south -splice 0x24 -font DejaVu-Sans -pointsize 14 \ + -annotate 0 'Pixelsrc - 48 x 48' \) \ + +append examples/skull/comparison.png +``` + +Iterations inspected at 1× and 8×: + +- Initial geometry: rounded back-left dome and asymmetric sockets established + the turn; tooth rows were too short and the chin too empty. +- Dental revision: taller individual teeth and umber separators improved the + bite; retained the cream forehead and beige side planes. +- Motion revision: explicit jaw poses replaced ineffective transforms. A dark + mouth cavity keeps the opening readable on white as well as dark backgrounds. + +Final checks: recognizable silhouette, readable at native size, consistent +upper-right lighting, transparent margins, three distinct jaw poses, identical +upper cranium across frames, and no strict-validation warnings. The older +avatar-prototype skull sources and renders have been retired in favor of these +examples; the reference image is unchanged. diff --git a/examples/skull/comparison.png b/examples/skull/comparison.png new file mode 100644 index 00000000..c6ae0e04 Binary files /dev/null and b/examples/skull/comparison.png differ diff --git a/examples/skull/skull.png b/examples/skull/skull.png new file mode 100644 index 00000000..27300e72 Binary files /dev/null and b/examples/skull/skull.png differ diff --git a/examples/skull/skull.pxl b/examples/skull/skull.pxl new file mode 100644 index 00000000..237bf36f --- /dev/null +++ b/examples/skull/skull.pxl @@ -0,0 +1,164 @@ +// 48x48, facing right. Geometry is authored here; PNGs are pxl output. +// Light comes from above/right. The jaw is a separate transparent layer. +{ + "type": "palette", + "name": "skull_bone", + "colors": { + "_": "transparent", + "cranium_outline": "#77746c", + "cranium_side": "#b8ae9d", + "temple_plane": "#e3dac9", + "dome_light": "#f9f5e2", + "brow_plane": "#e3dac9", + "near_socket_rim": "#f9f5e2", + "near_socket": "#514e45", + "near_socket_inner": "#79796f", + "far_socket": "#514e45", + "far_socket_inner": "#79796f", + "temple_seam": "#77746c", + "cheek_shadow": "#948875", + "cheek_plane": "#e3dac9", + "cheek_light": "#f9f5e2", + "face_plane": "#e3dac9", + "face_light": "#f9f5e2", + "nose_notch": "#514e45", + "nose_rim": "#c9bfac", + "far_cheek_rim": "#c9bfac", + "maxilla_shadow": "#c9bfac", + "upper_tooth_0": "#f9f5e2", + "upper_tooth_1": "#f9f5e2", + "upper_tooth_2": "#f9f5e2", + "upper_tooth_3": "#f9f5e2", + "upper_tooth_4": "#f9f5e2", + "upper_tooth_5": "#f9f5e2", + "jaw_outline": "#77746c", + "jaw_shadow": "#b8ae9d", + "jaw_side": "#e3dac9", + "chin_plane": "#e3dac9", + "chin_light": "#f9f5e2", + "jaw_rim": "#f9f5e2", + "lower_gum": "#c9bfac", + "lower_tooth_0": "#f9f5e2", + "lower_tooth_1": "#f9f5e2", + "lower_tooth_2": "#f9f5e2", + "lower_tooth_3": "#f9f5e2", + "lower_tooth_4": "#f9f5e2", + "lower_tooth_5": "#f9f5e2", + "upper_tooth_gaps": "#948875", + "lower_tooth_gaps": "#948875", + "mouth_cavity": "#514e45" + } +} + +{ + "type": "sprite", + "name": "skull_cranium", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "cranium_outline": {"polygon": [[4, 13], [5, 10], [8, 7], [12, 4], [17, 2], [23, 2], [28, 3], [32, 3], [36, 6], [39, 10], [40, 14], [41, 17], [40, 22], [38, 25], [37, 31], [26, 31], [22, 29], [17, 29], [13, 26], [10, 27], [6, 26], [4, 22]], "z": 0}, + "cranium_side": {"polygon": [[5, 13], [7, 10], [10, 7], [15, 4], [20, 3], [27, 4], [32, 4], [36, 7], [39, 11], [39, 17], [36, 21], [30, 23], [23, 23], [18, 25], [12, 26], [7, 25], [5, 21]], "z": 1}, + "temple_plane": {"polygon": [[7, 16], [10, 10], [15, 6], [20, 4], [29, 4], [35, 7], [38, 11], [36, 16], [29, 19], [21, 20], [17, 24], [11, 25], [8, 22]], "z": 2}, + "dome_light": {"polygon": [[14, 10], [17, 7], [21, 5], [28, 5], [33, 6], [36, 9], [38, 12], [38, 14], [34, 15], [31, 17], [28, 15], [24, 13], [20, 12], [18, 10]], "z": 3}, + "brow_plane": {"polygon": [[20, 12], [24, 12], [28, 14], [31, 16], [34, 14], [39, 13], [39, 17], [36, 20], [33, 21], [30, 19], [27, 16], [22, 15], [18, 20], [17, 19]], "z": 4}, + "near_socket_rim": {"polygon": [[20, 13], [25, 13], [28, 16], [30, 18], [29, 22], [27, 25], [22, 25], [18, 22], [18, 17]], "z": 5}, + "near_socket": {"polygon": [[21, 14], [25, 14], [27, 16], [29, 18], [28, 22], [26, 24], [22, 24], [19, 21], [19, 18]], "z": 6}, + "near_socket_inner": {"polygon": [[21, 17], [23, 17], [24, 19], [26, 19], [27, 21], [26, 23], [22, 23], [20, 21], [20, 19]], "z": 9}, + "far_socket": {"polygon": [[35, 16], [38, 14], [40, 14], [40, 20], [38, 23], [35, 22], [34, 19]], "z": 7}, + "far_socket_inner": {"polygon": [[37, 17], [38, 17], [38, 19], [39, 19], [38, 22], [36, 21], [36, 19], [35, 19]], "z": 10}, + "temple_seam": {"line": [[19, 14], [18, 17], [17, 21], [15, 23], [12, 24]], "z": 8}, + "cheek_shadow": {"polygon": [[14, 23], [19, 23], [21, 25], [27, 25], [26, 29], [23, 31], [17, 30], [12, 27]], "z": 11}, + "cheek_plane": {"polygon": [[14, 23], [18, 22], [21, 24], [26, 24], [25, 27], [24, 29], [18, 29], [14, 27], [12, 25]], "z": 13}, + "cheek_light": {"polygon": [[13, 24], [15, 23], [17, 23], [15, 24], [14, 26], [17, 28], [15, 27]], "z": 16}, + "face_plane": {"polygon": [[30, 19], [33, 19], [35, 22], [37, 24], [37, 32], [34, 33], [27, 32], [25, 30], [27, 26], [28, 23]], "z": 12}, + "face_light": {"polygon": [[31, 20], [33, 21], [34, 24], [36, 25], [36, 30], [33, 31], [31, 29], [29, 30], [28, 28], [29, 25]], "z": 14}, + "nose_notch": {"polygon": [[31, 22], [32, 23], [33, 22], [33, 25], [34, 27], [32, 28], [32, 26], [31, 28], [30, 27], [30, 24]], "z": 17}, + "nose_rim": {"line": [[34, 23], [35, 26], [34, 28]], "z": 19}, + "far_cheek_rim": {"line": [[39, 22], [39, 24], [37, 26]], "z": 15}, + "maxilla_shadow": {"polygon": [[25, 29], [28, 30], [31, 30], [34, 31], [37, 30], [37, 33], [27, 33], [25, 32]], "z": 18}, + "upper_tooth_0": {"rect": [26, 30, 1, 3], "z": 20}, + "upper_tooth_1": {"rect": [28, 31, 2, 3], "z": 21}, + "upper_tooth_2": {"rect": [30, 31, 2, 3], "z": 22}, + "upper_tooth_3": {"rect": [32, 31, 2, 3], "z": 23}, + "upper_tooth_4": {"rect": [34, 31, 2, 3], "z": 24}, + "upper_tooth_5": {"rect": [36, 30, 2, 4], "z": 25}, + "upper_tooth_gaps": {"points": [[29, 32], [29, 33], [31, 32], [31, 33], [33, 32], [33, 33], [35, 32], [35, 33]], "z": 26} + } +} + +{ + "type": "sprite", + "name": "skull_jaw", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "jaw_outline": {"polygon": [[11, 26], [13, 28], [16, 31], [20, 33], [25, 33], [28, 34], [37, 33], [37, 40], [35, 43], [29, 43], [25, 41], [21, 40], [15, 40], [12, 38], [11, 35]], "z": 0}, + "jaw_shadow": {"polygon": [[12, 28], [14, 30], [17, 33], [21, 35], [26, 34], [36, 34], [36, 40], [34, 42], [29, 42], [25, 40], [21, 39], [16, 39], [13, 37], [12, 34]], "z": 1}, + "jaw_side": {"polygon": [[12, 29], [15, 32], [19, 35], [24, 36], [26, 39], [22, 38], [17, 38], [14, 36], [13, 33]], "z": 2}, + "chin_plane": {"polygon": [[26, 35], [30, 36], [36, 35], [36, 40], [34, 42], [30, 42], [28, 40]], "z": 3}, + "chin_light": {"polygon": [[30, 36], [34, 36], [35, 38], [34, 40], [32, 42], [30, 40]], "z": 4}, + "jaw_rim": {"line": [[12, 28], [14, 31], [17, 33], [21, 35], [24, 35]], "z": 5}, + "lower_gum": {"line": [[25, 34], [28, 35], [36, 35]], "z": 6}, + "lower_tooth_0": {"rect": [26, 34, 1, 2], "z": 7}, + "lower_tooth_1": {"rect": [28, 35, 2, 2], "z": 8}, + "lower_tooth_2": {"rect": [30, 35, 2, 2], "z": 9}, + "lower_tooth_3": {"rect": [32, 35, 2, 2], "z": 10}, + "lower_tooth_4": {"rect": [34, 35, 2, 2], "z": 11}, + "lower_tooth_5": {"rect": [36, 34, 1, 2], "z": 12}, + "lower_tooth_gaps": {"points": [[29, 35], [29, 36], [31, 35], [31, 36], [33, 35], [33, 36], [35, 35], [35, 36]], "z": 13} + } +} + +{ + "type": "sprite", + "name": "skull_mouth_0", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "mouth_cavity": {"polygon": [[12, 27], [20, 30], [27, 31], [36, 31], [36, 35], [27, 36], [21, 34], [15, 31]], "z": 0} + } +} + +{ + "type": "composition", + "name": "skull", + "size": [ + 48, + 48 + ], + "cell_size": [ + 48, + 48 + ], + "sprites": { + "H": "skull_cranium", + "M": "skull_mouth_0", + "J": "skull_jaw" + }, + "layers": [ + { + "map": [ + "M" + ] + }, + { + "map": [ + "J" + ] + }, + { + "map": [ + "H" + ] + } + ] +} diff --git a/examples/skull/skull_4x.png b/examples/skull/skull_4x.png new file mode 100644 index 00000000..cdc0bdc3 Binary files /dev/null and b/examples/skull/skull_4x.png differ diff --git a/examples/skull/skull_8x.png b/examples/skull/skull_8x.png new file mode 100644 index 00000000..9883ba00 Binary files /dev/null and b/examples/skull/skull_8x.png differ diff --git a/examples/skull/skull_poses.png b/examples/skull/skull_poses.png new file mode 100644 index 00000000..61c4a077 Binary files /dev/null and b/examples/skull/skull_poses.png differ diff --git a/examples/skull/skull_talking.gif b/examples/skull/skull_talking.gif new file mode 100644 index 00000000..2f902e8e Binary files /dev/null and b/examples/skull/skull_talking.gif differ diff --git a/examples/skull/skull_talking.pxl b/examples/skull/skull_talking.pxl new file mode 100644 index 00000000..df2b524a --- /dev/null +++ b/examples/skull/skull_talking.pxl @@ -0,0 +1,326 @@ +// 48x48, facing right. Geometry is authored here; PNGs are pxl output. +// Light comes from above/right. The jaw is a separate transparent layer. +{ + "type": "palette", + "name": "skull_bone", + "colors": { + "_": "transparent", + "cranium_outline": "#77746c", + "cranium_side": "#b8ae9d", + "temple_plane": "#e3dac9", + "dome_light": "#f9f5e2", + "brow_plane": "#e3dac9", + "near_socket_rim": "#f9f5e2", + "near_socket": "#514e45", + "near_socket_inner": "#79796f", + "far_socket": "#514e45", + "far_socket_inner": "#79796f", + "temple_seam": "#77746c", + "cheek_shadow": "#948875", + "cheek_plane": "#e3dac9", + "cheek_light": "#f9f5e2", + "face_plane": "#e3dac9", + "face_light": "#f9f5e2", + "nose_notch": "#514e45", + "nose_rim": "#c9bfac", + "far_cheek_rim": "#c9bfac", + "maxilla_shadow": "#c9bfac", + "upper_tooth_0": "#f9f5e2", + "upper_tooth_1": "#f9f5e2", + "upper_tooth_2": "#f9f5e2", + "upper_tooth_3": "#f9f5e2", + "upper_tooth_4": "#f9f5e2", + "upper_tooth_5": "#f9f5e2", + "jaw_outline": "#77746c", + "jaw_shadow": "#b8ae9d", + "jaw_side": "#e3dac9", + "chin_plane": "#e3dac9", + "chin_light": "#f9f5e2", + "jaw_rim": "#f9f5e2", + "lower_gum": "#c9bfac", + "lower_tooth_0": "#f9f5e2", + "lower_tooth_1": "#f9f5e2", + "lower_tooth_2": "#f9f5e2", + "lower_tooth_3": "#f9f5e2", + "lower_tooth_4": "#f9f5e2", + "lower_tooth_5": "#f9f5e2", + "upper_tooth_gaps": "#948875", + "lower_tooth_gaps": "#948875", + "mouth_cavity": "#514e45" + } +} + +{ + "type": "sprite", + "name": "skull_cranium", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "cranium_outline": {"polygon": [[4, 13], [5, 10], [8, 7], [12, 4], [17, 2], [23, 2], [28, 3], [32, 3], [36, 6], [39, 10], [40, 14], [41, 17], [40, 22], [38, 25], [37, 31], [26, 31], [22, 29], [17, 29], [13, 26], [10, 27], [6, 26], [4, 22]], "z": 0}, + "cranium_side": {"polygon": [[5, 13], [7, 10], [10, 7], [15, 4], [20, 3], [27, 4], [32, 4], [36, 7], [39, 11], [39, 17], [36, 21], [30, 23], [23, 23], [18, 25], [12, 26], [7, 25], [5, 21]], "z": 1}, + "temple_plane": {"polygon": [[7, 16], [10, 10], [15, 6], [20, 4], [29, 4], [35, 7], [38, 11], [36, 16], [29, 19], [21, 20], [17, 24], [11, 25], [8, 22]], "z": 2}, + "dome_light": {"polygon": [[14, 10], [17, 7], [21, 5], [28, 5], [33, 6], [36, 9], [38, 12], [38, 14], [34, 15], [31, 17], [28, 15], [24, 13], [20, 12], [18, 10]], "z": 3}, + "brow_plane": {"polygon": [[20, 12], [24, 12], [28, 14], [31, 16], [34, 14], [39, 13], [39, 17], [36, 20], [33, 21], [30, 19], [27, 16], [22, 15], [18, 20], [17, 19]], "z": 4}, + "near_socket_rim": {"polygon": [[20, 13], [25, 13], [28, 16], [30, 18], [29, 22], [27, 25], [22, 25], [18, 22], [18, 17]], "z": 5}, + "near_socket": {"polygon": [[21, 14], [25, 14], [27, 16], [29, 18], [28, 22], [26, 24], [22, 24], [19, 21], [19, 18]], "z": 6}, + "near_socket_inner": {"polygon": [[21, 17], [23, 17], [24, 19], [26, 19], [27, 21], [26, 23], [22, 23], [20, 21], [20, 19]], "z": 9}, + "far_socket": {"polygon": [[35, 16], [38, 14], [40, 14], [40, 20], [38, 23], [35, 22], [34, 19]], "z": 7}, + "far_socket_inner": {"polygon": [[37, 17], [38, 17], [38, 19], [39, 19], [38, 22], [36, 21], [36, 19], [35, 19]], "z": 10}, + "temple_seam": {"line": [[19, 14], [18, 17], [17, 21], [15, 23], [12, 24]], "z": 8}, + "cheek_shadow": {"polygon": [[14, 23], [19, 23], [21, 25], [27, 25], [26, 29], [23, 31], [17, 30], [12, 27]], "z": 11}, + "cheek_plane": {"polygon": [[14, 23], [18, 22], [21, 24], [26, 24], [25, 27], [24, 29], [18, 29], [14, 27], [12, 25]], "z": 13}, + "cheek_light": {"polygon": [[13, 24], [15, 23], [17, 23], [15, 24], [14, 26], [17, 28], [15, 27]], "z": 16}, + "face_plane": {"polygon": [[30, 19], [33, 19], [35, 22], [37, 24], [37, 32], [34, 33], [27, 32], [25, 30], [27, 26], [28, 23]], "z": 12}, + "face_light": {"polygon": [[31, 20], [33, 21], [34, 24], [36, 25], [36, 30], [33, 31], [31, 29], [29, 30], [28, 28], [29, 25]], "z": 14}, + "nose_notch": {"polygon": [[31, 22], [32, 23], [33, 22], [33, 25], [34, 27], [32, 28], [32, 26], [31, 28], [30, 27], [30, 24]], "z": 17}, + "nose_rim": {"line": [[34, 23], [35, 26], [34, 28]], "z": 19}, + "far_cheek_rim": {"line": [[39, 22], [39, 24], [37, 26]], "z": 15}, + "maxilla_shadow": {"polygon": [[25, 29], [28, 30], [31, 30], [34, 31], [37, 30], [37, 33], [27, 33], [25, 32]], "z": 18}, + "upper_tooth_0": {"rect": [26, 30, 1, 3], "z": 20}, + "upper_tooth_1": {"rect": [28, 31, 2, 3], "z": 21}, + "upper_tooth_2": {"rect": [30, 31, 2, 3], "z": 22}, + "upper_tooth_3": {"rect": [32, 31, 2, 3], "z": 23}, + "upper_tooth_4": {"rect": [34, 31, 2, 3], "z": 24}, + "upper_tooth_5": {"rect": [36, 30, 2, 4], "z": 25}, + "upper_tooth_gaps": {"points": [[29, 32], [29, 33], [31, 32], [31, 33], [33, 32], [33, 33], [35, 32], [35, 33]], "z": 26} + } +} + +{ + "type": "sprite", + "name": "skull_jaw", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "jaw_outline": {"polygon": [[11, 26], [13, 28], [16, 31], [20, 33], [25, 33], [28, 34], [37, 33], [37, 40], [35, 43], [29, 43], [25, 41], [21, 40], [15, 40], [12, 38], [11, 35]], "z": 0}, + "jaw_shadow": {"polygon": [[12, 28], [14, 30], [17, 33], [21, 35], [26, 34], [36, 34], [36, 40], [34, 42], [29, 42], [25, 40], [21, 39], [16, 39], [13, 37], [12, 34]], "z": 1}, + "jaw_side": {"polygon": [[12, 29], [15, 32], [19, 35], [24, 36], [26, 39], [22, 38], [17, 38], [14, 36], [13, 33]], "z": 2}, + "chin_plane": {"polygon": [[26, 35], [30, 36], [36, 35], [36, 40], [34, 42], [30, 42], [28, 40]], "z": 3}, + "chin_light": {"polygon": [[30, 36], [34, 36], [35, 38], [34, 40], [32, 42], [30, 40]], "z": 4}, + "jaw_rim": {"line": [[12, 28], [14, 31], [17, 33], [21, 35], [24, 35]], "z": 5}, + "lower_gum": {"line": [[25, 34], [28, 35], [36, 35]], "z": 6}, + "lower_tooth_0": {"rect": [26, 34, 1, 2], "z": 7}, + "lower_tooth_1": {"rect": [28, 35, 2, 2], "z": 8}, + "lower_tooth_2": {"rect": [30, 35, 2, 2], "z": 9}, + "lower_tooth_3": {"rect": [32, 35, 2, 2], "z": 10}, + "lower_tooth_4": {"rect": [34, 35, 2, 2], "z": 11}, + "lower_tooth_5": {"rect": [36, 34, 1, 2], "z": 12}, + "lower_tooth_gaps": {"points": [[29, 35], [29, 36], [31, 35], [31, 36], [33, 35], [33, 36], [35, 35], [35, 36]], "z": 13} + } +} + +{ + "type": "sprite", + "name": "skull_mouth_0", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "mouth_cavity": {"polygon": [[12, 27], [20, 30], [27, 31], [36, 31], [36, 35], [27, 36], [21, 34], [15, 31]], "z": 0} + } +} + +{ + "type": "composition", + "name": "skull", + "size": [ + 48, + 48 + ], + "cell_size": [ + 48, + 48 + ], + "sprites": { + "H": "skull_cranium", + "M": "skull_mouth_0", + "J": "skull_jaw" + }, + "layers": [ + { + "map": [ + "M" + ] + }, + { + "map": [ + "J" + ] + }, + { + "map": [ + "H" + ] + } + ] +} + +// The head stays fixed; only the mandible moves. +{ + "type": "sprite", + "name": "skull_jaw_drop_1", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "jaw_outline": {"polygon": [[11, 27], [13, 29], [16, 32], [20, 34], [25, 34], [28, 35], [37, 34], [37, 41], [35, 44], [29, 44], [25, 42], [21, 41], [15, 41], [12, 39], [11, 36]], "z": 0}, + "jaw_shadow": {"polygon": [[12, 29], [14, 31], [17, 34], [21, 36], [26, 35], [36, 35], [36, 41], [34, 43], [29, 43], [25, 41], [21, 40], [16, 40], [13, 38], [12, 35]], "z": 1}, + "jaw_side": {"polygon": [[12, 30], [15, 33], [19, 36], [24, 37], [26, 40], [22, 39], [17, 39], [14, 37], [13, 34]], "z": 2}, + "chin_plane": {"polygon": [[26, 36], [30, 37], [36, 36], [36, 41], [34, 43], [30, 43], [28, 41]], "z": 3}, + "chin_light": {"polygon": [[30, 37], [34, 37], [35, 39], [34, 41], [32, 43], [30, 41]], "z": 4}, + "jaw_rim": {"line": [[12, 29], [14, 32], [17, 34], [21, 36], [24, 36]], "z": 5}, + "lower_gum": {"line": [[25, 35], [28, 36], [36, 36]], "z": 6}, + "lower_tooth_0": {"rect": [26, 35, 1, 2], "z": 7}, + "lower_tooth_1": {"rect": [28, 36, 2, 2], "z": 8}, + "lower_tooth_2": {"rect": [30, 36, 2, 2], "z": 9}, + "lower_tooth_3": {"rect": [32, 36, 2, 2], "z": 10}, + "lower_tooth_4": {"rect": [34, 36, 2, 2], "z": 11}, + "lower_tooth_5": {"rect": [36, 35, 1, 2], "z": 12}, + "lower_tooth_gaps": {"points": [[29, 36], [29, 37], [31, 36], [31, 37], [33, 36], [33, 37], [35, 36], [35, 37]], "z": 13} + } +} + +{ + "type": "sprite", + "name": "skull_jaw_drop_3", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "jaw_outline": {"polygon": [[11, 29], [13, 31], [16, 34], [20, 36], [25, 36], [28, 37], [37, 36], [37, 43], [35, 46], [29, 46], [25, 44], [21, 43], [15, 43], [12, 41], [11, 38]], "z": 0}, + "jaw_shadow": {"polygon": [[12, 31], [14, 33], [17, 36], [21, 38], [26, 37], [36, 37], [36, 43], [34, 45], [29, 45], [25, 43], [21, 42], [16, 42], [13, 40], [12, 37]], "z": 1}, + "jaw_side": {"polygon": [[12, 32], [15, 35], [19, 38], [24, 39], [26, 42], [22, 41], [17, 41], [14, 39], [13, 36]], "z": 2}, + "chin_plane": {"polygon": [[26, 38], [30, 39], [36, 38], [36, 43], [34, 45], [30, 45], [28, 43]], "z": 3}, + "chin_light": {"polygon": [[30, 39], [34, 39], [35, 41], [34, 43], [32, 45], [30, 43]], "z": 4}, + "jaw_rim": {"line": [[12, 31], [14, 34], [17, 36], [21, 38], [24, 38]], "z": 5}, + "lower_gum": {"line": [[25, 37], [28, 38], [36, 38]], "z": 6}, + "lower_tooth_0": {"rect": [26, 37, 1, 2], "z": 7}, + "lower_tooth_1": {"rect": [28, 38, 2, 2], "z": 8}, + "lower_tooth_2": {"rect": [30, 38, 2, 2], "z": 9}, + "lower_tooth_3": {"rect": [32, 38, 2, 2], "z": 10}, + "lower_tooth_4": {"rect": [34, 38, 2, 2], "z": 11}, + "lower_tooth_5": {"rect": [36, 37, 1, 2], "z": 12}, + "lower_tooth_gaps": {"points": [[29, 38], [29, 39], [31, 38], [31, 39], [33, 38], [33, 39], [35, 38], [35, 39]], "z": 13} + } +} + +{ + "type": "sprite", + "name": "skull_mouth_1", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "mouth_cavity": {"polygon": [[12, 27], [20, 30], [27, 31], [36, 31], [36, 36], [27, 37], [21, 35], [15, 32]], "z": 0} + } +} + +{ + "type": "sprite", + "name": "skull_mouth_3", + "size": [ + 48, + 48 + ], + "palette": "skull_bone", + "regions": { + "mouth_cavity": {"polygon": [[12, 27], [20, 30], [27, 31], [36, 31], [36, 38], [27, 39], [21, 37], [15, 34]], "z": 0} + } +} + +{ + "type": "composition", + "name": "skull_talk_small", + "size": [ + 48, + 48 + ], + "cell_size": [ + 48, + 48 + ], + "sprites": { + "H": "skull_cranium", + "M": "skull_mouth_1", + "J": "skull_jaw_drop_1" + }, + "layers": [ + { + "map": [ + "M" + ] + }, + { + "map": [ + "J" + ] + }, + { + "map": [ + "H" + ] + } + ] +} + +{ + "type": "composition", + "name": "skull_talk_wide", + "size": [ + 48, + 48 + ], + "cell_size": [ + 48, + 48 + ], + "sprites": { + "H": "skull_cranium", + "M": "skull_mouth_3", + "J": "skull_jaw_drop_3" + }, + "layers": [ + { + "map": [ + "M" + ] + }, + { + "map": [ + "J" + ] + }, + { + "map": [ + "H" + ] + } + ] +} + +{ + "type": "animation", + "name": "skull_talking", + "frames": [ + "skull", + "skull_talk_small", + "skull_talk_wide", + "skull_talk_small" + ], + "duration": 120, + "loop": true +}