<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: JANCTION Render</title>
    <description>The latest articles on DEV Community by JANCTION Render (@_903a3934b362f0afe2a8).</description>
    <link>https://dev.to/_903a3934b362f0afe2a8</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3202149%2Feb704b46-d350-4ee9-ad89-c8596a49e46e.png</url>
      <title>DEV Community: JANCTION Render</title>
      <link>https://dev.to/_903a3934b362f0afe2a8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_903a3934b362f0afe2a8"/>
    <language>en</language>
    <item>
      <title>White-background product shots for a whole catalog from GLB files: 9 products, 36 images in 44 seconds (measured)</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Wed, 21 Oct 2026 15:20:20 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/white-background-product-shots-for-a-whole-catalog-from-glb-files-9-products-36-images-in-44-887</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/white-background-product-shots-for-a-whole-catalog-from-glb-files-9-products-36-images-in-44-887</guid>
      <description>&lt;p&gt;If you sell physical products and already have 3D models (GLB, glTF, FBX, USD), you can turn every model into a set of product shots on a plain white background without opening Blender. This is how I did it with &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;JANCTION Render&lt;/a&gt;, and what it cost when I measured it on 2026-10-22.&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. Send a .blend file, a bpy script or a 3D file (glTF / FBX / USD) and get frames or an MP4 back. No local Blender or GPU is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  One request for the whole catalog
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /v1/batches&lt;/code&gt; takes up to 100 items. Each item points at a model; &lt;code&gt;defaults&lt;/code&gt; applies to all of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://render.janction.jp/v1/batches &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: &lt;/span&gt;&lt;span class="nv"&gt;$JANCTION_RENDER_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "defaults": {"kind": "final", "preset": "product", "background": "white"},
    "items": [
      {"ref": "bottle",  "scene_url": "https://example.com/models/bottle.glb"},
      {"ref": "speaker", "scene_url": "https://example.com/models/speaker.glb"},
      {"ref": "chair",   "scene_url": "https://example.com/models/chair.glb"}
    ]
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;preset: "product"&lt;/code&gt; renders 4 shots around the object (1440x1440, studio lighting, the object framed to its size).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;background: "white"&lt;/code&gt; makes only what the camera sees directly white. The lighting and the reflections on the product still come from the studio light, so metal and glass do not go flat. &lt;code&gt;"transparent"&lt;/code&gt; gives PNGs with alpha instead, and the default stays a neutral grey.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /v1/batches/{batch_id}&lt;/code&gt; returns the state of every item and its job id; each job lists its PNGs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;p&gt;I used 9 models from the Khronos glTF Sample Assets that are released as CC0: WaterBottle, BoomBox, Avocado, Lantern, SheenChair, ToyCar, Corset, BarramundiFish and GlassVaseFlowers. One batch request, a new key, the live service.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;images&lt;/td&gt;
&lt;td&gt;36 (9 products x 4 angles), 1440x1440 PNG, 128 samples&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;time from the request to the last image&lt;/td&gt;
&lt;td&gt;44 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU time&lt;/td&gt;
&lt;td&gt;118.2 GPU seconds in total (12.7 to 14.1 per product)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cost&lt;/td&gt;
&lt;td&gt;about 12 JPY at 0.1 JPY per GPU-second; with a new key it came out of the welcome credit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;failures&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;background&lt;/td&gt;
&lt;td&gt;the corner pixels are pure white (255, 255, 255)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same 9 products on the default grey background took 47 seconds and 136.1 GPU seconds the day before, so the white background does not cost more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things to know before you run your own catalog
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Glass on white has little contrast. For clear products, &lt;code&gt;background: "transparent"&lt;/code&gt; and your own backdrop may look better.&lt;/li&gt;
&lt;li&gt;The camera frames the whole model from each angle, so a long, thin object seen end-on comes out small in that shot (the fish in my test did in its first angle).&lt;/li&gt;
&lt;li&gt;A new key gets a welcome credit (100 JPY right away, 400 JPY more after saving a card that is not charged, valid 14 days). After that, renders use prepaid credit at 0.1 JPY per GPU-second.&lt;/li&gt;
&lt;li&gt;The farm has a small number of GPUs. When they are busy, items wait in the queue; the batch keeps going and reports each item when it finishes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  From an AI agent
&lt;/h2&gt;

&lt;p&gt;The same thing works from Claude, ChatGPT or any MCP client connected to &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt;: ask for product shots of a GLB and the agent calls &lt;code&gt;render_final&lt;/code&gt; with &lt;code&gt;preset="product"&lt;/code&gt;. The background option is on the HTTP API for now.&lt;/p&gt;

&lt;p&gt;Current prices and limits: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt; and &lt;a href="https://render.janction.jp/facts.json" rel="noopener noreferrer"&gt;https://render.janction.jp/facts.json&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>3d</category>
      <category>ecommerce</category>
      <category>blender</category>
      <category>api</category>
    </item>
    <item>
      <title>A Blender MCP server that tells your agent the price before it renders (real estimates, 48 to 1,800 frames)</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Wed, 21 Oct 2026 09:36:04 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/a-blender-mcp-server-that-tells-your-agent-the-price-before-it-renders-real-estimates-48-to-1800-4oac</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/a-blender-mcp-server-that-tells-your-agent-the-price-before-it-renders-real-estimates-48-to-1800-4oac</guid>
      <description>&lt;p&gt;&lt;em&gt;Update (2026-10-22): since the evening of 10/21, a key with no prepaid credit is no longer stopped for a small hold. When the estimate fits the free time left and only the 1.5x ceiling would not, the job runs free if that hold is 50 JPY or less, and the service covers any overrun. The 240-frame example below now runs with nothing held. Estimates also follow each key's own measured renders: on 10/22, another key that had rendered finals before got 488 GPU seconds ("about 2 minutes") for 240 frames and 3,661 GPU seconds ("about 15 minutes", 88 JPY held) for 1,800 frames.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you let an AI agent render Blender scenes on a cloud GPU, the question you want answered first is not "how fast" but "what will this cost me, and can it run away". This is how &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;JANCTION Render&lt;/a&gt; answers it, with estimates I took from the live service on 2026-10-21.&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. Send a .blend file, a bpy script or a 3D file (glTF / FBX / USD) and get frames or an MP4 back. No local Blender or GPU is needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The order the agent follows
&lt;/h2&gt;

&lt;p&gt;The MCP server's own instructions tell the agent to work in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;render_preview&lt;/code&gt; - a few frames in seconds, to check the scene&lt;/li&gt;
&lt;li&gt;ask the user&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render_estimate&lt;/code&gt; - when the job is long or the free time left is uncertain (no GPU used, nothing charged)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;render_final&lt;/code&gt; - with &lt;code&gt;max_yen&lt;/code&gt; as a ceiling if you want one&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;render_estimate&lt;/code&gt; takes the same arguments as the final render and returns time and money in one answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the estimates look like
&lt;/h2&gt;

&lt;p&gt;Same scene for all three (the public example &lt;code&gt;ex12_logo_ring_spin.py&lt;/code&gt;), a new key with its welcome credit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;request&lt;/th&gt;
&lt;th&gt;GPU seconds&lt;/th&gt;
&lt;th&gt;expected wait&lt;/th&gt;
&lt;th&gt;free time covers&lt;/th&gt;
&lt;th&gt;held from credit (ceiling)&lt;/th&gt;
&lt;th&gt;charged if it runs as estimated&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;48 frames, 1280x720&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;td&gt;"about 20 seconds"&lt;/td&gt;
&lt;td&gt;all of it&lt;/td&gt;
&lt;td&gt;0 JPY&lt;/td&gt;
&lt;td&gt;0 JPY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;240 frames, 1920x1080&lt;/td&gt;
&lt;td&gt;908&lt;/td&gt;
&lt;td&gt;"about 4 minutes"&lt;/td&gt;
&lt;td&gt;all of it&lt;/td&gt;
&lt;td&gt;37 JPY&lt;/td&gt;
&lt;td&gt;0 JPY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,800 frames, 1920x1080&lt;/td&gt;
&lt;td&gt;6,813&lt;/td&gt;
&lt;td&gt;"about 30 minutes"&lt;/td&gt;
&lt;td&gt;1,000 seconds&lt;/td&gt;
&lt;td&gt;872 JPY&lt;/td&gt;
&lt;td&gt;582 JPY&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few things in that table matter for an agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The hold is larger than the estimate. A render can take up to 1.5 times its estimate, so the service reserves that much from prepaid credit and only charges the time actually used. On the 240-frame job, the estimate fits the free time, but the 1.5x ceiling would not, so 37 JPY is held and 0 is expected to be charged.&lt;/li&gt;
&lt;li&gt;The answer includes the per-job and per-day limits that apply to the key (3,000 JPY per job and 10,000 JPY per day on this key), so the agent knows before it asks.&lt;/li&gt;
&lt;li&gt;When the scene has not been rendered as a final before, the estimate says so (&lt;code&gt;"confidence": "preliminary"&lt;/code&gt;) and asks for a short test render before trusting it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How close was it? Earlier the same day I rendered the 48-frame version of this scene for real: 89.39 GPU seconds against the 86 estimated. End to end it took 39 seconds, not 20: the estimate covers the queue and the render on the farm, and the 39 also includes the upload check and downloading 44 MB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ceilings and what happens without credit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;max_yen&lt;/code&gt; on &lt;code&gt;render_final&lt;/code&gt; refuses the job before anything is reserved if its hold would exceed the ceiling. &lt;code&gt;max_yen=0&lt;/code&gt; means "only if it fits the free time".&lt;/li&gt;
&lt;li&gt;If the key has no prepaid credit for the part beyond the free time, the job is not started (except the small holds of 50 JPY or less described in the update above). The agent gets a top-up link to show the user; it cannot pay by itself.&lt;/li&gt;
&lt;li&gt;Prices are 0.1 JPY per GPU-second. A new key gets a welcome credit (100 JPY right away, 400 JPY more after saving a card that is not charged, valid 14 days); after that, previews are free up to 120 GPU-seconds a day per key.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Asking for an estimate yourself
&lt;/h2&gt;

