@bitmagic/cli 0.1.71-dev.3 → 0.1.71

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.
@@ -13,9 +13,11 @@ skill's step 1 tells an agent how to copy them into a project's `tools/blender-l
13
13
  |---|---|---|
14
14
  | `find_blender.py` | python3 | prints the Blender executable, or how to install one |
15
15
  | `bmlevel/` | Blender, or python3 for a dry run | the authoring vocabulary (`__init__.py`), the bpy-free maths and JSON writers (`core.py`), the Blender backend (`scene_bpy.py`) and the recording backend (`scene_null.py`) |
16
+ | `bmedit/` | Blender (`colour.py`: python3) | edit GLBs and make props: `load(id)` from `build/inputs/<id>.glb`, `paint` / `recolor` / `replace_colour` by face, `box` / `cylinder` / `cone` / `sphere`, `join`, `turn`, `scatter`, `export(id)` to `build/assets/<id>.glb`; smart props (moving parts the engine animates) with `part()`, `anchor()` and `export(..., smart=)` — the vocabulary the web Creator's `blender` tool runs on the Asset Forger (`game/agent-docs/blender.md`) |
17
+ | `review_asset.py` | Blender | two three-quarter renders per GLB and a contact sheet: the review for props and edited assets |
16
18
  | `example_level.py` | either | a complete hut-and-courtyard level using every helper; the tests' fixture |
17
19
  | `audit.py` | Blender | ray-cast audit of the COLLIDERS: floor continuity, door and route clearance, sealed envelopes, z-fighting candidates |
18
- | `review.py` | Blender | deterministic review renders (overview, every door, every stair, every room) and a contact sheet; `--shot 'FROM -> TO'` aims a frame anywhere, `--only` renders just those, `--lighting game` swaps the review fill for the engine's interior preset and the level's own lamps |
20
+ | `review.py` | Blender | deterministic review renders (overview, every door, every stair, every room) and a contact sheet; `--shot 'FROM -> TO'` aims a frame anywhere, `--only` renders just those, `--lighting game` swaps the review fill for the engine's interior preset and the level's own lamps, `--engine cycles` renders without an OpenGL context |
19
21
  | `sync_world.py` | python3 | carries the doors, spawn and `terrain.shape: 'none'` into `src/work/world.json` |
20
22
  | `tests/` | python3 | `python3 -m unittest discover -s tests` — no Blender needed; `cli`'s `pnpm test` runs it |
21
23
 
@@ -0,0 +1,26 @@
1
+ """bmedit — edit a game's GLBs and make new low-poly props in a short Blender script.
2
+
3
+ from bmedit import load, palette, recolor, cone, box, join, export
4
+ ground = load('ground') # the game's asset, imported
5
+ palette(ground) # its face colours, most used first
6
+ recolor(ground, '#eef3f7', where=lambda p, n, c: n[1] > 0.6) # snow on everything flat
7
+ export('ground', ground) # replaces the asset, same id
8
+
9
+ post = join([box('post', (0.2, 1.2, 0.2), color='#6b4a2f'),
10
+ box('cap', (0.3, 0.1, 0.3), at=(0, 1.2, 0), color='#4a3220')], 'post')
11
+ export('fence-post', post) # a new asset, 1.3 m tall
12
+
13
+ Positions, sizes and normals are in GAME coordinates — metres, Y up, +Z forward, yaw in radians
14
+ about +Y — the same as bmlevel; the Blender axis flip happens inside. Colours are sRGB: '#rrggbb',
15
+ 0-255 or 0-1 triples. Painting is per face (flat low-poly look), stored as the mesh's COLOR_0.
16
+
17
+ `load()` and `export()` are the only file access a script has. The host decides where they point
18
+ (`configure()`): the Asset Forger's job directory, or the GDK project's `build/` folder.
19
+ """
20
+ try: # inside Blender
21
+ import bpy # noqa: F401
22
+ except ImportError: # plain python3: only bmedit.colour is usable (its tests run here)
23
+ __all__: list[str] = []
24
+ else:
25
+ from bmedit.blender import * # noqa: F401,F403
26
+ from bmedit.blender import __all__, configure, exports # noqa: F401
@@ -0,0 +1,652 @@
1
+ """The Blender half of bmedit: every builder, edit and the export. See __init__.py."""
2
+ from __future__ import annotations
3
+
4
+ import math
5
+ import os
6
+ import random
7
+ import re
8
+ from typing import Callable, Iterable, Optional, Sequence, Union
9
+
10
+ import bmesh
11
+ import bpy
12
+ from mathutils import Matrix, Vector
13
+
14
+ from bmedit.colour import Colour, distance, mix, to_hex, to_linear
15
+
16
+ __all__ = [
17
+ 'load', 'box', 'cylinder', 'cone', 'sphere', 'join', 'copy', 'move', 'remove', 'objects',
18
+ 'paint', 'recolor', 'replace_colour', 'palette', 'decimate', 'scatter', 'bounds', 'describe',
19
+ 'height_at', 'turn', 'part', 'anchor', 'export', 'mix',
20
+ ]
21
+
22
+ MAX_EXPORTS = 8
23
+ _ID = re.compile(r'^[a-z0-9][a-z0-9_-]{0,63}$')
24
+ _state: dict = {'inputs': os.path.abspath('build/inputs'), 'out': os.path.abspath('build/assets'), 'exports': []}
25
+
26
+ Objects = Union[bpy.types.Object, Iterable[bpy.types.Object]]
27
+ Vec = Sequence[float]
28
+
29
+
30
+ def configure(inputs_dir: str, out_dir: str) -> None:
31
+ """Where load() reads and export() writes. Called by the host before the script runs."""
32
+ _state['inputs'] = os.path.abspath(inputs_dir)
33
+ _state['out'] = os.path.abspath(out_dir)
34
+ _state['exports'] = []
35
+
36
+
37
+ def exports() -> list[dict]:
38
+ """What the script exported, for the host: [{id, file, targetHeight, triangles}]."""
39
+ return list(_state['exports'])
40
+
41
+
42
+ # ---- coordinates ---------------------------------------------------------------------------
43
+
44
+ def _to_b(p: Vec) -> Vector:
45
+ return Vector((p[0], -p[2], p[1]))
46
+
47
+
48
+ def _to_game(v: Vec) -> tuple[float, float, float]:
49
+ return (v[0], v[2], -v[1])
50
+
51
+
52
+ def _list(objs: Objects) -> list[bpy.types.Object]:
53
+ if isinstance(objs, bpy.types.Object):
54
+ return [objs]
55
+ return [o for o in objs if o.type == 'MESH']
56
+
57
+
58
+ def objects() -> list[bpy.types.Object]:
59
+ """Every mesh object in the scene."""
60
+ return [o for o in bpy.context.scene.objects if o.type == 'MESH']
61
+
62
+
63
+ # ---- load ----------------------------------------------------------------------------------
64
+
65
+ def load(input_id: str) -> list[bpy.types.Object]:
66
+ """Import one of the job's input GLBs (the game asset with that id) and return its meshes.
67
+
68
+ Transforms are applied, so every vertex position is where the game draws it."""
69
+ if not _ID.match(input_id):
70
+ raise ValueError(f'bad input id {input_id!r}')
71
+ path = os.path.join(_state['inputs'], f'{input_id}.glb')
72
+ if not os.path.exists(path):
73
+ have = sorted(f[:-4] for f in os.listdir(_state['inputs'])) if os.path.isdir(_state['inputs']) else []
74
+ raise FileNotFoundError(f'no input {input_id!r}; this job has {have}')
75
+ before = set(bpy.data.objects)
76
+ bpy.ops.import_scene.gltf(filepath=path)
77
+ new = [o for o in bpy.data.objects if o not in before]
78
+ meshes = [o for o in new if o.type == 'MESH']
79
+ for o in new:
80
+ if o.type != 'MESH':
81
+ continue
82
+ # Bake parent + own transform into the mesh, so positions are world positions.
83
+ world = o.matrix_world.copy()
84
+ o.parent = None
85
+ o.data.transform(world)
86
+ o.matrix_world = Matrix.Identity(4)
87
+ for o in new:
88
+ if o.type != 'MESH':
89
+ bpy.data.objects.remove(o, do_unlink=True)
90
+ for o in meshes:
91
+ _face_up(o)
92
+ return meshes
93
+
94
+
95
+ def _face_up(obj: bpy.types.Object) -> None:
96
+ """Flip a mesh whose faces mostly point DOWN. Some generated grounds are wound inside-out and
97
+ drawn double-sided; left as they are, `n[1] > 0.7` would find no flat ground to paint."""
98
+ mesh = obj.data
99
+ total = sum(p.area * p.normal.z for p in mesh.polygons)
100
+ area = sum(p.area for p in mesh.polygons)
101
+ if area > 0 and total / area < -0.3:
102
+ mesh.flip_normals()
103
+ print(f'[bmedit] {obj.name}: faces pointed down; flipped')
104
+
105
+
106
+ # ---- primitives ----------------------------------------------------------------------------
107
+
108
+ def _vertex_material() -> bpy.types.Material:
109
+ mat = bpy.data.materials.get('bmedit_vertex')
110
+ if mat is None:
111
+ mat = bpy.data.materials.new('bmedit_vertex')
112
+ mat.use_nodes = True
113
+ nodes = mat.node_tree.nodes
114
+ bsdf = nodes['Principled BSDF']
115
+ bsdf.inputs['Roughness'].default_value = 1.0
116
+ attr = nodes.new('ShaderNodeVertexColor')
117
+ attr.layer_name = 'Col'
118
+ mat.node_tree.links.new(attr.outputs['Color'], bsdf.inputs['Base Color'])
119
+ return mat
120
+
121
+
122
+ def _finish(name: str, bm: bmesh.types.BMesh, color: Colour, at: Vec, yaw: float) -> bpy.types.Object:
123
+ mesh = bpy.data.meshes.new(name)
124
+ bm.to_mesh(mesh)
125
+ bm.free()
126
+ for poly in mesh.polygons:
127
+ poly.use_smooth = False
128
+ mesh.materials.append(_vertex_material())
129
+ obj = bpy.data.objects.new(name, mesh)
130
+ bpy.context.scene.collection.objects.link(obj)
131
+ _colour_layer(obj)
132
+ _fill(obj, to_linear(color))
133
+ # Straight into the vertices: the object keeps an identity transform, so every position a
134
+ # later call reads (bounds, paint, scatter) is already where the game draws it.
135
+ mesh.transform(Matrix.Translation(_to_b(at)) @ Matrix.Rotation(yaw, 4, 'Z'))
136
+ return obj
137
+
138
+
139
+ def box(name: str, size: Vec, at: Vec = (0, 0, 0), color: Colour = '#999999', yaw: float = 0.0) -> bpy.types.Object:
140
+ """A box `size` = (width x, height y, depth z) whose BOTTOM centre sits at `at`."""
141
+ bm = bmesh.new()
142
+ bmesh.ops.create_cube(bm, size=1.0)
143
+ bmesh.ops.scale(bm, vec=Vector((size[0], size[2], size[1])), verts=bm.verts)
144
+ bmesh.ops.translate(bm, vec=Vector((0, 0, size[1] / 2)), verts=bm.verts)
145
+ return _finish(name, bm, color, at, yaw)
146
+
147
+
148
+ def cylinder(name: str, radius: float, height: float, at: Vec = (0, 0, 0), color: Colour = '#999999',
149
+ segments: int = 8, top_radius: Optional[float] = None, yaw: float = 0.0) -> bpy.types.Object:
150
+ """An upright cylinder (or frustum, with top_radius) standing on `at`."""
151
+ bm = bmesh.new()
152
+ bmesh.ops.create_cone(bm, cap_ends=True, cap_tris=False, segments=max(3, segments),
153
+ radius1=radius, radius2=radius if top_radius is None else top_radius, depth=height)
154
+ bmesh.ops.translate(bm, vec=Vector((0, 0, height / 2)), verts=bm.verts)
155
+ return _finish(name, bm, color, at, yaw)
156
+
157
+
158
+ def cone(name: str, radius: float, height: float, at: Vec = (0, 0, 0), color: Colour = '#999999',
159
+ segments: int = 8, yaw: float = 0.0) -> bpy.types.Object:
160
+ """An upright cone standing on `at` — a pine layer, a roof tip, a spike."""
161
+ return cylinder(name, radius, height, at, color, segments, top_radius=0.0, yaw=yaw)
162
+
163
+
164
+ def sphere(name: str, radius: float, at: Vec = (0, 0, 0), color: Colour = '#999999', detail: int = 1) -> bpy.types.Object:
165
+ """A faceted ball centred on `at` (detail 1 = 80 faces, 2 = 320)."""
166
+ bm = bmesh.new()
167
+ bmesh.ops.create_icosphere(bm, subdivisions=max(1, min(3, detail)), radius=radius)
168
+ return _finish(name, bm, color, at, 0.0)
169
+
170
+
171
+ # ---- object edits --------------------------------------------------------------------------
172
+
173
+ def join(objs: Objects, name: str) -> bpy.types.Object:
174
+ """Merge meshes into one object (one draw call in the game)."""
175
+ items = _list(objs)
176
+ if not items:
177
+ raise ValueError('join() needs at least one mesh')
178
+ for o in items:
179
+ _colour_layer(o)
180
+ with bpy.context.temp_override(active_object=items[0], selected_editable_objects=items, selected_objects=items):
181
+ bpy.ops.object.join()
182
+ items[0].name = name
183
+ items[0].data.name = name
184
+ return items[0]
185
+
186
+
187
+ def copy(obj: bpy.types.Object, at: Optional[Vec] = None, yaw: float = 0.0, scale: float = 1.0,
188
+ name: Optional[str] = None) -> bpy.types.Object:
189
+ """A copy of `obj`, rotated by `yaw` and scaled about its bottom centre, then moved so that
190
+ bottom centre sits at `at` (default: where it was)."""
191
+ dup = obj.copy()
192
+ dup.data = obj.data.copy()
193
+ dup.name = name or f'{obj.name}.copy'
194
+ bpy.context.scene.collection.objects.link(dup)
195
+ move(dup, at=at, yaw=yaw, scale=scale)
196
+ return dup
197
+
198
+
199
+ def move(obj: bpy.types.Object, at: Optional[Vec] = None, yaw: float = 0.0, scale: float = 1.0) -> None:
200
+ """Rotate/scale `obj` about its bottom centre, then put that point at `at` (game coords)."""
201
+ lo, hi = bounds(obj)
202
+ base = Vector(_to_b(((lo[0] + hi[0]) / 2, lo[1], (lo[2] + hi[2]) / 2)))
203
+ target = _to_b(at) if at is not None else base
204
+ m = Matrix.Translation(target) @ Matrix.Rotation(yaw, 4, 'Z') @ Matrix.Scale(scale, 4) @ Matrix.Translation(-base)
205
+ obj.data.transform(m)
206
+
207
+
208
+ def turn(objs: Objects, angle: float, axis: Vec = (0, 1, 0), about: Optional[Vec] = None) -> None:
209
+ """Rotate by `angle` radians about `axis` (game coords, right-handed: about +Z, +Y turns toward
210
+ -X) through the point `about` (default: the objects' box centre). A spoke is a box standing on
211
+ the hub turned about the hub; a leaning leg is turned about its foot."""
212
+ items = _list(objs)
213
+ if about is None:
214
+ lo, hi = bounds(items)
215
+ about = tuple((lo[k] + hi[k]) / 2 for k in range(3))
216
+ pivot = _to_b(about)
217
+ a = _to_b(axis)
218
+ m = Matrix.Translation(pivot) @ Matrix.Rotation(angle, 4, Vector(a).normalized()) @ Matrix.Translation(-pivot)
219
+ for o in items:
220
+ o.data.transform(m)
221
+ for child in o.children:
222
+ child.location = m @ child.location
223
+
224
+
225
+ def remove(objs: Objects) -> None:
226
+ for o in _list(objs):
227
+ bpy.data.objects.remove(o, do_unlink=True)
228
+
229
+
230
+ def decimate(objs: Objects, ratio: float) -> None:
231
+ """Keep about `ratio` (0..1) of each mesh's triangles — cheaper, chunkier."""
232
+ for o in _list(objs):
233
+ mod = o.modifiers.new('decimate', 'DECIMATE')
234
+ mod.ratio = max(0.01, min(1.0, ratio))
235
+ with bpy.context.temp_override(object=o, active_object=o):
236
+ bpy.ops.object.modifier_apply(modifier=mod.name)
237
+
238
+
239
+ # ---- colour --------------------------------------------------------------------------------
240
+
241
+ def _colour_layer(obj: bpy.types.Object):
242
+ """The object's face-corner colour attribute — an imported GLB's own COLOR_0 (byte or float:
243
+ both read and write linear `.color`), else a new one filled from its materials' colours, with
244
+ the materials switched to show it (white base, colour from the attribute)."""
245
+ mesh = obj.data
246
+ attrs = mesh.color_attributes
247
+ layer = attrs.active_color
248
+ if layer is not None and layer.domain == 'CORNER':
249
+ return layer
250
+ old = layer
251
+ new = attrs.new('Col', 'FLOAT_COLOR', 'CORNER')
252
+ base = [_material_colour(m) for m in mesh.materials] or [(0.8, 0.8, 0.8, 1.0)]
253
+ for poly in mesh.polygons:
254
+ for li in poly.loop_indices:
255
+ if old is not None: # a POINT-domain layer: each corner takes its vertex's colour
256
+ new.data[li].color = old.data[mesh.loops[li].vertex_index].color
257
+ else:
258
+ new.data[li].color = base[min(poly.material_index, len(base) - 1)]
259
+ attrs.active_color = new
260
+ # The glTF exporter's 'ACTIVE' mode writes the RENDER colour attribute.
261
+ attrs.default_color_name = new.name
262
+ for mat in mesh.materials:
263
+ _show_vertex_colour(mat, new.name)
264
+ return new
265
+
266
+
267
+ def _material_colour(mat) -> tuple[float, float, float, float]:
268
+ if mat is None:
269
+ return (0.8, 0.8, 0.8, 1.0)
270
+ if mat.use_nodes and 'Principled BSDF' in mat.node_tree.nodes:
271
+ c = mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value
272
+ return (c[0], c[1], c[2], 1.0)
273
+ c = mat.diffuse_color
274
+ return (c[0], c[1], c[2], 1.0)
275
+
276
+
277
+ def _show_vertex_colour(mat, layer_name: str) -> None:
278
+ """Base colour from the attribute, unless an image texture drives it (then the attribute tints)."""
279
+ if mat is None or not mat.use_nodes or 'Principled BSDF' not in mat.node_tree.nodes:
280
+ return
281
+ for node in mat.node_tree.nodes:
282
+ if node.bl_idname == 'ShaderNodeVertexColor':
283
+ node.layer_name = layer_name
284
+ return
285
+ bsdf = mat.node_tree.nodes['Principled BSDF']
286
+ base = bsdf.inputs['Base Color']
287
+ if base.is_linked:
288
+ return
289
+ base.default_value = (1.0, 1.0, 1.0, 1.0)
290
+ attr = mat.node_tree.nodes.new('ShaderNodeVertexColor')
291
+ attr.layer_name = layer_name
292
+ mat.node_tree.links.new(attr.outputs['Color'], base)
293
+
294
+
295
+ def _fill(obj: bpy.types.Object, rgba) -> None:
296
+ layer = _colour_layer(obj)
297
+ for d in layer.data:
298
+ d.color = rgba
299
+
300
+
301
+ def _faces(obj: bpy.types.Object):
302
+ """(polygon, game centre, game normal, current sRGB hex) per face."""
303
+ layer = _colour_layer(obj)
304
+ mesh = obj.data
305
+ # The shading normals (an imported GLB's own NORMAL data), not the winding: generated grounds
306
+ # are often wound the other way and drawn double-sided, so poly.normal can point down.
307
+ corners = mesh.corner_normals
308
+ for poly in mesh.polygons:
309
+ c = layer.data[poly.loop_indices[0]].color
310
+ n = Vector((0.0, 0.0, 0.0))
311
+ for li in poly.loop_indices:
312
+ n += corners[li].vector
313
+ n = n.normalized() if n.length > 1e-9 else poly.normal
314
+ yield poly, _to_game(poly.center), _to_game(n), to_hex(c), layer
315
+
316
+
317
+ def paint(objs: Objects, fn: Callable[[tuple, tuple, str], Optional[Colour]]) -> int:
318
+ """Call fn(position, normal, current_hex) for every face; a colour it returns repaints that
319
+ face, None keeps it. Position and normal are game coords (normal[1] > 0.7: roughly flat
320
+ ground; < 0.3: steep or a wall). Returns the number of faces repainted."""
321
+ changed = 0
322
+ for o in _list(objs):
323
+ for poly, pos, normal, current, layer in _faces(o):
324
+ out = fn(pos, normal, current)
325
+ if out is None:
326
+ continue
327
+ rgba = to_linear(out)
328
+ for li in poly.loop_indices:
329
+ layer.data[li].color = rgba
330
+ changed += 1
331
+ return changed
332
+
333
+
334
+ def recolor(objs: Objects, colour: Colour, where: Optional[Callable[[tuple, tuple, str], bool]] = None) -> int:
335
+ """Paint every face (or those `where(position, normal, current_hex)` accepts) one colour."""
336
+ return paint(objs, lambda p, n, c: colour if where is None or where(p, n, c) else None)
337
+
338
+
339
+ def replace_colour(objs: Objects, mapping: dict, tolerance: float = 0.08) -> int:
340
+ """Swap colours: {'#3f8f3a': '#eef3f7', ...}. A face within `tolerance` of a key takes its
341
+ value — the way to turn 'the green of the leaves' white without touching the bark."""
342
+ keys = list(mapping.items())
343
+
344
+ def swap(_p, _n, current):
345
+ best = min(keys, key=lambda kv: distance(kv[0], current))
346
+ return best[1] if distance(best[0], current) <= tolerance else None
347
+ return paint(objs, swap)
348
+
349
+
350
+ def palette(objs: Objects, top: int = 12) -> list[tuple[str, int]]:
351
+ """The face colours in use, most common first, as [(hex, faces)] — printed too, so the build
352
+ log shows what an edit has to work with. Near-identical colours are merged."""
353
+ counts: dict[str, int] = {}
354
+ for o in _list(objs):
355
+ for _poly, _p, _n, current, _l in _faces(o):
356
+ for known in counts:
357
+ if distance(known, current) < 0.03:
358
+ counts[known] += 1
359
+ break
360
+ else:
361
+ counts[current] = 1
362
+ ranked = sorted(counts.items(), key=lambda kv: -kv[1])[:top]
363
+ print('[bmedit] palette: ' + ', '.join(f'{h} x{n}' for h, n in ranked))
364
+ return ranked
365
+
366
+
367
+ # ---- placement -----------------------------------------------------------------------------
368
+
369
+ def bounds(objs: Objects) -> tuple[tuple[float, float, float], tuple[float, float, float]]:
370
+ """(min, max) corners in game coords over every vertex."""
371
+ lo = [math.inf] * 3
372
+ hi = [-math.inf] * 3
373
+ for o in _list(objs):
374
+ for v in o.data.vertices:
375
+ g = _to_game(o.matrix_world @ v.co)
376
+ for i in range(3):
377
+ lo[i] = min(lo[i], g[i])
378
+ hi[i] = max(hi[i], g[i])
379
+ if lo[0] == math.inf:
380
+ return (0.0, 0.0, 0.0), (0.0, 0.0, 0.0)
381
+ return (lo[0], lo[1], lo[2]), (hi[0], hi[1], hi[2])
382
+
383
+
384
+ def height_at(objs: Objects, x: float, z: float) -> Optional[float]:
385
+ """The top surface's height at game (x, z), or None off the mesh."""
386
+ best = None
387
+ for o in _list(objs):
388
+ origin = _to_b((x, 1e4, z))
389
+ hit, loc, _n, _i = o.ray_cast(o.matrix_world.inverted() @ origin, Vector((0, 0, -1)))
390
+ if hit:
391
+ y = _to_game(o.matrix_world @ loc)[1]
392
+ best = y if best is None else max(best, y)
393
+ return best
394
+
395
+
396
+ def scatter(proto: bpy.types.Object, count: int, on: Optional[Objects] = None,
397
+ area: Sequence[float] = (0.0, 0.0, 20.0), seed: int = 1, min_spacing: float = 2.0,
398
+ scale: Sequence[float] = (0.8, 1.2), avoid: Sequence[Sequence[float]] = (),
399
+ max_slope: float = 0.5) -> list[bpy.types.Object]:
400
+ """Place up to `count` copies of `proto` at random inside the circle `area` = (x, z, radius),
401
+ random yaw and scale, standing on `on`'s surface (flat enough: normal-y >= 1 - max_slope).
402
+ `avoid` = [(x, z, radius), ...] keeps spots clear (the spawn, a path). Returns the copies."""
403
+ rng = random.Random(seed)
404
+ placed: list[tuple[float, float]] = []
405
+ out = []
406
+ ground = _list(on) if on is not None else []
407
+ for _ in range(count * 30):
408
+ if len(out) >= count:
409
+ break
410
+ a = rng.uniform(0, math.tau)
411
+ r = area[2] * math.sqrt(rng.random())
412
+ x, z = area[0] + r * math.cos(a), area[1] + r * math.sin(a)
413
+ if any((x - px) ** 2 + (z - pz) ** 2 < min_spacing ** 2 for px, pz in placed):
414
+ continue
415
+ if any((x - ax) ** 2 + (z - az) ** 2 < ar ** 2 for ax, az, ar in avoid):
416
+ continue
417
+ y = 0.0
418
+ if ground:
419
+ hit = _surface(ground, x, z)
420
+ if hit is None or hit[1] < 1.0 - max_slope:
421
+ continue
422
+ y = hit[0]
423
+ out.append(copy(proto, at=(x, y, z), yaw=rng.uniform(0, math.tau), scale=rng.uniform(*scale),
424
+ name=f'{proto.name}.{len(out)}'))
425
+ placed.append((x, z))
426
+ return out
427
+
428
+
429
+ def _surface(objs: list, x: float, z: float) -> Optional[tuple[float, float]]:
430
+ best = None
431
+ for o in objs:
432
+ origin = o.matrix_world.inverted() @ _to_b((x, 1e4, z))
433
+ hit, loc, normal, _i = o.ray_cast(origin, Vector((0, 0, -1)))
434
+ if hit:
435
+ y = _to_game(o.matrix_world @ loc)[1]
436
+ if best is None or y > best[0]:
437
+ best = (y, _to_game(normal)[1])
438
+ return best
439
+
440
+
441
+ def describe(objs: Objects) -> None:
442
+ """Print name, triangle count and size of each mesh — cheap orientation for an edit."""
443
+ for o in _list(objs):
444
+ lo, hi = bounds(o)
445
+ tris = sum(len(p.vertices) - 2 for p in o.data.polygons)
446
+ size = tuple(round(hi[i] - lo[i], 2) for i in range(3))
447
+ print(f'[bmedit] {o.name}: {tris} tris, size {size}, min {tuple(round(v, 2) for v in lo)}')
448
+
449
+
450
+ # ---- export --------------------------------------------------------------------------------
451
+
452
+ def _coplanar_overlaps(items: list, limit: int = 5) -> tuple[int, list[str]]:
453
+ """Faces that lie in the same plane, facing the same way, and overlap: they z-fight (flicker
454
+ between their colours) in the game. Typical cause: trim laid flush on a surface — a rim whose
455
+ top cap sits at the platform's height, a stripe on a wall. Returns (count, examples)."""
456
+ faces = []
457
+ for o in items:
458
+ layer = o.data.color_attributes.active_color
459
+ for poly in o.data.polygons:
460
+ n = poly.normal
461
+ if n.length < 1e-6:
462
+ continue
463
+ pts = [o.data.vertices[v].co.copy() for v in poly.vertices]
464
+ colour = to_hex(layer.data[poly.loop_indices[0]].color) if layer and layer.domain == 'CORNER' else '?'
465
+ faces.append((n.normalized(), n.normalized().dot(pts[0]), pts, poly.center.copy(), poly.area, colour))
466
+ buckets: dict = {}
467
+ for i, (n, d, _p, _c, _a, _col) in enumerate(faces):
468
+ key = (round(n.x, 2), round(n.y, 2), round(n.z, 2), round(d * 200)) # same direction, within ~5 mm
469
+ buckets.setdefault(key, []).append(i)
470
+
471
+ def inside(point, pts, n) -> bool:
472
+ # Convex polygon test in its own plane: the point is on the inner side of every edge.
473
+ sign = 0
474
+ for k in range(len(pts)):
475
+ edge = pts[(k + 1) % len(pts)] - pts[k]
476
+ side = n.dot(edge.cross(point - pts[k]))
477
+ if abs(side) < 1e-7:
478
+ continue
479
+ if sign == 0:
480
+ sign = 1 if side > 0 else -1
481
+ elif (side > 0) != (sign > 0):
482
+ return False
483
+ return True
484
+
485
+ count, examples = 0, []
486
+ for group in buckets.values():
487
+ if len(group) < 2:
488
+ continue
489
+ for x in range(len(group)):
490
+ for y in range(x + 1, len(group)):
491
+ fa, fb = faces[group[x]], faces[group[y]]
492
+ small, big = (fa, fb) if fa[4] <= fb[4] else (fb, fa)
493
+ # Two faces of one colour flicker between identical pixels: invisible, not reported.
494
+ if small[5] == big[5] or not inside(small[3], big[2], big[0]):
495
+ continue
496
+ count += 1
497
+ if len(examples) < limit:
498
+ g = _to_game(small[3])
499
+ examples.append(f'({g[0]:.2f}, {g[1]:.2f}, {g[2]:.2f}) {small[5]} vs {big[5]}')
500
+ return count, examples
501
+
502
+
503
+ PART_PREFIX = 'BM_part_'
504
+ _PART_NAME = re.compile(r'^[A-Za-z][A-Za-z0-9_]*$')
505
+ MOTIONS = ('spin', 'upright', 'pendulum', 'none')
506
+
507
+
508
+ def part(obj: bpy.types.Object, name: str) -> bpy.types.Object:
509
+ """Mark `obj` as the moving part `name` of a smart prop (export it with `smart=`). A part
510
+ is one object: join its pieces first. Names: letters, digits and _, starting with a letter."""
511
+ if not _PART_NAME.match(name):
512
+ raise ValueError(f'part name {name!r}: letters, digits and _, starting with a letter')
513
+ obj.name = f'{PART_PREFIX}{name}'
514
+ obj.data.name = obj.name
515
+ return obj
516
+
517
+
518
+ ANCHOR_PREFIX = 'BM_anchor_'
519
+
520
+
521
+ def anchor(obj: bpy.types.Object, name: str, at: Vec) -> bpy.types.Object:
522
+ """A named point game code will want: a door, an entrance, a seat, a cabin floor. `at` is in
523
+ game coordinates at rest. On a part (after part()) it rides with the part and code finds it as
524
+ `smart.pivotOf(id, 'cabin_3').getObjectByName('BM_anchor_floor')` — every part may reuse the
525
+ same names. On any other exported object it stays put, found on the placed object:
526
+ `getObjectIdService().getObjectById(id).getObjectByName('BM_anchor_door')` — so those names
527
+ must be unique within the prop."""
528
+ if not _PART_NAME.match(name):
529
+ raise ValueError(f'anchor name {name!r}: letters, digits and _, starting with a letter')
530
+ owner = obj.name[len(PART_PREFIX):] if obj.name.startswith(PART_PREFIX) else re.sub(r'[^A-Za-z0-9_]', '_', obj.name)
531
+ empty = bpy.data.objects.new(f'{ANCHOR_PREFIX}{owner}__{name}', None)
532
+ bpy.context.scene.collection.objects.link(empty)
533
+ empty.parent = obj # the part keeps an identity transform, so `at` is also its local position
534
+ empty.location = _to_b(at)
535
+ return empty
536
+
537
+
538
+ def _vec(value, what: str) -> dict:
539
+ if not (isinstance(value, (list, tuple)) and len(value) == 3):
540
+ raise ValueError(f'{what} must be (x, y, z)')
541
+ return {'x': float(value[0]), 'y': float(value[1]), 'z': float(value[2])}
542
+
543
+
544
+ def _smart_declaration(smart: dict, items: list, lo, hi) -> tuple[dict, list[dict]]:
545
+ """Validate `smart` against the exported objects; return the GLB's bmSmartObject extras and
546
+ the asset-record light emitters (offsets in the asset frame: bottom-centre origin)."""
547
+ names = {o.name[len(PART_PREFIX):]: o for o in items if o.name.startswith(PART_PREFIX)}
548
+ parts = []
549
+ for p in smart.get('parts', []):
550
+ name = p.get('name')
551
+ if name not in names:
552
+ raise ValueError(f'smart part {name!r} has no object: call part(obj, {name!r}) on one of the exported objects')
553
+ motion = dict(p.get('motion') or {})
554
+ if motion.get('kind') not in MOTIONS:
555
+ raise ValueError(f'smart part {name!r}: motion kind must be one of {MOTIONS}')
556
+ if 'axis' in motion:
557
+ motion['axis'] = [float(v) for v in motion['axis']]
558
+ entry = {'name': name, 'motion': motion}
559
+ if p.get('parent'):
560
+ if p['parent'] not in names:
561
+ raise ValueError(f'smart part {name!r}: parent {p["parent"]!r} is not a part')
562
+ entry['parent'] = p['parent']
563
+ if p.get('pivot') is not None:
564
+ entry['pivot'] = _vec(p['pivot'], f'smart part {name!r} pivot')
565
+ parts.append(entry)
566
+ origin = ((lo[0] + hi[0]) / 2, lo[1], (lo[2] + hi[2]) / 2)
567
+ lights = []
568
+ for i, l in enumerate(smart.get('lights', [])):
569
+ if 'color' not in l:
570
+ raise ValueError('a smart light needs a color')
571
+ where = l.get('position')
572
+ if where is None:
573
+ if l.get('part') not in names:
574
+ raise ValueError('a smart light needs a position, or a part to sit at the centre of')
575
+ plo, phi = bounds(names[l['part']])
576
+ where = tuple((plo[k] + phi[k]) / 2 for k in range(3))
577
+ offset = {'x': where[0] - origin[0], 'y': where[1] - origin[1], 'z': where[2] - origin[2]}
578
+ emitter = {'color': to_hex(to_linear(l['color'])), 'offset': offset}
579
+ for key in ('intensity', 'distance'):
580
+ if key in l:
581
+ emitter[key] = float(l[key])
582
+ if l.get('part'):
583
+ if l['part'] not in names:
584
+ raise ValueError(f'smart light: part {l["part"]!r} is not a part')
585
+ emitter['part'] = l['part']
586
+ lights.append(emitter)
587
+ return {'parts': parts}, lights
588
+
589
+
590
+ def export(asset_id: str, objs: Optional[Objects] = None, smart: Optional[dict] = None) -> dict:
591
+ """Write `objs` (default: every mesh in the scene) as the game asset `asset_id`. An id the game
592
+ already has REPLACES that asset everywhere it is placed; a new id adds one, sized to the
593
+ meshes' real height. Returns {id, targetHeight, triangles}.
594
+
595
+ `smart` makes it a SMART OBJECT the engine animates with no game code:
596
+ {'parts': [{'name': 'wheel', 'motion': {'kind': 'spin', 'axis': (0, 0, 1), 'rpm': 3}},
597
+ {'name': 'cabin_1', 'parent': 'wheel', 'motion': {'kind': 'upright'}}],
598
+ 'lights': [{'color': '#ffd27a', 'part': 'cabin_1', 'intensity': 4}]}
599
+ Every part is an exported object marked with part(obj, name). Pivots default to the part's
600
+ box centre (the top centre for upright / pendulum); give 'pivot': (x, y, z) to override."""
601
+ if not _ID.match(asset_id):
602
+ raise ValueError(f'asset id {asset_id!r}: use lowercase letters, digits, - and _')
603
+ if any(e['id'] == asset_id for e in _state['exports']):
604
+ raise ValueError(f'{asset_id!r} was already exported in this script')
605
+ if len(_state['exports']) >= MAX_EXPORTS:
606
+ raise ValueError(f'at most {MAX_EXPORTS} exports per script')
607
+ items = _list(objs) if objs is not None else objects()
608
+ if not items:
609
+ raise ValueError('nothing to export')
610
+ for o in items:
611
+ _colour_layer(o)
612
+ lo, hi = bounds(items)
613
+ overlaps, where = _coplanar_overlaps(items)
614
+ if overlaps:
615
+ print(f'[bmedit] WARNING {asset_id}: {overlaps} overlapping coplanar face pair(s) will FLICKER in the game '
616
+ f'(z-fighting), e.g. at {"; ".join(where)}. Lift the upper surface by at least 1 cm, or make '
617
+ f'the trim not cover the surface under it.')
618
+ extras, lights = _smart_declaration(smart, items, lo, hi) if smart else (None, [])
619
+ scene = bpy.context.scene
620
+ if extras is not None:
621
+ scene['bmSmartObject'] = extras # scene custom properties are the GLB's scene extras
622
+ os.makedirs(_state['out'], exist_ok=True)
623
+ path = os.path.join(_state['out'], f'{asset_id}.glb')
624
+ try:
625
+ anchors = [c for o in items for c in o.children if c.name.startswith(ANCHOR_PREFIX)]
626
+ chosen = items + anchors
627
+ with bpy.context.temp_override(selected_objects=chosen, selected_editable_objects=chosen):
628
+ bpy.ops.object.select_all(action='DESELECT')
629
+ for o in chosen:
630
+ o.select_set(True)
631
+ bpy.ops.export_scene.gltf(
632
+ filepath=path, export_format='GLB', use_selection=True, export_apply=True, export_yup=True,
633
+ export_normals=True, export_vertex_color='ACTIVE', export_lights=False, export_cameras=False,
634
+ export_extras=extras is not None,
635
+ )
636
+ finally:
637
+ if 'bmSmartObject' in scene:
638
+ del scene['bmSmartObject']
639
+ record = {
640
+ 'id': asset_id,
641
+ 'file': f'{asset_id}.glb',
642
+ 'targetHeight': round(max(0.01, hi[1] - lo[1]), 3),
643
+ 'triangles': sum(sum(len(p.vertices) - 2 for p in o.data.polygons) for o in items),
644
+ }
645
+ if extras is not None:
646
+ record['smartParts'] = [p['name'] for p in extras['parts']]
647
+ if lights:
648
+ record['lights'] = lights
649
+ _state['exports'].append(record)
650
+ moving = f', smart: {", ".join(record["smartParts"])}' if extras else ''
651
+ print(f'[bmedit] exported {asset_id}: {record["triangles"]} tris, {record["targetHeight"]} m tall{moving}')
652
+ return record
@@ -0,0 +1,61 @@
1
+ """Colour maths for bmedit, free of bpy so plain python3 tests cover it.
2
+
3
+ Scripts speak sRGB — the numbers a colour picker shows, as `'#d8e4ea'`, `(216, 228, 234)` or
4
+ `(0.85, 0.89, 0.92)`. Blender's float colour attributes and glTF's COLOR_0 are LINEAR, so every
5
+ value is converted once on the way in and back on the way out. Storing sRGB numbers as linear is
6
+ what turned early forged levels pastel.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from typing import Sequence, Union
11
+
12
+ Colour = Union[str, Sequence[float]]
13
+
14
+
15
+ def srgb_to_linear(c: float) -> float:
16
+ return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4
17
+
18
+
19
+ def linear_to_srgb(c: float) -> float:
20
+ c = max(0.0, min(1.0, c))
21
+ return c * 12.92 if c <= 0.0031308 else 1.055 * c ** (1 / 2.4) - 0.055
22
+
23
+
24
+ def parse_srgb(colour: Colour) -> tuple[float, float, float]:
25
+ """'#rrggbb', 0-255 ints or 0-1 floats → sRGB floats in 0..1."""
26
+ if isinstance(colour, str):
27
+ h = colour.lstrip('#')
28
+ if len(h) == 3:
29
+ h = ''.join(ch * 2 for ch in h)
30
+ if len(h) != 6:
31
+ raise ValueError(f'colour {colour!r} is not #rgb or #rrggbb')
32
+ return (int(h[0:2], 16) / 255, int(h[2:4], 16) / 255, int(h[4:6], 16) / 255)
33
+ values = [float(v) for v in colour][:3]
34
+ if len(values) != 3:
35
+ raise ValueError(f'colour {colour!r} needs three channels')
36
+ if any(v > 1.0 for v in values):
37
+ values = [v / 255 for v in values]
38
+ return (values[0], values[1], values[2])
39
+
40
+
41
+ def to_linear(colour: Colour) -> tuple[float, float, float, float]:
42
+ r, g, b = parse_srgb(colour)
43
+ return (srgb_to_linear(r), srgb_to_linear(g), srgb_to_linear(b), 1.0)
44
+
45
+
46
+ def to_hex(linear: Sequence[float]) -> str:
47
+ """A stored linear colour as the sRGB hex a script would write."""
48
+ return '#' + ''.join(f'{round(linear_to_srgb(c) * 255):02x}' for c in linear[:3])
49
+
50
+
51
+ def distance(a: Colour, b: Colour) -> float:
52
+ """Distance between two sRGB colours, 0..~1.7; under 0.1 reads as 'the same colour'."""
53
+ pa, pb = parse_srgb(a), parse_srgb(b)
54
+ return sum((x - y) ** 2 for x, y in zip(pa, pb)) ** 0.5
55
+
56
+
57
+ def mix(a: Colour, b: Colour, t: float) -> tuple[float, float, float]:
58
+ """sRGB blend of two colours; t=0 is a, t=1 is b."""
59
+ pa, pb = parse_srgb(a), parse_srgb(b)
60
+ t = max(0.0, min(1.0, t))
61
+ return (pa[0] + (pb[0] - pa[0]) * t, pa[1] + (pb[1] - pa[1]) * t, pa[2] + (pb[2] - pa[2]) * t)
@@ -1,7 +1,7 @@
1
1
  """Headless review renders of a built level, run inside Blender:
2
2
 
3
3
  "$BLENDER" -b --python tools/blender-level/review.py -- build/level/hut.blend build/level/hut.mesh-level.json build/level/review/
4
- [--lighting review|game] [--shot 'FROM -> TO']... [--only] [--fov <degrees>]
4
+ [--lighting review|game] [--shot 'FROM -> TO']... [--only] [--fov <degrees>] [--engine eevee|cycles]
5
5
 
6
6
  Opens the .blend (named parts intact) and renders a deterministic set of shots from the level
7
7
  JSON — `overview` (top-down), `door-<id>-a/b` (both approaches of every door), `stairs-<name>`
@@ -18,6 +18,10 @@ is a look at the GEOMETRY. `--lighting game` instead runs the engine's `interior
18
18
  `lamp()`s and `spot()`s the level JSON declares, so the lighting pass can be judged here rather
