pixospritz-specs 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +266 -0
- package/constants/directions.json +67 -0
- package/constants/events.json +137 -0
- package/constants/shader-types.json +208 -0
- package/formats/manifest.schema.json +206 -0
- package/formats/map.schema.json +278 -0
- package/formats/save.schema.json +226 -0
- package/formats/sprite.schema.json +184 -0
- package/generate-c-headers.cjs +353 -0
- package/index.js +121 -0
- package/math/camera.spec.json +157 -0
- package/math/matrix.spec.json +160 -0
- package/math/vector.spec.json +137 -0
- package/package.json +36 -0
- package/shaders/common/lighting.glsl +150 -0
- package/shaders/common/transforms.glsl +164 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://pixospritz.dev/schemas/save.schema.json",
|
|
4
|
+
"title": "PixoSpritz Save File",
|
|
5
|
+
"description": "Schema for .pxsave game save files with cross-game compatibility",
|
|
6
|
+
"type": "object",
|
|
7
|
+
|
|
8
|
+
"required": ["version", "format", "gameId", "timestamp", "player"],
|
|
9
|
+
|
|
10
|
+
"properties": {
|
|
11
|
+
"version": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
14
|
+
"description": "Save format version (semver)",
|
|
15
|
+
"examples": ["1.0.0"]
|
|
16
|
+
},
|
|
17
|
+
"format": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"const": "pxsave",
|
|
20
|
+
"description": "File format identifier"
|
|
21
|
+
},
|
|
22
|
+
"gameId": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Unique identifier for the game package",
|
|
25
|
+
"examples": ["elemental-trials", "my-adventure"]
|
|
26
|
+
},
|
|
27
|
+
"gameVersion": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"pattern": "^\\d+\\.\\d+\\.\\d+$",
|
|
30
|
+
"description": "Version of the game that created this save"
|
|
31
|
+
},
|
|
32
|
+
"timestamp": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"format": "date-time",
|
|
35
|
+
"description": "ISO 8601 timestamp when save was created"
|
|
36
|
+
},
|
|
37
|
+
"playTime": {
|
|
38
|
+
"type": "integer",
|
|
39
|
+
"minimum": 0,
|
|
40
|
+
"description": "Total play time in milliseconds"
|
|
41
|
+
},
|
|
42
|
+
"slotId": {
|
|
43
|
+
"type": "string",
|
|
44
|
+
"description": "Save slot identifier",
|
|
45
|
+
"examples": ["slot-1", "autosave", "quicksave"]
|
|
46
|
+
},
|
|
47
|
+
"slotName": {
|
|
48
|
+
"type": "string",
|
|
49
|
+
"description": "User-friendly slot name",
|
|
50
|
+
"examples": ["Before Boss", "Village Start"]
|
|
51
|
+
},
|
|
52
|
+
"checksum": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"pattern": "^sha256:[a-f0-9]{64}$",
|
|
55
|
+
"description": "SHA-256 checksum for integrity verification"
|
|
56
|
+
},
|
|
57
|
+
"screenshot": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"contentEncoding": "base64",
|
|
60
|
+
"contentMediaType": "image/png",
|
|
61
|
+
"description": "Base64-encoded screenshot thumbnail"
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
"player": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"required": ["zone", "position"],
|
|
67
|
+
"description": "Player state",
|
|
68
|
+
"properties": {
|
|
69
|
+
"zone": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"description": "Current zone ID"
|
|
72
|
+
},
|
|
73
|
+
"position": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "type": "number" },
|
|
76
|
+
"minItems": 3,
|
|
77
|
+
"maxItems": 3,
|
|
78
|
+
"description": "[x, y, z] world position"
|
|
79
|
+
},
|
|
80
|
+
"facing": {
|
|
81
|
+
"type": "integer",
|
|
82
|
+
"minimum": 0,
|
|
83
|
+
"maximum": 7,
|
|
84
|
+
"description": "Direction index (0=N, 1=NE, 2=E, etc.)"
|
|
85
|
+
},
|
|
86
|
+
"sprite": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"description": "Current sprite/avatar ID"
|
|
89
|
+
},
|
|
90
|
+
"state": {
|
|
91
|
+
"type": "string",
|
|
92
|
+
"description": "Animation state",
|
|
93
|
+
"examples": ["idle", "walk", "run"]
|
|
94
|
+
},
|
|
95
|
+
"stats": {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"description": "Player statistics",
|
|
98
|
+
"properties": {
|
|
99
|
+
"hp": { "type": "integer" },
|
|
100
|
+
"maxHp": { "type": "integer" },
|
|
101
|
+
"mp": { "type": "integer" },
|
|
102
|
+
"maxMp": { "type": "integer" },
|
|
103
|
+
"level": { "type": "integer" },
|
|
104
|
+
"exp": { "type": "integer" }
|
|
105
|
+
},
|
|
106
|
+
"additionalProperties": { "type": "number" }
|
|
107
|
+
},
|
|
108
|
+
"inventory": {
|
|
109
|
+
"type": "array",
|
|
110
|
+
"description": "Portable inventory items",
|
|
111
|
+
"items": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"required": ["id", "quantity"],
|
|
114
|
+
"properties": {
|
|
115
|
+
"id": { "type": "string" },
|
|
116
|
+
"quantity": { "type": "integer", "minimum": 1 },
|
|
117
|
+
"data": { "type": "object" }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
"equipment": {
|
|
122
|
+
"type": "object",
|
|
123
|
+
"description": "Equipped items by slot",
|
|
124
|
+
"additionalProperties": { "type": "string" }
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
"flags": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"description": "Game state flags (persistent variables)",
|
|
132
|
+
"additionalProperties": {
|
|
133
|
+
"oneOf": [
|
|
134
|
+
{ "type": "boolean" },
|
|
135
|
+
{ "type": "number" },
|
|
136
|
+
{ "type": "string" }
|
|
137
|
+
]
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
"zones": {
|
|
142
|
+
"type": "object",
|
|
143
|
+
"description": "Per-zone state (opened chests, defeated enemies, etc.)",
|
|
144
|
+
"additionalProperties": {
|
|
145
|
+
"type": "object",
|
|
146
|
+
"properties": {
|
|
147
|
+
"visited": { "type": "boolean" },
|
|
148
|
+
"cleared": { "type": "boolean" },
|
|
149
|
+
"entities": {
|
|
150
|
+
"type": "object",
|
|
151
|
+
"description": "Entity-specific state",
|
|
152
|
+
"additionalProperties": { "type": "object" }
|
|
153
|
+
},
|
|
154
|
+
"triggers": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"items": { "type": "string" },
|
|
157
|
+
"description": "Triggered one-time events"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
"quests": {
|
|
164
|
+
"type": "array",
|
|
165
|
+
"description": "Quest progress tracking",
|
|
166
|
+
"items": {
|
|
167
|
+
"type": "object",
|
|
168
|
+
"required": ["id", "status"],
|
|
169
|
+
"properties": {
|
|
170
|
+
"id": { "type": "string" },
|
|
171
|
+
"status": {
|
|
172
|
+
"type": "string",
|
|
173
|
+
"enum": ["active", "completed", "failed", "hidden"]
|
|
174
|
+
},
|
|
175
|
+
"progress": { "type": "object" },
|
|
176
|
+
"startTime": { "type": "string", "format": "date-time" },
|
|
177
|
+
"endTime": { "type": "string", "format": "date-time" }
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
"portable": {
|
|
183
|
+
"type": "object",
|
|
184
|
+
"description": "Cross-game compatible data",
|
|
185
|
+
"properties": {
|
|
186
|
+
"namespace": {
|
|
187
|
+
"type": "string",
|
|
188
|
+
"description": "Namespace for portable items/flags"
|
|
189
|
+
},
|
|
190
|
+
"items": {
|
|
191
|
+
"type": "array",
|
|
192
|
+
"items": {
|
|
193
|
+
"type": "object",
|
|
194
|
+
"required": ["id"],
|
|
195
|
+
"properties": {
|
|
196
|
+
"id": { "type": "string" },
|
|
197
|
+
"type": { "type": "string" },
|
|
198
|
+
"data": { "type": "object" }
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"achievements": {
|
|
203
|
+
"type": "array",
|
|
204
|
+
"items": { "type": "string" }
|
|
205
|
+
},
|
|
206
|
+
"compatibleGames": {
|
|
207
|
+
"type": "array",
|
|
208
|
+
"items": { "type": "string" },
|
|
209
|
+
"description": "Game IDs that can import this save"
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
|
|
214
|
+
"meta": {
|
|
215
|
+
"type": "object",
|
|
216
|
+
"description": "Additional metadata",
|
|
217
|
+
"properties": {
|
|
218
|
+
"difficulty": { "type": "string" },
|
|
219
|
+
"newGamePlus": { "type": "boolean" },
|
|
220
|
+
"deaths": { "type": "integer" },
|
|
221
|
+
"secrets": { "type": "integer" }
|
|
222
|
+
},
|
|
223
|
+
"additionalProperties": true
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://pixospritz.dev/schemas/sprite.schema.json",
|
|
4
|
+
"title": "PixoSpritz Sprite Definition",
|
|
5
|
+
"description": "Schema for sprite/avatar definition files",
|
|
6
|
+
"type": "object",
|
|
7
|
+
|
|
8
|
+
"required": ["type", "src", "sheetSize", "tileSize"],
|
|
9
|
+
|
|
10
|
+
"properties": {
|
|
11
|
+
"type": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"enum": ["sprite", "avatar", "npc", "object", "effect"],
|
|
14
|
+
"description": "Sprite category"
|
|
15
|
+
},
|
|
16
|
+
"src": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Path to spritesheet image"
|
|
19
|
+
},
|
|
20
|
+
"portraitSrc": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"description": "Path to portrait image for dialogue"
|
|
23
|
+
},
|
|
24
|
+
"sheetSize": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": { "type": "integer", "minimum": 1 },
|
|
27
|
+
"minItems": 2,
|
|
28
|
+
"maxItems": 2,
|
|
29
|
+
"description": "[width, height] of spritesheet in pixels"
|
|
30
|
+
},
|
|
31
|
+
"tileSize": {
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": { "type": "integer", "minimum": 1 },
|
|
34
|
+
"minItems": 2,
|
|
35
|
+
"maxItems": 2,
|
|
36
|
+
"description": "[width, height] of each frame in pixels"
|
|
37
|
+
},
|
|
38
|
+
"state": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"description": "Initial animation state",
|
|
41
|
+
"default": "idle"
|
|
42
|
+
},
|
|
43
|
+
"frames": {
|
|
44
|
+
"type": "object",
|
|
45
|
+
"description": "Animation frames by direction/state",
|
|
46
|
+
"additionalProperties": {
|
|
47
|
+
"type": "array",
|
|
48
|
+
"items": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"items": { "type": "integer" },
|
|
51
|
+
"minItems": 2,
|
|
52
|
+
"maxItems": 2,
|
|
53
|
+
"description": "[x, y] position in spritesheet"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"animations": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "Named animation sequences",
|
|
60
|
+
"additionalProperties": {
|
|
61
|
+
"type": "object",
|
|
62
|
+
"properties": {
|
|
63
|
+
"frames": {
|
|
64
|
+
"type": "array",
|
|
65
|
+
"items": { "type": "integer" },
|
|
66
|
+
"description": "Frame indices"
|
|
67
|
+
},
|
|
68
|
+
"speed": {
|
|
69
|
+
"type": "number",
|
|
70
|
+
"minimum": 0,
|
|
71
|
+
"description": "Frames per second"
|
|
72
|
+
},
|
|
73
|
+
"loop": {
|
|
74
|
+
"type": "boolean",
|
|
75
|
+
"default": true
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"drawOffset": {
|
|
81
|
+
"type": "object",
|
|
82
|
+
"description": "Render offset by direction [x, y, z]",
|
|
83
|
+
"additionalProperties": {
|
|
84
|
+
"type": "array",
|
|
85
|
+
"items": { "type": "number" },
|
|
86
|
+
"minItems": 3,
|
|
87
|
+
"maxItems": 3
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"hotspotOffset": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": { "type": "number" },
|
|
93
|
+
"minItems": 3,
|
|
94
|
+
"maxItems": 3,
|
|
95
|
+
"description": "Collision/interaction point offset"
|
|
96
|
+
},
|
|
97
|
+
"boundingBox": {
|
|
98
|
+
"type": "object",
|
|
99
|
+
"properties": {
|
|
100
|
+
"width": { "type": "number" },
|
|
101
|
+
"height": { "type": "number" },
|
|
102
|
+
"depth": { "type": "number" },
|
|
103
|
+
"offset": {
|
|
104
|
+
"type": "array",
|
|
105
|
+
"items": { "type": "number" },
|
|
106
|
+
"minItems": 3,
|
|
107
|
+
"maxItems": 3
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"bindCamera": {
|
|
112
|
+
"type": "boolean",
|
|
113
|
+
"description": "Whether camera follows this sprite",
|
|
114
|
+
"default": false
|
|
115
|
+
},
|
|
116
|
+
"enableSpeech": {
|
|
117
|
+
"type": "boolean",
|
|
118
|
+
"description": "Whether sprite can display speech bubbles",
|
|
119
|
+
"default": false
|
|
120
|
+
},
|
|
121
|
+
"cutouts": {
|
|
122
|
+
"type": "object",
|
|
123
|
+
"description": "Named cutout images for expressions/states",
|
|
124
|
+
"additionalProperties": { "type": "string" }
|
|
125
|
+
},
|
|
126
|
+
"billboard": {
|
|
127
|
+
"type": "boolean",
|
|
128
|
+
"description": "Always face camera (3D mode)",
|
|
129
|
+
"default": true
|
|
130
|
+
},
|
|
131
|
+
"castShadow": {
|
|
132
|
+
"type": "boolean",
|
|
133
|
+
"default": true
|
|
134
|
+
},
|
|
135
|
+
"receiveShadow": {
|
|
136
|
+
"type": "boolean",
|
|
137
|
+
"default": true
|
|
138
|
+
},
|
|
139
|
+
"layer": {
|
|
140
|
+
"type": "integer",
|
|
141
|
+
"description": "Render layer for sorting",
|
|
142
|
+
"default": 0
|
|
143
|
+
},
|
|
144
|
+
"collisionType": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"enum": ["none", "box", "circle", "polygon"],
|
|
147
|
+
"default": "box"
|
|
148
|
+
},
|
|
149
|
+
"interactable": {
|
|
150
|
+
"type": "boolean",
|
|
151
|
+
"description": "Can player interact with this sprite",
|
|
152
|
+
"default": false
|
|
153
|
+
},
|
|
154
|
+
"scripts": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"description": "Attached behavior scripts",
|
|
157
|
+
"items": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"properties": {
|
|
160
|
+
"id": { "type": "string" },
|
|
161
|
+
"trigger": { "type": "string" },
|
|
162
|
+
"params": { "type": "object" }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
"actions": {
|
|
167
|
+
"type": "array",
|
|
168
|
+
"description": "AI/behavior actions",
|
|
169
|
+
"items": {
|
|
170
|
+
"type": "object",
|
|
171
|
+
"required": ["type"],
|
|
172
|
+
"properties": {
|
|
173
|
+
"type": { "type": "string" },
|
|
174
|
+
"params": { "type": "object" }
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"data": {
|
|
179
|
+
"type": "object",
|
|
180
|
+
"description": "Custom sprite data",
|
|
181
|
+
"additionalProperties": true
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|