&lt;p&gt;Over HTTP it is one call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://render.janction.jp/v1/estimate &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"X-API-Key: &lt;/span&gt;&lt;span class="nv"&gt;$JANCTION_RENDER_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"scene_url": "https://render.janction.jp/samples/ex12_logo_ring_spin.py",
       "kind": "final", "frame_start": 1, "frame_end": 240,
       "width": 1920, "height": 1080, "output": "mp4"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fields to read are &lt;code&gt;human&lt;/code&gt; (the wait in words), &lt;code&gt;seconds&lt;/code&gt; (GPU seconds), and in &lt;code&gt;cost&lt;/code&gt;: &lt;code&gt;covered_by_free_yen&lt;/code&gt;, &lt;code&gt;max_charge_yen&lt;/code&gt; (the hold) and &lt;code&gt;estimated_yen&lt;/code&gt; (the expected charge).&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits worth knowing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A final can be up to 3,000 frames in one job, rendered in parts of 240 under one job id.&lt;/li&gt;
&lt;li&gt;1920x1080 on free time, up to 3840x2160 with prepaid credit.&lt;/li&gt;
&lt;li&gt;The farm has a small number of GPUs; when they are busy, the estimate's queue wait grows and the agent should tell the user rather than retry.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Connect it from Claude, ChatGPT or any MCP client at &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt;. Current prices and limits: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt; and &lt;a href="https://render.janction.jp/facts.json" rel="noopener noreferrer"&gt;https://render.janction.jp/facts.json&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blender</category>
      <category>mcp</category>
      <category>ai</category>
      <category>rendering</category>
    </item>
    <item>
      <title>Render Blender in GitHub Actions without a GPU: a preview on every push, a 48-frame MP4 in 39 seconds (measured)</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Wed, 21 Oct 2026 08:23:57 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/render-blender-in-github-actions-without-a-gpu-a-preview-on-every-push-a-48-frame-mp4-in-39-33c7</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/render-blender-in-github-actions-without-a-gpu-a-preview-on-every-push-a-48-frame-mp4-in-39-33c7</guid>
      <description>&lt;p&gt;GitHub's hosted runners have no GPU, and installing Blender on every run is slow. This is how I render a Blender scene from a workflow with &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;JANCTION Render&lt;/a&gt;, and what it cost when I measured it on 2026-10-21.&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. A workflow can call the same API through a GitHub Action. You send a .blend file, a bpy script or a 3D file (glTF / FBX / USD) and get frames or an MP4 back. No Blender or GPU is needed on the runner.&lt;/p&gt;

&lt;h2&gt;
  
  
  The workflow
&lt;/h2&gt;

