janction-render 0.3.0__tar.gz → 0.3.2__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.0 → janction_render-0.3.2}/PKG-INFO +12 -6
- {janction_render-0.3.0 → janction_render-0.3.2}/README.md +11 -5
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render/__init__.py +1 -1
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render/client.py +66 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render/mcp_server.py +23 -7
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/PKG-INFO +12 -6
- {janction_render-0.3.0 → janction_render-0.3.2}/pyproject.toml +1 -1
- {janction_render-0.3.0 → janction_render-0.3.2}/LICENSE +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render/brief.py +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render/cli.py +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/SOURCES.txt +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/dependency_links.txt +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/entry_points.txt +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/requires.txt +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/top_level.txt +0 -0
- {janction_render-0.3.0 → janction_render-0.3.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: janction-render
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
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
|
|
@@ -25,7 +25,12 @@ without a GPU, or when rendering locally is slow.
|
|
|
25
25
|
|
|
26
26
|
- Input: a `.blend` file (textures travel with it), a **bpy Python script that builds the scene** (no local Blender
|
|
27
27
|
needed), or a **3D file** (glTF/GLB, FBX, USD, OBJ, STL, PLY, Alembic) that is imported into an empty scene.
|
|
28
|
-
- `environment="studio" | "sunset" | "overcast" | "night"` lights a scene with a bundled HDRI (CC0) for a good first render
|
|
28
|
+
- `environment="studio" | "sunset" | "overcast" | "night"` lights a scene with a bundled HDRI (CC0) for a good first render;
|
|
29
|
+
`environment="compare"` previews the same frame under all four presets in one labelled image, so the agent can pick one.
|
|
30
|
+
- A `.gltf` or `.obj` brings its `.bin` / `.mtl` / textures along automatically (from the same folder or the same URL folder).
|
|
31
|
+
- `orbit=True` turns any scene or imported model into a turntable: an orbit camera circles it once (`orbit_frames`, default 24;
|
|
32
|
+
a preview shows 0/90/180/270 degrees, a final render without `frame_end` gives the whole turn as an MP4).
|
|
33
|
+
- While a job renders, `render_status` counts finished frames inside the running chunk, so the ETA updates every few seconds.
|
|
29
34
|
- `scene_info` reads the scene without rendering (cameras, frame range, missing files).
|
|
30
35
|
- `render_preview` returns 1-4 low-cost frames tiled in one image within seconds, so the agent can look, fix, and repeat.
|
|
31
36
|
- `render_estimate` says how long a render will take ("about 3 minutes") and whether it fits today's free quota.
|
|
@@ -107,10 +112,11 @@ Then, in Claude Code:
|
|
|
107
112
|
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?)` | PNG or MP4; returns job_id + estimate |
|
|
108
113
|
| `render_status(job_id)` | progress and ETA (`eta.human`); `render_download(job_id, only="mp4" / "frames" / "all")` files or links; `render_cancel(job_id)` |
|
|
109
114
|
| `billing()` | free-beta quota (used today, daily limit, reset time); later balance and top-up link |
|
|
110
|
-
| `render_info()` | workers online, queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
115
|
+
| `render_info()` | workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
111
116
|
|
|
112
|
-
Options on `render_preview` / `render_final`: `environment` (`studio`, `sunset`, `overcast`, `night
|
|
113
|
-
`environment_visible=False` for a flat grey backdrop with HDRI lighting), `
|
|
117
|
+
Options on `render_preview` / `render_final`: `environment` (`studio`, `sunset`, `overcast`, `night`, `compare` on previews; `environment_strength`,
|
|
118
|
+
`environment_visible=False` for a flat grey backdrop with HDRI lighting), `orbit` / `orbit_frames` / `orbit_elevation` (turntable),
|
|
119
|
+
`blender` (`"5.2"`), and `assets` (stdio: local files
|
|
114
120
|
sent with the scene, found in the script through `os.environ["JR_ASSETS_DIR"]`; a `.blend`'s external files are collected
|
|
115
121
|
automatically with `pip install janction-render[blend]`) or `asset_urls` (remote).
|
|
116
122
|
|
|
@@ -143,7 +149,7 @@ POST /v1/files multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...) -> {scen
|
|
|
143
149
|
POST /v1/files/{id}/assets multipart "files" textures, glTF .bin ... GET /v1/files/lookup?sha256= reuse an upload
|
|
144
150
|
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota
|
|
145
151
|
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output,
|
|
146
|
-
environment, environment_strength, environment_visible, blender}
|
|
152
|
+
environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}
|
|
147
153
|
GET /v1/jobs/{id} status, progress, eta, artifacts[], cost, warnings, info DELETE /v1/jobs/{id} cancel
|
|
148
154
|
GET /v1/jobs/{id}/artifacts/{name} PNG / MP4
|
|
149
155
|
POST /mcp remote MCP (Streamable HTTP; Bearer api key or OAuth)
|
|
@@ -8,7 +8,12 @@ without a GPU, or when rendering locally is slow.
|
|
|
8
8
|
|
|
9
9
|
- Input: a `.blend` file (textures travel with it), a **bpy Python script that builds the scene** (no local Blender
|
|
10
10
|
needed), or a **3D file** (glTF/GLB, FBX, USD, OBJ, STL, PLY, Alembic) that is imported into an empty scene.
|
|
11
|
-
- `environment="studio" | "sunset" | "overcast" | "night"` lights a scene with a bundled HDRI (CC0) for a good first render
|
|
11
|
+
- `environment="studio" | "sunset" | "overcast" | "night"` lights a scene with a bundled HDRI (CC0) for a good first render;
|
|
12
|
+
`environment="compare"` previews the same frame under all four presets in one labelled image, so the agent can pick one.
|
|
13
|
+
- A `.gltf` or `.obj` brings its `.bin` / `.mtl` / textures along automatically (from the same folder or the same URL folder).
|
|
14
|
+
- `orbit=True` turns any scene or imported model into a turntable: an orbit camera circles it once (`orbit_frames`, default 24;
|
|
15
|
+
a preview shows 0/90/180/270 degrees, a final render without `frame_end` gives the whole turn as an MP4).
|
|
16
|
+
- While a job renders, `render_status` counts finished frames inside the running chunk, so the ETA updates every few seconds.
|
|
12
17
|
- `scene_info` reads the scene without rendering (cameras, frame range, missing files).
|
|
13
18
|
- `render_preview` returns 1-4 low-cost frames tiled in one image within seconds, so the agent can look, fix, and repeat.
|
|
14
19
|
- `render_estimate` says how long a render will take ("about 3 minutes") and whether it fits today's free quota.
|
|
@@ -90,10 +95,11 @@ Then, in Claude Code:
|
|
|
90
95
|
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?)` | PNG or MP4; returns job_id + estimate |
|
|
91
96
|
| `render_status(job_id)` | progress and ETA (`eta.human`); `render_download(job_id, only="mp4" / "frames" / "all")` files or links; `render_cancel(job_id)` |
|
|
92
97
|
| `billing()` | free-beta quota (used today, daily limit, reset time); later balance and top-up link |
|
|
93
|
-
| `render_info()` | workers online, queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
98
|
+
| `render_info()` | workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
94
99
|
|
|
95
|
-
Options on `render_preview` / `render_final`: `environment` (`studio`, `sunset`, `overcast`, `night
|
|
96
|
-
`environment_visible=False` for a flat grey backdrop with HDRI lighting), `
|
|
100
|
+
Options on `render_preview` / `render_final`: `environment` (`studio`, `sunset`, `overcast`, `night`, `compare` on previews; `environment_strength`,
|
|
101
|
+
`environment_visible=False` for a flat grey backdrop with HDRI lighting), `orbit` / `orbit_frames` / `orbit_elevation` (turntable),
|
|
102
|
+
`blender` (`"5.2"`), and `assets` (stdio: local files
|
|
97
103
|
sent with the scene, found in the script through `os.environ["JR_ASSETS_DIR"]`; a `.blend`'s external files are collected
|
|
98
104
|
automatically with `pip install janction-render[blend]`) or `asset_urls` (remote).
|
|
99
105
|
|
|
@@ -126,7 +132,7 @@ POST /v1/files multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...) -> {scen
|
|
|
126
132
|
POST /v1/files/{id}/assets multipart "files" textures, glTF .bin ... GET /v1/files/lookup?sha256= reuse an upload
|
|
127
133
|
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota
|
|
128
134
|
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output,
|
|
129
|
-
environment, environment_strength, environment_visible, blender}
|
|
135
|
+
environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}
|
|
130
136
|
GET /v1/jobs/{id} status, progress, eta, artifacts[], cost, warnings, info DELETE /v1/jobs/{id} cancel
|
|
131
137
|
GET /v1/jobs/{id}/artifacts/{name} PNG / MP4
|
|
132
138
|
POST /mcp remote MCP (Streamable HTTP; Bearer api key or OAuth)
|
|
@@ -39,6 +39,53 @@ def select_artifacts(artifacts: list[dict[str, Any]], only: Optional[str] = None
|
|
|
39
39
|
raise ValueError("only must be one of: " + ", ".join(ONLY_CHOICES))
|
|
40
40
|
|
|
41
41
|
|
|
42
|
+
def companion_refs(kind: str, text: str) -> list[str]:
|
|
43
|
+
"""glTF(JSON)か OBJ の中で参照している外部ファイルの相対パス(data: URI と絶対パスは除く)。
|
|
44
|
+
OBJ は mtllib の .mtl だけを返す(.mtl の中の画像は mtl_refs で)。"""
|
|
45
|
+
import json as _json
|
|
46
|
+
import re as _re
|
|
47
|
+
|
|
48
|
+
out: list[str] = []
|
|
49
|
+
|
|
50
|
+
def add(ref: str) -> None:
|
|
51
|
+
ref = (ref or "").strip().replace("\\", "/")
|
|
52
|
+
if not ref or ref.startswith(("data:", "http://", "https://", "/")) or ".." in ref.split("/"):
|
|
53
|
+
return
|
|
54
|
+
if ref not in out:
|
|
55
|
+
out.append(ref)
|
|
56
|
+
|
|
57
|
+
if kind == "gltf":
|
|
58
|
+
try:
|
|
59
|
+
doc = _json.loads(text)
|
|
60
|
+
except ValueError:
|
|
61
|
+
return out
|
|
62
|
+
for key in ("buffers", "images"):
|
|
63
|
+
for item in doc.get(key) or []:
|
|
64
|
+
if isinstance(item, dict) and isinstance(item.get("uri"), str):
|
|
65
|
+
add(item["uri"])
|
|
66
|
+
return out
|
|
67
|
+
if kind == "obj":
|
|
68
|
+
for line in text.splitlines():
|
|
69
|
+
parts = line.strip().split(None, 1)
|
|
70
|
+
if len(parts) == 2 and parts[0].lower() == "mtllib":
|
|
71
|
+
for name in parts[1].split():
|
|
72
|
+
add(name)
|
|
73
|
+
return out
|
|
74
|
+
if kind == "mtl":
|
|
75
|
+
for line in text.splitlines():
|
|
76
|
+
parts = line.strip().split()
|
|
77
|
+
if len(parts) >= 2 and parts[0].lower() in ("map_kd", "map_ks", "map_ka", "map_ns", "map_d", "map_bump", "bump",
|
|
78
|
+
"disp", "decal", "norm", "map_ke", "refl"):
|
|
79
|
+
add(parts[-1])
|
|
80
|
+
return out
|
|
81
|
+
return out
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def companion_kind(name: str) -> str:
|
|
85
|
+
ext = Path(name).suffix.lower()
|
|
86
|
+
return {".gltf": "gltf", ".obj": "obj", ".mtl": "mtl"}.get(ext, "")
|
|
87
|
+
|
|
88
|
+
|
|
42
89
|
def sha256_of(path: Path) -> str:
|
|
43
90
|
import hashlib
|
|
44
91
|
|
|
@@ -263,6 +310,25 @@ class Client:
|
|
|
263
310
|
missing: list[str] = []
|
|
264
311
|
if p.suffix.lower() == ".blend" and trace_assets:
|
|
265
312
|
items, missing = trace_blend_assets(p)
|
|
313
|
+
elif companion_kind(p.name) in ("gltf", "obj") and trace_assets:
|
|
314
|
+
# glTF の .bin と画像、OBJ の .mtl とその画像を、ファイルの横から集める
|
|
315
|
+
base = p.parent
|
|
316
|
+
queue = companion_refs(companion_kind(p.name), p.read_text(encoding="utf-8", errors="replace"))
|
|
317
|
+
seen: set[str] = set()
|
|
318
|
+
while queue:
|
|
319
|
+
rel = queue.pop(0)
|
|
320
|
+
if rel in seen:
|
|
321
|
+
continue
|
|
322
|
+
seen.add(rel)
|
|
323
|
+
fp = base / rel
|
|
324
|
+
if not fp.is_file():
|
|
325
|
+
missing.append(rel)
|
|
326
|
+
continue
|
|
327
|
+
items.append((rel, fp))
|
|
328
|
+
if companion_kind(rel) == "mtl":
|
|
329
|
+
folder = Path(rel).parent.as_posix()
|
|
330
|
+
for sub in companion_refs("mtl", fp.read_text(encoding="utf-8", errors="replace")):
|
|
331
|
+
queue.append(sub if folder in ("", ".") else f"{folder}/{sub}")
|
|
266
332
|
for a in assets or []:
|
|
267
333
|
ap = Path(a)
|
|
268
334
|
if not ap.is_file():
|
|
@@ -51,8 +51,12 @@ mcp = MCPServer(
|
|
|
51
51
|
),
|
|
52
52
|
)
|
|
53
53
|
|
|
54
|
+
ORBIT_DOC = (" orbit=True: turntable; an orbit camera circles the scene once over orbit_frames frames (default 24, "
|
|
55
|
+
"elevation orbit_elevation deg, default 18). A preview without frames shows 0/90/180/270 deg; a final without "
|
|
56
|
+
"frame_end renders the whole turn as an MP4. Best for imported models (.glb/.fbx/.obj).")
|
|
54
57
|
ENV_DOC = ("environment: '' keeps the scene's own world; 'studio' | 'sunset' | 'overcast' | 'night' replaces it with a "
|
|
55
|
-
"bundled HDRI (good first render for scenes without lighting work);
|
|
58
|
+
"bundled HDRI (good first render for scenes without lighting work); 'compare' (render_preview only) renders the "
|
|
59
|
+
"first frame under all four presets in one 2x2 image with labels, so you can pick one; environment_strength scales it (1.0); "
|
|
56
60
|
"environment_visible=False hides the HDRI from the camera (flat grey backdrop, HDRI lighting only). "
|
|
57
61
|
"blender: '' (5.0) or '5.2' to render with Blender 5.2 when available. assets: local files (images, glTF "
|
|
58
62
|
".bin, ...) sent along with the scene; a .blend finds them through relative paths, a script through "
|
|
@@ -82,7 +86,7 @@ def _quota_block(exc: ClientError) -> Optional[dict[str, Any]]:
|
|
|
82
86
|
x = exc.extra
|
|
83
87
|
return {"quota_exceeded": True, "detail": exc.detail, "scope": x.get("scope"),
|
|
84
88
|
"gpu_seconds_used_today": x.get("gpu_seconds_used_today"), "gpu_seconds_per_day": x.get("gpu_seconds_per_day"),
|
|
85
|
-
"resets_at": x.get("resets_at"),
|
|
89
|
+
"resets_at": x.get("resets_at_iso") or x.get("resets_at"),
|
|
86
90
|
"next": "tell the user today's free GPU time is used up and when it resets; a smaller job (fewer frames, "
|
|
87
91
|
"lower resolution or samples) may still fit"}
|
|
88
92
|
|
|
@@ -208,6 +212,9 @@ def render_preview(
|
|
|
208
212
|
environment_visible: bool = True,
|
|
209
213
|
blender: str = "",
|
|
210
214
|
assets: Optional[list[str]] = None,
|
|
215
|
+
orbit: bool = False,
|
|
216
|
+
orbit_frames: int = 24,
|
|
217
|
+
orbit_elevation: float = 18.0,
|
|
211
218
|
) -> list[Any]:
|
|
212
219
|
"""Render a fast, cheap preview of a Blender scene on a JANCTION GPU and show the image.
|
|
213
220
|
|
|
@@ -221,14 +228,15 @@ def render_preview(
|
|
|
221
228
|
Look at the returned image, fix the scene, preview again; when it looks right, ask the user and
|
|
222
229
|
call render_final. Returns scene_id (reuse it without re-uploading), job_id, saved PNG paths,
|
|
223
230
|
Blender warnings (e.g. missing textures), GPU seconds, and the expiry time (24h after last use).
|
|
224
|
-
""" + ENV_DOC
|
|
231
|
+
""" + ENV_DOC + ORBIT_DOC
|
|
225
232
|
c = _client()
|
|
226
233
|
try:
|
|
227
|
-
frame_list = parse_frames(frames)
|
|
234
|
+
frame_list = parse_frames(frames) if (frames or not orbit) else None
|
|
228
235
|
sid = _resolve_scene(c, scene_path, scene_id, scene_script, assets)
|
|
229
236
|
j = c.submit(sid, kind="preview", frames=frame_list, camera=camera or None,
|
|
230
237
|
width=width, height=height, samples=samples,
|
|
231
|
-
**_job_params(environment, environment_strength, environment_visible, blender)
|
|
238
|
+
**_job_params(environment, environment_strength, environment_visible, blender),
|
|
239
|
+
**({"orbit": True, "orbit_frames": orbit_frames, "orbit_elevation": orbit_elevation} if orbit else {}))
|
|
232
240
|
_log(f"preview job {j['job_id']} submitted frames={frame_list}")
|
|
233
241
|
j = c.wait(j["job_id"], timeout=PREVIEW_WAIT_S)
|
|
234
242
|
except ClientError as exc:
|
|
@@ -304,6 +312,9 @@ def render_final(
|
|
|
304
312
|
environment_visible: bool = True,
|
|
305
313
|
blender: str = "",
|
|
306
314
|
assets: Optional[list[str]] = None,
|
|
315
|
+
orbit: bool = False,
|
|
316
|
+
orbit_frames: int = 24,
|
|
317
|
+
orbit_elevation: float = 18.0,
|
|
307
318
|
) -> str:
|
|
308
319
|
"""Render the final frames (or a video) of a Blender scene on JANCTION GPUs.
|
|
309
320
|
|
|
@@ -313,14 +324,19 @@ def render_final(
|
|
|
313
324
|
(output='png'; 'auto' picks). Use the same environment / blender as the approved preview. Returns job_id and a
|
|
314
325
|
time estimate right away; the render runs in the background: poll with render_status, then fetch with
|
|
315
326
|
render_download. Inputs and results are deleted 24 hours after last use, so download them.
|
|
316
|
-
""" + ENV_DOC
|
|
327
|
+
""" + ENV_DOC + ORBIT_DOC
|
|
317
328
|
c = _client()
|
|
318
329
|
try:
|
|
319
330
|
sid = _resolve_scene(c, scene_path, scene_id, scene_script, assets)
|
|
331
|
+
extra: dict[str, Any] = {}
|
|
332
|
+
if orbit:
|
|
333
|
+
extra.update({"orbit": True, "orbit_frames": orbit_frames, "orbit_elevation": orbit_elevation})
|
|
334
|
+
if frame_end <= frame_start:
|
|
335
|
+
frame_end = None # type: ignore[assignment] # 1 周ぶんは受付が決める
|
|
320
336
|
j = c.submit(sid, kind="final", frame_start=frame_start, frame_end=frame_end,
|
|
321
337
|
width=width, height=height, samples=samples, fps=fps, output=output,
|
|
322
338
|
camera=camera or None,
|
|
323
|
-
**_job_params(environment, environment_strength, environment_visible, blender))
|
|
339
|
+
**_job_params(environment, environment_strength, environment_visible, blender), **extra)
|
|
324
340
|
except ClientError as exc:
|
|
325
341
|
block = _payment_block(exc) or _quota_block(exc)
|
|
326
342
|
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.
|
|
3
|
+
Version: 0.3.2
|
|
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
|
|
@@ -25,7 +25,12 @@ without a GPU, or when rendering locally is slow.
|
|
|
25
25
|
|
|
26
26
|
- Input: a `.blend` file (textures travel with it), a **bpy Python script that builds the scene** (no local Blender
|
|
27
27
|
needed), or a **3D file** (glTF/GLB, FBX, USD, OBJ, STL, PLY, Alembic) that is imported into an empty scene.
|
|
28
|
-
- `environment="studio" | "sunset" | "overcast" | "night"` lights a scene with a bundled HDRI (CC0) for a good first render
|
|
28
|
+
- `environment="studio" | "sunset" | "overcast" | "night"` lights a scene with a bundled HDRI (CC0) for a good first render;
|
|
29
|
+
`environment="compare"` previews the same frame under all four presets in one labelled image, so the agent can pick one.
|
|
30
|
+
- A `.gltf` or `.obj` brings its `.bin` / `.mtl` / textures along automatically (from the same folder or the same URL folder).
|
|
31
|
+
- `orbit=True` turns any scene or imported model into a turntable: an orbit camera circles it once (`orbit_frames`, default 24;
|
|
32
|
+
a preview shows 0/90/180/270 degrees, a final render without `frame_end` gives the whole turn as an MP4).
|
|
33
|
+
- While a job renders, `render_status` counts finished frames inside the running chunk, so the ETA updates every few seconds.
|
|
29
34
|
- `scene_info` reads the scene without rendering (cameras, frame range, missing files).
|
|
30
35
|
- `render_preview` returns 1-4 low-cost frames tiled in one image within seconds, so the agent can look, fix, and repeat.
|
|
31
36
|
- `render_estimate` says how long a render will take ("about 3 minutes") and whether it fits today's free quota.
|
|
@@ -107,10 +112,11 @@ Then, in Claude Code:
|
|
|
107
112
|
| `render_final(scene_id, frame_start, frame_end, width, height, samples, fps, output, environment?, blender?)` | PNG or MP4; returns job_id + estimate |
|
|
108
113
|
| `render_status(job_id)` | progress and ETA (`eta.human`); `render_download(job_id, only="mp4" / "frames" / "all")` files or links; `render_cancel(job_id)` |
|
|
109
114
|
| `billing()` | free-beta quota (used today, daily limit, reset time); later balance and top-up link |
|
|
110
|
-
| `render_info()` | workers online, queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
115
|
+
| `render_info()` | workers online or gated (GPU lent to another workload), queue, expected wait, supported inputs, environment presets, Blender versions |
|
|
111
116
|
|
|
112
|
-
Options on `render_preview` / `render_final`: `environment` (`studio`, `sunset`, `overcast`, `night
|
|
113
|
-
`environment_visible=False` for a flat grey backdrop with HDRI lighting), `
|
|
117
|
+
Options on `render_preview` / `render_final`: `environment` (`studio`, `sunset`, `overcast`, `night`, `compare` on previews; `environment_strength`,
|
|
118
|
+
`environment_visible=False` for a flat grey backdrop with HDRI lighting), `orbit` / `orbit_frames` / `orbit_elevation` (turntable),
|
|
119
|
+
`blender` (`"5.2"`), and `assets` (stdio: local files
|
|
114
120
|
sent with the scene, found in the script through `os.environ["JR_ASSETS_DIR"]`; a `.blend`'s external files are collected
|
|
115
121
|
automatically with `pip install janction-render[blend]`) or `asset_urls` (remote).
|
|
116
122
|
|
|
@@ -143,7 +149,7 @@ POST /v1/files multipart "file" (.blend|.py|.glb|.fbx|.usd|.obj|...) -> {scen
|
|
|
143
149
|
POST /v1/files/{id}/assets multipart "files" textures, glTF .bin ... GET /v1/files/lookup?sha256= reuse an upload
|
|
144
150
|
POST /v1/estimate {kind, frames|frame_start/frame_end, width, height, samples, scene_id?} -> seconds, wall_seconds, human, quota
|
|
145
151
|
POST /v1/jobs {scene_id, kind: info|preview|final, frames|frame_start/frame_end, width, height, samples, camera, fps, output,
|
|
146
|
-
environment, environment_strength, environment_visible, blender}
|
|
152
|
+
environment, environment_strength, environment_visible, blender, orbit, orbit_frames, orbit_elevation}
|
|
147
153
|
GET /v1/jobs/{id} status, progress, eta, artifacts[], cost, warnings, info DELETE /v1/jobs/{id} cancel
|
|
148
154
|
GET /v1/jobs/{id}/artifacts/{name} PNG / MP4
|
|
149
155
|
POST /mcp remote MCP (Streamable HTTP; Bearer api key or OAuth)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "janction-render"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.2"
|
|
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
|
|
File without changes
|
{janction_render-0.3.0 → janction_render-0.3.2}/janction_render.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|