diff --git a/app/main.py b/app/main.py
index 4683660..eb448ef 100644
--- a/app/main.py
+++ b/app/main.py
@@ -221,6 +221,14 @@ def _build_acquisitions():
# Mask the viser link when the demo.py that was serving it has since died.
if j["status"] == "done" and j["viser_url"] and not _viser_alive(j["viser_url"]):
d["viser_url"] = None
+ # PLY download link
+ ply_url = None
+ ply_path_db = d.get("ply_path")
+ if ply_path_db and d.get("worker_host"):
+ dir_name = ply_path_db.rstrip("/").split("/")[-2]
+ file_name = ply_path_db.rstrip("/").split("/")[-1]
+ ply_url = f"http://{d['worker_host']}:8300/{dir_name}/{file_name}"
+ d["ply_url"] = ply_url
# GLB download link: only when glb_path is set in DB (conversion confirmed)
glb_url = None
glb_path = d.get("glb_path")
diff --git a/app/static/style.css b/app/static/style.css
index 06c7ef9..e608a2b 100644
--- a/app/static/style.css
+++ b/app/static/style.css
@@ -172,3 +172,5 @@ code { background: rgba(255,255,255,0.05); padding: 0 0.25rem; border-radius: 3p
border-radius: 4px;
}
.docs-link:hover { background: #2d2f31; }
+.btn-glb, .btn-ply-dl { display: inline-block; text-decoration: none; padding: 3px 10px; border: 1px solid #8bc34a; border-radius: 3px; color: #8bc34a; font-size: 0.72rem; background: transparent; cursor: pointer; font-family: inherit; }
+.btn-glb:hover, .btn-ply-dl:hover { background: #8bc34a; color: #000; }
diff --git a/app/templates/_jobs_table.html b/app/templates/_jobs_table.html
index 0942ebe..bb99bef 100644
--- a/app/templates/_jobs_table.html
+++ b/app/templates/_jobs_table.html
@@ -56,6 +56,9 @@
{% else %}
{% endif %}
+ {% if j.ply_url %}
+ PLY ↓
+ {% endif %}
{% if j.glb_url %}
GLB ↓
{% endif %}