&lt;p&gt;Add one secret, &lt;code&gt;JANCTION_RENDER_API_KEY&lt;/code&gt; (a new key comes from &lt;code&gt;curl -s -X POST https://render.janction.jp/v1/keys&lt;/code&gt;, no sign-up), and this file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;render&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scenes/**"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;preview&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JasmyLab-JANCTION/render-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.JANCTION_RENDER_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;scene-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scenes/logo_ring.py&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;preview&lt;/span&gt;
          &lt;span class="na"&gt;frames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1,13,25,37"&lt;/span&gt;     &lt;span class="c1"&gt;# up to 4 frames in one contact sheet&lt;/span&gt;
          &lt;span class="na"&gt;max-cost-yen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;          &lt;span class="c1"&gt;# free preview time only&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;render-preview&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;render-output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the video, switch to &lt;code&gt;kind: final&lt;/code&gt;, give a frame range and a cap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;JasmyLab-JANCTION/render-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;api-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.JANCTION_RENDER_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;scene-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scenes/logo_ring.py&lt;/span&gt;
          &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;final&lt;/span&gt;
          &lt;span class="na"&gt;frames&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-48"&lt;/span&gt;
          &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1280&lt;/span&gt;
          &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;720&lt;/span&gt;
          &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mp4&lt;/span&gt;
          &lt;span class="na"&gt;max-cost-yen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The action estimates first and stops before anything starts if the job could cost more than &lt;code&gt;max-cost-yen&lt;/code&gt;. The same cap goes with the job, so the service refuses it before any credit is held.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;p&gt;Scene: the public example &lt;code&gt;ex12_logo_ring_spin.py&lt;/code&gt; (a metal ring logo turning once in 48 frames; the script sets up its own lights and EEVEE). I ran the action's script, the same &lt;code&gt;render.sh&lt;/code&gt; the action runs, from a Windows PC against the live service with a new key.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;step&lt;/th&gt;
&lt;th&gt;result&lt;/th&gt;
&lt;th&gt;GPU seconds&lt;/th&gt;
&lt;th&gt;time, end to end&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;estimate (no GPU)&lt;/td&gt;
&lt;td&gt;"about 97 GPU seconds, about 25 seconds" for the final&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;preview, 4 frames, 1280x720&lt;/td&gt;
&lt;td&gt;contact sheet + 4 PNGs&lt;/td&gt;
&lt;td&gt;3.46&lt;/td&gt;
&lt;td&gt;11 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;final, 48 frames, 1280x720, 128 samples&lt;/td&gt;
&lt;td&gt;48 PNGs + MP4 (H.264, 24 fps, 48 frames)&lt;/td&gt;
&lt;td&gt;89.39&lt;/td&gt;
&lt;td&gt;39 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The 39 seconds include the upload check (the same file was already uploaded, so nothing was sent again), the render (48 frames in 5 chunks), and downloading 44 MB. The MP4 checked out with ffprobe as 1280x720, 24 fps, 48 frames.&lt;/p&gt;

&lt;p&gt;Cost: finals are 0.1 JPY per GPU-second, so the final was about 9 JPY of GPU time. With a new key it came out of the welcome credit (100 JPY right away, 400 JPY more after saving a card that is not charged, valid 14 days), so the job showed 0 JPY charged. After that, previews stay free up to 120 GPU-seconds a day per key, and finals use prepaid credit.&lt;/p&gt;

&lt;p&gt;Two things the numbers do not show:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first run on a fresh runner also installs the command line tool from PyPI into a virtual environment. That takes runner time (not GPU time) and is not in the table.&lt;/li&gt;
&lt;li&gt;The farm has a small number of GPUs. When they are busy, your job waits in the queue, and the action keeps waiting until &lt;code&gt;timeout-seconds&lt;/code&gt; (default 900). Only frames already rendered are charged if it times out.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits that matter in CI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A final can be up to 3,000 frames in one job; the service renders it in parts of 240 and returns one result.&lt;/li&gt;
&lt;li&gt;1920x1080 on free time, up to 3840x2160 with prepaid credit.&lt;/li&gt;
&lt;li&gt;Pull requests from forks: on &lt;code&gt;pull_request&lt;/code&gt; they get no secrets; on &lt;code&gt;pull_request_target&lt;/code&gt; the action refuses forks unless you set &lt;code&gt;allow-fork-pull-requests: true&lt;/code&gt;, because a fork could spend your credit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When this is not the right tool
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;If you need to edit a scene interactively, use Blender itself (or a local Blender MCP server).&lt;/li&gt;
&lt;li&gt;If your runner already has an NVIDIA GPU, rendering locally is faster.&lt;/li&gt;
&lt;li&gt;It renders with Blender's own engines (Cycles, EEVEE). Third-party renderers such as Arnold, Redshift or Octane are not available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The action is on the GitHub Marketplace as "JANCTION Render - Blender cloud GPU" (source: &lt;a href="https://github.com/JasmyLab-JANCTION/render-action" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/render-action&lt;/a&gt;). Pricing and the current limits are at &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt; and &lt;a href="https://render.janction.jp/facts.json" rel="noopener noreferrer"&gt;https://render.janction.jp/facts.json&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>blender</category>
      <category>githubactions</category>
      <category>ci</category>
      <category>rendering</category>
    </item>
    <item>
      <title>I turned a GLB into a product video from an AI chat: 5 seconds, about 60 JPY, and you only pay the GPU seconds used</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Tue, 13 Oct 2026 09:24:25 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/i-turned-a-glb-into-a-product-video-from-an-ai-chat-5-seconds-about-60-jpy-and-you-only-pay-the-3hp4</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/i-turned-a-glb-into-a-product-video-from-an-ai-chat-5-seconds-about-60-jpy-and-you-only-pay-the-3hp4</guid>
      <description>&lt;p&gt;I run JANCTION Render, a cloud GPU renderer for Blender that AI assistants call over MCP. Today I added Product Video on top of it: you give it a product 3D model (.glb, .fbx, .obj, .usdz) and it sends back a finished short video with captions and an end card, a 360 turntable, or four product images.&lt;/p&gt;

&lt;p&gt;What I measured on our GPUs today (Khronos sample models, CC0):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 s video at 1920x1080: about 220 GPU-seconds, about 2 minutes from order to delivery when the GPUs are free&lt;/li&gt;
&lt;li&gt;5 s 360 turntable, square: about 114 GPU-seconds&lt;/li&gt;
&lt;li&gt;four product images (front, three-quarter, side, back): 15 GPU-seconds&lt;/li&gt;
&lt;li&gt;caption or colour change on a delivered video: no re-render, 0 JPY&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How the price works. The GPU is billed at cost, the same 0.1 JPY per GPU-second as JANCTION Render, plus a fixed production fee for the compositing, captions, checks and the saved project (40 JPY for 5 s, 90 for 15 s, 160 for 30 s, 30 for a 5 s turntable, 20 for four images). The quote shows a maximum; on delivery you pay the fee plus the GPU seconds actually used, and the rest goes back to your balance. My first paid order today was quoted at a 61 JPY maximum and charged 53 JPY. Nothing is charged if it fails, and shots rendered before are reused without GPU cost.&lt;/p&gt;

&lt;p&gt;The flow an agent follows: plan_video (what can be made) -&amp;gt; quote_video (maximum, typical price, minutes) -&amp;gt; you say yes -&amp;gt; submit_video with the price you agreed to -&amp;gt; get_video_outputs. The server refuses an order whose price differs from the one shown, and you can set per-order and daily limits or require a human approval click above an amount. The MCP tools cannot change those limits.&lt;/p&gt;

&lt;p&gt;For shop and asset-store pages there is also a listing pack: the four images plus a 360 turntable of the same model in one quote, about 64 JPY.&lt;/p&gt;

&lt;p&gt;What it does not do: videos from text alone, people, live action. You need a 3D model; if you do not have one, try product=sample:water-bottle, which is free a few times per account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://render.janction.jp/video/" rel="noopener noreferrer"&gt;https://render.janction.jp/video/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blender</category>
      <category>ai</category>
      <category>mcp</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>The cheapest way to render a 1-minute Blender animation without buying a GPU: six options, with measured numbers</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Tue, 13 Oct 2026 05:51:45 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/the-cheapest-way-to-render-a-1-minute-blender-animation-without-buying-a-gpu-six-options-with-5341</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/the-cheapest-way-to-render-a-1-minute-blender-animation-without-buying-a-gpu-six-options-with-5341</guid>
      <description>&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update (2026-10-13): one instruction now takes up to 3,000 frames and a long final comes back as one joined MP4, so the one-minute render below is a single command. The first version of this post said to send six 240-frame parts and join six MP4s.&lt;/p&gt;

&lt;p&gt;Disclosure: this post comes from the team behind JANCTION Render, one of the six options below. The laptop and JANCTION Render numbers are our own measurements. For the other services we describe how they charge and what they ask of you, and link to them instead of quoting prices that change.&lt;/p&gt;

&lt;p&gt;Short answer: if waiting costs you nothing, the free routes are your own computer and SheepIt's volunteer farm. If you want the minute back the same day without setting up a machine, you pay for GPU time somewhere. On JANCTION Render, one minute of a simple scene at 1920x1080 and 128 samples comes to about 7,800 GPU-seconds, about 780 JPY (around $5), and a heavier scene such as Blender's Classroom demo to about 1,290 JPY (around $8).&lt;/p&gt;

&lt;h2&gt;
  
  
  What "one minute" means
&lt;/h2&gt;

&lt;p&gt;At 24 fps, one minute is 1,440 frames. Every option below comes down to how long one frame takes, times 1,440, and who pays for that time. Resolution and Cycles samples move the number more than anything else, so settle them before comparing: denoising with fewer samples often looks the same as many samples without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Your own computer first (free, slow)
&lt;/h2&gt;

&lt;p&gt;Before paying anyone, make sure Cycles uses the GPU you already have: Edit &amp;gt; Preferences &amp;gt; System &amp;gt; Cycles Render Devices, then Metal on Apple silicon Macs, HIP on recent AMD GPUs, oneAPI on Intel Arc, CUDA or OptiX on NVIDIA, and set Render Properties &amp;gt; Device to GPU Compute. For drafts, EEVEE is much faster than Cycles.&lt;/p&gt;

&lt;p&gt;What it costs in time, measured on a simple scene (a rotating cube) on a laptop with a Core Ultra 9 386H: 20.0 seconds per frame on the CPU at 1920x1080 and 128 samples, so about 8 hours for the minute, and 6.6 seconds per frame at 1280x720 and 64 samples, about 2.6 hours. The same laptop's GeForce RTX 5070 Ti took 6.0 and 2.5 seconds per frame: about 2.4 hours and 1 hour. These are single frames multiplied by 1,440; a real scene with more geometry, textures and light bounces takes longer.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. SheepIt Render Farm (free, you wait)
&lt;/h2&gt;

&lt;p&gt;SheepIt is a free, community-run farm: your frames render on volunteers' computers, and letting your own machine render for others earns points that move your projects up the queue. It costs nothing but waiting. Your .blend is opened on other people's machines, so it suits personal projects better than client work under an NDA. &lt;a href="https://www.sheepit-renderfarm.com" rel="noopener noreferrer"&gt;https://www.sheepit-renderfarm.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Google Colab notebooks (free GPU when one is available)
&lt;/h2&gt;

&lt;p&gt;Several open-source notebooks install Blender on a Colab GPU and render a .blend from your Google Drive. It is free when a GPU is available, but free-tier GPUs and session length are not guaranteed, long renders get disconnected, and you set up and watch each run. Read Colab's terms before relying on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Rent a GPU by the hour (RunPod, Vast.ai and similar)
&lt;/h2&gt;

&lt;p&gt;You start a machine with a GPU, install Blender, upload the file, render, download and stop the machine. You pay for every hour the machine is on, including setup, uploads and the evening you forget to stop it, and everything on it is yours to manage.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Commercial render farms (GarageFarm, RebusFarm, Fox Renderfarm and others)
&lt;/h2&gt;

&lt;p&gt;You upload the .blend through their site or plugin and they render on many machines at once, so a minute comes back fast. They charge by node-hour or GHz-hour, show an estimate before you start, and several offer trial credit. For heavy production scenes they are the strongest option; for a short one-off they can be more than you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. A per-second GPU API (JANCTION Render)
&lt;/h2&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API, and that you can also call from a terminal or a script. You send a .blend, a bpy script or a 3D file (glTF / FBX / USD / OBJ), get a preview in seconds, then the frames or an MP4. You pay for the GPU-seconds actually used, 0.1 JPY per GPU-second.&lt;/p&gt;

&lt;p&gt;Measured per frame on its GPU (from 24-frame batches, including Blender start-up and scene loading, so a long run comes out a little lower), times 1,440:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;simple scene, 1280x720, 64 samples: 2.46 GPU-seconds per frame, 3,542 GPU-seconds for the minute, about 354 JPY (about $2.2)&lt;/li&gt;
&lt;li&gt;simple scene, 1920x1080, 128 samples: 5.39 per frame, 7,762 for the minute, about 776 JPY (about $4.9)&lt;/li&gt;
&lt;li&gt;Blender's Classroom demo, 1920x1080, 128 samples with denoising: 8.93 per frame, 12,859 for the minute, about 1,286 JPY (about $8.1)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dollar figures use 158 JPY per USD (ECB reference rate, 2026-10-09); charges are in JPY.&lt;/p&gt;

&lt;p&gt;Each new key gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card), for 14 days. That covers the 720p minute above. After it, previews stay free up to 2 GPU-minutes a day and finals are paid from prepaid credit.&lt;/p&gt;

&lt;p&gt;Limits worth knowing before you start: 1920x1080 on free time and up to 3840x2160 on prepaid credit; one instruction takes up to 3,000 frames, rendered as 240-frame parts under one job id and joined into one MP4, so a one-minute animation comes back as one file; at most 10 GPU-hours per job; files are deleted 24 hours after last use (7 days for keys that have topped up). Jobs run on JANCTION's own GPUs and wait in a queue when they are busy, and &lt;a href="https://render.janction.jp/status" rel="noopener noreferrer"&gt;https://render.janction.jp/status&lt;/a&gt; shows the wait.&lt;/p&gt;

&lt;p&gt;From a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;janction-render
janction-render preview minute.blend
janction-render estimate minute.blend &lt;span class="nt"&gt;--frames&lt;/span&gt; 1-1440 &lt;span class="nt"&gt;--size&lt;/span&gt; 1920x1080
janction-render render minute.blend &lt;span class="nt"&gt;--frames&lt;/span&gt; 1-1440 &lt;span class="nt"&gt;--output&lt;/span&gt; mp4 &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first janction-render command makes a free key, the preview comes back in seconds, the estimate shows the GPU-seconds and the price before anything runs, and the render waits for the whole minute and downloads it as one joined MP4.&lt;/p&gt;