19
19
  than through a `bitmagic verify`. EEVEE is not three.js — trust "too dark" and "too bright", not
20
20
  an exact colour.
21
+
22
+ `--engine cycles` renders with Cycles instead of EEVEE, on the GPU through OptiX or CUDA when
23
+ there is one, else on the CPU. EEVEE needs an OpenGL context, which a headless Linux server with
24
+ only the CUDA driver (no EGL) cannot give it; Cycles in background mode needs none.
21
25
  """
22
26
  import json
23
27
  import math
@@ -44,7 +48,7 @@ def flag_values(name: str) -> list[str]:
44
48
 
45
49
  # `--shot`, `--lighting` and `--fov` each consume the token after them, which would otherwise read
46
50
  # as a positional path.
47
- consumed = {argv[i + 1] for i, a in enumerate(argv) if a in ('--shot', '--lighting', '--fov') and i + 1 < len(argv)}
51
+ consumed = {argv[i + 1] for i, a in enumerate(argv) if a in ('--shot', '--lighting', '--fov', '--engine') and i + 1 < len(argv)}
48
52
  positional = [a for a in positional if a not in consumed]
49
53
  if len(positional) < 3:
50
54
  print(__doc__)
@@ -57,6 +61,10 @@ if LIGHTING not in ('review', 'game'):
57
61
  SHOT_SPECS = flag_values('--shot')
58
62
  ONLY = '--only' in argv
59
63
  FOV = float(flag_value('--fov')) if flag_value('--fov') else None
64
+ ENGINE = (flag_value('--engine', 'eevee') or 'eevee').lower()
65
+ if ENGINE not in ('eevee', 'cycles'):
66
+ print(f"--engine takes 'eevee' or 'cycles', not {ENGINE!r}")
67
+ sys.exit(2)
60
68
  if ONLY and not SHOT_SPECS:
61
69
  print('--only needs at least one --shot')
62
70
  sys.exit(2)
@@ -70,10 +78,38 @@ os.makedirs(OUT, exist_ok=True)
70
78
 
71
79
  bpy.ops.wm.open_mainfile(filepath=os.path.abspath(BLEND))
72
80
  scene = bpy.context.scene
73
- engines = [e.identifier for e in bpy.types.RenderSettings.bl_rna.properties['engine'].enum_items]
74
- scene.render.engine = 'BLENDER_EEVEE_NEXT' if 'BLENDER_EEVEE_NEXT' in engines else 'BLENDER_EEVEE'
75
- if hasattr(scene, 'eevee'):
76
- scene.eevee.taa_render_samples = 16
81
+
82
+
83
+ def use_cycles() -> str:
84
+ """Cycles on the first GPU backend that has a device (OptiX, then CUDA), else the CPU. Low
85
+ samples plus the denoiser: this is a look at geometry, not a beauty render."""
86
+ scene.render.engine = 'CYCLES'
87
+ prefs = bpy.context.preferences.addons['cycles'].preferences
88
+ backend = 'CPU'
89
+ for kind in ('OPTIX', 'CUDA'):
90
+ try:
91
+ prefs.compute_device_type = kind
92
+ except TypeError: # this Blender build lacks the backend
93
+ continue
94
+ prefs.get_devices()
95
+ if any(d.type == kind for d in prefs.devices):
96
+ for d in prefs.devices:
97
+ d.use = d.type == kind
98
+ backend = kind
99
+ break
100
+ scene.cycles.device = 'CPU' if backend == 'CPU' else 'GPU'
101
+ scene.cycles.samples = 16
102
+ scene.cycles.use_denoising = True
103
+ return backend
104
+
105
+
106
+ if ENGINE == 'cycles':
107
+ print(f'ENGINE cycles on {use_cycles()}', flush=True)
108
+ else:
109
+ engines = [e.identifier for e in bpy.types.RenderSettings.bl_rna.properties['engine'].enum_items]
110
+ scene.render.engine = 'BLENDER_EEVEE_NEXT' if 'BLENDER_EEVEE_NEXT' in engines else 'BLENDER_EEVEE'
111
+ if hasattr(scene, 'eevee'):
112
+ scene.eevee.taa_render_samples = 16
77
113
  scene.render.resolution_x, scene.render.resolution_y = WIDTH, HEIGHT
78
114
  scene.render.resolution_percentage = 100
79
115
  scene.render.image_settings.file_format = 'PNG'
@@ -0,0 +1,138 @@
1
+ """Headless review renders of GLB assets (bmedit exports), run inside Blender:
2
+
3
+ "$BLENDER" -b --python tools/blender-level/review_asset.py -- <out dir> <a.glb> [<b.glb> ...] [--engine eevee|cycles]
4
+
5
+ Renders each asset alone from two three-quarter angles — front-left and back-right, from above,
6
+ framed to its size — into the output directory, plus `contact-sheet.png` with all of them (two
7
+ columns per asset, in the order given; at most four assets). It is a look at shape and colour:
8
+ a flat sky light and a sun, vertex colours as authored. Blender is not three.js — trust "wrong
9
+ colour family", "too dark", "floating", not an exact shade.
10
+ """
11
+ import math
12
+ import os
13
+ import sys
14
+
15
+ import bpy
16
+ from mathutils import Vector
17
+
18
+ argv = sys.argv[sys.argv.index('--') + 1:] if '--' in sys.argv else sys.argv[1:]
19
+ ENGINE = argv[argv.index('--engine') + 1].lower() if '--engine' in argv and argv.index('--engine') + 1 < len(argv) else 'eevee'
20
+ positional = [a for a in argv if not a.startswith('--') and a != ENGINE]
21
+ if len(positional) < 2 or ENGINE not in ('eevee', 'cycles'):
22
+ print(__doc__)
23
+ sys.exit(2)
24
+ OUT, GLBS = positional[0], positional[1:5]
25
+ WIDTH, HEIGHT = 640, 480
26
+ os.makedirs(OUT, exist_ok=True)
27
+
28
+ bpy.ops.wm.read_factory_settings(use_empty=True)
29
+ scene = bpy.context.scene
30
+
31
+
32
+ def use_cycles() -> str:
33
+ """Cycles on the first GPU backend that has a device (OptiX, then CUDA), else the CPU."""
34
+ scene.render.engine = 'CYCLES'
35
+ prefs = bpy.context.preferences.addons['cycles'].preferences
36
+ backend = 'CPU'
37
+ for kind in ('OPTIX', 'CUDA'):
38
+ try:
39
+ prefs.compute_device_type = kind
40
+ except TypeError:
41
+ continue
42
+ prefs.get_devices()
43
+ if any(d.type == kind for d in prefs.devices):
44
+ for d in prefs.devices:
45
+ d.use = d.type == kind
46
+ backend = kind
47
+ break
48
+ scene.cycles.device = 'CPU' if backend == 'CPU' else 'GPU'
49
+ scene.cycles.samples = 16
50
+ scene.cycles.use_denoising = True
51
+ return backend
52
+
53
+
54
+ if ENGINE == 'cycles':
55
+ print(f'ENGINE cycles on {use_cycles()}', flush=True)
56
+ else:
57
+ engines = [e.identifier for e in bpy.types.RenderSettings.bl_rna.properties['engine'].enum_items]
58
+ scene.render.engine = 'BLENDER_EEVEE_NEXT' if 'BLENDER_EEVEE_NEXT' in engines else 'BLENDER_EEVEE'
59
+ if hasattr(scene, 'eevee'):
60
+ scene.eevee.taa_render_samples = 16
61
+ scene.render.resolution_x, scene.render.resolution_y = WIDTH, HEIGHT
62
+ scene.render.resolution_percentage = 100
63
+ scene.render.image_settings.file_format = 'PNG'
64
+ scene.world = bpy.data.worlds.new('review')
65
+ scene.world.use_nodes = True
66
+ bg = scene.world.node_tree.nodes['Background']
67
+ bg.inputs[0].default_value = (0.45, 0.55, 0.7, 1)
68
+ bg.inputs[1].default_value = 0.7
69
+
70
+ cam_data = bpy.data.cameras.new('review')
71
+ cam_data.lens = 35
72
+ cam = bpy.data.objects.new('review', cam_data)
73
+ scene.collection.objects.link(cam)
74
+ scene.camera = cam
75
+ sun_data = bpy.data.lights.new('review-sun', 'SUN')
76
+ sun_data.energy = 3.0
77
+ sun = bpy.data.objects.new('review-sun', sun_data)
78
+ scene.collection.objects.link(sun)
79
+ sun.rotation_euler = (math.radians(45), math.radians(10), math.radians(35))
80
+
81
+
82
+ def load(path: str) -> list:
83
+ before = set(bpy.data.objects)
84
+ bpy.ops.import_scene.gltf(filepath=path)
85
+ return [o for o in bpy.data.objects if o not in before]
86
+
87
+
88
+ def frame(objs: list) -> tuple[Vector, float]:
89
+ pts = [o.matrix_world @ Vector(c) for o in objs if o.type == 'MESH' for c in o.bound_box]
90
+ lo = Vector((min(p.x for p in pts), min(p.y for p in pts), min(p.z for p in pts)))
91
+ hi = Vector((max(p.x for p in pts), max(p.y for p in pts), max(p.z for p in pts)))
92
+ return (lo + hi) / 2, max((hi - lo).length / 2, 0.1)
93
+
94
+
95
+ paths: list[str] = []
96
+ names: list[str] = []
97
+ for glb in GLBS:
98
+ stem = os.path.splitext(os.path.basename(glb))[0]
99
+ objs = load(glb)
100
+ centre, radius = frame(objs)
101
+ distance = radius / math.tan(math.radians(20)) * 1.1
102
+ # Blender is Z up; the game's +Z forward is Blender's -Y, so "front" looks from -Y.
103
+ for label, yaw in (('front', math.radians(-35)), ('back', math.radians(145))):
104
+ direction = Vector((math.sin(yaw), -math.cos(yaw), 0.55)).normalized()
105
+ cam.location = centre + direction * distance
106
+ cam.rotation_euler = (centre - cam.location).to_track_quat('-Z', 'Y').to_euler()
107
+ cam_data.clip_end = distance * 4
108
+ path = os.path.join(OUT, f'{stem}-{label}.png')
109
+ scene.render.filepath = path
110
+ bpy.ops.render.render(write_still=True)
111
+ paths.append(path)
112
+ names.append(f'{stem}-{label}')
113
+ for o in objs:
114
+ bpy.data.objects.remove(o, do_unlink=True)
115
+
116
+ import numpy as np # Blender bundles numpy # noqa: E402
117
+
118
+ cols = 2
119
+ thumb_w, thumb_h = WIDTH // 2, HEIGHT // 2
120
+ rows = math.ceil(len(paths) / cols)
121
+ sheet = np.zeros((rows * thumb_h, cols * thumb_w, 4), dtype=np.float32)
122
+ sheet[..., 3] = 1
123
+ for i, p in enumerate(paths):
124
+ img = bpy.data.images.load(p)
125
+ px = np.array(img.pixels[:], dtype=np.float32).reshape(img.size[1], img.size[0], 4)
126
+ small = px[::2, ::2][:thumb_h, :thumb_w]
127
+ r, c = divmod(i, cols)
128
+ y0 = (rows - 1 - r) * thumb_h # Blender image rows run bottom-up
129
+ sheet[y0:y0 + small.shape[0], c * thumb_w:c * thumb_w + small.shape[1]] = small
130
+ bpy.data.images.remove(img)
131
+ out_img = bpy.data.images.new('contact', cols * thumb_w, rows * thumb_h, alpha=True)
132
+ out_img.pixels = sheet.ravel().tolist()
133
+ sheet_path = os.path.join(OUT, 'contact-sheet.png')
134
+ out_img.filepath_raw = sheet_path
135
+ out_img.file_format = 'PNG'
136
+ out_img.save()
137
+ order = ', '.join(f'{i + 1}:{n}' for i, n in enumerate(names))
138
+ print(f'CONTACT_SHEET {sheet_path} ({cols} per row, left to right, top to bottom: {order})')
@@ -0,0 +1,36 @@
1
+ """Blender-free checks of bmedit's colour maths: `python3 -m unittest discover -s tools/blender-level/tests`."""
2
+ import os
3
+ import sys
4
+ import unittest
5
+
6
+ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
7
+ from bmedit.colour import distance, mix, parse_srgb, to_hex, to_linear # noqa: E402
8
+
9
+
10
+ class ColourTest(unittest.TestCase):
11
+ def test_parses_every_spelling_of_a_colour(self):
12
+ self.assertEqual(parse_srgb('#ff8000'), (1.0, 128 / 255, 0.0))
13
+ self.assertEqual(parse_srgb('f80'), (1.0, 136 / 255, 0.0))
14
+ self.assertEqual(parse_srgb((255, 128, 0)), (1.0, 128 / 255, 0.0))
15
+ self.assertEqual(parse_srgb((1.0, 0.5, 0.0)), (1.0, 0.5, 0.0))
16
+ with self.assertRaises(ValueError):
17
+ parse_srgb('#12')
18
+
19
+ def test_stores_linear_and_reads_back_the_same_hex(self):
20
+ # sRGB mid-grey is ~0.214 linear: the stored value must NOT be the picker's 0.5.
21
+ r, g, b, a = to_linear('#808080')
22
+ self.assertAlmostEqual(r, 0.2158, places=3)
23
+ self.assertEqual(a, 1.0)
24
+ for hex_colour in ('#eef3f7', '#3c7524', '#000000', '#ffffff'):
25
+ self.assertEqual(to_hex(to_linear(hex_colour)), hex_colour)
26
+
27
+ def test_distance_and_mix(self):
28
+ self.assertEqual(distance('#ffffff', '#ffffff'), 0.0)
29
+ self.assertLess(distance('#3c7524', '#3d7625'), 0.03)
30
+ self.assertGreater(distance('#3c7524', '#eef3f7'), 0.5)
31
+ self.assertEqual(mix('#000000', '#ffffff', 0.5), (0.5, 0.5, 0.5))
32
+ self.assertEqual(mix('#000000', '#ffffff', 2.0), (1.0, 1.0, 1.0))
33
+
34
+
35
+ if __name__ == '__main__':
36
+ unittest.main()
@@ -49,6 +49,7 @@ import { readVerifyRecord } from '../verify/result.js';
49
49
  import { readFaviconOverride } from '../publish/favicon.js';
