| FROM nvidia/cuda:12.1.0-runtime-ubuntu22.04 | |
| # System deps: Blender needs X11 libs even headless, ffmpeg for encoding | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| wget xz-utils \ | |
| libx11-6 libxi6 libxxf86vm1 libxfixes3 libxrender1 \ | |
| libgl1-mesa-glx libglib2.0-0 libsm6 libgomp1 libtbb12 \ | |
| ffmpeg python3-pip python3-dev \ | |
| libegl1 libegl1-mesa libgles2 \ | |
| fonts-dejavu-core \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Blender 3.6.5 LTS — mature, stable CUDA/OptiX support | |
| RUN BLENDER_URL="https://download.blender.org/release/Blender3.6/blender-3.6.5-linux-x64.tar.xz" \ | |
| && BLENDER_MIRROR="https://mirror.clarkson.edu/blender/release/Blender3.6/blender-3.6.5-linux-x64.tar.xz" \ | |
| && (wget --retry-connrefused --waitretry=15 --timeout=30 --tries=5 -q "$BLENDER_URL" \ | |
| || wget --retry-connrefused --waitretry=15 --timeout=30 --tries=5 -q "$BLENDER_MIRROR") \ | |
| && tar -xf blender-3.6.5-linux-x64.tar.xz -C /opt \ | |
| && rm blender-3.6.5-linux-x64.tar.xz \ | |
| && ln -s /opt/blender-3.6.5-linux-x64/blender /usr/local/bin/blender | |
| # Verify Blender | |
| RUN blender --background --python-expr "import bpy; print(f'Blender {bpy.app.version_string} OK, CUDA: {bpy.app.build_options.cuda}')" | |
| # Python deps | |
| RUN pip3 install --no-cache-dir gradio huggingface_hub | |
| # App code (files are at repo root on HF Space) | |
| COPY scene.py /app/scene.py | |
| COPY app.py /app/app.py | |
| WORKDIR /app | |
| ENV PYTHONUNBUFFERED=1 | |
| ENV BLENDER_SYSTEM_SCRIPTS=/opt/blender-3.6.5-linux-x64/3.6/scripts | |
| # Pre-compile CUDA kernels by rendering a simple scene (saves ~10 min on first frame) | |
| RUN printf 'import bpy\nbpy.ops.mesh.primitive_cube_add()\nbpy.context.scene.render.engine = "CYCLES"\nbpy.context.scene.render.resolution_x = 64\nbpy.context.scene.render.resolution_y = 64\nprefs = bpy.context.preferences.addons["cycles"].preferences\nprefs.compute_device_type = "CUDA"\nprefs.get_devices()\nfor d in prefs.devices:\n d.use = (d.type == "CUDA")\nbpy.context.scene.cycles.device = "GPU"\nbpy.context.scene.cycles.samples = 1\nbpy.context.scene.render.filepath = "/tmp/warmup.png"\nbpy.ops.render.render(write_still=True)\nprint("CUDA KERNELS COMPILED")' > /tmp/cuda_warmup.py && blender --background --python /tmp/cuda_warmup.py 2>&1 | tail -5 || true | |
| CMD ["python3", "app.py"] | |