glazed 0.1.0__tar.gz

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.
glazed-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Junha Lee
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
glazed-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,311 @@
1
+ Metadata-Version: 2.4
2
+ Name: glazed
3
+ Version: 0.1.0
4
+ Summary: Studio-lit Blender Cycles renders of point clouds, meshes, and scenes mixing both.
5
+ Author-email: Junha Lee <junha.lee@postech.ac.kr>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/junha-l/glazed
8
+ Project-URL: Issues, https://github.com/junha-l/glazed/issues
9
+ Keywords: blender,cycles,rendering,point-cloud,mesh,visualization
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Multimedia :: Graphics :: 3D Rendering
13
+ Classifier: Topic :: Scientific/Engineering :: Visualization
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: numpy>=1.21
18
+ Requires-Dist: tomli>=1.1; python_version < "3.11"
19
+ Provides-Extra: render
20
+ Requires-Dist: bpy>=5.0; extra == "render"
21
+ Requires-Dist: matplotlib>=3.8; extra == "render"
22
+ Dynamic: license-file
23
+
24
+ <div align="center">
25
+
26
+ # 🍩 glazed
27
+
28
+ **Studio-lit Blender Cycles renders of point clouds, meshes, and scenes mixing both.**
29
+
30
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-3776AB?logo=python&logoColor=white)](#installation)
31
+ [![Blender 5.x Cycles](https://img.shields.io/badge/Blender-5.x%20Cycles-E87D0D?logo=blender&logoColor=white)](#rendering)
32
+ [![Preview: three.js](https://img.shields.io/badge/preview-three.js-000000?logo=threedotjs&logoColor=white)](#preview-in-the-browser)
33
+ [![Claude Code plugin](https://img.shields.io/badge/Claude%20Code-plugin-D97757?logo=claude&logoColor=white)](#claude-code-plugin)
34
+
35
+ [Installation](#installation) ·
36
+ [Quickstart](#quickstart) ·
37
+ [Preview](#preview-in-the-browser) ·
38
+ [Rendering](#rendering) ·
39
+ [Scene files](#scene-files) ·
40
+ [Claude Code plugin](#claude-code-plugin)
41
+
42
+ | ![Dough and glaze meshes with an RGB point cloud of sprinkles](https://raw.githubusercontent.com/junha-l/glazed/main/docs/gallery-meshes.png) | ![A point cloud of the donut, coloured by height through viridis](https://raw.githubusercontent.com/junha-l/glazed/main/docs/gallery-points.png) | ![The glazed donut on a dark backdrop](https://raw.githubusercontent.com/junha-l/glazed/main/docs/gallery-backdrop.png) |
43
+ |:---:|:---:|:---:|
44
+ | Meshes and an RGB point cloud | A point cloud through a colormap | Any backdrop |
45
+
46
+ [![The preview page: the glazed donut in the browser beside camera, lighting, backdrop, and image controls, and the matching glazed command](https://raw.githubusercontent.com/junha-l/glazed/main/docs/preview.png)](#preview-in-the-browser)
47
+
48
+ <sub>Pick the view in a live browser preview, then render it with the command it hands back.</sub>
49
+
50
+ </div>
51
+
52
+ Raw 3D assets in, finished pieces out. Like a potter's glaze and firing, glazed
53
+ colours point clouds, meshes, and scenes mixing both, then fires them in Blender
54
+ Cycles: seamless backdrop, soft side light, contact shadows, and colormaps that
55
+ stay true to their colorbars. Renders stills, turntable videos, and GIFs.
56
+
57
+ ## Highlights
58
+
59
+ - **Point clouds, meshes, or both** in one scene: `.npy`, `.ply`, `.stl`, `.obj`,
60
+ `.glb`, `.gltf`, and `.fbx`, laid out by a small TOML scene file.
61
+ - **A studio look out of the box**: a seamless backdrop, a soft side light, contact
62
+ shadows, and Blender's Standard view, so colormaps match their colorbars.
63
+ - **Stills, turntable videos, and GIFs** from one command, with camera paths for
64
+ custom shots.
65
+ - **A live browser preview** that frames and lights the scene like the render and
66
+ hands back the matching command.
67
+ - **Exports from any research codebase**: `glazed.io` needs only numpy and takes
68
+ torch tensors on any device.
69
+ - **A Claude Code plugin** that teaches Claude to export and render your project's
70
+ outputs.
71
+
72
+ ## Installation
73
+
74
+ glazed has two parts, usually installed in two environments:
75
+
76
+ ```bash
77
+ pip install glazed # glazed.io and the preview: numpy only, Python >= 3.9
78
+ pip install "glazed[render]" # the renderer: Blender's bpy, Python 3.13 only
79
+ ```
80
+
81
+ | Part | Install into | Needs |
82
+ |---|---|---|
83
+ | `glazed.io` and `--preview` | your research project's environment | Python ≥ 3.9, numpy |
84
+ | The renderer | a separate environment | Python 3.13, for Blender's `bpy` 5.x |
85
+ | Videos and GIFs | | `ffmpeg` on the PATH |
86
+
87
+ To work on glazed itself, install a checkout: `pip install /path/to/glazed`,
88
+ adding `-e` while developing.
89
+
90
+ ### Without installing
91
+
92
+ Blender can run glazed from a source checkout with its own Python:
93
+
94
+ ```bash
95
+ blender -b -P render.py -- examples/donut.npy
96
+ ```
97
+
98
+ This needs Blender 5.x, with `matplotlib` installed into Blender's bundled Python.
99
+
100
+ ## Quickstart
101
+
102
+ The repository ships a glazed donut to try everything on. In the render
103
+ environment:
104
+
105
+ ```bash
106
+ glazed examples/glazed_donut.toml --preview # pick a view in the browser
107
+ glazed examples/glazed_donut.toml --elev 35 --gpu # outs/glazed_donut.png
108
+ glazed examples/glazed_donut.toml --mode mp4 gif --gpu # a turntable video and GIF
109
+ ```
110
+
111
+ The example files are baked by `examples/make_donut.py` using only `glazed.io`,
112
+ so it doubles as a worked example of exporting scenes.
113
+
114
+ ## Exporting from your project
115
+
116
+ ```python
117
+ from glazed.io import save_mesh, save_points, write_scene
118
+
119
+ save_mesh("out/object.ply", vertices, faces) # numpy arrays or torch tensors
120
+ save_points("out/pred.npy", points, values=per_point_error)
121
+ write_scene("out/scene.toml", [
122
+ {"path": "out/object.ply", "color": "#c9ccd1"},
123
+ {"path": "out/pred.npy"},
124
+ ])
125
+ ```
126
+
127
+ Point clouds are `.npy` arrays of shape (N, 3) xyz, (N, 4) xyz + value, or
128
+ (N, 6) xyz + RGB. Meshes can be `.ply`, `.stl`, `.obj`, `.glb`, `.gltf`, or `.fbx`;
129
+ `save_mesh` writes PLY, which Blender reads with coordinates as stored, while OBJ
130
+ files are treated as Y-up. `glazed.io` also has `sample_surface`, `to_z_up`,
131
+ `check_alignment`, `grid_locations`, `read_scene`, and `check_scene`.
132
+
133
+ ## Preview in the browser
134
+
135
+ A Cycles render takes minutes, so pick the view and lighting in a live preview
136
+ first:
137
+
138
+ ```bash
139
+ glazed examples/glazed_donut.toml --preview
140
+ ```
141
+
142
+ This opens the scene in the browser, framed and lit like the render. Drag to
143
+ orbit, scroll to zoom, and adjust the lighting, backdrop, colormap, and image size
144
+ in the panel, which shows the matching `glazed` command to copy, including the
145
+ other options you passed. **Render with Cycles** renders the current view at
146
+ preview quality to check the real look, and **Play turntable** plays a video's
147
+ orbit at its real speed.
148
+
149
+ | Live preview | Cycles render of the copied command |
150
+ |:---:|:---:|
151
+ | ![The glazed donut in the live preview](https://raw.githubusercontent.com/junha-l/glazed/main/docs/preview-live.png) | ![The same view rendered by Cycles](https://raw.githubusercontent.com/junha-l/glazed/main/docs/preview-cycles.png) |
152
+
153
+ The same view, `glazed examples/glazed_donut.toml --azim 30 --elev 40`, in the
154
+ preview and rendered by Cycles.
155
+
156
+ The preview needs only numpy, so it runs in a research environment too. There,
157
+ the Cycles button is off, since it needs bpy, and colormaps other than viridis
158
+ need matplotlib. On a remote machine, pick a port and forward it:
159
+ `glazed scene.toml --preview --port 8765`, then `ssh -L 8765:localhost:8765 <host>`
160
+ and open `http://localhost:8765`. The page loads three.js from a CDN, so the
161
+ browser needs internet access. Soft floor shadows are approximate, mostly where
162
+ several objects' shadows overlap; the Cycles button shows the real ones.
163
+
164
+ ## Rendering
165
+
166
+ ```bash
167
+ glazed examples/glazed_donut.toml --elev 35 --gpu # dough and glaze meshes, RGB sprinkles
168
+ glazed examples/donut.npy --gpu # a point cloud, coloured by height
169
+ glazed examples/glazed_donut.toml --mode mp4 gif --gpu # a turntable video and GIF
170
+ glazed mesh.ply cloud.npy --bg "#2b2f36" --gpu # any files, dark backdrop
171
+ glazed --help # every option
172
+ ```
173
+
174
+ ### Outputs
175
+
176
+ Output goes to `outs/<first input's name>` plus an extension per mode. Set the
177
+ path with `--out figs/teaser`; `--out figs/teaser.png` works too, without doubling
178
+ the extension.
179
+
180
+ | Output | Path |
181
+ |---|---|
182
+ | Still (`--mode still`, the default) | `outs/glazed_donut.png` |
183
+ | Video and GIF (`--mode mp4 gif`) | `outs/glazed_donut.mp4`, `.gif`, with frames kept in `outs/glazed_donut_frames/` |
184
+ | Frames only (`--mode png`) | `outs/glazed_donut_frames/frame_00000.png`, ... |
185
+ | Several colormaps (`--cmap viridis magma`) | `outs/donut_viridis.png`, `outs/donut_magma.png` |
186
+ | `--colorbar`, `--save-blend` | `outs/donut_colorbar.png`, `outs/donut.blend`, suffixed per colormap like the renders |
187
+
188
+ `--no-keep-frames` deletes the frames once the video is encoded.
189
+
190
+ ### Lighting and camera
191
+
192
+ The studio is one soft key light from the side, white ambient fill, and a floor
193
+ that only catches shadows. The lights turn with the camera, like a turntable under
194
+ fixed lights, so an orbit looks the same from every angle.
195
+
196
+ | Option | Default | |
197
+ |---|---|---|
198
+ | `--exposure` | `0` | stops; `-1` halves the brightness |
199
+ | `--key` | `1` | key light strength |
200
+ | `--ambient` | `1` | fill light; lower gives darker shadows and more contrast |
201
+ | `--key-azim` | `-90` | key angle from the camera, degrees, negative to its left; near 0 looks flat, near ±90 shows the most depth |
202
+ | `--key-elev` | `35` | key height, degrees; lower gives stronger shading on curved surfaces |
203
+ | `--bg` | `white` | backdrop, any matplotlib colour; `--transparent` leaves it transparent for compositing |
204
+ | `--azim`, `--elev` | `45`, `22` | camera angle, degrees; an orbit starts here |
205
+ | `--distance` | fits the scene | multiple of the scene's half-size |
206
+ | `--lens` | `50` | mm; shorter gives stronger perspective |
207
+ | `--cmap`, `--vmin`, `--vmax` | `viridis`, data range | colours per-point values; the range is shared across the scene |
208
+
209
+ ### Turntables and camera paths
210
+
211
+ Video modes orbit the scene, by default `--frames 120 --fps 30 --turns 1`, which
212
+ loops seamlessly. `--elev-amp 10` adds an up-and-down sway, `--dolly 0.15` pushes
213
+ in by 15% over the shot, and `--ease` slows the start and end, which breaks the
214
+ loop. `--gif-width` sets the GIF's width (720).
215
+
216
+ `--waypoints path.json` replaces the orbit with a smooth spline through camera
217
+ positions. Coordinates are in normalised scene units: the scene is centred on the
218
+ origin with a largest half-side of 1. `target` is optional and defaults to the
219
+ orbit's centre.
220
+
221
+ ```json
222
+ {"eye": [[3, -3, 1], [3, 3, 1.5], [-3, 3, 1]], "target": [[0, 0, 0]], "loop": true}
223
+ ```
224
+
225
+ ### Quality
226
+
227
+ Renders default to `--res 1400 1050 --samples 256 --supersample 2`, rendering at
228
+ twice the resolution and filtering down for clean edges. `--gpu` uses the first of
229
+ OptiX, CUDA, HIP, Metal, or oneAPI it finds, and falls back to the CPU. Preview
230
+ views with `--res 480 360 --samples 32 --supersample 1`; for videos,
231
+ `--res 1280 720 --samples 128 --supersample 1` keeps frame times down.
232
+ `--save-blend` also saves the scene as a `.blend` to adjust by hand in Blender.
233
+
234
+ ### Python API
235
+
236
+ In the render environment:
237
+
238
+ ```python
239
+ from glazed.io import AssetSpec
240
+ from glazed.render import render
241
+ from glazed.settings import RenderSettings, View
242
+
243
+ render([AssetSpec("examples/donut.ply", color="#d9a066"),
244
+ AssetSpec("examples/glaze.ply", color="#f4a6c6"),
245
+ AssetSpec("examples/sprinkles.npy", radius=0.0009)],
246
+ out="outs/glazed_donut", settings=RenderSettings(gpu=True), view=View(elev=35))
247
+ ```
248
+
249
+ `out` works like `--out` and defaults to `outs/render`. `modes` takes the
250
+ `--mode` values, e.g. `modes=("mp4", "gif")`, and the other options live in
251
+ `glazed.settings` as dataclasses: `RenderSettings`, `Lighting`, `View`,
252
+ `Animation`, and `Colormap`.
253
+
254
+ ## Scene files
255
+
256
+ ```toml
257
+ [[objects]]
258
+ path = "cloud.npy"
259
+ radius_scale = 1.25
260
+
261
+ [[objects]]
262
+ path = "mesh.ply"
263
+ color = "#c9ccd1"
264
+ location = [7.5, 0, 0] # in the file's own units
265
+ rotation = [0, 0, 90] # degrees about x, y, z
266
+ ```
267
+
268
+ | Key | Default | |
269
+ |---|---|---|
270
+ | `path` | required | relative to the scene file |
271
+ | `color` | `"#cccccc"` | any matplotlib colour; `"original"` keeps a mesh's own materials. Ignored for (N, 4) and (N, 6) point clouds |
272
+ | `location` | `[0, 0, 0]` | file units |
273
+ | `rotation` | `[0, 0, 0]` | degrees about x, y, z, pivoting on the file's origin |
274
+ | `scale` | `1.0` | uniform |
275
+ | `radius` | automatic | point clouds, file units |
276
+ | `radius_scale` | `1.0` | point clouds, multiplier on the automatic radius |
277
+ | `smooth` | `true` | meshes, smooth shading |
278
+
279
+ The world is Z-up. `--color`, `--radius` and `--radius-scale` set defaults that
280
+ entries override. The same structure in JSON (`{"objects": [{...}, ...]}`) also
281
+ works.
282
+
283
+ ## Claude Code plugin
284
+
285
+ This repository is also a Claude Code plugin. Its `glazed-render` skill teaches
286
+ Claude, working in your research project, to export the project's outputs with
287
+ `glazed.io`, keep the parts of a scene aligned, and render them. Domain guides in
288
+ `skills/glazed-render/references/` cover specific kinds of projects, starting with
289
+ hand-object grasps. Install it once, for every project:
290
+
291
+ ```
292
+ /plugin marketplace add /path/to/glazed # or <owner>/<repo> once it's on GitHub
293
+ /plugin install glazed@glazed
294
+ ```
295
+
296
+ ## Extending
297
+
298
+ - **New file type:** list its suffix in `glazed/io.py`, then map it to a Blender
299
+ importer in `IMPORTERS`, or to an `Asset` subclass in `LOADERS`, in
300
+ `glazed/render/assets.py`. For the preview, map it to a three.js loader in
301
+ `LOADERS` in `glazed/preview.html`.
302
+ - **New asset type:** subclass `Asset`, build its objects in `__init__`, and
303
+ override `paint()`.
304
+ - **New domain guide for the skill:** add a Markdown file to
305
+ `skills/glazed-render/references/` and list it in `SKILL.md`.
306
+
307
+ ## Acknowledgements
308
+
309
+ glazed renders with [Blender](https://www.blender.org/)'s Cycles through its
310
+ `bpy` module, and its preview runs on [three.js](https://threejs.org/), whose
311
+ percentage-closer soft shadows example the preview's floor shadows adapt.
glazed-0.1.0/README.md ADDED
@@ -0,0 +1,288 @@
1
+ <div align="center">
2
+
3
+ # 🍩 glazed
4
+
5
+ **Studio-lit Blender Cycles renders of point clouds, meshes, and scenes mixing both.**
6
+
7
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-3776AB?logo=python&logoColor=white)](#installation)
8
+ [![Blender 5.x Cycles](https://img.shields.io/badge/Blender-5.x%20Cycles-E87D0D?logo=blender&logoColor=white)](#rendering)
9
+ [![Preview: three.js](https://img.shields.io/badge/preview-three.js-000000?logo=threedotjs&logoColor=white)](#preview-in-the-browser)
10
+ [![Claude Code plugin](https://img.shields.io/badge/Claude%20Code-plugin-D97757?logo=claude&logoColor=white)](#claude-code-plugin)
11
+
12
+ [Installation](#installation) ·
13
+ [Quickstart](#quickstart) ·
14
+ [Preview](#preview-in-the-browser) ·
15
+ [Rendering](#rendering) ·
16
+ [Scene files](#scene-files) ·
17
+ [Claude Code plugin](#claude-code-plugin)
18
+
19
+ | ![Dough and glaze meshes with an RGB point cloud of sprinkles](https://raw.githubusercontent.com/junha-l/glazed/main/docs/gallery-meshes.png) | ![A point cloud of the donut, coloured by height through viridis](https://raw.githubusercontent.com/junha-l/glazed/main/docs/gallery-points.png) | ![The glazed donut on a dark backdrop](https://raw.githubusercontent.com/junha-l/glazed/main/docs/gallery-backdrop.png) |
20
+ |:---:|:---:|:---:|
21
+ | Meshes and an RGB point cloud | A point cloud through a colormap | Any backdrop |
22
+
23
+ [![The preview page: the glazed donut in the browser beside camera, lighting, backdrop, and image controls, and the matching glazed command](https://raw.githubusercontent.com/junha-l/glazed/main/docs/preview.png)](#preview-in-the-browser)
24
+
25
+ <sub>Pick the view in a live browser preview, then render it with the command it hands back.</sub>
26
+
27
+ </div>
28
+
29
+ Raw 3D assets in, finished pieces out. Like a potter's glaze and firing, glazed
30
+ colours point clouds, meshes, and scenes mixing both, then fires them in Blender
31
+ Cycles: seamless backdrop, soft side light, contact shadows, and colormaps that
32
+ stay true to their colorbars. Renders stills, turntable videos, and GIFs.
33
+
34
+ ## Highlights
35
+
36
+ - **Point clouds, meshes, or both** in one scene: `.npy`, `.ply`, `.stl`, `.obj`,
37
+ `.glb`, `.gltf`, and `.fbx`, laid out by a small TOML scene file.
38
+ - **A studio look out of the box**: a seamless backdrop, a soft side light, contact
39
+ shadows, and Blender's Standard view, so colormaps match their colorbars.
40
+ - **Stills, turntable videos, and GIFs** from one command, with camera paths for
41
+ custom shots.
42
+ - **A live browser preview** that frames and lights the scene like the render and
43
+ hands back the matching command.
44
+ - **Exports from any research codebase**: `glazed.io` needs only numpy and takes
45
+ torch tensors on any device.
46
+ - **A Claude Code plugin** that teaches Claude to export and render your project's
47
+ outputs.
48
+
49
+ ## Installation
50
+
51
+ glazed has two parts, usually installed in two environments:
52
+
53
+ ```bash
54
+ pip install glazed # glazed.io and the preview: numpy only, Python >= 3.9
55
+ pip install "glazed[render]" # the renderer: Blender's bpy, Python 3.13 only
56
+ ```
57
+
58
+ | Part | Install into | Needs |
59
+ |---|---|---|
60
+ | `glazed.io` and `--preview` | your research project's environment | Python ≥ 3.9, numpy |
61
+ | The renderer | a separate environment | Python 3.13, for Blender's `bpy` 5.x |
62
+ | Videos and GIFs | | `ffmpeg` on the PATH |
63
+
64
+ To work on glazed itself, install a checkout: `pip install /path/to/glazed`,
65
+ adding `-e` while developing.
66
+
67
+ ### Without installing
68
+
69
+ Blender can run glazed from a source checkout with its own Python:
70
+
71
+ ```bash
72
+ blender -b -P render.py -- examples/donut.npy
73
+ ```
74
+
75
+ This needs Blender 5.x, with `matplotlib` installed into Blender's bundled Python.
76
+
77
+ ## Quickstart
78
+
79
+ The repository ships a glazed donut to try everything on. In the render
80
+ environment:
81
+
82
+ ```bash
83
+ glazed examples/glazed_donut.toml --preview # pick a view in the browser
84
+ glazed examples/glazed_donut.toml --elev 35 --gpu # outs/glazed_donut.png
85
+ glazed examples/glazed_donut.toml --mode mp4 gif --gpu # a turntable video and GIF
86
+ ```
87
+
88
+ The example files are baked by `examples/make_donut.py` using only `glazed.io`,
89
+ so it doubles as a worked example of exporting scenes.
90
+
91
+ ## Exporting from your project
92
+
93
+ ```python
94
+ from glazed.io import save_mesh, save_points, write_scene
95
+
96
+ save_mesh("out/object.ply", vertices, faces) # numpy arrays or torch tensors
97
+ save_points("out/pred.npy", points, values=per_point_error)
98
+ write_scene("out/scene.toml", [
99
+ {"path": "out/object.ply", "color": "#c9ccd1"},
100
+ {"path": "out/pred.npy"},
101
+ ])
102
+ ```
103
+
104
+ Point clouds are `.npy` arrays of shape (N, 3) xyz, (N, 4) xyz + value, or
105
+ (N, 6) xyz + RGB. Meshes can be `.ply`, `.stl`, `.obj`, `.glb`, `.gltf`, or `.fbx`;
106
+ `save_mesh` writes PLY, which Blender reads with coordinates as stored, while OBJ
107
+ files are treated as Y-up. `glazed.io` also has `sample_surface`, `to_z_up`,
108
+ `check_alignment`, `grid_locations`, `read_scene`, and `check_scene`.
109
+
110
+ ## Preview in the browser
111
+
112
+ A Cycles render takes minutes, so pick the view and lighting in a live preview
113
+ first:
114
+
115
+ ```bash
116
+ glazed examples/glazed_donut.toml --preview
117
+ ```
118
+
119
+ This opens the scene in the browser, framed and lit like the render. Drag to
120
+ orbit, scroll to zoom, and adjust the lighting, backdrop, colormap, and image size
121
+ in the panel, which shows the matching `glazed` command to copy, including the
122
+ other options you passed. **Render with Cycles** renders the current view at
123
+ preview quality to check the real look, and **Play turntable** plays a video's
124
+ orbit at its real speed.
125
+
126
+ | Live preview | Cycles render of the copied command |
127
+ |:---:|:---:|
128
+ | ![The glazed donut in the live preview](https://raw.githubusercontent.com/junha-l/glazed/main/docs/preview-live.png) | ![The same view rendered by Cycles](https://raw.githubusercontent.com/junha-l/glazed/main/docs/preview-cycles.png) |
129
+
130
+ The same view, `glazed examples/glazed_donut.toml --azim 30 --elev 40`, in the
131
+ preview and rendered by Cycles.
132
+
133
+ The preview needs only numpy, so it runs in a research environment too. There,
134
+ the Cycles button is off, since it needs bpy, and colormaps other than viridis
135
+ need matplotlib. On a remote machine, pick a port and forward it:
136
+ `glazed scene.toml --preview --port 8765`, then `ssh -L 8765:localhost:8765 <host>`
137
+ and open `http://localhost:8765`. The page loads three.js from a CDN, so the
138
+ browser needs internet access. Soft floor shadows are approximate, mostly where
139
+ several objects' shadows overlap; the Cycles button shows the real ones.
140
+
141
+ ## Rendering
142
+
143
+ ```bash
144
+ glazed examples/glazed_donut.toml --elev 35 --gpu # dough and glaze meshes, RGB sprinkles
145
+ glazed examples/donut.npy --gpu # a point cloud, coloured by height
146
+ glazed examples/glazed_donut.toml --mode mp4 gif --gpu # a turntable video and GIF
147
+ glazed mesh.ply cloud.npy --bg "#2b2f36" --gpu # any files, dark backdrop
148
+ glazed --help # every option
149
+ ```
150
+
151
+ ### Outputs
152
+
153
+ Output goes to `outs/<first input's name>` plus an extension per mode. Set the
154
+ path with `--out figs/teaser`; `--out figs/teaser.png` works too, without doubling
155
+ the extension.
156
+
157
+ | Output | Path |
158
+ |---|---|
159
+ | Still (`--mode still`, the default) | `outs/glazed_donut.png` |
160
+ | Video and GIF (`--mode mp4 gif`) | `outs/glazed_donut.mp4`, `.gif`, with frames kept in `outs/glazed_donut_frames/` |
161
+ | Frames only (`--mode png`) | `outs/glazed_donut_frames/frame_00000.png`, ... |
162
+ | Several colormaps (`--cmap viridis magma`) | `outs/donut_viridis.png`, `outs/donut_magma.png` |
163
+ | `--colorbar`, `--save-blend` | `outs/donut_colorbar.png`, `outs/donut.blend`, suffixed per colormap like the renders |
164
+
165
+ `--no-keep-frames` deletes the frames once the video is encoded.
166
+
167
+ ### Lighting and camera
168
+
169
+ The studio is one soft key light from the side, white ambient fill, and a floor
170
+ that only catches shadows. The lights turn with the camera, like a turntable under
171
+ fixed lights, so an orbit looks the same from every angle.
172
+
173
+ | Option | Default | |
174
+ |---|---|---|
175
+ | `--exposure` | `0` | stops; `-1` halves the brightness |
176
+ | `--key` | `1` | key light strength |
177
+ | `--ambient` | `1` | fill light; lower gives darker shadows and more contrast |
178
+ | `--key-azim` | `-90` | key angle from the camera, degrees, negative to its left; near 0 looks flat, near ±90 shows the most depth |
179
+ | `--key-elev` | `35` | key height, degrees; lower gives stronger shading on curved surfaces |
180
+ | `--bg` | `white` | backdrop, any matplotlib colour; `--transparent` leaves it transparent for compositing |
181
+ | `--azim`, `--elev` | `45`, `22` | camera angle, degrees; an orbit starts here |
182
+ | `--distance` | fits the scene | multiple of the scene's half-size |
183
+ | `--lens` | `50` | mm; shorter gives stronger perspective |
184
+ | `--cmap`, `--vmin`, `--vmax` | `viridis`, data range | colours per-point values; the range is shared across the scene |
185
+
186
+ ### Turntables and camera paths
187
+
188
+ Video modes orbit the scene, by default `--frames 120 --fps 30 --turns 1`, which
189
+ loops seamlessly. `--elev-amp 10` adds an up-and-down sway, `--dolly 0.15` pushes
190
+ in by 15% over the shot, and `--ease` slows the start and end, which breaks the
191
+ loop. `--gif-width` sets the GIF's width (720).
192
+
193
+ `--waypoints path.json` replaces the orbit with a smooth spline through camera
194
+ positions. Coordinates are in normalised scene units: the scene is centred on the
195
+ origin with a largest half-side of 1. `target` is optional and defaults to the
196
+ orbit's centre.
197
+
198
+ ```json
199
+ {"eye": [[3, -3, 1], [3, 3, 1.5], [-3, 3, 1]], "target": [[0, 0, 0]], "loop": true}
200
+ ```
201
+
202
+ ### Quality
203
+
204
+ Renders default to `--res 1400 1050 --samples 256 --supersample 2`, rendering at
205
+ twice the resolution and filtering down for clean edges. `--gpu` uses the first of
206
+ OptiX, CUDA, HIP, Metal, or oneAPI it finds, and falls back to the CPU. Preview
207
+ views with `--res 480 360 --samples 32 --supersample 1`; for videos,
208
+ `--res 1280 720 --samples 128 --supersample 1` keeps frame times down.
209
+ `--save-blend` also saves the scene as a `.blend` to adjust by hand in Blender.
210
+
211
+ ### Python API
212
+
213
+ In the render environment:
214
+
215
+ ```python
216
+ from glazed.io import AssetSpec
217
+ from glazed.render import render
218
+ from glazed.settings import RenderSettings, View
219
+
220
+ render([AssetSpec("examples/donut.ply", color="#d9a066"),
221
+ AssetSpec("examples/glaze.ply", color="#f4a6c6"),
222
+ AssetSpec("examples/sprinkles.npy", radius=0.0009)],
223
+ out="outs/glazed_donut", settings=RenderSettings(gpu=True), view=View(elev=35))
224
+ ```
225
+
226
+ `out` works like `--out` and defaults to `outs/render`. `modes` takes the
227
+ `--mode` values, e.g. `modes=("mp4", "gif")`, and the other options live in
228
+ `glazed.settings` as dataclasses: `RenderSettings`, `Lighting`, `View`,
229
+ `Animation`, and `Colormap`.
230
+
231
+ ## Scene files
232
+
233
+ ```toml
234
+ [[objects]]
235
+ path = "cloud.npy"
236
+ radius_scale = 1.25
237
+
238
+ [[objects]]
239
+ path = "mesh.ply"
240
+ color = "#c9ccd1"
241
+ location = [7.5, 0, 0] # in the file's own units
242
+ rotation = [0, 0, 90] # degrees about x, y, z
243
+ ```
244
+
245
+ | Key | Default | |
246
+ |---|---|---|
247
+ | `path` | required | relative to the scene file |
248
+ | `color` | `"#cccccc"` | any matplotlib colour; `"original"` keeps a mesh's own materials. Ignored for (N, 4) and (N, 6) point clouds |
249
+ | `location` | `[0, 0, 0]` | file units |
250
+ | `rotation` | `[0, 0, 0]` | degrees about x, y, z, pivoting on the file's origin |
251
+ | `scale` | `1.0` | uniform |
252
+ | `radius` | automatic | point clouds, file units |
253
+ | `radius_scale` | `1.0` | point clouds, multiplier on the automatic radius |
254
+ | `smooth` | `true` | meshes, smooth shading |
255
+
256
+ The world is Z-up. `--color`, `--radius` and `--radius-scale` set defaults that
257
+ entries override. The same structure in JSON (`{"objects": [{...}, ...]}`) also
258
+ works.
259
+
260
+ ## Claude Code plugin
261
+
262
+ This repository is also a Claude Code plugin. Its `glazed-render` skill teaches
263
+ Claude, working in your research project, to export the project's outputs with
264
+ `glazed.io`, keep the parts of a scene aligned, and render them. Domain guides in
265
+ `skills/glazed-render/references/` cover specific kinds of projects, starting with
266
+ hand-object grasps. Install it once, for every project:
267
+
268
+ ```
269
+ /plugin marketplace add /path/to/glazed # or <owner>/<repo> once it's on GitHub
270
+ /plugin install glazed@glazed
271
+ ```
272
+
273
+ ## Extending
274
+
275
+ - **New file type:** list its suffix in `glazed/io.py`, then map it to a Blender
276
+ importer in `IMPORTERS`, or to an `Asset` subclass in `LOADERS`, in
277
+ `glazed/render/assets.py`. For the preview, map it to a three.js loader in
278
+ `LOADERS` in `glazed/preview.html`.
279
+ - **New asset type:** subclass `Asset`, build its objects in `__init__`, and
280
+ override `paint()`.
281
+ - **New domain guide for the skill:** add a Markdown file to
282
+ `skills/glazed-render/references/` and list it in `SKILL.md`.
283
+
284
+ ## Acknowledgements
285
+
286
+ glazed renders with [Blender](https://www.blender.org/)'s Cycles through its
287
+ `bpy` module, and its preview runs on [three.js](https://threejs.org/), whose
288
+ percentage-closer soft shadows example the preview's floor shadows adapt.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"] # for the SPDX license field
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "glazed"
7
+ version = "0.1.0"
8
+ description = "Studio-lit Blender Cycles renders of point clouds, meshes, and scenes mixing both."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "Junha Lee", email = "junha.lee@postech.ac.kr" }]
13
+ keywords = ["blender", "cycles", "rendering", "point-cloud", "mesh", "visualization"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Intended Audience :: Science/Research",
17
+ "Topic :: Multimedia :: Graphics :: 3D Rendering",
18
+ "Topic :: Scientific/Engineering :: Visualization",
19
+ ]
20
+ requires-python = ">=3.9"
21
+ dependencies = [ # enough to write scenes (glazed.io) in any research environment
22
+ "numpy>=1.21",
23
+ "tomli>=1.1; python_version < '3.11'",
24
+ ]
25
+
26
+ [project.optional-dependencies]
27
+ render = [ # the bpy wheels for Blender 5.x need Python 3.13
28
+ "bpy>=5.0",
29
+ "matplotlib>=3.8",
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/junha-l/glazed"
34
+ Issues = "https://github.com/junha-l/glazed/issues"
35
+
36
+ [project.scripts]
37
+ glazed = "glazed.cli:main"
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
41
+
42
+ [tool.setuptools.package-data]
43
+ glazed = ["preview.html"] # the --preview page
glazed-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ """glazed: studio-lit Cycles renders of point clouds, meshes, and scenes mixing both."""
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()