50
50
  import { readCategories } from '../publish/categories.js';
51
51
  import { readPlatformIndicators } from '../publish/platform.js';
52
+ import { readArtStyleIndicator } from '../publish/art-style.js';
52
53
  import { allVerifyScreenshotPaths, verifyArtifactPaths } from '../verify/artifacts.js';
53
54
  import { checkVerifyGate, injectMetaBlock } from '../publish/meta-block.js';
54
55
  import { ORIGINAL_PROMPT_FLAG } from '../telemetry/creator-prompt.js';
@@ -328,6 +329,7 @@ export async function runPublish(args, deps = defaultDeps()) {
328
329
  for (const note of platform.notes)
329
330
  log(note);
330
331
  const categories = readCategories(context.root);
332
+ const artStyle = readArtStyleIndicator(context.root);
331
333
  // `visibility`, `name`, `description`, and `thumbnailUrl` are re-sent EXACTLY as `begin` got
332
334
  // them, not implied. `complete` re-authorizes against its OWN body — `begin` writes nothing,
333
335
  // so nothing it validated is bound. Sending a DIFFERENT visibility here than `begin` saw
@@ -363,6 +365,8 @@ export async function runPublish(args, deps = defaultDeps()) {
363
365
  // ABSENT key means "preserve what is stored" server-side and is a different message from
364
366
  // 'desktop'/null; see readPlatformIndicators.
365
367
  ...platform.fields,
368
+ // The game's medium, same absent-key rule; see readArtStyleIndicator.
369
+ ...(artStyle !== undefined ? { artStyle } : {}),
366
370
  // Category tags from `worldProfileData.categories`, same absent-key rule: an undeclared
367
371
  // set lets the server keep stored tags or AI-classify an untagged game; a declared set
368
372
  // (even empty) is the creator's choice and wins. See publish/categories.ts.
@@ -1 +1 @@
1
- {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAuB,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAoB,MAAM,2BAA2B,CAAC;AACjH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,0BAA0B,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAEvF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EACL,QAAQ,IAAI,YAAY,EACxB,iBAAiB,IAAI,qBAAqB,EAC1C,gBAAgB,GAEjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,YAAY,EACZ,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,yBAAyB,EACzB,YAAY,GAEb,MAAM,sBAAsB,CAAC;AAE9B,2FAA2F;AAC3F,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAuB;IACvD,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACtD,MAAM,IAAI,QAAQ,CAAC,mDAAmD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAChG,CAAC;AAoCD,SAAS,WAAW;IAClB,OAAO;QACL,KAAK,EAAE,UAAU,CAAC,KAAK;QACvB,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACtE,QAAQ,EAAE,YAAY;QACtB,iBAAiB,EAAE,qBAAqB;QACxC,8FAA8F;QAC9F,2FAA2F;QAC3F,iFAAiF;QACjF,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC/B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;YAC1D,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC;QAChC,CAAC;QACD,MAAM;KACP,CAAC;AACJ,CAAC;AA6BD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAAY,EACZ,WAAqC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;IAEpE,IAAI,CAAC;QACH,OAAO;YACL,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACrC,QAAQ,EAAE,gBAAgB;YAC1B,WAAW,EAAE,YAAY;YACzB,KAAK,EAAE,qBAAqB;YAC5B,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,gGAAgG;IAClG,CAAC;IACD,MAAM,WAAW,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,eAAe,KAAK,QAAQ,CAAC;IACrF,MAAM,UAAU,GAAkD,WAAW;QAC3E,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC;QACpH,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,mBAAmB,EAAE,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;IACvH,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,OAAO;gBACL,KAAK,EAAE,QAAQ,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC;gBAChG,QAAQ,EAAE,eAAe;gBACzB,WAAW,EAAE,WAAW;gBACxB,KAAK,EAAE,SAAS,CAAC,KAAK;gBACtB,SAAS,EAAE,KAAK;aACjB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;QACpE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,eAAe,CAC5B,OAAuB,EACvB,WAAwB,EACxB,KAAa,EACb,OAAgB,EAChB,GAA8B;IAE9B,MAAM,MAAM,GAAG,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,4FAA4F;QAC5F,8FAA8F;QAC9F,kBAAkB;QAClB,MAAM,IAAI,QAAQ,CAChB,mCAAmC;YACjC,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,wBAAwB,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACvG,0FAA0F;YAC1F,yBAAyB,EAC3B,CAAC,CACF,CAAC;IACJ,CAAC;IAED,GAAG,CAAC,cAAc,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,0FAA0F;QAC1F,oCAAoC;QACpC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,yBAAyB,CAC5C,WAAW,EACX,KAAK,EACL,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,EAC/F,OAAO,CACR,CAAC;IACF,MAAM,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACtE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC;AACtF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAiB,EACjB,OAAuB,WAAW,EAAE;IAEpC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,UAAU,CAAC;IACzC,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,MAAM;QAAE,MAAM,IAAI,QAAQ,CAAC,wCAAwC,CAAC,CAAC;IAC7G,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,KAAK,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,OAAO,CAAU,EAAE,CAAC;YAC/F,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,KAAK;gBAAE,MAAM,IAAI,QAAQ,CAAC,KAAK,GAAG,uCAAuC,CAAC,CAAC;QAC1H,CAAC;QACD,IAAI,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;;YACtC,MAAM,CAAC,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,MAAM,IAAI,QAAQ,CAAC,kCAAkC,CAAC,CAAC;IACtF,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,SAAS;QAAE,MAAM,IAAI,QAAQ,CAAC,yCAAyC,CAAC,CAAC;IACvG,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAChD,wFAAwF;IACxF,kEAAkE;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC;IACpC,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;IAEhD,8FAA8F;IAC9F,gGAAgG;IAChG,+DAA+D;IAC/D,MAAM,SAAS,GAAG;QAChB,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7E,CAAC;IAEF,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAClD,iGAAiG;IACjG,+FAA+F;IAC/F,MAAM,WAAW,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;IAE5C,MAAM,IAAI,GAAG,eAAe,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;IACpG,IAAI,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAElD,sFAAsF;IACtF,4FAA4F;IAC5F,wFAAwF;IACxF,qDAAqD;IACrD,EAAE;IACF,gGAAgG;IAChG,6FAA6F;IAC7F,8FAA8F;IAC9F,MAAM,QAAQ,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,IAAI,QAAQ,EAAE,WAAW,KAAK,WAAW,IAAI,QAAQ,CAAC,UAAU,KAAK,UAAU,EAAE,CAAC;QAChF,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,WAAW,GAAG,4BAA4B,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/F,MAAM,QAAQ,GAAG,oBAAoB,CAAC,WAAW,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,cAAc,CAChC,WAAW,EACX,QAAQ,EACR,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EACxC,IAAI,CAAC,OAAO,CACb,CAAC;IACF,MAAM,OAAO,GAAY,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IAE/C,6FAA6F;IAC7F,oEAAoE;IACpE,MAAM,SAAS,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IACnF,MAAM,YAAY,GAAG,SAAS,CAAC,GAAG,CAAC;IAEnC,+FAA+F;IAC/F,+FAA+F;IAC/F,8FAA8F;IAC9F,IAAI,OAAO,GAAyB,IAAI,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,kBAAkB,CAAC;YACjC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,KAAK,EAAE,WAAW;YAClB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;YAC/B,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,aAAa;YAC7C,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,KAAK;SAC9B,CAAC,CAAC;QACH,IAAI,OAAO,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtC,4FAA4F;YAC5F,2FAA2F;YAC3F,oCAAoC;YACpC,GAAG,CAAC,4BAA4B,OAAO,CAAC,cAAc,CAAC,MAAM,+BAA+B,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnI,CAAC;QACD,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,0FAA0F;YAC1F,4FAA4F;YAC5F,oFAAoF;YACpF,GAAG,CACD,4BAA4B,OAAO,CAAC,aAAa,CAAC,MAAM,mBAAmB,UAAU,CAAC,OAAO,CAAC,iBAAiB,CAAC,MAAM;gBACpH,4DAA4D,CAC/D,CAAC;QACJ,CAAC;QACD,6FAA6F;QAC7F,6FAA6F;QAC7F,+CAA+C;QAC/C,GAAG,CAAC,mBAAmB,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,GAAG,CAAC,sCAAsC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChI,CAAC;IAED,gGAAgG;IAChG,8FAA8F;IAC9F,8FAA8F;IAC9F,gBAAgB;IAChB,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE,KAAK,EAAE;QACnD,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;QAC/B,kFAAkF;QAClF,mFAAmF;QACnF,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,SAAS;QACZ,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,aAAa;QAC7C,YAAY;QACZ,gBAAgB,EAAE,mBAAmB,CAAC,OAAO,CAAC,IAAI,CAAC;QACnD,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrD,EAAE,OAAO,CAAC,CAAC;IAEZ,MAAM,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,IAAI,SAAiB,CAAC;IACtB,IAAI,CAAC;QACH,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,6FAA6F;QAC7F,4FAA4F;QAC5F,mEAAmE;QACnE,MAAM,IAAI,QAAQ,CAChB,uBAAuB,QAAQ,0DAA0D,EACzF,CAAC,CACF,CAAC;IACJ,CAAC;IAED,6FAA6F;IAC7F,4FAA4F;IAC5F,iGAAiG;IACjG,kFAAkF;IAClF,EAAE;IACF,2FAA2F;IAC3F,+FAA+F;IAC/F,2FAA2F;IAC3F,2EAA2E;IAC3E,MAAM,aAAa,GAAG,gBAAgB,CACpC,eAAe,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,EAC3C,KAAK,CAAC,UAAU,CACjB,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,CAAC,UAAU,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACjE,MAAM,eAAe,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE1F,0FAA0F;IAC1F,yFAAyF;IACzF,6FAA6F;IAC7F,sFAAsF;IACtF,MAAM,SAAS,CAAC,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAE7E,8FAA8F;IAC9F,6FAA6F;IAC7F,8FAA8F;IAC9F,IAAI,cAAc,GAAG,KAAK,CAAC;IAC3B,IAAI,OAAO,IAAI,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,kBAAkB,EAAE,CAAC;QACjE,IAAI,CAAC;YACH,MAAM,gBAAgB,CACpB,KAAK,CAAC,eAAe,EACrB,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,QAAQ,CAAC,EACjC,KAAK,CAAC,kBAAkB,EACxB,OAAO,CACR,CAAC;YACF,cAAc,GAAG,IAAI,CAAC;QACxB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,iCAAiC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC9H,CAAC;IACH,CAAC;IAED,6FAA6F;IAC7F,8FAA8F;IAC9F,+FAA+F;IAC/F,uDAAuD;IACvD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhD,6FAA6F;IAC7F,6FAA6F;IAC7F,yFAAyF;IACzF,0FAA0F;IAC1F,kFAAkF;IAClF,8FAA8F;IAC9F,uFAAuF;IACvF,EAAE;IACF,4FAA4F;IAC5F,6FAA6F;IAC7F,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,WAAW,EAAE,KAAK,EAAE;QACrD,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;QAC/B,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,cAAc,EAAE,KAAK,CAAC,cAAc;QACpC,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,GAAG,SAAS;QACZ,YAAY;QACZ,WAAW,EAAE,cAAc;QAC3B,MAAM,EAAE,eAAe;QACvB,0FAA0F;QAC1F,2FAA2F;QAC3F,4FAA4F;QAC5F,aAAa,EAAE,OAAO,CAAC,QAAQ,CAAC,aAAa;QAC7C,WAAW;QACX,6FAA6F;QAC7F,8EAA8E;QAC9E,GAAG,CAAC,cAAc,IAAI,OAAO,IAAI,KAAK,CAAC,SAAS;YAC9C,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,MAAM,EAAE;YAC9D,CAAC,CAAC,EAAE,CAAC;QACP,eAAe,EAAE,WAAW,CAAC,IAAI;QACjC,uFAAuF;QACvF,sFAAsF;QACtF,yFAAyF;QACzF,8CAA8C;QAC9C,GAAG,QAAQ,CAAC,MAAM;QAClB,wFAAwF;QACxF,uFAAuF;QACvF,4EAA4E;QAC5E,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpD,EAAE,OAAO,CAAC,CAAC;IAEZ,uFAAuF;IACvF,8CAA8C;IAC9C,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC/F,IAAI,OAAO,KAAK,IAAI;QAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAEnC,kFAAkF;IAClF,8FAA8F;IAC9F,gGAAgG;IAChG,MAAM,QAAQ,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC1C,GAAG,CAAC,aAAa,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC,CAAC;IACjD,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAClC,GAAG,CAAC,4EAA4E,CAAC,CAAC;IACpF,CAAC;IACD,6FAA6F;IAC7F,8FAA8F;IAC9F,wFAAwF;IACxF,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,IAAI,EAAE,CAAC;QACjC,GAAG,CAAC,sBAAsB,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,8FAA8F;IAC9F,+FAA+F;IAC/F,sFAAsF;IACtF,4FAA4F;IAC5F,iBAAiB;IACjB,IAAI,IAAI,CAAC,SAAS;QAAE,GAAG,CAAC,qBAAqB,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC/D,iGAAiG;IACjG,iGAAiG;IACjG,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,YAAY,EAAE,QAAQ,IAAI,EAAE;QAAE,GAAG,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;IACtF,8FAA8F;IAC9F,gGAAgG;IAChG,yDAAyD;IACzD,EAAE;IACF,kGAAkG;IAClG,kGAAkG;IAClG,kGAAkG;IAClG,uDAAuD;IACvD,gGAAgG;IAChG,kGAAkG;IAClG,4FAA4F;IAC5F,6FAA6F;IAC7F,IAAI,CAAC;QACH,kBAAkB,CAAC,OAAO,CAAC,IAAI,EAAE;YAC/B,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,uFAAuF;YACvF,0FAA0F;YAC1F,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAClD,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;YAC/B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,oFAAoF;YACpF,qFAAqF;YACrF,gDAAgD;YAChD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1C,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IAED,2FAA2F;IAC3F,oEAAoE;IACpE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;QACnC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI;QACxB,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI;KACjC,CAAC,CAAC;IACH,+FAA+F;IAC/F,8FAA8F;IAC9F,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,GAAG,CAAC,YAAY,MAAM,yDAAyD,CAAC,CAAC;IACnF,CAAC;IACD,MAAM,CAAC,MAAM,CAAC;QACZ,EAAE,EAAE,IAAI;QACR,4FAA4F;QAC5F,2FAA2F;QAC3F,GAAG,EAAE,IAAI,CAAC,GAAG;QACb,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClD,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,cAAc,EAAE,IAAI,CAAC,cAAc;QACnC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM;QAC/B,eAAe,EAAE,SAAS,CAAC,MAAM;QACjC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClE,CAAC,CAAC;IAEH,8FAA8F;IAC9F,8FAA8F;IAC9F,IAAI,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC;QAChC,0FAA0F;QAC1F,4FAA4F;QAC5F,0CAA0C;QAC1C,GAAG,CAAC,mEAAmE,CAAC,CAAC;QACzE,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAC/D,GAAG,CAAC,sCAAsC,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACnH,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ;QAAE,GAAG,CAAC,cAAc,OAAO,EAAE,CAAC,CAAC;IACnE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;QACd,6FAA6F;QAC7F,+FAA+F;QAC/F,MAAM,IAAI,QAAQ,CAChB,6BAA6B,QAAQ,kDAAkD;YACrF,qBAAqB,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YACzE,cAAc,QAAQ,IAAI;YAC1B,kFAAkF,EACpF,CAAC,CACF,CAAC;IACJ,CAAC;IACD,GAAG,CAAC,kDAAkD,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,aAAa,CAAC;IAC1C,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,0EAA0E;KACxF;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8EAA8E,EAAE;QACvH,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yDAAyD,EAAE;QAClG,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qHAAqH,EAAE;QACvK,iBAAiB,EAAE,oBAAoB;QACvC,UAAU,EAAE;YACV,IAAI,EAAE,QAAQ;YACd,WAAW,EACT,qFAAqF;kBACnF,6DAA6D;SAClE;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,iFAAiF;SAC/F;QACD,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,wFAAwF;SACtG;QACD,KAAK,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,oFAAoF;SAClG;QACD,YAAY,EAAE;YACZ,IAAI,EAAE,SAAS;YACf,WAAW,EACT,qGAAqG;SACxG;QACD,aAAa,EAAE;YACb,IAAI,EAAE,SAAS;YACf,WAAW,EACT,mFAAmF;kBACjF,wFAAwF;SAC7F;QACD,OAAO,EAAE;YACP,IAAI,EAAE,SAAS;YACf,WAAW,EACT,2FAA2F;SAC9F;QACD,aAAa,EAAE;YACb,IAAI,EAAE,SAAS;YACf,WAAW,EACT,yFAAyF;kBACvF,iFAAiF;SACtF;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,kEAAkE;SAChF;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type ArtStyle } from '@bitmagic/asset-core/art-style';
2
+ /**
3
+ * The `artStyle` a publish syncs to the catalog, in the shape `publish/complete` accepts it.
4
+ *
5
+ * The column is sticky server-side, so `undefined` (omit the key) means "keep what is stored":
6
+ * that is what an unreadable game.json or a value that is neither style sends — a typo must not
7
+ * overwrite a correct stored style. A readable game.json that declares nothing sends `voxel`,
8
+ * because absent there MEANS voxel.
9
+ */
10
+ export declare function readArtStyleIndicator(root: string): ArtStyle | undefined;
@@ -0,0 +1,17 @@
1
+ import { DEFAULT_ART_STYLE } from '@bitmagic/asset-core/art-style';
2
+ import { readArtStyleDeclaration } from '../project/art-style.js';
3
+ /**
4
+ * The `artStyle` a publish syncs to the catalog, in the shape `publish/complete` accepts it.
5
+ *
6
+ * The column is sticky server-side, so `undefined` (omit the key) means "keep what is stored":
7
+ * that is what an unreadable game.json or a value that is neither style sends — a typo must not
8
+ * overwrite a correct stored style. A readable game.json that declares nothing sends `voxel`,
9
+ * because absent there MEANS voxel.
10
+ */
11
+ export function readArtStyleIndicator(root) {
12
+ const declaration = readArtStyleDeclaration(root);
13
+ if (!declaration.workCopyReadable || declaration.rejected !== undefined)
14
+ return undefined;
15
+ return declaration.artStyle ?? DEFAULT_ART_STYLE;
16
+ }
17
+ //# sourceMappingURL=art-style.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"art-style.js","sourceRoot":"","sources":["../../src/publish/art-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,gCAAgC,CAAC;AAClF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,WAAW,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,WAAW,CAAC,gBAAgB,IAAI,WAAW,CAAC,QAAQ,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAC1F,OAAO,WAAW,CAAC,QAAQ,IAAI,iBAAiB,CAAC;AACnD,CAAC"}
@@ -136,6 +136,12 @@ export interface CompletePublishRequest {
136
136
  primaryPlatform?: 'desktop' | 'mobile';
137
137
  /** `null` clears the stored orientation — the project no longer declares one. */
138
138
  mobileOrientation?: 'portrait' | 'landscape' | null;
139
+ /**
140
+ * The project's game.json `artStyle` (absent there = voxel), so the catalog knows the game's
141
+ * medium — an admin-generated cover is drawn in it. Sticky server-side and forward-compatible
142
+ * like the platform fields: absent keeps what is stored, an older server ignores the key.
143
+ */
144
+ artStyle?: 'voxel' | 'low-poly';
139
145
  /**
140
146
  * Category tags declared in the project's `worldProfileData.categories` — see
141
147
  * `publish/categories.ts` for the three messages (absent / non-empty / explicit empty).
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/publish/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/publish/client.ts"],"names":[],"mappings":"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"}
@@ -455,6 +455,7 @@ The standard set is what you read first. After that, ask for what you want to se
455
455
  | \`--fov <deg>\` | horizontal field of view for the perspective shots; default 24 mm ≈ 74° |
456
456
  | \`--lighting review\` | default. A camera-mounted fill and a sun, so nothing can hide in shadow |
457
457
  | \`--lighting game\` | the engine's \`interior\` preset — the sun at 8%, the hemisphere at 0.65, your \`lamp()\`s and \`spot()\`s as real lights, emissive materials glowing at their \`glow\` |
458
+ | \`--engine cycles\` | render with Cycles (OptiX or CUDA GPU, else CPU) instead of EEVEE — for a headless Linux box where EEVEE fails with no EGL/GLX context |
458
459
 
459
460
  Judge geometry under \`--lighting review\`; judge the lighting pass under \`--lighting game\`. The
460
461
  second is close enough to the engine that a room which is black there is black in the game, so
@@ -1 +1 @@
1
- {"version":3,"file":"blender-level-skill-files.js","sourceRoot":"","sources":["../../src/scaffold/blender-level-skill-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,MAAM,UAAU,wBAAwB;IACtC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8QR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iCAAiC;IAC/C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC1C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2FR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC1C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyER,CAAC;AACF,CAAC;AAED,MAAM,UAAU,mCAAmC;IACjD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgHR,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"blender-level-skill-files.js","sourceRoot":"","sources":["../../src/scaffold/blender-level-skill-files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,MAAM,UAAU,wBAAwB;IACtC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8QR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iCAAiC;IAC/C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC1C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4FR,CAAC;AACF,CAAC;AAED,MAAM,UAAU,4BAA4B;IAC1C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyER,CAAC;AACF,CAAC;AAED,MAAM,UAAU,mCAAmC;IACjD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgHR,CAAC;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitmagic/cli",
3
- "version": "0.1.71-dev.3",
3
+ "version": "0.1.71",
4
4
  "description": "Build Bitmagic games from your own agent tool",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "Bitmagic Oy",
@@ -25,9 +25,9 @@
25
25
  "playwright-core": "^1.59.1",
26
26
  "tar": "^7.4.3",
27
27
  "ws": "^8.21.3",
28
- "@bitmagic/animation-forger": "0.1.26-dev.3",
29
- "@bitmagic/asset-core": "0.2.26-dev.3",
30
- "@bitmagic/world-forger": "0.1.31-dev.3"
28
+ "@bitmagic/asset-core": "0.2.26",
29
+ "@bitmagic/animation-forger": "0.1.26",
30
+ "@bitmagic/world-forger": "0.1.31"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@eslint/js": "^9.38.0",