@forgeax-extension/character-3d 0.1.2

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 (110) hide show
  1. package/SOURCE_PROVENANCE.md +8 -0
  2. package/dist/assets/index-CIx3aXo1.js +4336 -0
  3. package/dist/assets/index-CIx3aXo1.js.map +1 -0
  4. package/dist/assets/index-CmhOHLEB.css +1 -0
  5. package/dist/hdr/README.md +28 -0
  6. package/dist/hdr/presets.json +8 -0
  7. package/dist/index.html +13 -0
  8. package/forgeax-extension.json +428 -0
  9. package/marketplace-card.json +56 -0
  10. package/package.json +59 -0
  11. package/packages/external-asset-meta/package.json +24 -0
  12. package/packages/external-asset-meta/src/cook.test.ts +211 -0
  13. package/packages/external-asset-meta/src/cook.ts +188 -0
  14. package/packages/external-asset-meta/src/draco3dgltf.d.ts +11 -0
  15. package/packages/external-asset-meta/src/index.ts +18 -0
  16. package/packages/external-asset-meta/src/normalize.test.ts +36 -0
  17. package/packages/external-asset-meta/src/normalize.ts +101 -0
  18. package/packages/external-asset-meta/src/types.ts +82 -0
  19. package/schemas/adopt-playable-character.args.json +26 -0
  20. package/schemas/adopt-playable-character.returns.json +31 -0
  21. package/schemas/apply-motion.args.json +47 -0
  22. package/schemas/apply-motion.returns.json +23 -0
  23. package/schemas/auto-rig.args.json +35 -0
  24. package/schemas/auto-rig.returns.json +23 -0
  25. package/schemas/delete-asset.args.json +18 -0
  26. package/schemas/delete-asset.returns.json +18 -0
  27. package/schemas/engine-import-status.args.json +18 -0
  28. package/schemas/engine-import-status.returns.json +50 -0
  29. package/schemas/export-playable-character.args.json +21 -0
  30. package/schemas/export-playable-character.returns.json +47 -0
  31. package/schemas/gen3d-asset-manifest.json +281 -0
  32. package/schemas/generate-meshy-text-mock.args.json +42 -0
  33. package/schemas/generate-meshy-text-mock.returns.json +301 -0
  34. package/schemas/get-credentials.args.json +7 -0
  35. package/schemas/get-credentials.returns.json +45 -0
  36. package/schemas/get-playable-profile.args.json +11 -0
  37. package/schemas/get-playable-profile.returns.json +188 -0
  38. package/schemas/image-to-3d.args.json +47 -0
  39. package/schemas/image-to-3d.returns.json +306 -0
  40. package/schemas/import-to-engine.args.json +18 -0
  41. package/schemas/import-to-engine.returns.json +35 -0
  42. package/schemas/list-assets.args.json +22 -0
  43. package/schemas/list-assets.returns.json +296 -0
  44. package/schemas/list-motions.args.json +29 -0
  45. package/schemas/list-motions.returns.json +41 -0
  46. package/schemas/pose-standardization.args.json +28 -0
  47. package/schemas/pose-standardization.returns.json +29 -0
  48. package/schemas/provider-status.args.json +7 -0
  49. package/schemas/provider-status.returns.json +70 -0
  50. package/schemas/refine-mesh.args.json +33 -0
  51. package/schemas/refine-mesh.returns.json +306 -0
  52. package/schemas/rename-asset.args.json +22 -0
  53. package/schemas/rename-asset.returns.json +14 -0
  54. package/schemas/retopo-lowpoly.args.json +34 -0
  55. package/schemas/retopo-lowpoly.returns.json +24 -0
  56. package/schemas/score-quality.args.json +36 -0
  57. package/schemas/score-quality.returns.json +12 -0
  58. package/schemas/set-credentials.args.json +32 -0
  59. package/schemas/set-credentials.returns.json +45 -0
  60. package/schemas/set-playable-motion-mapping.args.json +25 -0
  61. package/schemas/set-playable-motion-mapping.returns.json +33 -0
  62. package/schemas/set-playable-profile.args.json +32 -0
  63. package/schemas/set-playable-profile.returns.json +67 -0
  64. package/schemas/text-to-3d.args.json +51 -0
  65. package/schemas/text-to-3d.returns.json +306 -0
  66. package/schemas/upload-image.args.json +19 -0
  67. package/schemas/upload-image.returns.json +21 -0
  68. package/schemas/upload-video.args.json +14 -0
  69. package/schemas/upload-video.returns.json +14 -0
  70. package/schemas/views-to-3d.args.json +58 -0
  71. package/schemas/views-to-3d.returns.json +306 -0
  72. package/server/adopt-playable-character.ts +291 -0
  73. package/server/asset-storage.ts +136 -0
  74. package/server/asset-upload.ts +123 -0
  75. package/server/audit.ts +58 -0
  76. package/server/cache.ts +75 -0
  77. package/server/cos-uploader.ts +141 -0
  78. package/server/credentials-store.ts +186 -0
  79. package/server/engine-import.ts +238 -0
  80. package/server/env.ts +287 -0
  81. package/server/export-playable-character.ts +364 -0
  82. package/server/generate.ts +89 -0
  83. package/server/merge-playable-character.ts +259 -0
  84. package/server/motion-catalog.ts +137 -0
  85. package/server/per-game-store.ts +1016 -0
  86. package/server/providers/gateway-client.ts +171 -0
  87. package/server/providers/gateway-data.ts +182 -0
  88. package/server/providers/gateway-models.ts +49 -0
  89. package/server/providers/hunyuan-rest.ts +317 -0
  90. package/server/providers/hunyuan-workflow.ts +225 -0
  91. package/server/providers/meshy-direct-client.ts +223 -0
  92. package/server/providers/meshy.ts +548 -0
  93. package/server/providers/rodin-gateway.ts +193 -0
  94. package/server/providers/rodin.ts +253 -0
  95. package/server/providers/visvise.ts +329 -0
  96. package/server/rate-guard.ts +29 -0
  97. package/server/tool-handlers.ts +2193 -0
  98. package/shared/catalog.ts +307 -0
  99. package/shared/manifest.ts +378 -0
  100. package/shared/meshy-actions.ts +690 -0
  101. package/shared/playable-preview-url.test.ts +14 -0
  102. package/shared/playable-preview-url.ts +13 -0
  103. package/shared/playable-profile.test.ts +127 -0
  104. package/shared/playable-profile.ts +171 -0
  105. package/shared/provider-params.test.ts +172 -0
  106. package/shared/provider-params.ts +389 -0
  107. package/shared/quality/heuristics.test.ts +84 -0
  108. package/shared/quality/heuristics.ts +100 -0
  109. package/shared/rodin-image.test.ts +51 -0
  110. package/shared/rodin-image.ts +125 -0