&lt;p&gt;From an AI agent: add &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt; as a connector in Claude or ChatGPT, or run &lt;code&gt;claude mcp add --transport http janction-render https://render.janction.jp/mcp&lt;/code&gt; in Claude Code, then ask for a preview of the scene and the minute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Money for the minute&lt;/th&gt;
&lt;th&gt;Your effort&lt;/th&gt;
&lt;th&gt;Time until you have it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Own laptop, CPU (simple scene, 1080p, 128 samples)&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;set and leave&lt;/td&gt;
&lt;td&gt;about 8 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Own laptop, RTX 5070 Ti (same scene)&lt;/td&gt;
&lt;td&gt;none&lt;/td&gt;
&lt;td&gt;set and leave&lt;/td&gt;
&lt;td&gt;about 2.4 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SheepIt&lt;/td&gt;
&lt;td&gt;none (you earn points)&lt;/td&gt;
&lt;td&gt;upload&lt;/td&gt;
&lt;td&gt;depends on the queue and your points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Colab notebook&lt;/td&gt;
&lt;td&gt;none on the free tier&lt;/td&gt;
&lt;td&gt;set up and watch each run&lt;/td&gt;
&lt;td&gt;disconnections on long runs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hourly GPU rental&lt;/td&gt;
&lt;td&gt;per hour the machine is on&lt;/td&gt;
&lt;td&gt;run the machine yourself&lt;/td&gt;
&lt;td&gt;as fast as the GPU you rent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commercial farm&lt;/td&gt;
&lt;td&gt;per node-hour or GHz-hour&lt;/td&gt;
&lt;td&gt;upload through their site or plugin&lt;/td&gt;
&lt;td&gt;fast, many machines at once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JANCTION Render&lt;/td&gt;
&lt;td&gt;about 354 to 1,286 JPY (measured scenes above)&lt;/td&gt;
&lt;td&gt;a command or a chat&lt;/td&gt;
&lt;td&gt;queue when the GPUs are busy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Measurements: &lt;a href="https://render.janction.jp/benchmarks" rel="noopener noreferrer"&gt;https://render.janction.jp/benchmarks&lt;/a&gt;. Cost per frame and per animation: &lt;a href="https://render.janction.jp/blender-render-cost" rel="noopener noreferrer"&gt;https://render.janction.jp/blender-render-cost&lt;/a&gt;. Prices: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;. Checked on 2026-10-13.&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;. Code and client: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blender</category>
      <category>gpu</category>
      <category>cloud</category>
      <category>3d</category>
    </item>
    <item>
      <title>Add 3D product shots to your app in 40 lines: upload, a fixed-price order, a webhook (JANCTION Render, FastAPI)</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:25:47 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/add-3d-product-shots-to-your-app-in-40-lines-upload-a-fixed-price-order-a-webhook-janction-3eej</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/add-3d-product-shots-to-your-app-in-40-lines-upload-a-fixed-price-order-a-webhook-janction-3eej</guid>
      <description>&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Short answer: if your users upload 3D models, you do not need a GPU to show them rendered. Upload the file to a render API, order four product shots at a price you know before anything runs, and receive one webhook when the images are ready. JANCTION Render is a cloud GPU render farm for Blender that code and AI agents call as an HTTP API or an MCP server. Four 1440x1440 product shots of the Khronos WaterBottle sample took 13.9 GPU-seconds on it, about 1.4 JPY at 0.1 JPY per GPU-second; a 24-frame 720p turntable of the same file took 85.2 GPU-seconds, about 8.5 JPY.&lt;/p&gt;

&lt;p&gt;This post is the complete server side: a FastAPI app that takes a GLB from a user, orders the shots, and stores the links when the webhook arrives. The same code is in the API guide at &lt;a href="https://render.janction.jp/blender-render-api#embed" rel="noopener noreferrer"&gt;https://render.janction.jp/blender-render-api#embed&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The app
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# pip install fastapi httpx uvicorn
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UploadFile&lt;/span&gt;

&lt;span class="n"&gt;JR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://render.janction.jp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JANCTION_RENDER_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;# one key for your app: POST /v1/keys creates it, GET /v1/me shows the credit
&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-API-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;                      &lt;span class="c1"&gt;# your database in real life
&lt;/span&gt;
&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/products/{sku}/shots&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;# your user uploads a GLB; you order 4 product shots
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;order_shots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;UploadFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;up&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1/files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
        &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                      &lt;span class="c1"&gt;# 100 MB per upload; a larger model goes in as a link (scene_url)
&lt;/span&gt;        &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1/outcomes/product-shot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                          &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Idempotency-Key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shots-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                          &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;square&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transparent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;notify_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jr_done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))})&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                       &lt;span class="c1"&gt;# credit is short: send the user to r.json()["checkout_url"], then retry
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;credit&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pay_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;checkout_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                                   &lt;span class="c1"&gt;# j["outcome"]["price_yen"] is the ceiling; you pay the GPU seconds used
&lt;/span&gt;    &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sku&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ceiling_yen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price_yen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ceiling_yen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price_yen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/jr/done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;jr_done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;# JANCTION Render POSTs here once, when the job is done or failed
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;jr_done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                    &lt;span class="c1"&gt;# {"event": "job.done" | "job.failed", "job_id": ..., "artifacts": [...]}
&lt;/span&gt;    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;jr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/v1/jobs/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;# read it back with your key; do not trust the body
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;                      &lt;span class="c1"&gt;# view_url links last 24 hours: copy the images to your own storage
&lt;/span&gt;        &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;done&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;images&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;view_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;artifacts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;endswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)])&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]].&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;why&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}).&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it with &lt;code&gt;uvicorn app:app&lt;/code&gt; behind an https address (the webhook URL must be https), and &lt;code&gt;curl -X POST https://render.janction.jp/v1/keys&lt;/code&gt; once to get the key for &lt;code&gt;JANCTION_RENDER_API_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each line relies on
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;POST /v1/outcomes/product-shot&lt;/code&gt; is a fixed-price order: four PNGs at 0, 90, 180 and 270 degrees on a plain backdrop, framed at the model's real size, studio light. The reply carries &lt;code&gt;outcome.price_yen&lt;/code&gt;, the ceiling, before anything renders; the job then charges only the GPU seconds it used, never more than the ceiling. &lt;code&gt;turntable&lt;/code&gt; is the other order, a 360-degree MP4.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Idempotency-Key&lt;/code&gt; makes a retried request return the first job instead of rendering twice. Here it is the SKU plus a hash of the file, so the same upload for the same product is always the same job.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;notify_url&lt;/code&gt; gets exactly one POST when the job is done or failed, with the download links in the body. The handler reads the job back with the key anyway, so a forged POST to your webhook changes nothing.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;view_url&lt;/code&gt; links open without a key and expire after 24 hours. Copy the images to your storage in the handler; the orders dict here is a stand-in for that.&lt;/li&gt;
&lt;li&gt;A 402 means the key's credit does not cover the order. The reply has &lt;code&gt;checkout_url&lt;/code&gt;, a Stripe page for a top-up from 500 JPY, and after paying the same request goes through. For an app that must not stop, a saved card can top up by itself (&lt;code&gt;POST /v1/billing/autocharge&lt;/code&gt;), and &lt;code&gt;POST /v1/me/limits&lt;/code&gt; caps what a key may spend per job and per day.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Many models at once
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;POST /v1/batches&lt;/code&gt; takes up to 100 items, each with its own &lt;code&gt;scene_url&lt;/code&gt; or &lt;code&gt;scene_id&lt;/code&gt;, one outcome for all of them and one &lt;code&gt;notify_url&lt;/code&gt;. Items that fail get their own error while the rest continue, and &lt;code&gt;POST /v1/batches/{id}/retry&lt;/code&gt; sends only the failures again.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;A new key starts with 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card): up to 500 JPY, or 5,000 GPU-seconds, for 14 days. After that, previews stay free up to 2 GPU-minutes a day and everything else is 0.1 JPY per GPU-second from prepaid credit. At the measured 13.9 GPU-seconds per set of four shots, the welcome credit covers about 350 products; after it, a set is about 1.4 JPY. Prices: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;. Per-order ceilings: &lt;a href="https://render.janction.jp/products" rel="noopener noreferrer"&gt;https://render.janction.jp/products&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One thing to know before you plan around it: the service runs on a small number of GPUs today, so a burst of orders waits in a queue. &lt;code&gt;GET /v1/health&lt;/code&gt; shows how many workers are free, and the job's &lt;code&gt;eta&lt;/code&gt; says how long the wait is expected to be.&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>webdev</category>
      <category>blender</category>
    </item>
    <item>
      <title>Rendering Blender without an NVIDIA GPU (MacBook, laptop, headless server): measured cost per frame</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Fri, 09 Oct 2026 14:18:43 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/rendering-blender-without-an-nvidia-gpu-macbook-laptop-headless-server-measured-cost-per-frame-3c5k</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/rendering-blender-without-an-nvidia-gpu-macbook-laptop-headless-server-measured-cost-per-frame-3c5k</guid>
      <description>&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update (2026-10-14): one instruction now renders up to 3,000 frames (in parts of 240 under one job id), and up to 4K on prepaid credit. The limits below were updated to match.&lt;/p&gt;

&lt;p&gt;Update (2026-10-12): the welcome credit changed on 2026-10-12. A new key now gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card), up to 500 JPY in all. The prices below were updated to match &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Short answer: keep editing on your machine and send the render to a GPU somewhere else. JANCTION Render is a cloud GPU render farm for Blender that takes a .blend or a bpy script and returns frames or an MP4. On it, Blender's own Classroom demo scene rendered at 1920x1080 with 128 Cycles samples and denoising in 8.93 GPU-seconds per frame, which is 0.89 JPY per frame, and the Barcelona Pavillion demo in 10.55 GPU-seconds (1.05 JPY). A simple 24-frame 1280x720 animation at 64 samples took about 59 GPU-seconds. Each new key gets 100 JPY of GPU time free with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card): up to 500 JPY, or 5,000 GPU-seconds, for 14 days.&lt;/p&gt;

&lt;h2&gt;
  
  
  If Cycles is slow on your MacBook
&lt;/h2&gt;

&lt;p&gt;Try the free fixes on the Mac first. Cycles can use the Apple GPU through Metal (Preferences, System, Cycles Render Devices). EEVEE is much faster for drafts. Fewer samples with denoising often look the same as many samples without it.&lt;/p&gt;

&lt;p&gt;When the final still takes hours, move only the final. You keep working while it renders, and you pay per GPU-second instead of keeping a machine busy.&lt;/p&gt;

&lt;h2&gt;
  
  
  If your laptop has no NVIDIA GPU
&lt;/h2&gt;

&lt;p&gt;Send the file. There are three ways in, depending on where you work.&lt;/p&gt;

&lt;p&gt;From a chat app such as Claude.ai or ChatGPT: add &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt; as a connector, drop the .blend at &lt;a href="https://render.janction.jp/upload" rel="noopener noreferrer"&gt;https://render.janction.jp/upload&lt;/a&gt; (the link is valid for 12 hours), paste the link and ask for a preview, then the animation.&lt;/p&gt;

