janction-render 0.3.4__tar.gz → 0.4.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.
- {janction_render-0.3.4 → janction_render-0.4.0}/PKG-INFO +4 -4
- {janction_render-0.3.4 → janction_render-0.4.0}/README.md +3 -3
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render/__init__.py +1 -1
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render/cli.py +6 -3
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render/client.py +4 -4
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render/mcp_app.html +2 -2
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render/mcp_server.py +10 -4
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/PKG-INFO +4 -4
- {janction_render-0.3.4 → janction_render-0.4.0}/pyproject.toml +1 -1
- {janction_render-0.3.4 → janction_render-0.4.0}/LICENSE +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render/brief.py +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/SOURCES.txt +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/dependency_links.txt +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/entry_points.txt +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/requires.txt +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/top_level.txt +0 -0
- {janction_render-0.3.4 → janction_render-0.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: janction-render
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Cloud GPU render farm for Blender, for AI agents: MCP server (remote + stdio) and CLI. Render Blender without a GPU from Claude, ChatGPT, Claude Code, Codex, Cursor.
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -114,7 +114,7 @@ Then, in Claude Code:
|
|
|
114
114
|
| `scene_info(scene_script | scene_url | scene_path | scene_id, assets?)` | cameras, frame range, fps, resolution, objects, lights, missing files. No render. |
|
|
115
115
|
| `render_preview(..., frames="1-24", environment?, blender?)` | up to 4 frames (720p budget) tiled with frame labels; returns the image inline |
|
|
116
116
|
| `render_estimate(scene_id, frame_start, frame_end, width, height, samples)` | GPU seconds, queue wait, "about N minutes", fits today's free quota? No GPU time used |
|
|
117
|
-
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?)` |
|
|
117
|
+
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?, engine?)` | frames (png / exr) or video (mp4 / webm / prores); returns job_id + estimate |
|
|
118
118
|
| `render_status(job_id)` | progress and ETA (`eta.human`); `render_download(job_id, only="mp4" / "frames" / "all")` files or links; `render_cancel(job_id)` |
|
|
119
119
|
| `billing()` | free-beta quota (used today, daily limit, reset time); later balance and top-up link |
|
|
120
120
|
| `render_info()` | workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
@@ -143,7 +143,7 @@ sun = bpy.data.objects.new("Sun", bpy.data.lights.new("Sun", "SUN"))
|
|
|
143
143
|
scene.collection.objects.link(sun)
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
The service sets engine (Cycles), resolution, samples and denoising; your script sets the scene, camera and frame range.
|
|
146
|
+
The service sets the engine (Cycles by default; `engine="eevee"` for cheaper animations: about half the per-frame cost after ~7 s of shader compilation per job), resolution, samples and denoising; your script sets the scene, camera and frame range. In Blender 5.0 materials always use nodes: set the Principled BSDF Base Color, not `diffuse_color`.
|
|
147
147
|
Scripts run in an isolated container with no network. See `samples/cube_scene.py`.
|
|
148
148
|
|
|
149
149
|
## HTTP API
|
|
@@ -153,7 +153,7 @@ POST /v1/keys -> {api_key} (header X-A
|
|
|
153
153
|
POST /v1/files multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...) -> {scene_id}
|
|
154
154
|
POST /v1/files/{id}/assets multipart "files" textures, glTF .bin ... GET /v1/files/lookup?sha256= reuse an upload
|
|
155
155
|
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota
|
|
156
|
-
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output,
|
|
156
|
+
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output (png|exr|mp4|webm|prores), engine (cycles|eevee),
|
|
157
157
|
environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}
|
|
158
158
|
GET /v1/jobs/{id} status, progress, eta, artifacts[], cost, warnings, info DELETE /v1/jobs/{id} cancel
|
|
159
159
|
GET /v1/jobs/{id}/artifacts/{name} PNG / MP4
|
|
@@ -97,7 +97,7 @@ Then, in Claude Code:
|
|
|
97
97
|
| `scene_info(scene_script | scene_url | scene_path | scene_id, assets?)` | cameras, frame range, fps, resolution, objects, lights, missing files. No render. |
|
|
98
98
|
| `render_preview(..., frames="1-24", environment?, blender?)` | up to 4 frames (720p budget) tiled with frame labels; returns the image inline |
|
|
99
99
|
| `render_estimate(scene_id, frame_start, frame_end, width, height, samples)` | GPU seconds, queue wait, "about N minutes", fits today's free quota? No GPU time used |
|
|
100
|
-
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?)` |
|
|
100
|
+
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?, engine?)` | frames (png / exr) or video (mp4 / webm / prores); returns job_id + estimate |
|
|
101
101
|
| `render_status(job_id)` | progress and ETA (`eta.human`); `render_download(job_id, only="mp4" / "frames" / "all")` files or links; `render_cancel(job_id)` |
|
|
102
102
|
| `billing()` | free-beta quota (used today, daily limit, reset time); later balance and top-up link |
|
|
103
103
|
| `render_info()` | workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
@@ -126,7 +126,7 @@ sun = bpy.data.objects.new("Sun", bpy.data.lights.new("Sun", "SUN"))
|
|
|
126
126
|
scene.collection.objects.link(sun)
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
The service sets engine (Cycles), resolution, samples and denoising; your script sets the scene, camera and frame range.
|
|
129
|
+
The service sets the engine (Cycles by default; `engine="eevee"` for cheaper animations: about half the per-frame cost after ~7 s of shader compilation per job), resolution, samples and denoising; your script sets the scene, camera and frame range. In Blender 5.0 materials always use nodes: set the Principled BSDF Base Color, not `diffuse_color`.
|
|
130
130
|
Scripts run in an isolated container with no network. See `samples/cube_scene.py`.
|
|
131
131
|
|
|
132
132
|
## HTTP API
|
|
@@ -136,7 +136,7 @@ POST /v1/keys -> {api_key} (header X-A
|
|
|
136
136
|
POST /v1/files multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...) -> {scene_id}
|
|
137
137
|
POST /v1/files/{id}/assets multipart "files" textures, glTF .bin ... GET /v1/files/lookup?sha256= reuse an upload
|
|
138
138
|
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota
|
|
139
|
-
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output,
|
|
139
|
+
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output (png|exr|mp4|webm|prores), engine (cycles|eevee),
|
|
140
140
|
environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}
|
|
141
141
|
GET /v1/jobs/{id} status, progress, eta, artifacts[], cost, warnings, info DELETE /v1/jobs/{id} cancel
|
|
142
142
|
GET /v1/jobs/{id}/artifacts/{name} PNG / MP4
|
|
@@ -79,7 +79,7 @@ def cmd_preview(c: Client, args: argparse.Namespace) -> int:
|
|
|
79
79
|
w, h = args.size
|
|
80
80
|
frames = parse_frames(args.frames, default=args.frame)
|
|
81
81
|
j = c.submit(sid, kind="preview", frames=frames, camera=args.camera, width=w, height=h,
|
|
82
|
-
samples=args.samples)
|
|
82
|
+
samples=args.samples, engine=args.engine)
|
|
83
83
|
print(f"job {j['job_id']} queued: frames {frames} (estimate ~{j['estimate']['seconds']}s)", file=sys.stderr)
|
|
84
84
|
j = c.wait(j["job_id"], timeout=args.timeout, on_progress=_progress)
|
|
85
85
|
if j["status"] != "done":
|
|
@@ -98,7 +98,7 @@ def cmd_render(c: Client, args: argparse.Namespace) -> int:
|
|
|
98
98
|
w, h = args.size
|
|
99
99
|
fs, fe = args.frames
|
|
100
100
|
j = c.submit(sid, kind="final", frame_start=fs, frame_end=fe, width=w, height=h,
|
|
101
|
-
samples=args.samples, fps=args.fps, output=args.output, camera=args.camera)
|
|
101
|
+
samples=args.samples, fps=args.fps, output=args.output, camera=args.camera, engine=args.engine)
|
|
102
102
|
print(f"job {j['job_id']} queued: {fe - fs + 1} frames in {j['progress']['chunks_total']} chunks, "
|
|
103
103
|
f"estimate ~{j['estimate']['seconds']}s", file=sys.stderr)
|
|
104
104
|
if not args.wait:
|
|
@@ -187,6 +187,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
187
187
|
s.add_argument("--camera", default=None)
|
|
188
188
|
s.add_argument("--size", type=_size, default=(1280, 720))
|
|
189
189
|
s.add_argument("--samples", type=int, default=16)
|
|
190
|
+
s.add_argument("--engine", choices=["cycles", "eevee"], default=None, help="cycles (default) or eevee (cheaper drafts)")
|
|
190
191
|
s.add_argument("--out", default=None)
|
|
191
192
|
s.add_argument("--timeout", type=float, default=300)
|
|
192
193
|
s.set_defaults(fn=cmd_preview)
|
|
@@ -197,8 +198,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
197
198
|
s.add_argument("--frames", type=_frames, required=True, help="e.g. 1-240 or 12")
|
|
198
199
|
s.add_argument("--size", type=_size, default=(1920, 1080))
|
|
199
200
|
s.add_argument("--samples", type=int, default=128)
|
|
201
|
+
s.add_argument("--engine", choices=["cycles", "eevee"], default=None, help="cycles (default) or eevee (cheaper drafts)")
|
|
200
202
|
s.add_argument("--fps", type=int, default=24)
|
|
201
|
-
s.add_argument("--output", choices=["auto", "png", "mp4"], default="auto"
|
|
203
|
+
s.add_argument("--output", choices=["auto", "png", "exr", "mp4", "webm", "prores"], default="auto",
|
|
204
|
+
help="png/exr = frames, mp4/webm/prores = video (auto: mp4 for a range, png for one frame)")
|
|
202
205
|
s.add_argument("--camera", default=None)
|
|
203
206
|
s.add_argument("--out", default=None)
|
|
204
207
|
s.add_argument("--wait", action="store_true", help="wait until done and download")
|
|
@@ -19,7 +19,7 @@ CACHE = Path.home() / ".janction-render.json"
|
|
|
19
19
|
|
|
20
20
|
# 送れるシーン: .blend、bpy スクリプト、こちらの Blender が読み込める 3D ファイル
|
|
21
21
|
SCENE_SUFFIXES = (".blend", ".py", ".fbx", ".glb", ".gltf", ".obj", ".stl", ".ply", ".usd", ".usda", ".usdc", ".usdz", ".abc")
|
|
22
|
-
ONLY_CHOICES = ("all", "mp4", "frames", "sheet", "output")
|
|
22
|
+
ONLY_CHOICES = ("all", "mp4", "frames", "sheet", "output", "video")
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def select_artifacts(artifacts: list[dict[str, Any]], only: Optional[str] = None) -> list[dict[str, Any]]:
|
|
@@ -27,14 +27,14 @@ def select_artifacts(artifacts: list[dict[str, Any]], only: Optional[str] = None
|
|
|
27
27
|
o = (only or "all").strip().lower()
|
|
28
28
|
if o in ("", "all"):
|
|
29
29
|
return list(artifacts)
|
|
30
|
-
if o
|
|
31
|
-
return [a for a in artifacts if a["name"].endswith(".mp4")]
|
|
30
|
+
if o in ("mp4", "video"):
|
|
31
|
+
return [a for a in artifacts if a["name"].endswith((".mp4", ".webm", ".mov"))]
|
|
32
32
|
if o == "frames":
|
|
33
33
|
return [a for a in artifacts if a["name"].startswith("frame_")]
|
|
34
34
|
if o == "sheet":
|
|
35
35
|
return [a for a in artifacts if a["name"] == "sheet.png"]
|
|
36
36
|
if o == "output":
|
|
37
|
-
picked = [a for a in artifacts if a["name"] in ("output.mp4", "sheet.png")]
|
|
37
|
+
picked = [a for a in artifacts if a["name"] in ("output.mp4", "output.webm", "output.mov", "sheet.png")]
|
|
38
38
|
return picked or [a for a in artifacts if a["name"].startswith("frame_")][:1]
|
|
39
39
|
raise ValueError("only must be one of: " + ", ".join(ONLY_CHOICES))
|
|
40
40
|
|
|
@@ -90,7 +90,7 @@ function render() {
|
|
|
90
90
|
if (state.image) html += `<img class="sheet" src="${state.image}" alt="render preview">`;
|
|
91
91
|
const out = job.output_url;
|
|
92
92
|
const links = job.links || {};
|
|
93
|
-
if (status === "done" && out && /\.mp4(\?|$)/.test(out)) {
|
|
93
|
+
if (status === "done" && out && /\.(mp4|webm|mov)(\?|$)/.test(out)) {
|
|
94
94
|
html += `<video controls playsinline src="${esc(out)}"></video>`;
|
|
95
95
|
}
|
|
96
96
|
if (status === "done" && isCompare(job)) {
|
|
@@ -99,7 +99,7 @@ function render() {
|
|
|
99
99
|
}
|
|
100
100
|
html += `<div class="row">`;
|
|
101
101
|
if (status === "queued" || status === "running") html += `<button data-act="refresh">Refresh</button>`;
|
|
102
|
-
if (status === "done" && out) html += `<button class="primary" data-open="${esc(out)}">Open ${/\.mp4/.test(out) ? "
|
|
102
|
+
if (status === "done" && out) html += `<button class="primary" data-open="${esc(out)}">Open ${/\.(mp4|webm|mov)/.test(out) ? "video" : "image"}</button>`;
|
|
103
103
|
const frameLinks = Object.entries(links).filter(([n]) => n.startsWith("frame_"));
|
|
104
104
|
if (status === "done" && frameLinks.length) html += `<button data-open="${esc(frameLinks[0][1])}">Open first frame</button>`;
|
|
105
105
|
if (status === "done" && job.kind === "preview") html += `<button data-say="This preview looks right. Please ask me about frames, resolution and samples, then render the final.">Looks good, go final</button><button data-say="Please adjust the scene and preview again.">Needs changes</button>`;
|
|
@@ -41,7 +41,8 @@ mcp = MCPServer(
|
|
|
41
41
|
"in one image; look at it, fix the scene, repeat) -> ask the user 'is this OK?' -> render_estimate (tell the "
|
|
42
42
|
"user how long it takes and whether it fits today's free quota) -> render_final (frames or MP4) -> "
|
|
43
43
|
"render_status / render_download. Always tell the user the time estimate (estimate.human / eta.human). "
|
|
44
|
-
"Blender 5.0 with Cycles on GPU (blender='5.2' selects Blender 5.2 when the worker has it)
|
|
44
|
+
"Blender 5.0 with Cycles on GPU (blender='5.2' selects Blender 5.2 when the worker has it); engine='eevee' switches to EEVEE "
|
|
45
|
+
"(about half the per-frame cost on animations of a few dozen frames or more; each job pays ~7 s of shader compilation, so previews stay on Cycles); output='png'|'exr' returns frames, 'mp4'|'webm'|'prores' a video. Blender 5.0 API notes for scripts: materials always use nodes, so set a color on the Principled BSDF (mat.node_tree.nodes['Principled BSDF'].inputs['Base Color'].default_value = (r, g, b, 1)); mat.diffuse_color only affects the viewport. Animate with obj.keyframe_insert(); obj.animation_data.action.fcurves no longer exists (set bpy.context.preferences.edit.keyframe_new_interpolation_type='LINEAR' before inserting keyframes for constant-speed motion); do not set Material.use_nodes; leave resolution, samples and denoising to the service. Inputs: a .blend, a bpy "
|
|
45
46
|
"script, or a 3D file (FBX, glTF/GLB, USD, OBJ, STL, PLY, Alembic) that is imported into an empty scene; images "
|
|
46
47
|
"and other assets can be sent with the scene (assets=[...]). environment='studio'|'sunset'|'overcast'|'night' "
|
|
47
48
|
"lights the scene with a bundled HDRI for a good-looking first render. Inputs and results are deleted 24 hours "
|
|
@@ -172,8 +173,11 @@ def _resolve_scene(c: Client, scene_path: str, scene_id: str, scene_script: str
|
|
|
172
173
|
return up["scene_id"]
|
|
173
174
|
|
|
174
175
|
|
|
175
|
-
def _job_params(environment: str, environment_strength: float, environment_visible: bool, blender: str
|
|
176
|
+
def _job_params(environment: str, environment_strength: float, environment_visible: bool, blender: str,
|
|
177
|
+
engine: str = "") -> dict[str, Any]:
|
|
176
178
|
out: dict[str, Any] = {}
|
|
179
|
+
if engine:
|
|
180
|
+
out["engine"] = engine
|
|
177
181
|
if environment:
|
|
178
182
|
out.update({"environment": environment, "environment_strength": environment_strength,
|
|
179
183
|
"environment_visible": environment_visible})
|
|
@@ -256,6 +260,7 @@ def render_preview(
|
|
|
256
260
|
orbit_elevation: float = 18.0,
|
|
257
261
|
orbit_target: str = "",
|
|
258
262
|
orbit_distance: float = 1.0,
|
|
263
|
+
engine: str = "",
|
|
259
264
|
) -> list[Any]:
|
|
260
265
|
"""Render a fast, cheap preview of a Blender scene on a JANCTION GPU and show the image.
|
|
261
266
|
|
|
@@ -276,7 +281,7 @@ def render_preview(
|
|
|
276
281
|
sid = _resolve_scene(c, scene_path, scene_id, scene_script, assets)
|
|
277
282
|
j = c.submit(sid, kind="preview", frames=frame_list, camera=camera or None,
|
|
278
283
|
width=width, height=height, samples=samples,
|
|
279
|
-
**_job_params(environment, environment_strength, environment_visible, blender),
|
|
284
|
+
**_job_params(environment, environment_strength, environment_visible, blender, engine=engine),
|
|
280
285
|
**({"orbit": True, "orbit_frames": orbit_frames, "orbit_elevation": orbit_elevation,
|
|
281
286
|
"orbit_target": orbit_target, "orbit_distance": orbit_distance} if orbit else {}))
|
|
282
287
|
_log(f"preview job {j['job_id']} submitted frames={frame_list}")
|
|
@@ -359,6 +364,7 @@ def render_final(
|
|
|
359
364
|
orbit_elevation: float = 18.0,
|
|
360
365
|
orbit_target: str = "",
|
|
361
366
|
orbit_distance: float = 1.0,
|
|
367
|
+
engine: str = "",
|
|
362
368
|
) -> str:
|
|
363
369
|
"""Render the final frames (or a video) of a Blender scene on JANCTION GPUs.
|
|
364
370
|
|
|
@@ -381,7 +387,7 @@ def render_final(
|
|
|
381
387
|
j = c.submit(sid, kind="final", frame_start=frame_start, frame_end=frame_end,
|
|
382
388
|
width=width, height=height, samples=samples, fps=fps, output=output,
|
|
383
389
|
camera=camera or None,
|
|
384
|
-
**_job_params(environment, environment_strength, environment_visible, blender), **extra)
|
|
390
|
+
**_job_params(environment, environment_strength, environment_visible, blender, engine=engine), **extra)
|
|
385
391
|
except ClientError as exc:
|
|
386
392
|
block = _payment_block(exc) or _quota_block(exc)
|
|
387
393
|
return _j(block if block else {"ok": False, "error": str(exc)})
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: janction-render
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Cloud GPU render farm for Blender, for AI agents: MCP server (remote + stdio) and CLI. Render Blender without a GPU from Claude, ChatGPT, Claude Code, Codex, Cursor.
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -114,7 +114,7 @@ Then, in Claude Code:
|
|
|
114
114
|
| `scene_info(scene_script | scene_url | scene_path | scene_id, assets?)` | cameras, frame range, fps, resolution, objects, lights, missing files. No render. |
|
|
115
115
|
| `render_preview(..., frames="1-24", environment?, blender?)` | up to 4 frames (720p budget) tiled with frame labels; returns the image inline |
|
|
116
116
|
| `render_estimate(scene_id, frame_start, frame_end, width, height, samples)` | GPU seconds, queue wait, "about N minutes", fits today's free quota? No GPU time used |
|
|
117
|
-
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?)` |
|
|
117
|
+
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?, engine?)` | frames (png / exr) or video (mp4 / webm / prores); returns job_id + estimate |
|
|
118
118
|
| `render_status(job_id)` | progress and ETA (`eta.human`); `render_download(job_id, only="mp4" / "frames" / "all")` files or links; `render_cancel(job_id)` |
|
|
119
119
|
| `billing()` | free-beta quota (used today, daily limit, reset time); later balance and top-up link |
|
|
120
120
|
| `render_info()` | workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
@@ -143,7 +143,7 @@ sun = bpy.data.objects.new("Sun", bpy.data.lights.new("Sun", "SUN"))
|
|
|
143
143
|
scene.collection.objects.link(sun)
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
-
The service sets engine (Cycles), resolution, samples and denoising; your script sets the scene, camera and frame range.
|
|
146
|
+
The service sets the engine (Cycles by default; `engine="eevee"` for cheaper animations: about half the per-frame cost after ~7 s of shader compilation per job), resolution, samples and denoising; your script sets the scene, camera and frame range. In Blender 5.0 materials always use nodes: set the Principled BSDF Base Color, not `diffuse_color`.
|
|
147
147
|
Scripts run in an isolated container with no network. See `samples/cube_scene.py`.
|
|
148
148
|
|
|
149
149
|
## HTTP API
|
|
@@ -153,7 +153,7 @@ POST /v1/keys -> {api_key} (header X-A
|
|
|
153
153
|
POST /v1/files multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...) -> {scene_id}
|
|
154
154
|
POST /v1/files/{id}/assets multipart "files" textures, glTF .bin ... GET /v1/files/lookup?sha256= reuse an upload
|
|
155
155
|
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota
|
|
156
|
-
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output,
|
|
156
|
+
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output (png|exr|mp4|webm|prores), engine (cycles|eevee),
|
|
157
157
|
environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}
|
|
158
158
|
GET /v1/jobs/{id} status, progress, eta, artifacts[], cost, warnings, info DELETE /v1/jobs/{id} cancel
|
|
159
159
|
GET /v1/jobs/{id}/artifacts/{name} PNG / MP4
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "janction-render"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.0"
|
|
8
8
|
description = "Cloud GPU render farm for Blender, for AI agents: MCP server (remote + stdio) and CLI. Render Blender without a GPU from Claude, ChatGPT, Claude Code, Codex, Cursor."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{janction_render-0.3.4 → janction_render-0.4.0}/janction_render.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|