@@ -0,0 +1,67 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:set-playable-profile returns",
4
+ "type": "object",
5
+ "properties": {
6
+ "ok": { "const": true },
7
+ "gameProfile": {
8
+ "type": "object",
9
+ "properties": {
10
+ "schemaVersion": { "const": 1 },
11
+ "profileId": { "type": "string" },
12
+ "profileVersion": { "type": "integer", "minimum": 1 },
13
+ "displayName": { "type": "string" },
14
+ "slots": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "properties": {
19
+ "slotId": { "type": "string" },
20
+ "displayName": { "type": "string" },
21
+ "required": { "type": "boolean" },
22
+ "playbackMode": { "enum": ["loop", "once", "freeze_frame"] },
23
+ "speed": { "type": "number", "exclusiveMinimum": 0 },
24
+ "matchKeywords": { "type": "array", "items": { "type": "string" } },
25
+ "rootMotion": { "enum": ["preserve", "remove_xz", "remove_xyz"] }
26
+ },
27
+ "required": ["slotId", "displayName", "required", "playbackMode", "speed", "matchKeywords", "rootMotion"],
28
+ "additionalProperties": false
29
+ }
30
+ },
31
+ "updatedAt": { "type": "string" }
32
+ },
33
+ "required": ["schemaVersion", "profileId", "profileVersion", "displayName", "slots", "updatedAt"],
34
+ "additionalProperties": false
35
+ },
36
+ "override": {
37
+ "type": "object",
38
+ "properties": {
39
+ "schemaVersion": { "const": 1 },
40
+ "slots": {
41
+ "type": "array",
42
+ "items": {
43
+ "type": "object",
44
+ "properties": {
45
+ "slotId": { "type": "string" },
46
+ "displayName": { "type": "string" },
47
+ "required": { "type": "boolean" },
48
+ "playbackMode": { "enum": ["loop", "once", "freeze_frame"] },
49
+ "speed": { "type": "number", "exclusiveMinimum": 0 },
50
+ "matchKeywords": { "type": "array", "items": { "type": "string" } },
51
+ "rootMotion": { "enum": ["preserve", "remove_xz", "remove_xyz"] }
52
+ },
53
+ "required": ["slotId", "displayName", "required", "playbackMode", "speed", "matchKeywords", "rootMotion"],
54
+ "additionalProperties": false
55
+ }
56
+ },
57
+ "basedOnProfileId": { "type": "string" },
58
+ "basedOnProfileVersion": { "type": "integer", "minimum": 1 },
59
+ "updatedAt": { "type": "string" }
60
+ },
61
+ "required": ["schemaVersion", "slots", "basedOnProfileId", "basedOnProfileVersion", "updatedAt"],
62
+ "additionalProperties": false
63
+ }
64
+ },
65
+ "required": ["ok", "gameProfile", "override"],
66
+ "additionalProperties": false
67
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:text-to-3d args",
4
+ "type": "object",
5
+ "properties": {
6
+ "slug": {
7
+ "type": "string",
8
+ "description": "Active game slug. Assets are stored per game under .forgeax/games/<slug>/assets/3d/. The workbench UI fills this automatically for manual use; an AI/agent caller MUST pass the active game's slug (e.g. 'mini-gta'). Required."
9
+ },
10
+ "assetSlot": {
11
+ "type": "string",
12
+ "enum": ["characters", "meshes"],
13
+ "default": "meshes",
14
+ "description": "3D asset slot (subdir under assets/3d/). characters for playable/NPC bodies, meshes for props/environment."
15
+ },
16
+ "assetName": {
17
+ "type": "string",
18
+ "description": "Desired base file name (without extension). Sanitized + de-duplicated by the store. Defaults to a name derived from the prompt."
19
+ },
20
+ "prompt": {
21
+ "type": "string",
22
+ "minLength": 1,
23
+ "description": "Text prompt describing the 3D asset. Meshy rejects over 800 characters with HTTP 400 before any mesh is billed — compress the same spec first; do not switch vendor. Hunyuan/Rodin are not bound to this cap."
24
+ },
25
+ "provider": {
26
+ "type": "string",
27
+ "enum": ["hunyuan_workflow", "meshy", "rodin", "visvise"],
28
+ "default": "hunyuan_workflow",
29
+ "description": "Generation provider. Defaults to hunyuan_workflow. Rodin uses LiteLLM rodin-3d (not Hyper3D). VISVISE uses visvise-3d / mid / low via providerParams.quality. Meshy remains in the enum but is hidden in the UI."
30
+ },
31
+ "enablePbr": { "type": "boolean", "default": true },
32
+ "enableFbxUrl": {
33
+ "type": "boolean",
34
+ "default": false,
35
+ "description": "Request an FBX output URL in addition to GLB."
36
+ },
37
+ "targetPolycount": {
38
+ "type": "integer",
39
+ "minimum": 1000,
40
+ "maximum": 300000,
41
+ "default": 30000
42
+ },
43
+ "providerParams": {
44
+ "type": "object",
45
+ "additionalProperties": true,
46
+ "description": "Provider-specific native params (validated server-side against shared/provider-params.ts; unverified/inapplicable fields are dropped). Rodin keys: mesh_mode, subdivisionlevel, material, TAPose, hd_texture, addons, use_original_alpha — same bag as the sidebar; server appends --flags to prompt. No quality_override. See docs/PROVIDER_PARAMS.md."
47
+ }
48
+ },
49
+ "required": ["slug", "prompt"],
50
+ "additionalProperties": false
51
+ }
@@ -0,0 +1,306 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:text-to-3d returns",
4
+ "type": "object",
5
+ "properties": {
6
+ "ok": {
7
+ "const": true
8
+ },
9
+ "cacheKey": {
10
+ "type": "string"
11
+ },
12
+ "cacheHit": {
13
+ "type": "boolean"
14
+ },
15
+ "usedMock": {
16
+ "type": "boolean",
17
+ "description": "True when the real provider was not configured and a deterministic mock was used (quota-safe fallback)."
18
+ },
19
+ "manifest": {
20
+ "type": "object",
21
+ "properties": {
22
+ "manifestVersion": {
23
+ "const": 1
24
+ },
25
+ "assetId": {
26
+ "type": "string"
27
+ },
28
+ "kind": {
29
+ "enum": [
30
+ "mesh",
31
+ "animation"
32
+ ]
33
+ },
34
+ "provider": {
35
+ "enum": [
36
+ "meshy",
37
+ "hunyuan_workflow",
38
+ "hunyuan_rest",
39
+ "rodin",
40
+ "visvise"
41
+ ]
42
+ },
43
+ "providerMode": {
44
+ "enum": [
45
+ "mock",
46
+ "real"
47
+ ]
48
+ },
49
+ "mode": {
50
+ "enum": [
51
+ "text",
52
+ "image",
53
+ "views",
54
+ "refine"
55
+ ]
56
+ },
57
+ "sourceJobId": {
58
+ "type": [
59
+ "string",
60
+ "null"
61
+ ]
62
+ },
63
+ "sourceInputAssetIds": {
64
+ "type": "array",
65
+ "items": {
66
+ "type": "string"
67
+ }
68
+ },
69
+ "prompt": {
70
+ "type": [
71
+ "string",
72
+ "null"
73
+ ]
74
+ },
75
+ "files": {
76
+ "type": "array",
77
+ "items": {
78
+ "type": "object",
79
+ "properties": {
80
+ "fileId": {
81
+ "type": "string"
82
+ },
83
+ "role": {
84
+ "enum": [
85
+ "source_mesh",
86
+ "rigged_model",
87
+ "preview_image",
88
+ "texture",
89
+ "animation_clip",
90
+ "animated_model"
91
+ ]
92
+ },
93
+ "format": {
94
+ "enum": [
95
+ "glb",
96
+ "fbx",
97
+ "obj",
98
+ "mtl",
99
+ "usdz",
100
+ "stl",
101
+ "png",
102
+ "jpg",
103
+ "mp4"
104
+ ]
105
+ },
106
+ "storageKey": {
107
+ "type": "string"
108
+ },
109
+ "bytes": {
110
+ "type": "integer",
111
+ "minimum": 0
112
+ },
113
+ "sha256": {
114
+ "type": "string"
115
+ },
116
+ "localUrl": {
117
+ "type": [
118
+ "string",
119
+ "null"
120
+ ]
121
+ },
122
+ "hasSkeleton": {
123
+ "type": "boolean"
124
+ },
125
+ "skeletonProfile": {
126
+ "enum": [
127
+ "humanoid",
128
+ "unknown"
129
+ ]
130
+ },
131
+ "animationInputReady": {
132
+ "type": "boolean"
133
+ },
134
+ "motionType": {
135
+ "type": "integer",
136
+ "minimum": 9,
137
+ "maximum": 16,
138
+ "description": "Present only on role=animated_model files: the motion_retarget v1 motion this clip is (9 跨步 / 10 摔倒 / 11 跳跃 / 12 踢腿 / 13 挥击 / 14 步行 / 15 跑步 / 16 跳舞). Structural so multiple motions coexist per asset. Absent for non-animated roles."
139
+ }
140
+ },
141
+ "required": [
142
+ "fileId",
143
+ "role",
144
+ "format",
145
+ "storageKey",
146
+ "bytes",
147
+ "sha256",
148
+ "localUrl",
149
+ "hasSkeleton",
150
+ "skeletonProfile",
151
+ "animationInputReady"
152
+ ],
153
+ "additionalProperties": false
154
+ }
155
+ },
156
+ "readiness": {
157
+ "type": "object",
158
+ "properties": {
159
+ "hasSourceMesh": {
160
+ "type": "boolean"
161
+ },
162
+ "rigged": {
163
+ "type": "boolean"
164
+ },
165
+ "animated": {
166
+ "type": "boolean"
167
+ }
168
+ },
169
+ "required": [
170
+ "hasSourceMesh",
171
+ "rigged",
172
+ "animated"
173
+ ],
174
+ "additionalProperties": false
175
+ },
176
+ "quality": {
177
+ "type": "object",
178
+ "properties": {
179
+ "geometry": {
180
+ "type": [
181
+ "number",
182
+ "null"
183
+ ]
184
+ },
185
+ "topology": {
186
+ "type": [
187
+ "number",
188
+ "null"
189
+ ]
190
+ },
191
+ "texture": {
192
+ "type": [
193
+ "number",
194
+ "null"
195
+ ]
196
+ },
197
+ "pbr": {
198
+ "type": [
199
+ "number",
200
+ "null"
201
+ ]
202
+ },
203
+ "prompt_fidelity": {
204
+ "type": [
205
+ "number",
206
+ "null"
207
+ ]
208
+ },
209
+ "total": {
210
+ "type": [
211
+ "number",
212
+ "null"
213
+ ]
214
+ }
215
+ },
216
+ "required": [
217
+ "geometry",
218
+ "topology",
219
+ "texture",
220
+ "pbr",
221
+ "prompt_fidelity",
222
+ "total"
223
+ ],
224
+ "additionalProperties": false
225
+ },
226
+ "createdAt": {
227
+ "type": "string"
228
+ },
229
+ "updatedAt": {
230
+ "type": "string"
231
+ },
232
+ "meshyTaskRefs": {
233
+ "type": "object",
234
+ "description": "Meshy preview vs result task ids. Manual refine uses previewTaskId; rig uses resultTaskId.",
235
+ "properties": {
236
+ "previewTaskId": {
237
+ "type": [
238
+ "string",
239
+ "null"
240
+ ]
241
+ },
242
+ "resultTaskId": {
243
+ "type": [
244
+ "string",
245
+ "null"
246
+ ]
247
+ }
248
+ },
249
+ "required": [
250
+ "previewTaskId",
251
+ "resultTaskId"
252
+ ],
253
+ "additionalProperties": false
254
+ },
255
+ "visviseRefs": {
256
+ "type": "object",
257
+ "description": "VISVISE COS URLs from generate/rig. Downstream rig/motion must reuse these; do not re-host on ForgeaX COS first.",
258
+ "properties": {
259
+ "meshUrl": {
260
+ "type": [
261
+ "string",
262
+ "null"
263
+ ]
264
+ },
265
+ "rigUrl": {
266
+ "type": [
267
+ "string",
268
+ "null"
269
+ ]
270
+ }
271
+ },
272
+ "required": [
273
+ "meshUrl",
274
+ "rigUrl"
275
+ ],
276
+ "additionalProperties": false
277
+ }
278
+ },
279
+ "required": [
280
+ "manifestVersion",
281
+ "assetId",
282
+ "kind",
283
+ "provider",
284
+ "providerMode",
285
+ "mode",
286
+ "sourceJobId",
287
+ "sourceInputAssetIds",
288
+ "prompt",
289
+ "files",
290
+ "readiness",
291
+ "quality",
292
+ "createdAt",
293
+ "updatedAt"
294
+ ],
295
+ "additionalProperties": false
296
+ }
297
+ },
298
+ "required": [
299
+ "ok",
300
+ "cacheKey",
301
+ "cacheHit",
302
+ "usedMock",
303
+ "manifest"
304
+ ],
305
+ "additionalProperties": false
306
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:upload-image args",
4
+ "type": "object",
5
+ "properties": {
6
+ "base64": {
7
+ "type": "string",
8
+ "minLength": 1,
9
+ "description": "Base64-encoded image bytes (a leading data: URL prefix is tolerated). Decoded image is hard-capped at 8MB. This is a transfer artifact (hosted so URL-fetching providers can reach a local file), not a 3D asset."
10
+ },
11
+ "mimetype": {
12
+ "type": "string",
13
+ "enum": ["image/png", "image/jpeg", "image/jpg", "image/webp", "image/gif"],
14
+ "description": "Image MIME type. Used for the COS object Content-Type and key extension."
15
+ }
16
+ },
17
+ "required": ["base64", "mimetype"],
18
+ "additionalProperties": false
19
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:upload-image returns",
4
+ "type": "object",
5
+ "properties": {
6
+ "ok": { "const": true },
7
+ "url": {
8
+ "type": "string",
9
+ "description": "Time-limited presigned COS URL of the hosted image. Feed into gen3d:image-to-3d / views-to-3d / pose-standardization. Expires after expiresInSec."
10
+ },
11
+ "bytes": { "type": "integer", "minimum": 1 },
12
+ "sha256": { "type": "string" },
13
+ "expiresInSec": {
14
+ "type": "integer",
15
+ "minimum": 1,
16
+ "description": "Seconds until the presigned URL expires (from upload time; default 24h)."
17
+ }
18
+ },
19
+ "required": ["ok", "url", "bytes", "sha256", "expiresInSec"],
20
+ "additionalProperties": false
21
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:upload-video args",
4
+ "type": "object",
5
+ "properties": {
6
+ "mimetype": {
7
+ "type": "string",
8
+ "enum": ["video/mp4", "video/webm"],
9
+ "description": "Video MIME type for the COS PUT. Browser uploads bytes directly; the server never accepts 100MB base64."
10
+ }
11
+ },
12
+ "required": ["mimetype"],
13
+ "additionalProperties": false
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:upload-video returns",
4
+ "type": "object",
5
+ "properties": {
6
+ "ok": { "type": "boolean", "const": true },
7
+ "uploadUrl": { "type": "string", "description": "Presigned PUT URL for the browser." },
8
+ "publicUrl": { "type": "string", "description": "Presigned GET URL to pass as apply-motion.videoUrl after PUT." },
9
+ "expiresInSec": { "type": "integer" },
10
+ "maxBytes": { "type": "integer", "description": "Hard cap (~100MB). Enforce in the browser before PUT." }
11
+ },
12
+ "required": ["ok", "uploadUrl", "publicUrl", "expiresInSec", "maxBytes"],
13
+ "additionalProperties": false
14
+ }
@@ -0,0 +1,58 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "gen3d:views-to-3d args",
4
+ "type": "object",
5
+ "properties": {
6
+ "slug": {
7
+ "type": "string",
8
+ "description": "Active game slug. Assets are stored per game under .forgeax/games/<slug>/assets/3d/. The workbench UI fills this automatically for manual use; an AI/agent caller MUST pass the active game's slug (e.g. 'mini-gta'). Required."
9
+ },
10
+ "assetSlot": {
11
+ "type": "string",
12
+ "enum": ["characters", "meshes"],
13
+ "default": "meshes",
14
+ "description": "3D asset slot (subdir under assets/3d/)."
15
+ },
16
+ "assetName": {
17
+ "type": "string",
18
+ "description": "Desired base file name (without extension). Sanitized + de-duplicated by the store."
19
+ },
20
+ "views": {
21
+ "type": "object",
22
+ "description": "Named view-slot image URLs. front_image_url is required; others optional.",
23
+ "properties": {
24
+ "front_image_url": { "type": "string", "minLength": 1 },
25
+ "back_image_url": { "type": "string" },
26
+ "left_image_url": { "type": "string" },
27
+ "right_image_url": { "type": "string" },
28
+ "top_image_url": { "type": "string" },
29
+ "bottom_image_url": { "type": "string" },
30
+ "front_left_image_url": { "type": "string" },
31
+ "front_right_image_url": { "type": "string" }
32
+ },
33
+ "required": ["front_image_url"],
34
+ "additionalProperties": false
35
+ },
36
+ "provider": {
37
+ "type": "string",
38
+ "enum": ["hunyuan_workflow", "meshy", "rodin", "visvise"],
39
+ "default": "hunyuan_workflow",
40
+ "description": "Generation provider. Defaults to hunyuan_workflow. Rodin views uses rodin-3d image_urls (front first). VISVISE views is rejected with views_not_supported."
41
+ },
42
+ "enablePbr": { "type": "boolean", "default": true },
43
+ "enableFbxUrl": { "type": "boolean", "default": false },
44
+ "targetPolycount": {
45
+ "type": "integer",
46
+ "minimum": 1000,
47
+ "maximum": 300000,
48
+ "default": 30000
49
+ },
50
+ "providerParams": {
51
+ "type": "object",
52
+ "additionalProperties": true,
53
+ "description": "Provider-specific native params (validated server-side against shared/provider-params.ts; unverified/inapplicable fields are dropped). See docs/PROVIDER_PARAMS.md."
54
+ }
55
+ },
56
+ "required": ["slug", "views"],
57
+ "additionalProperties": false
58
+ }