&lt;p&gt;From a terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;janction-render
janction-render preview scene.blend
janction-render render scene.blend &lt;span class="nt"&gt;--frames&lt;/span&gt; 1-48 &lt;span class="nt"&gt;--size&lt;/span&gt; 1280x720 &lt;span class="nt"&gt;--output&lt;/span&gt; mp4 &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command creates a free key. The preview comes back in seconds, and the render command waits for the MP4 and downloads it.&lt;/p&gt;

&lt;h2&gt;
  
  
  From a headless server or a script
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;blender -b scene.blend -a&lt;/code&gt; works on a server only if Blender is installed there and, for reasonable speed, a GPU that Cycles supports is attached. Without either, the same job goes to the HTTP API or the Python client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;janction_render.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                                   &lt;span class="c1"&gt;# or Client(api_key="jr_...")
&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;# a bpy script, a .blend, or a .glb / .fbx / .usd / .obj file
&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bpy script only builds the scene, the camera and the frame range; the service sets resolution, samples and the GPU. Blender 5.0 and 5.2 are available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it cheap?
&lt;/h2&gt;

&lt;p&gt;It costs 0.1 JPY per GPU-second, and the GPU seconds include Blender starting and loading the scene. From the measurements above, a 1080p frame of a demo-scene-sized file is about 1 JPY, and a 24-frame 720p clip of a simple scene is about 6 JPY. Previews are free up to 2 GPU-minutes a day after the welcome credit, so checking a scene usually costs nothing. Each key has a spending cap per job and per day, and a job that needs more credit than the key has is refused before it runs.&lt;/p&gt;

&lt;p&gt;The numbers and the scripts that produced them: &lt;a href="https://render.janction.jp/benchmarks" rel="noopener noreferrer"&gt;https://render.janction.jp/benchmarks&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;One instruction goes up to 3,000 frames (parts of 240 under one job id, so a one-minute animation comes back as one file), 1080p on free time and up to 4K on prepaid credit. Inputs and results are deleted 24 hours after last use (7 days for keys that have topped up). When JANCTION's GPUs are busy, a job waits in a queue, and the status page says so.&lt;/p&gt;

&lt;p&gt;More: &lt;a href="https://render.janction.jp/render-blender-without-gpu" rel="noopener noreferrer"&gt;https://render.janction.jp/render-blender-without-gpu&lt;/a&gt;, &lt;a href="https://render.janction.jp/render-blender-animation-online" rel="noopener noreferrer"&gt;https://render.janction.jp/render-blender-animation-online&lt;/a&gt; and &lt;a href="https://render.janction.jp/blender-render-cost" rel="noopener noreferrer"&gt;https://render.janction.jp/blender-render-cost&lt;/a&gt;. Prices: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;. Code and client: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blender</category>
      <category>python</category>
      <category>gpu</category>
      <category>cloud</category>
    </item>
    <item>
      <title>GLB to a 360-degree turntable MP4 and four product shots, one API call each (measured)</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Fri, 09 Oct 2026 10:09:25 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/glb-to-a-360-degree-turntable-mp4-and-four-product-shots-one-api-call-each-measured-2g9b</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/glb-to-a-360-degree-turntable-mp4-and-four-product-shots-one-api-call-each-measured-2g9b</guid>
      <description>&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update (2026-10-14): one instruction now renders up to 3,000 frames (in parts of 240 under one job id), and up to 4K on prepaid credit. The limits below were updated to match.&lt;/p&gt;

&lt;p&gt;Update (2026-10-12): the welcome credit changed on 2026-10-12. A new key now gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card), up to 500 JPY in all. The prices below were updated to match &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Short answer: upload the model, then order a turntable or product shots from a render API. JANCTION Render is a cloud GPU render farm for Blender that code and AI agents call. On it, a 24-frame 720p turntable of the Khronos glTF sample Duck took 42.56 GPU-seconds, and four 1440x1440 product shots with a transparent background took 12.73 GPU-seconds. At 0.1 JPY per GPU-second that is about 4 JPY and about 1 JPY, and each new key gets 100 JPY of GPU time free with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card).&lt;/p&gt;

&lt;h2&gt;
  
  
  The code
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pip install janction-render&lt;/code&gt;. The first call creates a free key and keeps it in &lt;code&gt;~/.janction-render.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;janction_render.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product.glb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                  &lt;span class="c1"&gt;# .glb, .gltf, .fbx, .usd or .obj, or a .blend
&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;turntable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;720p&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;outcome&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;price_yen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;               &lt;span class="c1"&gt;# the price ceiling, known before anything renders
&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;shots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;product-shot&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;square&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transparent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;shots&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;900&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shots&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shots&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;frames&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;    &lt;span class="c1"&gt;# 0, 90, 180 and 270 degrees
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same two orders exist in the HTTP API (&lt;code&gt;POST /v1/files&lt;/code&gt;, then &lt;code&gt;POST /v1/outcomes/turntable&lt;/code&gt; or &lt;code&gt;POST /v1/outcomes/product-shot&lt;/code&gt;) and in the CLI (&lt;code&gt;janction-render outcomes&lt;/code&gt; lists them).&lt;/p&gt;

&lt;h2&gt;
  
  
  What the two orders do
&lt;/h2&gt;

&lt;p&gt;A turntable is one full rotation with an orbiting camera at 24 fps, in studio light unless you pick sunset, overcast or night. It comes in 720p or 1080p with 24, 48 or 96 frames. The camera sits 18 degrees above the model by default, and &lt;code&gt;orbit_target&lt;/code&gt; centres it on one object when the file has several.&lt;/p&gt;

&lt;p&gt;Product shots are four stills at 0, 90, 180 and 270 degrees, 1080p or square, with an optional transparent background.&lt;/p&gt;

&lt;p&gt;The price is known before the render starts and works as a ceiling. A 720p turntable is at most 9, 16 or 30 JPY for 24, 48 or 96 frames, a 1080p one 16, 30 or 59 JPY, and product shots 6 JPY. The ceiling is reserved first, you pay the GPU seconds actually used up to it, and nothing is charged while the free GPU time covers the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measured on the Duck
&lt;/h2&gt;

&lt;p&gt;These are from one run on 2026-10-09, with the 120 KB Duck.glb from the Khronos glTF sample assets.&lt;/p&gt;

&lt;p&gt;The upload took 0.8 seconds. The 720p, 24-frame turntable used 42.56 GPU-seconds. It waited 103 seconds behind three larger jobs that were already queued, then rendered in 18 seconds split across four workers, so the MP4 arrived 124 seconds after the order. The square product shots with a transparent background used 12.73 GPU-seconds, started at once and arrived 13 seconds after the order, as four 1440x1440 PNGs with an alpha channel.&lt;/p&gt;

&lt;p&gt;An earlier measurement on the benchmarks page: a 48-frame full turn at 960x540 used 75.7 GPU-seconds (&lt;a href="https://render.janction.jp/benchmarks" rel="noopener noreferrer"&gt;https://render.janction.jp/benchmarks&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  From an AI agent instead of code
&lt;/h2&gt;

&lt;p&gt;The service is also a remote MCP server at &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt; for Claude, ChatGPT, Codex and Cursor, so "make a 360-degree video of this GLB" works in a chat. The agent can call &lt;code&gt;render_preview&lt;/code&gt; with &lt;code&gt;orbit=True&lt;/code&gt; first, which shows the model from 0, 90, 180 and 270 degrees, and then &lt;code&gt;render_final&lt;/code&gt; with &lt;code&gt;orbit=True&lt;/code&gt;, which renders the full turn as an MP4. Files on your disk go through &lt;a href="https://render.janction.jp/upload" rel="noopener noreferrer"&gt;https://render.janction.jp/upload&lt;/a&gt; when the chat app cannot read them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;One instruction goes up to 3,000 frames (parts of 240 under one job id), 1080p on free time and up to 4K on prepaid credit. Inputs and results are deleted 24 hours after last use (7 days for keys that have topped up). When JANCTION's GPUs are busy, a job waits in a queue, and the status page says so.&lt;/p&gt;

&lt;p&gt;More: &lt;a href="https://render.janction.jp/product-turntable" rel="noopener noreferrer"&gt;https://render.janction.jp/product-turntable&lt;/a&gt;, &lt;a href="https://render.janction.jp/gltf-to-mp4" rel="noopener noreferrer"&gt;https://render.janction.jp/gltf-to-mp4&lt;/a&gt; and &lt;a href="https://render.janction.jp/product-shots-multi-angle" rel="noopener noreferrer"&gt;https://render.janction.jp/product-shots-multi-angle&lt;/a&gt;. Prices: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;. Code and client: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>api</category>
      <category>blender</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>Blender rendering from an OpenAI Agents SDK or LangChain agent, and the 5-second MCP timeout that breaks it</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Fri, 09 Oct 2026 09:53:53 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/blender-rendering-from-an-openai-agents-sdk-or-langchain-agent-and-the-5-second-mcp-timeout-that-420g</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/blender-rendering-from-an-openai-agents-sdk-or-langchain-agent-and-the-5-second-mcp-timeout-that-420g</guid>
      <description>&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update (2026-10-12): the welcome credit changed on 2026-10-12. A new key now gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card), up to 500 JPY in all. The prices below were updated to match &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. It is free to start (100 JPY of GPU time with no card, 400 JPY more after saving a card that is not charged), then 0.1 JPY per GPU-second. This post is for people building their own agent: how to connect it from the OpenAI Agents SDK, LangChain or plain Python, and the one setting that makes the first call fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The error
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;McpError: Timed out while waiting for response to ClientRequest. Waited 5.0 seconds.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;MCPServerStreamableHttp&lt;/code&gt; in the OpenAI Agents SDK (0.23.1) waits 5 seconds for a tool call by default (&lt;code&gt;client_session_timeout_seconds=5&lt;/code&gt;). A render tool answers when the image exists, not when the job is queued. We called &lt;code&gt;render_preview&lt;/code&gt; on the sample scene with four lighting presets, once with the default and once with 120 seconds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;default: failed after 5.1 s with the error above&lt;/li&gt;
&lt;li&gt;120 s: the image came back after 7.3 s (4.03 GPU-seconds of rendering)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A lighter preview of the same scene (one preset) came back in 4.7 to 5.0 seconds, right at the edge, so the default can look fine in a quick test and then fail on the first real scene. Set the timeout explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI Agents SDK
&lt;/h2&gt;

