diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml
new file mode 100644
index 0000000..241bf9e
--- /dev/null
+++ b/.github/workflows/site.yml
@@ -0,0 +1,43 @@
+# Deploy the static marketing site (site/) to GitHub Pages at
+# render.preshow.link — same mechanism as UV Studio's uv.preshow.link.
+#
+# The deploy is OPT-IN — it only runs when the repo variable
+# DEPLOY_PAGES == 'true'. To enable it (needs a public repo OR a plan with
+# private Pages, e.g. Pro):
+# repo Settings → Pages → Source: "GitHub Actions"
+# gh variable set DEPLOY_PAGES --body true
+# Then add a DNS CNAME record: render.preshow.link → hayhamlt.github.io
+# The custom domain is baked in via the CNAME file below, so the site is
+# served at root — no subpath rewrites needed.
+name: Site
+
+on:
+ push:
+ branches: [main]
+ paths: ['site/**', '.github/workflows/site.yml']
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ deploy:
+ if: ${{ vars.DEPLOY_PAGES == 'true' }}
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deploy.outputs.page_url }}
+ steps:
+ - uses: actions/checkout@v4
+ - run: echo 'render.preshow.link' > site/CNAME
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: site
+ - id: deploy
+ uses: actions/deploy-pages@v4
diff --git a/README.md b/README.md
index 1d5db12..0c57701 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
-# Render Mapper Pro
+# PrevizRender (formerly Render Mapper Pro)
A standalone desktop app that maps videos onto 3D‑scene materials and renders them headlessly — built for LED‑wall / screen‑content workflows where one scene drives many video surfaces.
+PrevizRender is one of three sibling tools built by [hamLT](https://motion.hamlt.com) and powered by [Toy Robot Media](https://toyrobotmedia.com): **[Preshow.link](https://www.preshow.link)** plans and previzes the show, **[UV Studio](https://uv.preshow.link)** maps artwork onto the venue's screens, and **PrevizRender** renders the comps locally. Product site: **[render.preshow.link](https://render.preshow.link)** (deployed from [`site/`](site/) via GitHub Pages, same as UV Studio's). (Installer and bundle artifacts keep the `RenderMapperPro` name so auto-updates and install paths stay valid.)
+
It supports **two render backends**, chosen automatically by scene type: **Blender** (`.blend`, `.fbx`, `.usd`, …) and **Cinema 4D + Redshift** (`.c4d`). It runs the renderer in the background, so a renderer crash can never take down the app, and ships bundled static `ffmpeg`/`ffprobe` so audio muxing and clip probing work out of the box.
-
+
## Download
diff --git a/app_qt.py b/app_qt.py
index 57134d6..9bb2de9 100644
--- a/app_qt.py
+++ b/app_qt.py
@@ -302,7 +302,7 @@ def __init__(self) -> None:
self._c4dpy_path = _find_c4dpy() # Cinema 4D headless Python, if installed
self._deadline_repo_path = ""
self._deadline_command_path = ""
- self._deadline_job_name_template = "Render Mapper Pro Job - {scene_name}"
+ self._deadline_job_name_template = f"{APP_NAME} Job - {{scene_name}}"
self._deadline_comment = ""
self._discovered_materials: list[str] = []
self._discovered_cameras: list[str] = []
@@ -728,7 +728,7 @@ def _guide_sections() -> list[tuple[str, str]]:
return [
("Getting Started", """
Welcome
-
Render Mapper Pro maps your videos onto a 3D scene's
+
PrevizRender maps your videos onto a 3D scene's
materials and renders them — on your machine or a render farm. Each tab
above covers one part of the app; here's the whole flow first.
@@ -1341,13 +1341,23 @@ def centered(w):
name = centered(QLabel(APP_NAME))
name.setStyleSheet(f"color:{pal.text}; font-size:19px; font-weight:700; margin-top:8px;")
- ver = centered(QLabel(f"Version {APP_VERSION}"))
+ ver = centered(QLabel(f"Version {APP_VERSION} · formerly Render Mapper Pro"))
ver.setStyleSheet(f"color:{pal.text_muted}; font-size:12px;")
desc = centered(QLabel("Automated video-texture mapping and headless\n"
"rendering — Blender, Cinema 4D and three.js."))
desc.setStyleSheet(f"color:{pal.text_muted}; font-size:12px; margin-top:8px;")
desc.setWordWrap(True)
+ family = centered(QLabel(
+ 'Sibling apps: '
+ f'Preshow.link for show previz · '
+ f'UV Studio for screen UVs'))
+ family.setStyleSheet(f"color:{pal.text_muted}; font-size:12px; margin-top:4px;")
+ family.setOpenExternalLinks(True)
+ family.setTextInteractionFlags(Qt.TextInteractionFlag.TextBrowserInteraction)
+
sep = QFrame()
sep.setFrameShape(QFrame.Shape.HLine)
sep.setStyleSheet(f"color:{pal.border}; margin:14px 40px;")
@@ -2737,7 +2747,7 @@ def _job_engine(j: RenderJob) -> str:
error(
self, "App Component Missing",
"The app's render component couldn't be found — the installation may be "
- f"damaged. Reinstall Render Mapper Pro.\n\nDetails: {exc}")
+ f"damaged. Reinstall {APP_NAME}.\n\nDetails: {exc}")
self._is_rendering = False
return
# Bundled ffmpeg path for the workers: C4D always muxes its movie with it,
@@ -3456,8 +3466,8 @@ def _open_path(path: str) -> None:
# ── Project save/open ────────────────────────────────────────────────
def _save_project(self) -> None:
p, _ = QFileDialog.getSaveFileName(
- self, "Save Project", str(Path.home() / f"render_mapper_project{PROJECT_EXT}"),
- f"Render Mapper Project (*{PROJECT_EXT})")
+ self, "Save Project", str(Path.home() / f"previzrender_project{PROJECT_EXT}"),
+ f"PrevizRender Project (*{PROJECT_EXT})")
if not p:
return
if not p.lower().endswith(PROJECT_EXT):
@@ -3475,7 +3485,7 @@ def _save_project(self) -> None:
def _open_project(self) -> None:
p, _ = QFileDialog.getOpenFileName(
self, "Open Project", str(Path.home()),
- f"Render Mapper Project (*{PROJECT_EXT})")
+ f"PrevizRender Project (*{PROJECT_EXT})")
if not p:
return
try:
@@ -3584,7 +3594,7 @@ def _send_test() -> None:
if not self._discord_webhook:
self._show_toast("Enter a webhook URL first.", "warning")
return
- self._dispatch_discord("✅ Test notification from Render Mapper Pro")
+ self._dispatch_discord(f"✅ Test notification from {APP_NAME}")
self._show_toast("Test sent — check Discord (and Live Logs for errors).", "info")
test_btn.clicked.connect(_send_test)
@@ -3981,9 +3991,9 @@ def _apply_profile_data(self, d: dict) -> None:
self.deadline_panel.dl_chunk_spin.setValue(int(d.get("deadline_chunk_size", 1)))
self.deadline_panel.dl_suspended_cb.setChecked(bool(d.get("deadline_suspended", False)))
self.deadline_panel.dl_submit_scene_cb.setChecked(bool(d.get("deadline_submit_scene", True)))
- self._deadline_job_name_template = str(d.get("deadline_job_name_template", "Render Mapper Pro Job - {scene_name}"))
+ self._deadline_job_name_template = str(d.get("deadline_job_name_template", f"{APP_NAME} Job - {{scene_name}}"))
if self._deadline_job_name_template == "BlenderRender Job - {scene_name}": # migrate old app name
- self._deadline_job_name_template = "Render Mapper Pro Job - {scene_name}"
+ self._deadline_job_name_template = f"{APP_NAME} Job - {{scene_name}}"
self.deadline_panel.dl_name_template_edit.setText(self._deadline_job_name_template)
self.deadline_panel.dl_machine_limit_spin.setValue(int(d.get("deadline_machine_limit", 0)))
self.deadline_panel.dl_limits_edit.setText(str(d.get("deadline_limits", "")))
@@ -4185,7 +4195,7 @@ def note_missing(vp: str, vn: str) -> None:
deadline_chunk_size=int(jd.get("deadline_chunk_size", 1)),
deadline_suspended=bool(jd.get("deadline_suspended", False)),
deadline_submit_scene=bool(jd.get("deadline_submit_scene", True)),
- deadline_job_name_template=str(jd.get("deadline_job_name_template", "Render Mapper Pro Job - {scene_name}")),
+ deadline_job_name_template=str(jd.get("deadline_job_name_template", f"{APP_NAME} Job - {{scene_name}}")),
deadline_machine_limit=int(jd.get("deadline_machine_limit", 0)),
deadline_limits=str(jd.get("deadline_limits", "")),
deadline_command_path=str(jd.get("deadline_command_path", "")),
@@ -4672,7 +4682,7 @@ def run_qt_app() -> None:
if probe.state() == QLocalSocket.LocalSocketState.ConnectedState:
probe.waitForBytesWritten(250)
probe.disconnectFromServer()
- print("Render Mapper Pro is already running — focusing the existing window.", file=sys.stderr)
+ print(f"{APP_NAME} is already running — focusing the existing window.", file=sys.stderr)
return
# No live instance; clear any stale socket and become the server.
QLocalServer.removeServer(SINGLE_INSTANCE_KEY)
diff --git a/app_version.py b/app_version.py
index 899eaa9..71aaa27 100644
--- a/app_version.py
+++ b/app_version.py
@@ -5,4 +5,8 @@
tag whose value doesn't match this string.
"""
__version__ = "1.8.34"
-APP_NAME = "Render Mapper Pro" # display name; single source shared by the app + mixins
+# Display name; single source shared by the app + mixins. "PrevizRender" is
+# the product name (formerly "Render Mapper Pro"); installer/bundle artifact
+# names in BlenderVideoMapper.spec and installer/windows.iss intentionally keep
+# the old name so the auto-update chain and install paths stay valid.
+APP_NAME = "PrevizRender"
diff --git a/app_window/reporting_mixin.py b/app_window/reporting_mixin.py
index 08b9bc4..294b353 100644
--- a/app_window/reporting_mixin.py
+++ b/app_window/reporting_mixin.py
@@ -9,6 +9,7 @@
from datetime import datetime
from pathlib import Path
+from app_version import APP_NAME
from app_window.base import _WindowMembers
from core.logging_setup import get_logger
from core.metrics import estimate_energy_cost
@@ -105,7 +106,7 @@ def _build_html_report(self) -> str:
'.err{color:#ed4245;font-family:ui-monospace,monospace;font-size:12px;'
'white-space:pre-wrap;margin:6px 0}.brand{color:#e8833a;font-weight:700}'
''
- '
Render Mapper Pro — Render Report
'
+ f'
{APP_NAME} — Render Report
'
f'
{stamp} · Scene: {scene}
'
'
Job
Status
Frames
'
'
Duration
Avg/frame
Est. Cost
'
diff --git a/core/logging_setup.py b/core/logging_setup.py
index 7a1295a..8219f12 100644
--- a/core/logging_setup.py
+++ b/core/logging_setup.py
@@ -63,7 +63,7 @@ def setup_logging(log_path: Path | str | None = None, level: int = logging.INFO,
logger.propagate = False
logger.info("%s", "=" * 60)
- logger.info("Render Mapper Pro %s — session start", version or "?")
+ logger.info("PrevizRender %s — session start", version or "?")
return logger
diff --git a/docs/screenshots/previzrender.png b/docs/screenshots/previzrender.png
new file mode 100644
index 0000000..e045d7b
Binary files /dev/null and b/docs/screenshots/previzrender.png differ
diff --git a/docs/screenshots/render-mapper-pro.png b/docs/screenshots/render-mapper-pro.png
deleted file mode 100644
index 8e60ad7..0000000
Binary files a/docs/screenshots/render-mapper-pro.png and /dev/null differ
diff --git a/site/img/app.png b/site/img/app.png
new file mode 100644
index 0000000..e045d7b
Binary files /dev/null and b/site/img/app.png differ
diff --git a/site/img/toy-robot-media-logo.png b/site/img/toy-robot-media-logo.png
new file mode 100644
index 0000000..9b7821b
Binary files /dev/null and b/site/img/toy-robot-media-logo.png differ
diff --git a/site/index.html b/site/index.html
new file mode 100644
index 0000000..e69e4a8
--- /dev/null
+++ b/site/index.html
@@ -0,0 +1,506 @@
+
+
+
+
+
+PrevizRender — render the comps, before load-in.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Map videos onto 3D-scene materials and render headlessly — Blender or Cinema 4D + Redshift, on your own machine. One scene, many screens, no farm required.
No render setup, no scripting. Scan the scene, link clips to materials, queue it.
+
+
+
+
1
Add a scene
+
Drag a .blend / .c4d / .glb (or .fbx, .usd, …) onto the Scene box, then Scan — materials, cameras, and render settings load automatically.
+
+
+
2
Add clips
+
Drag your videos into the list and pick a camera. Resolution, fps, and frame ranges auto-fill from the scene.
+
+
+
3
Link them
+
Auto-map matches clips to materials by name — or link any pair by hand. Every screen gets its content.
+
+
+
4
Queue & render
+
Hit Start and watch the live preview. The renderer runs headless in the background — a crash can never take down the app.
+
+
+
+
+
+
+
+
+
+ A closer look
+
A render pipeline in one window
+
Click a feature to read what it does.
+
+
+
+
+
+
+
+
+
+
+
+
PrevizRender
+
+
+
The right backend is chosen automatically by scene type — Blender for .blend / .fbx / .usd and friends, Cinema 4D + Redshift for .c4d. Same workflow either way.
+
+
+
+
+
+
+
+
+
+ Backends
+
Your scenes, your renderers
+
PrevizRender drives the renderer you already use — headlessly, in the background.
+
+
+
+
Bl Blender
+
.blend, .fbx, .obj, .glb, .usd, .abc and more. No Blender on the machine? The app offers a managed runtime download — one click, with a progress bar.
+ Nothing else to install
+
+
+
C4 Cinema 4D + Redshift
+
.c4d scenes render through your own C4D + Redshift install — the app pulls the Redshift sampling settings straight from the scene.
+ Uses your licensed install
+
+
+
+
+
+
+
+
+
+ Part of the family
+
Plan it. Map it. Render it.
+
Three sibling tools by hamLT, powered by Toy Robot Media — one for each stage of getting content onto real-world screens.