| """Deployable Gradio wrapper for the Robot Learning Landscape. |
| |
| The landscape is a self-contained interactive HTML page (constellation map, |
| Magic-Move detail panels, per-paradigm SMIL animations). It is embedded in an |
| <iframe srcdoc=...> so all of its JavaScript (View Transitions, click handling) |
| runs normally β inline <script> inside a plain gr.HTML does NOT execute, but an |
| iframe's srcdoc is a real browsing context and does. |
| |
| Run (creates a public *.gradio.live share link): |
| .venv_robot_paradigms/bin/python landscape_app.py |
| |
| Environment toggles: |
| LANDSCAPE_SHARE=0 # local only, no public link |
| LANDSCAPE_PORT=7861 # change the local port |
| """ |
| import os |
| import json |
|
|
| import gradio as gr |
|
|
| import gen_landscape |
| import gen_evolution |
| import gen_vlm |
| import gen_vlm_axes |
| import gen_worldmodel |
| import gen_reading |
| import gen_compare |
| import gen_unified_story |
| import gen_algorithm_lab |
| import gen_contribution_atlas |
|
|
|
|
| def build_landscape_html() -> str: |
| """Render the latest landscape HTML in-memory (stays in sync with the data).""" |
| return gen_landscape.render() |
|
|
|
|
| def build_evolution_html() -> str: |
| """Render the chronological evolution-timeline page in-memory.""" |
| data = gen_evolution.build_data() |
| return gen_evolution.TEMPLATE.replace("__DATA_JSON__", json.dumps(data)) |
|
|
|
|
| def build_vlm_html() -> str: |
| """Render the Vision-Language-Model landscape in-memory.""" |
| return gen_vlm.render() |
|
|
|
|
| def build_vlm_axes_html() -> str: |
| """Render the VLM three-axes overview in-memory.""" |
| return gen_vlm_axes.render() |
|
|
|
|
| def build_worldmodel_html() -> str: |
| """Render the World Model landscape in-memory.""" |
| return gen_worldmodel.render() |
|
|
|
|
| def build_reading_html() -> str: |
| """Render the 'My Reading' directory in-memory.""" |
| return gen_reading.render() |
|
|
|
|
| def build_compare_html() -> str: |
| """Render the old-vs-new animation A/B compare page.""" |
| return gen_compare.render() |
|
|
|
|
| def build_unified_story_html() -> str: |
| """Render the animated unified-model story page in-memory.""" |
| return gen_unified_story.render() |
|
|
|
|
| def build_algorithm_lab_html() -> str: |
| """Render the per-paradigm synchronized algorithm explainer.""" |
| return gen_algorithm_lab.render() |
|
|
|
|
| def build_contribution_atlas_html() -> str: |
| """Render the contribution-focused evolution atlas.""" |
| return gen_contribution_atlas.render() |
|
|
|
|
| def _esc(html: str) -> str: |
| |
| return html.replace("&", "&").replace('"', """) |
|
|
|
|
| def combined_html() -> str: |
| """Wrap the landscape + timeline as two nested iframes with a top toggle bar. |
| |
| Each page keeps its own (colliding) CSS/JS because it lives in its own nested |
| iframe; the wrapper just shows/hides them. srcdoc is escaped once here and a |
| second time by iframe_embed (double-decoded by the browser, layer by layer).""" |
| inner_l = _esc(build_landscape_html()) |
| inner_t = _esc(build_evolution_html()) |
| inner_v = _esc(build_vlm_html()) |
| inner_x = _esc(build_vlm_axes_html()) |
| inner_w = _esc(build_worldmodel_html()) |
| inner_r = _esc(build_reading_html()) |
| inner_c = _esc(build_compare_html()) |
| inner_u = _esc(build_unified_story_html()) |
| inner_a = _esc(build_algorithm_lab_html()) |
| inner_d = _esc(build_contribution_atlas_html()) |
| wrapper = ( |
| '<!doctype html><html><head><meta charset="utf-8"/>' |
| '<style>body{margin:0;background:#070b16;font-family:Inter,-apple-system,sans-serif;}' |
| '.bar{height:44px;display:flex;align-items:center;justify-content:center;gap:6px;' |
| 'background:#0a0f1e;border-bottom:1px solid #16203a;overflow-x:auto;white-space:nowrap;}' |
| '.bar button{cursor:pointer;border:none;border-radius:999px;padding:7px 15px;font-size:13px;' |
| 'flex:0 0 auto;' |
| 'font-weight:700;color:#cbd5e1;background:transparent;font-family:inherit;}' |
| '.bar button.active{background:linear-gradient(90deg,#7c3aed,#0ea5e9);color:#fff;}' |
| 'iframe{border:none;width:100%;height:calc(100vh - 44px);display:block;}' |
| '.hidden{display:none;}</style></head><body>' |
| '<div class="bar">' |
| '<button id="b0" class="active" onclick="show(0)">π¬ Unified Story</button>' |
| '<button id="b1" onclick="show(1)">π§ͺ Algorithm Lab</button>' |
| '<button id="b2" onclick="show(2)">𧬠Contribution Atlas</button>' |
| '<button id="b3" onclick="show(3)">π Robot Landscape</button>' |
| '<button id="b4" onclick="show(4)">β³ Robot Timeline</button>' |
| '<button id="b5" onclick="show(5)">ποΈ VLM Landscape</button>' |
| '<button id="b6" onclick="show(6)">π§ VLM Axes</button>' |
| '<button id="b7" onclick="show(7)">π World Models</button>' |
| '<button id="b8" onclick="show(8)">π My Reading</button>' |
| '<button id="b9" onclick="show(9)">π Compare</button></div>' |
| '<iframe id="f0" srcdoc="__U__"></iframe>' |
| '<iframe id="f1" class="hidden" srcdoc="__A__"></iframe>' |
| '<iframe id="f2" class="hidden" srcdoc="__D__"></iframe>' |
| '<iframe id="f3" class="hidden" srcdoc="__L__"></iframe>' |
| '<iframe id="f4" class="hidden" srcdoc="__T__"></iframe>' |
| '<iframe id="f5" class="hidden" srcdoc="__V__"></iframe>' |
| '<iframe id="f6" class="hidden" srcdoc="__X__"></iframe>' |
| '<iframe id="f7" class="hidden" srcdoc="__W__"></iframe>' |
| '<iframe id="f8" class="hidden" srcdoc="__R__"></iframe>' |
| '<iframe id="f9" class="hidden" srcdoc="__C__"></iframe>' |
| '<script>function show(n){for(var i=0;i<10;i++){' |
| 'document.getElementById("f"+i).classList.toggle("hidden",i!==n);' |
| 'document.getElementById("b"+i).classList.toggle("active",i===n);}}' |
| 'window.addEventListener("message",function(e){var d=e.data||{};' |
| 'if(d.type==="openAlgorithmLab"){show(1);' |
| 'var f=document.getElementById("f1");' |
| 'try{f.contentWindow.location.hash=d.id||"";}catch(_){}}});</script>' |
| '</body></html>' |
| ) |
| return (wrapper.replace("__U__", inner_u).replace("__A__", inner_a).replace("__D__", inner_d) |
| .replace("__L__", inner_l).replace("__T__", inner_t) |
| .replace("__V__", inner_v).replace("__X__", inner_x).replace("__W__", inner_w) |
| .replace("__R__", inner_r).replace("__C__", inner_c)) |
|
|
|
|
| def iframe_embed(html: str) -> str: |
| srcdoc = _esc(html) |
| return ( |
| f'<iframe srcdoc="{srcdoc}" ' |
| 'title="Robot Learning Landscape" ' |
| 'allow="fullscreen; clipboard-write" ' |
| 'style="width:100%;height:92vh;min-height:700px;border:none;' |
| 'border-radius:14px;background:#070b16;display:block;"></iframe>' |
| ) |
|
|
|
|
| with gr.Blocks(title="Robot Learning Landscape") as demo: |
| gr.HTML(iframe_embed(combined_html()), padding=False, container=False, min_height=700) |
|
|
|
|
| if __name__ == "__main__": |
| share = os.environ.get("LANDSCAPE_SHARE", "1") == "1" |
| port = int(os.environ.get("LANDSCAPE_PORT", "7861")) |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=port, |
| share=share, |
| inbrowser=False, |
| theme=gr.themes.Soft(primary_hue="indigo", secondary_hue="violet"), |
| css=".gradio-container{max-width:100% !important; padding:6px !important;}" |
| " footer{display:none !important;}", |
| ) |
|
|