&lt;p&gt;The service is a remote MCP server at &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt;. The key goes in as a bearer token; &lt;code&gt;curl -s -X POST https://render.janction.jp/v1/keys&lt;/code&gt; gives one, with no sign-up.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPServerStreamableHttp&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;MCPServerStreamableHttp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;janction-render&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_session_timeout_seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://render.janction.jp/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer jr_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3D artist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Render Blender scenes with janction-render.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mcp_servers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Render a preview of https://render.janction.jp/samples/cube_scene.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;final_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent sees 12 tools. The ones it uses in order are &lt;code&gt;scene_info&lt;/code&gt;, &lt;code&gt;render_preview&lt;/code&gt;, &lt;code&gt;render_estimate&lt;/code&gt;, &lt;code&gt;render_final&lt;/code&gt;, &lt;code&gt;render_status&lt;/code&gt; and &lt;code&gt;render_download&lt;/code&gt;. Long renders do not need a longer timeout: a short final returns its links in one call, a longer one returns a job id, and &lt;code&gt;render_download(job_id, wait_seconds=45)&lt;/code&gt; waits up to 45 seconds per call. 120 seconds covers every tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  LangChain
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;langchain-mcp-adapters&lt;/code&gt; (0.3.2), the same server is one entry in &lt;code&gt;MultiServerMCPClient&lt;/code&gt;. The transport name is &lt;code&gt;streamable_http&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_mcp_adapters.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiServerMCPClient&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MultiServerMCPClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;janction-render&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://render.janction.jp/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transport&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streamable_http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer jr_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}})&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# render_preview, render_final, render_status, render_download, ...
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Without an agent framework
&lt;/h2&gt;

&lt;p&gt;If your code decides what to render and only needs the frames, the Python client is shorter. &lt;code&gt;pip install janction-render&lt;/code&gt;; the first call creates a free key and keeps it in &lt;code&gt;~/.janction-render.json&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;janction_render.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                                   &lt;span class="c1"&gt;# or Client(api_key="jr_...")
&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;# a bpy script, a .blend, or a .glb / .fbx / .usd / .obj file
&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a service rather than a script: pass &lt;code&gt;notify_url&lt;/code&gt; (https) to &lt;code&gt;POST /v1/jobs&lt;/code&gt; and get one JSON POST when the job finishes instead of polling, and send an &lt;code&gt;Idempotency-Key&lt;/code&gt; header so a retry does not start a second job.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs an agent
&lt;/h2&gt;

&lt;p&gt;Each new key gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card): up to 500 JPY, or 5,000 GPU-seconds, for 14 days. After that, previews stay free up to 2 GPU-minutes a day and other GPU time is 0.1 JPY per GPU-second. A 24-frame 720p MP4 at 64 samples took about 58 GPU-seconds, about 6 JPY. When a key is out of credit, the job is refused before it runs: the HTTP API answers 402 with a top-up link, and over MCP the tool result carries the same link for a person to open. Each key also has a spending cap per job and per day. More on that: &lt;a href="https://dev.to/_903a3934b362f0afe2a8/letting-an-ai-agent-pay-for-renders-without-surprises-free-credit-first-a-top-up-link-spending-3i1m"&gt;https://dev.to/_903a3934b362f0afe2a8/letting-an-ai-agent-pay-for-renders-without-surprises-free-credit-first-a-top-up-link-spending-3i1m&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same examples, kept current: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render#from-your-own-agent-or-app" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render#from-your-own-agent-or-app&lt;/a&gt;. A plain-text summary for models: &lt;a href="https://render.janction.jp/llms.txt" rel="noopener noreferrer"&gt;https://render.janction.jp/llms.txt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt; (pricing: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;, facts: &lt;a href="https://render.janction.jp/facts" rel="noopener noreferrer"&gt;https://render.janction.jp/facts&lt;/a&gt;). Code and client: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>mcp</category>
      <category>langchain</category>
      <category>openai</category>
    </item>
    <item>
      <title>Letting an AI agent pay for renders without surprises: free credit first, a top-up link, spending caps and safe retries</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Thu, 08 Oct 2026 17:08:57 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/letting-an-ai-agent-pay-for-renders-without-surprises-free-credit-first-a-top-up-link-spending-3i1m</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/letting-an-ai-agent-pay-for-renders-without-surprises-free-credit-first-a-top-up-link-spending-3i1m</guid>
      <description>&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Update (2026-10-12): the welcome credit changed on 2026-10-12. A new key now gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card), up to 500 JPY in all. The prices below were updated to match &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. It is free to start (100 JPY of GPU time with no card, 400 JPY more after saving a card that is not charged), then 0.1 JPY per GPU-second; paid use started on 2026-10-08. This post is about the part most people skip until it bites them: what happens to money when the thing calling the API is an agent, not a person.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three ways an agent spends money you did not expect
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;It retries. A timeout on the client side, the request went through on the server side, and now there are two jobs.&lt;/li&gt;
&lt;li&gt;It picks a bigger job than you had in mind. 240 frames at 1080p instead of a 4-frame preview, because the user said "render it".&lt;/li&gt;
&lt;li&gt;It loops. Preview, adjust, preview, adjust, all day, each time a few GPU seconds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these are bugs in the agent. They are the natural behaviour of something that does what it was told. The service has to make them safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before any money moves
&lt;/h2&gt;

&lt;p&gt;The free part comes first. Each new key gets 100 JPY of GPU time with no card, and 400 JPY more after saving a card on a page that charges nothing (once per card): up to 500 JPY, or 5,000 GPU-seconds, for 14 days. After that, previews stay free up to 2 GPU-minutes a day. A 4-frame preview takes a few GPU seconds, so an agent can iterate on a scene for a long time before anything is charged.&lt;/p&gt;

&lt;p&gt;A job only counts as free when 1.5 times its estimate fits in the free time left. Renders sometimes run past their estimate, and this rule keeps that from turning into a charge nobody saw coming. When the margin is not there, credit is held for the part that may go past the free time, and only GPU time actually used past it is charged.&lt;/p&gt;

&lt;p&gt;A quote comes before the work. &lt;code&gt;render_estimate&lt;/code&gt; returns GPU seconds, a wall-clock guess, the amount, the currency and an expiry. A 24-frame 720p clip at 64 samples takes about 59 GPU-seconds, so the agent can say "about 6 JPY and a minute or two, go ahead?" before the GPU is touched.&lt;/p&gt;

&lt;p&gt;The agent cannot pay. When a job needs more credit than the key has, the answer comes back before the job runs: HTTP 402 &lt;code&gt;payment_required&lt;/code&gt; with a &lt;code&gt;checkout_url&lt;/code&gt;. The agent shows the link, a person pays on the Stripe page, and the agent sends the same job again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits that hold even when the agent is wrong
&lt;/h2&gt;

&lt;p&gt;Spending caps per key. Each key has a cap per job and a cap per day, 3,000 JPY and 10,000 JPY by default. A job that would go over either is refused with 403 &lt;code&gt;spend_cap_exceeded&lt;/code&gt; before anything is reserved, even if the balance would cover it. The caps can be read with &lt;code&gt;GET /v1/me&lt;/code&gt; and changed with &lt;code&gt;POST /v1/me/limits&lt;/code&gt;, and the tool descriptions tell agents to ask the user before raising them.&lt;/p&gt;

&lt;p&gt;Safe retries. Send an &lt;code&gt;Idempotency-Key&lt;/code&gt; with a job. A retry with the same key gets the first job back instead of queuing a second one. Rate limits answer with &lt;code&gt;Retry-After&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A price ceiling for the common jobs. A turntable video and a 4-angle product shot are quoted first, and the quote is a ceiling: the actual GPU seconds are charged and the rest is released.&lt;/p&gt;

&lt;p&gt;No paying twice for the same frames. Final renders reuse frames the same key already rendered from the same scene with the same settings. Rendering frames 1-96, then 1-120, then 1-144 costs about the same as rendering 1-144 once.&lt;/p&gt;

&lt;p&gt;Failures cost little. A failed render counts only the frames that finished, for up to 5 failed GPU-minutes per key a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recurring spending stays a person's decision
&lt;/h2&gt;

&lt;p&gt;Two options exist for people who render often, and an agent cannot switch on either of them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Auto top-up: a saved card adds 2,000 JPY (2,200 JPY of credit) when the balance drops below 200 JPY, at most 10,000 JPY a month and 3 times a day by default. A card problem pauses it and says why, and it can be turned off at any time.&lt;/li&gt;
&lt;li&gt;Monthly plans: Starter is 2,980 JPY a month for 3,500 JPY of credit, Pro is 9,800 JPY for 12,000 JPY. Unused credit carries over, and a plan can be cancelled at any time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;billing()&lt;/code&gt; shows both, with links the person opens: a confirmation page first, then Stripe. An agent can show the link; it cannot subscribe, cancel or turn auto top-up on by itself.&lt;/p&gt;

&lt;p&gt;On the first night of paid use, the whole loop was run once with a real card: the 402, the checkout link, the payment, the credit showing up in &lt;code&gt;billing()&lt;/code&gt;, and a refund that came off the balance by itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more than the price
&lt;/h2&gt;

&lt;p&gt;A render farm priced per GPU-hour is fine when a person watches the queue. An agent does not watch. The questions that decide whether you let an agent spend are simple: can it overspend by accident (caps), can a network hiccup double the bill (retries), can it tell you the cost before it starts (quotes), and can it start a subscription you did not agree to (it cannot). If a service cannot answer those, the price per hour does not matter much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying it
&lt;/h2&gt;

&lt;p&gt;Connect from Claude, ChatGPT, Claude Code, Codex or Cursor with the MCP endpoint &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt;, or call the HTTP API with a key from &lt;code&gt;POST /v1/keys&lt;/code&gt; (no sign-up). Ask for an estimate first, read the amount, then preview.&lt;/p&gt;

&lt;p&gt;Building your own agent or app? Copy-paste examples for the Python client, the OpenAI Agents SDK and LangChain: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render#from-your-own-agent-or-app" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render#from-your-own-agent-or-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt; (pricing: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;, facts: &lt;a href="https://render.janction.jp/facts" rel="noopener noreferrer"&gt;https://render.janction.jp/facts&lt;/a&gt;). Code and client: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>blender</category>
      <category>api</category>
    </item>
    <item>
      <title>Blender MCP servers for AI agents (October 2026): which ones control the scene, and which one renders it</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Tue, 06 Oct 2026 14:20:49 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/blender-mcp-servers-for-ai-agents-october-2026-which-ones-control-the-scene-and-which-one-3ica</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/blender-mcp-servers-for-ai-agents-october-2026-which-ones-control-the-scene-and-which-one-3ica</guid>
      <description>&lt;p&gt;Update (2026-10-14): one instruction now renders up to 3,000 frames (in parts of 240 under one job id), and up to 4K on prepaid credit. The limits below were updated to match.&lt;/p&gt;

&lt;p&gt;Update (2026-10-12): free to start, 100 JPY of GPU time per new key with no card and 400 JPY more after saving a card on a page that charges nothing (once per card), up to 500 JPY in all; then 0.1 JPY per GPU-second, and previews stay free up to 2 GPU-minutes a day. Paid use started on 2026-10-08, and this post describes the current pricing. Auto top-up and monthly plans are optional (&lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. This post is written by its operator (JasmyLab Inc.), so read the comparison with that in mind. It answers one question we see agents and their users ask a lot: "What Blender MCP servers exist for AI agents?" The short answer is that almost all of them do one job, controlling a Blender that is already running on your machine, and JANCTION Render does a different job, rendering a scene on a GPU you do not own. The two are used together, not instead of each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two different jobs
&lt;/h2&gt;

&lt;p&gt;A Blender MCP server, in the usual sense, connects an MCP client (Claude Desktop, Claude Code, Codex, Cursor and so on) to a Blender process on your computer. The agent reads the scene, runs &lt;code&gt;bpy&lt;/code&gt; code or typed tools, looks at the viewport, and the render happens on your CPU or GPU. If the machine has no GPU, Cycles still works on the CPU; it is just slow.&lt;/p&gt;

&lt;p&gt;JANCTION Render does not touch your Blender. The agent sends a &lt;code&gt;.blend&lt;/code&gt;, a &lt;code&gt;bpy&lt;/code&gt; script or a 3D file (glTF / GLB, FBX, USD, OBJ, STL, PLY, Alembic), gets a 4-frame preview in a few GPU seconds, and then asks for the final frames or an MP4. Blender 5.0 or 5.2 with Cycles runs on JANCTION's NVIDIA GPUs. Nothing is installed locally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Servers that control a Blender you run
&lt;/h2&gt;

&lt;p&gt;Links checked on 2026-10-06. Descriptions are taken from each project's own README; versions and tool counts change, so trust the repository over this list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Blender Lab MCP Server&lt;/strong&gt; (&lt;a href="https://www.blender.org/lab/mcp-server/" rel="noopener noreferrer"&gt;https://www.blender.org/lab/mcp-server/&lt;/a&gt;). Blender's own project. Requires Blender 5.1 or newer with the add-on. The project page calls it experimental and warns that model-written code runs without guards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ahujasid/mcp-for-blender&lt;/strong&gt; (&lt;a href="https://github.com/ahujasid/mcp-for-blender" rel="noopener noreferrer"&gt;https://github.com/ahujasid/mcp-for-blender&lt;/a&gt;). Formerly &lt;code&gt;blender-mcp&lt;/code&gt;, the best-known community server. Prompt-assisted modeling, scene creation and manipulation; a third-party integration, not made by Blender.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RFingAdam/mcp-blender&lt;/strong&gt; (&lt;a href="https://github.com/RFingAdam/mcp-blender" rel="noopener noreferrer"&gt;https://github.com/RFingAdam/mcp-blender&lt;/a&gt;). 218 tools across modeling, materials, sculpting, animation, AI 3D generation and MSFS content creation, with a render-analyze-refine loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PoBruno/mcp-blender-agent&lt;/strong&gt; (&lt;a href="https://github.com/PoBruno/mcp-blender-agent" rel="noopener noreferrer"&gt;https://github.com/PoBruno/mcp-blender-agent&lt;/a&gt;). About 216 typed tools across 12 domains, built around deterministic, validated operations with structured outputs instead of improvised Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;kleer001/blender-mcp&lt;/strong&gt; (&lt;a href="https://github.com/kleer001/blender-mcp" rel="noopener noreferrer"&gt;https://github.com/kleer001/blender-mcp&lt;/a&gt;). Another bridge to a running Blender, targeting Blender 4.2 LTS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;djeada/blender-mcp-server&lt;/strong&gt; (&lt;a href="https://github.com/djeada/blender-mcp-server" rel="noopener noreferrer"&gt;https://github.com/djeada/blender-mcp-server&lt;/a&gt;). 27 tools across 7 namespaces: objects, materials, renders, exports, Python execution and async jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;loonghao/dcc-mcp-blender&lt;/strong&gt; (&lt;a href="https://github.com/loonghao/dcc-mcp-blender" rel="noopener noreferrer"&gt;https://github.com/loonghao/dcc-mcp-blender&lt;/a&gt;). The Blender part of the DCC-MCP family, with an Agent Skill and a Codex plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hotspoons/blender-agent&lt;/strong&gt; (&lt;a href="https://github.com/hotspoons/blender-agent" rel="noopener noreferrer"&gt;https://github.com/hotspoons/blender-agent&lt;/a&gt;). A self-hosted autonomous agent on top of Blender, with a browser UI, an OpenAI-compatible API and an MCP interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these need Blender installed on the machine that runs them, and all of them render where that Blender runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The server that renders without a local Blender
&lt;/h2&gt;

&lt;p&gt;JANCTION Render exposes 12 MCP tools. The ones an agent uses in order are &lt;code&gt;scene_info&lt;/code&gt; (read cameras, frame range and missing files without rendering), &lt;code&gt;render_preview&lt;/code&gt; (1 to 4 frames tiled in one image), &lt;code&gt;render_estimate&lt;/code&gt; (GPU seconds and wall time before committing), &lt;code&gt;render_final&lt;/code&gt;, &lt;code&gt;render_status&lt;/code&gt; and &lt;code&gt;render_download&lt;/code&gt;. The same functions exist as an HTTP API and a command line.&lt;/p&gt;

&lt;p&gt;Numbers we measured on the service, not projections: a 4-frame 720p preview takes about 4 GPU seconds; a 24-frame 720p animation delivered as MP4 takes about 58 GPU seconds. Each new API key starts with a welcome credit of up to 500 JPY (100 JPY with no card, 400 JPY more after saving a card that is not charged; 14 days); after that, previews stay free up to 2 GPU-minutes a day and finals cost 0.1 JPY per GPU-second from prepaid credit. Final renders go up to 3,000 frames per instruction (parts of 240 under one job id), 1080p on free time and up to 4K on prepaid credit, and inputs and results are deleted 24 hours after last use (7 days for keys that have topped up). Jobs run on JANCTION's own GPUs and can wait in a queue when they are busy; the status page and the agent's &lt;code&gt;eta&lt;/code&gt; say so.&lt;/p&gt;

&lt;p&gt;Connecting takes one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http janction-render https://render.janction.jp/mcp
codex mcp add janction-render &lt;span class="nt"&gt;--url&lt;/span&gt; https://render.janction.jp/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude.ai and ChatGPT add the same URL as a remote MCP connector. Cursor, Windsurf, Cline and Goose use Streamable HTTP at that URL. A key is created on first connection; there is no sign-up and no card.&lt;/p&gt;

&lt;h2&gt;
  
  
  How they fit together
&lt;/h2&gt;

&lt;p&gt;The workflow that works today: edit with a local server, render with JANCTION. The agent builds or fixes the scene in your Blender through one of the servers above, saves the &lt;code&gt;.blend&lt;/code&gt; with textures packed, and hands it to JANCTION Render for the preview and the final MP4. If the AI you are talking to runs in a browser tab and cannot read your disk, drop the file at &lt;a href="https://render.janction.jp/upload" rel="noopener noreferrer"&gt;https://render.janction.jp/upload&lt;/a&gt;, which gives a link valid for 12 hours, and paste the link to the agent.&lt;/p&gt;

&lt;p&gt;If there is no Blender on the machine at all, the agent can write the scene as a &lt;code&gt;bpy&lt;/code&gt; script and send that. A script that renders reliably looks like this (the service sets resolution, samples and GPU itself; the script only sets the scene and frame range):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;bpy&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;ob&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ob&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;do_unlink&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;
&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame_start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame_end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;

&lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;primitive_plane_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mesh&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;primitive_cube_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;cube&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;
&lt;span class="n"&gt;mat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Red&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_nodes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node_tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Principled BSDF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Base Color&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;default_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;materials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keyframe_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rotation_euler&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rotation_euler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;6.283&lt;/span&gt;
&lt;span class="n"&gt;cube&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keyframe_insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rotation_euler&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;light_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SUN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;camera_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.785&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bpy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The full sample lives at &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render/blob/main/samples/cube_scene.py" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render/blob/main/samples/cube_scene.py&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  From your own agent or app
&lt;/h2&gt;

&lt;p&gt;The same service is a Python package and a remote MCP server, so an agent you build calls it the way Claude or Codex does.&lt;/p&gt;

&lt;p&gt;Python (&lt;code&gt;pip install janction-render&lt;/code&gt;; the first call creates a free key and keeps it in &lt;code&gt;~/.janction-render.json&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;janction_render.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;

&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                                   &lt;span class="c1"&gt;# or Client(api_key="jr_...")
&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;# a bpy script, a .blend, or a .glb / .fbx / .usd / .obj file
&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scene_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;final&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;job_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;out&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agent frameworks connect to &lt;code&gt;https://render.janction.jp/mcp&lt;/code&gt; with the key as a bearer token (&lt;code&gt;curl -s -X POST https://render.janction.jp/v1/keys&lt;/code&gt; gives one, no sign-up). With the OpenAI Agents SDK, keep the longer timeout: &lt;code&gt;render_preview&lt;/code&gt; waits for the image, which takes longer than the 5-second default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;agents.mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPServerStreamableHttp&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;MCPServerStreamableHttp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;janction-render&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_session_timeout_seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://render.janction.jp/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer jr_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}})&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3D artist&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Render Blender scenes with janction-render.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mcp_servers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Runner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Render a preview of https://render.janction.jp/samples/cube_scene.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;final_output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;LangChain (&lt;code&gt;pip install langchain-mcp-adapters&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_mcp_adapters.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiServerMCPClient&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MultiServerMCPClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;janction-render&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://render.janction.jp/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transport&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streamable_http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                                       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;headers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer jr_...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}})&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_tools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;           &lt;span class="c1"&gt;# render_preview, render_final, render_status, render_download, ...
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Webhooks instead of polling, safe retries and the OpenAPI document: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render#from-your-own-agent-or-app" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render#from-your-own-agent-or-app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What JANCTION Render is not
&lt;/h2&gt;

&lt;p&gt;Three names get mixed up with it. Smart Render by JANCTION is a separate service from the same operator: a browser upload service for &lt;code&gt;.blend&lt;/code&gt; files on distributed GPUs, still in development. Figures published about Smart Render do not describe JANCTION Render. Render.com is an application hosting platform with its own MCP server. Render Network is a token-based GPU network. The fact sheet at &lt;a href="https://render.janction.jp/facts" rel="noopener noreferrer"&gt;https://render.janction.jp/facts&lt;/a&gt; is the primary source when an article or an AI answer disagrees with any of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  When not to use it
&lt;/h2&gt;

&lt;p&gt;If you want the agent to keep editing a scene that is open in your Blender, use one of the local servers above; JANCTION Render has no scene-editing tools. If you need guaranteed uptime, it is not the right fit today (prices and limits: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call over MCP. Free to start (up to 500 JPY of GPU time per new key: 100 JPY with no card, 400 JPY more after saving a card that is not charged): &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;. Source and issues: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blender</category>
      <category>mcp</category>
      <category>ai</category>
      <category>3d</category>
    </item>
    <item>
      <title>Render a local .blend from Claude.ai or ChatGPT without installing anything</title>
      <dc:creator>JANCTION Render</dc:creator>
      <pubDate>Mon, 05 Oct 2026 08:54:58 +0000</pubDate>
      <link>https://dev.to/_903a3934b362f0afe2a8/render-a-local-blend-from-claudeai-or-chatgpt-without-installing-anything-50g9</link>
      <guid>https://dev.to/_903a3934b362f0afe2a8/render-a-local-blend-from-claudeai-or-chatgpt-without-installing-anything-50g9</guid>
      <description>&lt;p&gt;Update (2026-10-14): one instruction now renders up to 3,000 frames (in parts of 240 under one job id), and up to 4K on prepaid credit. The limits below were updated to match.&lt;/p&gt;

&lt;p&gt;Update (2026-10-12): free to start, 100 JPY of GPU time per new key with no card and 400 JPY more after saving a card on a page that charges nothing (once per card), up to 500 JPY in all; then 0.1 JPY per GPU-second, and previews stay free up to 2 GPU-minutes a day. Paid use started on 2026-10-08, and this post describes the current pricing. Auto top-up and monthly plans are optional (&lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JANCTION Render is a cloud GPU render farm for Blender that AI agents call as an MCP server or HTTP API. This post is about one specific gap we closed this week: how to get a .blend file that sits on your computer into a render job when the AI you are talking to runs in a browser tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Claude.ai and ChatGPT connect to JANCTION Render as a remote MCP server. That works well for scenes the AI writes itself (a bpy script) or for files that already have an https URL. It does not work for a file on your desktop: a remote connector cannot read your disk, and most people will not install a CLI or a Blender add-on just to try something once.&lt;/p&gt;

&lt;p&gt;Until now the honest answer was "install the add-on, or use the CLI". That is where most first attempts stopped.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix: an upload link
&lt;/h2&gt;

&lt;p&gt;There is now a page at &lt;a href="https://render.janction.jp/upload" rel="noopener noreferrer"&gt;https://render.janction.jp/upload&lt;/a&gt;. Drop a file there and you get a link that works for 12 hours. No account, no login, no card. Then you paste the link to your AI.&lt;/p&gt;

&lt;p&gt;Three steps, nothing to install:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://render.janction.jp/upload" rel="noopener noreferrer"&gt;https://render.janction.jp/upload&lt;/a&gt; and drop your .blend (or a glTF / GLB, FBX, USD, OBJ, STL, PLY, Alembic file, or a bpy script).&lt;/li&gt;
&lt;li&gt;Copy the link the page shows.&lt;/li&gt;
&lt;li&gt;Tell the AI: "Render this file: ".&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent passes the link as &lt;code&gt;scene_url&lt;/code&gt;, JANCTION reads the file directly (it does not go back out over the internet), and the first thing you get is a 4-frame preview. Approve it, then ask for the final frames or an MP4.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens behind the link, in plain terms
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The file is stored for the lifetime of the link (12 hours). Once a render job has used it, the scene it created follows the normal rule: inputs and results are deleted 24 hours after last use (7 days for keys that have topped up), and nothing is used for training.&lt;/li&gt;
&lt;li&gt;Result links are signed and valid for about 24 hours. Download what you need.&lt;/li&gt;
&lt;li&gt;A link carries one file. If your glTF or OBJ references textures or a .bin, pack it as a .glb or into the .blend first. The scene reader (&lt;code&gt;scene_info&lt;/code&gt;) tells you if something is missing before any GPU time is spent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits and price, as of October 2026
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Each new API key starts with a welcome credit of up to 500 JPY (100 JPY with no card, 400 JPY more after saving a card that is not charged; 14 days) that covers previews and finals; the key is created for you on first connection. After that, previews stay free up to 2 GPU-minutes a day and finals cost 0.1 JPY per GPU-second from prepaid credit.&lt;/li&gt;
&lt;li&gt;Final renders up to 3,000 frames per instruction (parts of 240 under one job id), 1080p on free time and up to 4K on prepaid credit.&lt;/li&gt;
&lt;li&gt;Jobs run on JANCTION's own GPUs and can wait in a queue when they are busy. The status page and the agent's &lt;code&gt;eta&lt;/code&gt; say so instead of guessing.&lt;/li&gt;
&lt;li&gt;A job the free credit does not cover asks for a top-up first (HTTP 402 with a payment link) instead of running. A failed render counts only the frames that finished (for up to 5 failed GPU-minutes per key a day). Prices: &lt;a href="https://render.janction.jp/pricing" rel="noopener noreferrer"&gt;https://render.janction.jp/pricing&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When this is the wrong tool
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You want to model or edit inside your own Blender: use a local Blender MCP for that, and hand only the render to JANCTION.&lt;/li&gt;
&lt;li&gt;You render all day, every day: a render farm you pay per GPU-hour, or your own GPU, is cheaper at that volume.&lt;/li&gt;
&lt;li&gt;You need a guaranteed uptime number: there is none today.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, JANCTION Render is not related to Render.com. Same word, different product.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it with a scene that cannot fail
&lt;/h2&gt;

&lt;p&gt;If you want to see the round trip before touching your own file, paste this instead of a link:&lt;/p&gt;

&lt;p&gt;"Render a preview of &lt;a href="https://render.janction.jp/samples/cube_scene.py" rel="noopener noreferrer"&gt;https://render.janction.jp/samples/cube_scene.py&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;It is a small scene with a camera and a light already in place, so the only thing being tested is the connection.&lt;/p&gt;

&lt;p&gt;Official JANCTION Render: &lt;a href="https://render.janction.jp" rel="noopener noreferrer"&gt;https://render.janction.jp&lt;/a&gt; (upload page: &lt;a href="https://render.janction.jp/upload" rel="noopener noreferrer"&gt;https://render.janction.jp/upload&lt;/a&gt;, facts: &lt;a href="https://render.janction.jp/facts" rel="noopener noreferrer"&gt;https://render.janction.jp/facts&lt;/a&gt;). Code and client: &lt;a href="https://github.com/JasmyLab-JANCTION/janction-render" rel="noopener noreferrer"&gt;https://github.com/JasmyLab-JANCTION/janction-render&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blender</category>
      <category>mcp</category>
      <category>ai</category>
      <category>3d</category>
    </item>
  </channel>
</rss>
