lilyzhng commited on
Commit
badef93
Β·
verified Β·
1 Parent(s): 20f9023

Deploy as Docker static server with pre-rendered illustrations

Browse files
Dockerfile ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+ RUN pip install --no-cache-dir aiohttp
3
+ COPY static /app/static
4
+ COPY server.py /app/server.py
5
+ WORKDIR /app
6
+ EXPOSE 7860
7
+ CMD ["python", "server.py"]
server.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from aiohttp import web
3
+
4
+ async def handle(request):
5
+ path = request.match_info.get('path', '')
6
+ if not path or path == '/':
7
+ path = 'index.html'
8
+ file_path = os.path.join('static', path)
9
+ if os.path.isfile(file_path):
10
+ return web.FileResponse(file_path)
11
+ return web.Response(text='Not found', status=404)
12
+
13
+ app = web.Application()
14
+ app.router.add_get('/{path:.*}', handle)
15
+ app.router.add_get('/', handle)
16
+
17
+ if __name__ == '__main__':
18
+ web.run_app(app, host='0.0.0.0', port=7860)
static/data/handdraw_v1/html/deepseek_hourglass.html ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><meta charset="UTF-8"><title>Draw: CONCEPT</title></head>
4
+ <body style="display:flex;align-items:center;justify-content:center;min-height:100vh;background:#e8dcc8;">
5
+ <svg id="art" viewBox="0 0 300 300" width="300" height="300" xmlns="http://www.w3.org/2000/svg"></svg>
6
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
7
+ <script>
8
+ const INK = '#1a1a1a';
9
+ const WHITE = '#f0ebe0';
10
+
11
+ const svg = document.getElementById('art');
12
+ const rc = rough.svg(svg);
13
+
14
+ const outlineOpts = { stroke: INK, strokeWidth: 3.5, fill: "none", roughness: 0.8 };
15
+ svg.appendChild(rc.polygon([[150, 50], [70, 150], [230, 150]], outlineOpts));
16
+ svg.appendChild(rc.polygon([[150, 250], [70, 150], [230, 150]], outlineOpts));
17
+
18
+ const sandOpts = { stroke: INK, strokeWidth: 2, roughness: 1.2 };
19
+ svg.appendChild(rc.line(150, 100, 120, 130, sandOpts));
20
+ svg.appendChild(rc.line(150, 110, 130, 140, sandOpts));
21
+ svg.appendChild(rc.line(150, 200, 180, 170, sandOpts));
22
+ svg.appendChild(rc.line(150, 190, 170, 160, sandOpts));
23
+
24
+ const sparkOpts = { stroke: INK, strokeWidth: 2.5, roughness: 0.8 };
25
+ svg.appendChild(rc.line(40, 40, 50, 50, sparkOpts));
26
+ svg.appendChild(rc.line(260, 260, 250, 250, sparkOpts));
27
+ </script>
28
+ </body>
29
+ </html>
static/data/handdraw_v1/html/gpt4omini_hourglass.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>GPT-4o-mini: Hourglass Attempt</title>
6
+ </head>
7
+ <body style="display:flex;align-items:center;justify-content:center;min-height:100vh;background:#e8dcc8;">
8
+ <canvas id="canvas" width="400" height="400"></canvas>
9
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
10
+ <script>
11
+ const INK = "#1a1a1a";
12
+ const canvas = document.getElementById("canvas");
13
+ const rc = rough.canvas(canvas);
14
+
15
+ const outlineOpts = { stroke: INK, strokeWidth: 3.5, fill: "none", roughness: 0.8 };
16
+ rc.line(150, 50, 250, 50, outlineOpts); // top line
17
+ rc.line(150, 50, 100, 200, outlineOpts); // left diagonal
18
+ rc.line(250, 50, 300, 200, outlineOpts); // right diagonal
19
+ rc.line(100, 200, 300, 200, outlineOpts); // bottom line
20
+ rc.line(100, 200, 150, 350, outlineOpts); // left diagonal down
21
+ rc.line(300, 200, 250, 350, outlineOpts); // right diagonal down
22
+ rc.line(150, 350, 250, 350, outlineOpts); // bottom line
23
+ </script>
24
+ </body>
25
+ </html>
static/data/handdraw_v1/html/gpt54_hourglass.html ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><meta charset="UTF-8"><title>Draw: HOURGLASS</title></head>
4
+ <body style="display:flex;align-items:center;justify-content:center;min-height:100vh;background:#e8dcc8;">
5
+ <svg id="art" viewBox="0 0 300 300" width="300" height="300" xmlns="http://www.w3.org/2000/svg"></svg>
6
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
7
+ <script>
8
+ const INK = '#1a1a1a';
9
+ const WHITE = '#f0ebe0';
10
+
11
+ const svg = document.getElementById('art');
12
+ const rc = rough.svg(svg);
13
+
14
+ const outline = { stroke: INK, strokeWidth: 3.5, fill: 'none', roughness: 0.9 };
15
+ const wood = { stroke: INK, strokeWidth: 3, fill: '#8b5a2b', fillStyle: 'hachure', hachureGap: 6, roughness: 0.8 };
16
+ const sand = { stroke: INK, strokeWidth: 2.2, fill: '#d9b36c', fillStyle: 'dots', hachureGap: 5, roughness: 0.7 };
17
+ const detail = { stroke: INK, strokeWidth: 2.3, roughness: 0.8 };
18
+
19
+ svg.appendChild(rc.rectangle(92, 32, 116, 22, wood));
20
+ svg.appendChild(rc.rectangle(92, 246, 116, 22, wood));
21
+
22
+ svg.appendChild(rc.line(104, 43, 88, 257, outline));
23
+ svg.appendChild(rc.line(196, 43, 212, 257, outline));
24
+
25
+ svg.appendChild(rc.polygon([[112, 56], [188, 56], [156, 136], [144, 136]], outline));
26
+ svg.appendChild(rc.polygon([[144, 164], [156, 164], [188, 244], [112, 244]], outline));
27
+
28
+ svg.appendChild(rc.line(144, 136, 156, 164, detail));
29
+ svg.appendChild(rc.line(156, 136, 144, 164, detail));
30
+
31
+ svg.appendChild(rc.polygon([[121, 66], [179, 66], [162, 102], [138, 102]], sand));
32
+ svg.appendChild(rc.polygon([[124, 233], [176, 233], [150, 186]], sand));
33
+
34
+ svg.appendChild(rc.line(150, 104, 150, 184, { stroke: INK, strokeWidth: 1.8, roughness: 0.5 }));
35
+ svg.appendChild(rc.circle(150, 145, 4, { stroke: INK, strokeWidth: 1.5, fill: INK, fillStyle: 'solid', roughness: 0.4 }));
36
+ svg.appendChild(rc.circle(150, 170, 4, { stroke: INK, strokeWidth: 1.5, fill: INK, fillStyle: 'solid', roughness: 0.4 }));
37
+
38
+ svg.appendChild(rc.line(125, 78, 134, 123, { stroke: WHITE, strokeWidth: 1.8, roughness: 0.6 }));
39
+ svg.appendChild(rc.line(172, 178, 164, 223, { stroke: WHITE, strokeWidth: 1.8, roughness: 0.6 }));
40
+
41
+ svg.appendChild(rc.line(56, 76, 43, 61, detail));
42
+ svg.appendChild(rc.line(50, 85, 35, 80, detail));
43
+ svg.appendChild(rc.line(245, 221, 258, 207, detail));
44
+ svg.appendChild(rc.line(250, 231, 264, 228, detail));
45
+ </script>
46
+ </body>
47
+ </html>
static/data/handdraw_v1/html/qwen30b_hourglass.html ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><meta charset="UTF-8"><title>Hourglass</title></head>
4
+ <body style="display:flex;align-items:center;justify-content:center;min-height:100vh;background:#e8dcc8;">
5
+ <svg id="art" viewBox="0 0 300 300" width="300" height="300" xmlns="http://www.w3.org/2000/svg"></svg>
6
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
7
+ <script>
8
+ const INK = '#1a1a1a';
9
+ const WHITE = '#f0ebe0';
10
+
11
+ const svg = document.getElementById('art');
12
+ const rc = rough.svg(svg);
13
+
14
+ // Hourglass illustration
15
+
16
+ // Main hourglass outline
17
+ const outlineOpts = { stroke: INK, strokeWidth: 3.5, fill: 'none', roughness: 0.8 };
18
+ // Top bulb
19
+ svg.appendChild(rc.path('M 100 50 A 50 50 0 0 1 200 50', outlineOpts));
20
+ // Bottom bulb
21
+ svg.appendChild(rc.path('M 100 250 A 50 50 0 0 1 200 250', outlineOpts));
22
+ // Neck
23
+ svg.appendChild(rc.line(125, 100, 125, 200, outlineOpts));
24
+ svg.appendChild(rc.line(175, 100, 175, 200, outlineOpts));
25
+
26
+ // Sand particles in top bulb
27
+ const sandOpts = { stroke: INK, strokeWidth: 1.5, roughness: 0.8 };
28
+ svg.appendChild(rc.line(115, 60, 120, 70, sandOpts));
29
+ svg.appendChild(rc.line(130, 65, 135, 75, sandOpts));
30
+ svg.appendChild(rc.line(145, 70, 150, 80, sandOpts));
31
+ svg.appendChild(rc.line(160, 60, 165, 70, sandOpts));
32
+ svg.appendChild(rc.line(175, 65, 180, 75, sandOpts));
33
+
34
+ // Sand particles in bottom bulb
35
+ svg.appendChild(rc.line(115, 230, 120, 220, sandOpts));
36
+ svg.appendChild(rc.line(130, 225, 135, 215, sandOpts));
37
+ svg.appendChild(rc.line(145, 220, 150, 210, sandOpts));
38
+ svg.appendChild(rc.line(160, 230, 165, 220, sandOpts));
39
+ svg.appendChild(rc.line(175, 225, 180, 215, sandOpts));
40
+
41
+ // Sand stream in neck
42
+ svg.appendChild(rc.line(130, 100, 135, 120, sandOpts));
43
+ svg.appendChild(rc.line(140, 110, 145, 130, sandOpts));
44
+ svg.appendChild(rc.line(150, 120, 155, 140, sandOpts));
45
+ svg.appendChild(rc.line(160, 130, 165, 150, sandOpts));
46
+ svg.appendChild(rc.line(170, 140, 175, 160, sandOpts));
47
+
48
+ // Decorative elements
49
+ const sparkOpts = { stroke: INK, strokeWidth: 2.5, roughness: 0.8 };
50
+ svg.appendChild(rc.line(90, 45, 80, 35, sparkOpts));
51
+ svg.appendChild(rc.line(210, 45, 220, 35, sparkOpts));
52
+ svg.appendChild(rc.line(90, 255, 80, 265, sparkOpts));
53
+ svg.appendChild(rc.line(210, 255, 220, 265, sparkOpts));
54
+
55
+ </script>
56
+ </body>
57
+ </html>
static/data/handdraw_v1/html/qwen30b_hourglass_v2.html ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><meta charset="UTF-8"><title>Hourglass</title></head>
4
+ <body style="display:flex;align-items:center;justify-content:center;min-height:100vh;background:#e8dcc8;">
5
+ <svg id="art" viewBox="0 0 300 300" width="300" height="300" xmlns="http://www.w3.org/2000/svg"></svg>
6
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
7
+ <script>
8
+ const INK = '#1a1a1a';
9
+ const WHITE = '#f0ebe0';
10
+
11
+ const svg = document.getElementById('art');
12
+ const rc = rough.svg(svg);
13
+
14
+ // Hourglass illustration
15
+ const outlineOpts = { stroke: INK, strokeWidth: 3.5, fill: 'none', roughness: 0.8 };
16
+
17
+ // Top bulb
18
+ svg.appendChild(rc.polygon([[150, 60], [100, 120], [200, 120]], outlineOpts));
19
+
20
+ // Middle narrow section
21
+ svg.appendChild(rc.rectangle(130, 120, 40, 60, outlineOpts));
22
+
23
+ // Bottom bulb
24
+ svg.appendChild(rc.polygon([[150, 240], [100, 180], [200, 180]], outlineOpts));
25
+
26
+ // Sand particles in top bulb
27
+ const sandOpts = { stroke: INK, strokeWidth: 1.5, roughness: 0.8 };
28
+ svg.appendChild(rc.line(135, 90, 140, 100, sandOpts));
29
+ svg.appendChild(rc.line(165, 95, 160, 105, sandOpts));
30
+ svg.appendChild(rc.line(145, 85, 150, 95, sandOpts));
31
+
32
+ // Sand particles in bottom bulb
33
+ svg.appendChild(rc.line(135, 210, 140, 200, sandOpts));
34
+ svg.appendChild(rc.line(165, 215, 160, 205, sandOpts));
35
+ svg.appendChild(rc.line(145, 220, 150, 210, sandOpts));
36
+
37
+ // Optional: add some texture to the hourglass
38
+ svg.appendChild(rc.line(125, 120, 125, 180, { stroke: INK, strokeWidth: 1, roughness: 0.8 }));
39
+ svg.appendChild(rc.line(175, 120, 175, 180, { stroke: INK, strokeWidth: 1, roughness: 0.8 }));
40
+
41
+ </script>
42
+ </body>
43
+ </html>
static/data/handdraw_v1/html/sonnet_hourglass.html ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head><meta charset="UTF-8"><title>Draw: HOURGLASS</title></head>
4
+ <body style="display:flex;align-items:center;justify-content:center;min-height:100vh;background:#e8dcc8;">
5
+ <svg id="art" viewBox="0 0 300 300" width="300" height="300" xmlns="http://www.w3.org/2000/svg"></svg>
6
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
7
+ <script>
8
+ const INK = '#1a1a1a';
9
+ const WHITE = '#f0ebe0';
10
+
11
+ const svg = document.getElementById('art');
12
+ const rc = rough.svg(svg);
13
+
14
+ // === HOURGLASS ILLUSTRATION ===
15
+ const outlineOpts = { stroke: INK, strokeWidth: 3.5, fill: 'none', roughness: 0.8 };
16
+ const sandOpts = { stroke: INK, strokeWidth: 2, fill: INK, fillStyle: 'solid', roughness: 0.6 };
17
+
18
+ // Hourglass outline using curved paths for more traditional shape
19
+ svg.appendChild(rc.path('M 80 60 L 220 60 L 150 150 Z', outlineOpts));
20
+ svg.appendChild(rc.path('M 80 240 L 220 240 L 150 150 Z', outlineOpts));
21
+
22
+ // Top and bottom caps
23
+ svg.appendChild(rc.rectangle(70, 50, 160, 15, outlineOpts));
24
+ svg.appendChild(rc.rectangle(70, 235, 160, 15, outlineOpts));
25
+
26
+ // Sand in top chamber
27
+ svg.appendChild(rc.polygon([[95, 75], [185, 75], [140, 125]], sandOpts));
28
+
29
+ // Sand in bottom chamber
30
+ svg.appendChild(rc.polygon([[95, 225], [155, 225], [125, 195]], sandOpts));
31
+
32
+ // Falling sand
33
+ svg.appendChild(rc.line(150, 145, 148, 160, { stroke: INK, strokeWidth: 2, roughness: 0.5 }));
34
+ svg.appendChild(rc.line(151, 162, 149, 175, { stroke: INK, strokeWidth: 2, roughness: 0.5 }));
35
+ svg.appendChild(rc.line(150, 177, 148, 190, { stroke: INK, strokeWidth: 2, roughness: 0.5 }));
36
+
37
+ // Center waist detail
38
+ svg.appendChild(rc.circle(150, 150, 8, { stroke: INK, strokeWidth: 2, fill: 'none', roughness: 0.6 }));
39
+
40
+ </script>
41
+ </body>
42
+ </html>
static/index.html ADDED
@@ -0,0 +1,1491 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SuperGeneral β€” Compositional Tool Environments for Long-Horizon Agents</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400&family=Space+Grotesk:wght@300;400;500;600;700&display=swap" rel="stylesheet">
8
+ <style>
9
+ :root {
10
+ --bg: #F5F0E8;
11
+ --charcoal: #1E1E1E;
12
+ --panel: #252525;
13
+ --text: #1E1E1E;
14
+ --text-light: #E0DCD4;
15
+ --text-dim: #888;
16
+ --green: #39FF14;
17
+ --cyan: #00E5FF;
18
+ --amber: #FFB800;
19
+ --red: #FF3B3B;
20
+ --font-mono: 'Space Mono', 'SF Mono', 'Menlo', monospace;
21
+ --font-sans: 'Space Grotesk', system-ui, -apple-system, sans-serif;
22
+ }
23
+ * { margin: 0; padding: 0; box-sizing: border-box; }
24
+ body { background: var(--bg); font-family: var(--font-sans); color: var(--text); line-height: 1.6; }
25
+ .container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
26
+
27
+ /* ── Chrome ── */
28
+ .window-dots { display: flex; gap: 7px; margin-bottom: 18px; }
29
+ .dot { width: 12px; height: 12px; border-radius: 50%; }
30
+ .dot-red { background: #FF5F57; }
31
+ .dot-yellow { background: #FFBD2E; }
32
+ .dot-green { background: #28C840; }
33
+
34
+ /* ── Section headers ── */
35
+ .section-header {
36
+ font-family: var(--font-mono); font-size: 12px; font-weight: 700;
37
+ letter-spacing: 4px; text-transform: uppercase; color: var(--text-dim);
38
+ margin-bottom: 24px; margin-top: 64px;
39
+ }
40
+ .section-header span { color: var(--amber); }
41
+
42
+ /* ── Panels ── */
43
+ .panel {
44
+ background: var(--charcoal); border-radius: 10px;
45
+ padding: 32px 36px; margin-bottom: 28px;
46
+ }
47
+ .panel-title {
48
+ font-family: var(--font-sans); font-size: 15px; font-weight: 600;
49
+ color: var(--cyan); margin-bottom: 24px; line-height: 1.4;
50
+ }
51
+
52
+ /* ══════════════════════════════════════════════ */
53
+ /* SECTION 1: HERO */
54
+ /* ══════════════════════════════════════════════ */
55
+ .teaser {
56
+ background: var(--charcoal); padding: 56px 48px 48px; margin-bottom: 40px;
57
+ position: relative; overflow: hidden;
58
+ }
59
+ /* Hero: left title + right demo */
60
+ .hero-split {
61
+ display: grid; grid-template-columns: 2fr 3fr; gap: 32px; align-items: center;
62
+ }
63
+ .hero-left { padding-right: 8px; }
64
+ .hero-label {
65
+ font-family: var(--font-mono); font-size: 11px; font-weight: 700;
66
+ letter-spacing: 4px; text-transform: uppercase; color: #555; margin-bottom: 14px;
67
+ }
68
+ .hero-title {
69
+ font-family: var(--font-sans); font-size: 56px; font-weight: 700;
70
+ color: var(--text-light); letter-spacing: -1px; line-height: 1.1;
71
+ }
72
+ .hero-subtitle {
73
+ font-family: var(--font-sans); font-size: 56px; font-weight: 700;
74
+ color: var(--cyan); letter-spacing: -1px; line-height: 1.1;
75
+ margin-bottom: 20px;
76
+ }
77
+
78
+ /* Demo card β€” fixed height to prevent layout shift */
79
+ .hero-card {
80
+ background: #181818; border-radius: 10px; padding: 24px 28px;
81
+ border: 1px solid #2a2a2a;
82
+ }
83
+ .hero-prompt {
84
+ font-family: var(--font-mono); font-size: 15px; font-weight: 700;
85
+ color: var(--green); margin-bottom: 16px; min-height: 24px;
86
+ }
87
+ .term-cursor {
88
+ display: inline-block; width: 9px; height: 18px;
89
+ background: var(--green); animation: blink 1s step-end infinite;
90
+ vertical-align: text-bottom; margin-left: 2px;
91
+ }
92
+ @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
93
+
94
+ .hero-body {
95
+ display: grid; grid-template-columns: 1fr 1fr; gap: 28px; align-items: start;
96
+ }
97
+
98
+ /* Decomposition tree */
99
+ .hero-tree {
100
+ font-family: var(--font-mono); font-size: 12px; line-height: 1.8;
101
+ color: var(--text-dim);
102
+ }
103
+ .hero-tree-label {
104
+ color: var(--cyan); font-style: italic; margin-bottom: 8px; font-size: 11px;
105
+ }
106
+ .hero-tree-think {
107
+ font-family: var(--font-mono); font-size: 11px; color: var(--text-dim);
108
+ line-height: 1.6; margin-bottom: 10px; font-style: italic;
109
+ opacity: 0; transition: opacity 0.4s;
110
+ }
111
+ .hero-tree-think.visible { opacity: 1; }
112
+ .hero-tree-root {
113
+ color: var(--text-light); font-weight: 700; font-size: 13px; margin-bottom: 4px;
114
+ opacity: 0; transition: opacity 0.3s;
115
+ }
116
+ .hero-tree-root.visible { opacity: 1; }
117
+ .tree-row {
118
+ opacity: 0; transition: opacity 0.35s; display: flex; align-items: center; gap: 6px;
119
+ }
120
+ .tree-indent { padding-left: 20px; }
121
+ .tree-row.visible { opacity: 1; }
122
+ .tree-branch { color: #444; user-select: none; }
123
+ .tree-name { color: var(--text-light); }
124
+ .tree-arrow { color: #555; }
125
+ .tree-ref { color: var(--text-dim); }
126
+ .tree-dim { color: #555; font-size: 10px; }
127
+ .tree-check { color: var(--green); opacity: 0; transition: opacity 0.3s 0.15s; font-size: 11px; }
128
+ .tree-row.visible .tree-check { opacity: 1; }
129
+
130
+ /* Render area */
131
+ .hero-render {
132
+ display: flex; justify-content: center; align-items: center;
133
+ opacity: 0; transition: opacity 0.8s; align-self: stretch;
134
+ min-width: 300px; min-height: 300px;
135
+ }
136
+ .hero-render.visible { opacity: 1; }
137
+ .hero-render svg {
138
+ background: #e8dcc8; border-radius: 10px;
139
+ border: 1px dashed rgba(26,26,26,0.15);
140
+ }
141
+
142
+ .hero-pipeline {
143
+ display: flex; align-items: center; justify-content: center; gap: 0; flex-wrap: wrap;
144
+ font-family: var(--font-mono); font-size: 11px;
145
+ margin-top: 20px; padding-top: 20px; border-top: 1px solid #2a2a2a;
146
+ }
147
+ .hero-pipe-step {
148
+ color: var(--green); padding: 5px 10px;
149
+ border: 1px solid rgba(57,255,20,0.25); border-radius: 3px;
150
+ }
151
+ .hero-pipe-arrow { color: var(--text-dim); padding: 0 6px; }
152
+
153
+ /* Cherry blossom growth animations */
154
+ @keyframes hero-grow-up { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
155
+ @keyframes hero-shrink-down { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(100% 0 0 0); } }
156
+ @keyframes hero-draw { to { stroke-dashoffset: 0; } }
157
+ @keyframes hero-pop { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } }
158
+ @keyframes hero-sway {
159
+ 0%, 100% { transform: rotate(0deg); }
160
+ 25% { transform: rotate(1.2deg); }
161
+ 75% { transform: rotate(-1.5deg); }
162
+ }
163
+ /* Reverse: fade out */
164
+ @keyframes hero-fade-out { to { opacity: 0; } }
165
+
166
+ /* ══════════════════════════════════════════════ */
167
+ /* SECTION 2: MODEL PICKER */
168
+ /* ══════════════════════════════════════════════ */
169
+ .model-buttons {
170
+ display: flex; gap: 10px; margin-bottom: 28px; flex-wrap: wrap;
171
+ }
172
+ .model-btn {
173
+ font-family: var(--font-mono); font-size: 12px; font-weight: 700;
174
+ padding: 10px 20px; border-radius: 6px; border: 1.5px solid #3a3a3a;
175
+ background: rgba(255,255,255,0.03); color: var(--text-dim); cursor: pointer;
176
+ transition: all 0.25s;
177
+ }
178
+ .model-btn:hover { border-color: var(--text-light); color: var(--text-light); background: rgba(255,255,255,0.06); }
179
+ .model-btn.active { border-color: var(--green); color: var(--green); background: rgba(57,255,20,0.1); }
180
+
181
+ .eval-grid {
182
+ display: grid; grid-template-columns: 1fr 1fr; gap: 28px; align-items: start;
183
+ }
184
+ .traj-panel { background: var(--panel); border-radius: 8px; padding: 24px 28px; height: 580px; overflow-y: auto; }
185
+ .traj-header {
186
+ display: flex; justify-content: space-between; align-items: center;
187
+ margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid #333;
188
+ }
189
+ .traj-model { font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--text-light); }
190
+ .traj-result { font-family: var(--font-mono); font-size: 11px; padding: 3px 8px; border-radius: 3px; }
191
+ .traj-result.pass { background: rgba(57,255,20,0.15); color: var(--green); }
192
+ .traj-result.fail { background: rgba(255,59,59,0.15); color: var(--red); }
193
+ .traj-result.unclear { background: rgba(255,184,0,0.15); color: var(--amber); }
194
+ .traj-summary {
195
+ font-family: var(--font-sans); font-size: 12px; color: var(--text-dim);
196
+ margin-top: 14px; padding-top: 12px; border-top: 1px solid #333; line-height: 1.5;
197
+ }
198
+ .traj-summary strong { color: var(--text-light); }
199
+ .traj-tool-use {
200
+ font-family: var(--font-sans); font-size: 12px; color: var(--text-dim);
201
+ margin-top: 10px; padding-top: 10px; border-top: 1px solid #333; line-height: 1.5;
202
+ }
203
+ .traj-tool-use strong { color: var(--text-light); }
204
+ .tool-use-yes { color: var(--green); font-weight: 700; font-family: var(--font-mono); font-size: 11px; }
205
+ .tool-use-no { color: var(--red); font-weight: 700; font-family: var(--font-mono); font-size: 11px; }
206
+ .tool-use-detail { color: var(--text-dim); }
207
+ .traj-blocks-inline {
208
+ display: flex; gap: 10px; flex-wrap: wrap; margin-top: 10px;
209
+ }
210
+ .block-thumb {
211
+ display: flex; flex-direction: column; align-items: center; gap: 4px;
212
+ }
213
+ .block-thumb svg {
214
+ background: #e8dcc8; border-radius: 6px;
215
+ border: 1px solid #333;
216
+ }
217
+ .block-thumb-label {
218
+ font-family: var(--font-mono); font-size: 9px; color: var(--text-dim);
219
+ }
220
+
221
+ .render-panel { background: var(--panel); border-radius: 8px; padding: 24px 28px; height: 580px; overflow-y: auto; }
222
+ .render-header {
223
+ font-family: var(--font-mono); font-size: 12px; font-weight: 700;
224
+ color: var(--text-light); margin-bottom: 16px; padding-bottom: 12px;
225
+ border-bottom: 1px solid #333;
226
+ }
227
+ .render-frame {
228
+ background: #e8dcc8; border-radius: 8px; overflow: hidden;
229
+ aspect-ratio: 1; border: 1.5px solid #333; margin-bottom: 16px;
230
+ }
231
+ .render-frame iframe { width: 100%; height: 100%; border: none; pointer-events: none; }
232
+
233
+
234
+ /* ══════════════════════════════════════════════ */
235
+ /* SECTION 3: PIPELINE + SCALE OUT + LEADERBOARD */
236
+ /* ══════════════════════════════════════════════ */
237
+
238
+ /* Distill layout: core tree + arrow + domain grid */
239
+ .distill-layout {
240
+ display: flex; align-items: flex-start; gap: 0;
241
+ }
242
+ .distill-core {
243
+ flex-shrink: 0; width: 260px; padding-right: 24px;
244
+ }
245
+ .distill-core-label {
246
+ font-family: var(--font-mono); font-size: 11px; font-weight: 700;
247
+ letter-spacing: 2px; text-transform: uppercase; color: var(--cyan);
248
+ margin-bottom: 12px;
249
+ }
250
+ .distill-core-sub {
251
+ font-family: var(--font-sans); font-size: 12px; color: var(--text-dim);
252
+ margin-top: 16px; line-height: 1.5;
253
+ }
254
+ .distill-arrow {
255
+ flex-shrink: 0; font-size: 24px; color: var(--text-dim);
256
+ padding: 0 20px; align-self: center;
257
+ }
258
+ .distill-domains {
259
+ flex: 1; display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px;
260
+ }
261
+
262
+ .domain-col {
263
+ background: var(--panel); border-radius: 8px; padding: 16px;
264
+ border-top: 3px solid var(--text-dim);
265
+ }
266
+ .domain-col.d1 { border-top-color: var(--green); }
267
+ .domain-col.d2 { border-top-color: var(--cyan); }
268
+ .domain-col.d4 { border-top-color: var(--amber); }
269
+ .domain-col.d5 { border-top-color: #c084fc; }
270
+ .domain-title {
271
+ font-family: var(--font-mono); font-size: 11px; font-weight: 700;
272
+ letter-spacing: 1px; margin-bottom: 10px;
273
+ }
274
+ .domain-col.d1 .domain-title { color: var(--green); }
275
+ .domain-col.d2 .domain-title { color: var(--cyan); }
276
+ .domain-col.d4 .domain-title { color: var(--amber); }
277
+ .domain-col.d5 .domain-title { color: #c084fc; }
278
+ .domain-col .hero-tree { font-size: 10px; line-height: 1.9; }
279
+ .domain-mode {
280
+ margin-top: 10px; padding-top: 8px; border-top: 1px solid #333; text-align: center;
281
+ }
282
+ .domain-mode-tag {
283
+ font-family: var(--font-mono); font-size: 9px; font-weight: 700;
284
+ letter-spacing: 1px; text-transform: uppercase; padding: 3px 8px;
285
+ border-radius: 3px;
286
+ }
287
+ .domain-mode-tag.visual { color: var(--green); background: rgba(57,255,20,0.1); }
288
+ .domain-mode-tag.text { color: var(--amber); background: rgba(255,184,0,0.1); }
289
+ .domain-mode-tag.mixed { color: #c084fc; background: rgba(192,132,252,0.1); }
290
+ .domain-mode-tag.tools { color: var(--cyan); background: rgba(0,229,255,0.1); }
291
+
292
+ .lb-grid-4 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
293
+ .lb-panel { padding: 20px; }
294
+ .lb-panel table { font-size: 11px; table-layout: fixed; }
295
+ .lb-panel th { font-size: 10px; }
296
+ .lb-panel td { padding: 7px 6px; }
297
+ .lb-panel th:nth-child(1),
298
+ .lb-panel td:nth-child(1) { width: 28%; }
299
+ .lb-panel th:nth-child(2),
300
+ .lb-panel th:nth-child(3),
301
+ .lb-panel th:nth-child(4) { width: 10%; text-align: center; }
302
+ .lb-panel td:nth-child(2),
303
+ .lb-panel td:nth-child(3),
304
+ .lb-panel td:nth-child(4) { text-align: center; }
305
+ .lb-panel th:nth-child(5),
306
+ .lb-panel td:nth-child(5) { width: 42%; padding-left: 36px; }
307
+ .lb-coming-soon {
308
+ font-family: var(--font-mono); font-size: 12px; color: var(--text-dim);
309
+ text-align: center; padding: 48px 0; opacity: 0.5;
310
+ }
311
+ table {
312
+ width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-size: 13px;
313
+ }
314
+ th {
315
+ color: var(--text-dim); font-weight: 400; text-align: left; padding: 6px 8px;
316
+ border-bottom: 1px solid #333; font-size: 11px; letter-spacing: 1px; text-transform: uppercase;
317
+ }
318
+ td { color: var(--text-light); padding: 10px 8px; border-bottom: 1px solid #2a2a2a; }
319
+ tr.highlight td { color: var(--green); }
320
+ tr.correct td.shape { color: var(--green); }
321
+ tr.wrong td.shape { color: var(--red); }
322
+ .rank { color: var(--text-dim); width: 30px; }
323
+ .steps { color: var(--text-dim); font-size: 11px; }
324
+ .metric-yes { color: var(--green); }
325
+ .metric-no { color: var(--red); opacity: 0.6; }
326
+ .reward-cell {
327
+ display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
328
+ }
329
+ .reward-num {
330
+ font-family: var(--font-mono); font-size: 13px; font-weight: 600; color: var(--text-light);
331
+ }
332
+ .reward-bar {
333
+ display: block; height: 8px; background: var(--green);
334
+ border-radius: 2px; opacity: 0.7; min-width: 4px;
335
+ }
336
+ .hl { color: var(--green); font-weight: 600; }
337
+
338
+ /* ── Try It Live ── */
339
+ .tryit-bar {
340
+ display: flex; align-items: center; gap: 12px; margin-bottom: 20px;
341
+ padding-bottom: 20px; border-bottom: 1px solid #333;
342
+ }
343
+ .tryit-select {
344
+ font-family: var(--font-mono); font-size: 12px; padding: 8px 12px;
345
+ background: #181818; color: var(--text-light); border: 1.5px solid #3a3a3a;
346
+ border-radius: 6px; cursor: pointer;
347
+ }
348
+ .tryit-select:focus { border-color: var(--green); outline: none; }
349
+ .tryit-btn {
350
+ font-family: var(--font-mono); font-size: 12px; font-weight: 700;
351
+ padding: 8px 20px; border-radius: 6px; border: 1.5px solid var(--green);
352
+ background: rgba(57,255,20,0.1); color: var(--green); cursor: pointer;
353
+ transition: all 0.2s; white-space: nowrap;
354
+ }
355
+ .tryit-btn:hover { background: rgba(57,255,20,0.2); }
356
+ .tryit-btn:disabled { opacity: 0.4; cursor: not-allowed; }
357
+ .tryit-label {
358
+ font-family: var(--font-mono); font-size: 10px; font-weight: 700;
359
+ letter-spacing: 2px; text-transform: uppercase; color: var(--text-dim);
360
+ margin-bottom: 10px;
361
+ }
362
+ .live-traj-panel {
363
+ background: var(--panel); border-radius: 8px; padding: 24px 28px;
364
+ max-height: 580px; overflow-y: auto; display: none;
365
+ }
366
+ .live-traj-panel.active { display: block; }
367
+ .live-step {
368
+ border-left: 3px solid var(--amber); padding: 8px 14px; margin-bottom: 8px;
369
+ background: rgba(255,255,255,0.02);
370
+ }
371
+ .live-step.done { border-left-color: var(--green); }
372
+ .live-step.talk { border-left-color: #555; }
373
+ .live-step-label {
374
+ font-family: var(--font-mono); font-size: 9px; letter-spacing: 2px;
375
+ text-transform: uppercase; margin-bottom: 3px; color: var(--text-dim);
376
+ }
377
+ .live-step-cmd {
378
+ font-family: var(--font-mono); font-size: 11px; color: var(--amber);
379
+ background: #111; padding: 4px 8px; border: 1px solid #333;
380
+ white-space: pre-wrap; word-break: break-all;
381
+ }
382
+ .live-step-obs {
383
+ font-family: var(--font-mono); font-size: 10px; color: #aaa;
384
+ background: #111; padding: 4px 8px; border: 1px solid #333;
385
+ margin-top: 4px; max-height: 80px; overflow-y: auto;
386
+ white-space: pre-wrap; word-break: break-all;
387
+ }
388
+ .live-reward {
389
+ font-family: var(--font-mono); font-size: 14px; font-weight: 700;
390
+ color: var(--green); margin-top: 12px; padding-top: 12px;
391
+ border-top: 1px solid #333;
392
+ }
393
+ .live-spinner {
394
+ display: inline-block; width: 12px; height: 12px;
395
+ border: 2px solid var(--green); border-top-color: transparent;
396
+ border-radius: 50%; animation: spin 0.8s linear infinite;
397
+ margin-left: 8px; vertical-align: middle;
398
+ }
399
+ @keyframes spin { to { transform: rotate(360deg); } }
400
+
401
+ /* ── Footer ── */
402
+ .footer {
403
+ text-align: center; padding: 40px;
404
+ font-family: var(--font-mono); font-size: 11px; color: var(--text-dim);
405
+ }
406
+ .footer a { color: var(--cyan); text-decoration: none; }
407
+
408
+ @media (max-width: 900px) {
409
+ .hero-split { grid-template-columns: 1fr; }
410
+ .hero-title, .hero-subtitle { font-size: 36px; }
411
+ .hero-body { grid-template-columns: 1fr; }
412
+ .hero-render { margin-top: 16px; }
413
+ .eval-grid { grid-template-columns: 1fr; }
414
+ .lb-grid-4 { grid-template-columns: 1fr 1fr; }
415
+ .distill-layout { flex-direction: column; }
416
+ .distill-core { width: 100%; padding-right: 0; margin-bottom: 16px; }
417
+ .distill-arrow { display: none; }
418
+ .distill-domains { grid-template-columns: 1fr 1fr; }
419
+ }
420
+ </style>
421
+ </head>
422
+ <body>
423
+
424
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
425
+ <!-- SECTION 1: ANIMATED TEASER β€” "The Building Block Concept" -->
426
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
427
+ <div class="teaser">
428
+ <div class="container">
429
+ <div class="hero-split">
430
+ <div class="hero-left">
431
+ <div class="hero-label">OpenEnv Hackathon 2026</div>
432
+ <h1 class="hero-title">SuperGeneral</h1>
433
+ <div class="hero-subtitle">Compositional Tool Environments for Long-Horizon Agents</div>
434
+ </div>
435
+
436
+ <div class="hero-card">
437
+ <div class="hero-prompt" id="heroPrompt"></div>
438
+ <div class="hero-body">
439
+ <div class="hero-tree">
440
+ <div class="hero-tree-label" id="treeLabel"></div>
441
+ <div class="hero-tree-think" id="treeThink"></div>
442
+ <div class="hero-tree-root" id="treeRoot"></div>
443
+ <!-- Level 1: tree + growing -->
444
+ <div class="tree-row" id="tr0">
445
+ <span class="tree-branch">&boxvr;&boxh;</span>
446
+ <span class="tree-name">tree</span>
447
+ <span class="tree-dim">(composition)</span>
448
+ </div>
449
+ <!-- Level 2: tree parts -->
450
+ <div class="tree-row tree-indent" id="tr1">
451
+ <span class="tree-branch">&boxvr;&boxh;</span>
452
+ <span class="tree-name">trunk</span>
453
+ <span class="tree-arrow">&rarr;</span>
454
+ <span class="tree-ref">curve.js</span>
455
+ <span class="tree-check">&check;</span>
456
+ </div>
457
+ <div class="tree-row tree-indent" id="tr2">
458
+ <span class="tree-branch">&boxvr;&boxh;</span>
459
+ <span class="tree-name">branches</span>
460
+ <span class="tree-arrow">&rarr;</span>
461
+ <span class="tree-ref">path.js</span>
462
+ <span class="tree-check">&check;</span>
463
+ </div>
464
+ <div class="tree-row tree-indent" id="tr3">
465
+ <span class="tree-branch">&boxvr;&boxh;</span>
466
+ <span class="tree-name">forks</span>
467
+ <span class="tree-arrow">&rarr;</span>
468
+ <span class="tree-ref">circle.js</span>
469
+ <span class="tree-check">&check;</span>
470
+ </div>
471
+ <div class="tree-row tree-indent" id="tr4">
472
+ <span class="tree-branch">&boxur;&boxh;</span>
473
+ <span class="tree-name">blossoms</span>
474
+ <span class="tree-arrow">&rarr;</span>
475
+ <span class="tree-ref">circle.js</span>
476
+ <span class="tree-check">&check;</span>
477
+ </div>
478
+ <!-- Level 1 continued: growing -->
479
+ <div class="tree-row" id="tr5">
480
+ <span class="tree-branch">&boxur;&boxh;</span>
481
+ <span class="tree-name">growing</span>
482
+ <span class="tree-dim">(animation)</span>
483
+ </div>
484
+ <!-- Level 2: growth animations -->
485
+ <div class="tree-row tree-indent" id="tr6">
486
+ <span class="tree-branch">&boxvr;&boxh;</span>
487
+ <span class="tree-name">grow-up</span>
488
+ <span class="tree-arrow">&rarr;</span>
489
+ <span class="tree-ref">clip-path</span>
490
+ <span class="tree-check">&check;</span>
491
+ </div>
492
+ <div class="tree-row tree-indent" id="tr7">
493
+ <span class="tree-branch">&boxvr;&boxh;</span>
494
+ <span class="tree-name">draw-in</span>
495
+ <span class="tree-arrow">&rarr;</span>
496
+ <span class="tree-ref">stroke-dash</span>
497
+ <span class="tree-check">&check;</span>
498
+ </div>
499
+ <div class="tree-row tree-indent" id="tr8">
500
+ <span class="tree-branch">&boxur;&boxh;</span>
501
+ <span class="tree-name">pop</span>
502
+ <span class="tree-arrow">&rarr;</span>
503
+ <span class="tree-ref">scale</span>
504
+ <span class="tree-check">&check;</span>
505
+ </div>
506
+ </div>
507
+ <div class="hero-render" id="heroRender">
508
+ <svg id="svg-hero-tree" viewBox="0 0 300 300" width="100%" height="100%" style="max-width:420px;max-height:420px;"></svg>
509
+ </div>
510
+ </div>
511
+ <div class="hero-pipeline" id="heroPipeline">
512
+ <span class="hero-pipe-step">Tool Use</span>
513
+ <span class="hero-pipe-arrow">&rarr;</span>
514
+ <span class="hero-pipe-step">Tool Composition</span>
515
+ <span class="hero-pipe-arrow">&rarr;</span>
516
+ <span class="hero-pipe-step">Tool Creation</span>
517
+ </div>
518
+ </div>
519
+ </div>
520
+ </div>
521
+ </div>
522
+
523
+ <div class="container">
524
+
525
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
526
+ <!-- SECTION 2: INTERACTIVE MODEL PICKER β€” "The Evaluation" -->
527
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
528
+ <div class="section-header"><span>01</span> &mdash; The Recomposition Evaluation</div>
529
+
530
+ <div class="panel">
531
+ <div class="window-dots">
532
+ <div class="dot dot-red"></div>
533
+ <div class="dot dot-yellow"></div>
534
+ <div class="dot dot-green"></div>
535
+ </div>
536
+ <div class="panel-title" style="color:var(--green); font-family:var(--font-mono); font-weight:700;">&rsaquo; Compose an hourglass</div>
537
+
538
+ <div class="model-buttons" id="modelButtons"></div>
539
+
540
+ <div class="eval-grid">
541
+ <div class="traj-panel" id="trajPanel"></div>
542
+ <div class="render-panel" id="renderPanel"></div>
543
+ </div>
544
+
545
+ <!-- Try It Live β€” below pre-computed results -->
546
+ <div style="margin-top:28px; padding-top:24px; border-top:1px solid #333;">
547
+ <div class="tryit-label">Try It Live &mdash; run an agent on the SuperGeneral environment</div>
548
+ <div class="tryit-bar">
549
+ <select id="tryitTask" class="tryit-select">
550
+ <option value="hourglass">Hourglass (near)</option>
551
+ <option value="diamond">Diamond (zero)</option>
552
+ <option value="seesaw">Seesaw (medium)</option>
553
+ <option value="temple">Temple (far)</option>
554
+ </select>
555
+ <select id="tryitModel" class="tryit-select">
556
+ <option value="openai/gpt-4o-mini">GPT-4o-mini ($)</option>
557
+ <option value="qwen/qwen3-coder-30b-a3b-instruct">Qwen3-Coder-30B (free)</option>
558
+ <option value="deepseek/deepseek-chat-v3-0324">DeepSeek-V3 (free)</option>
559
+ </select>
560
+ <button id="tryitBtn" class="tryit-btn" onclick="runLiveAgent()">&#9654; Run Agent</button>
561
+ </div>
562
+ <div class="eval-grid" id="liveGrid" style="display:none;">
563
+ <div class="live-traj-panel active" id="liveTrajPanel"></div>
564
+ <div class="render-panel" id="liveRenderPanel" style="display:flex; align-items:center; justify-content:center; color:var(--text-dim); font-family:var(--font-mono); font-size:12px;">Waiting for agent output&hellip;</div>
565
+ </div>
566
+ </div>
567
+
568
+ </div>
569
+
570
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
571
+ <!-- SECTION 3: CORE PRINCIPLE + SCALE OUT β€” "The Distillation" -->
572
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
573
+ <div class="section-header"><span>02</span> &mdash; Scale Down &rarr; Scale Out</div>
574
+
575
+ <div class="panel">
576
+ <div class="window-dots">
577
+ <div class="dot dot-red"></div>
578
+ <div class="dot dot-yellow"></div>
579
+ <div class="dot dot-green"></div>
580
+ </div>
581
+ <div class="panel-title">One strategy. Every domain.</div>
582
+
583
+ <div class="distill-layout">
584
+ <!-- Core Strategy tree -->
585
+ <div class="distill-core">
586
+ <div class="distill-core-label">Core Strategy</div>
587
+ <div class="hero-tree" style="font-size:13px; line-height:2;">
588
+ <div class="tree-row" style="opacity:1;">
589
+ <span class="tree-branch">&boxvr;&boxh;</span>
590
+ <span class="tree-name" style="color:var(--cyan)">Tool Use</span>
591
+ <span class="tree-dim">&mdash; use existing building blocks</span>
592
+ </div>
593
+ <div class="tree-row" style="opacity:1;">
594
+ <span class="tree-branch">&boxvr;&boxh;</span>
595
+ <span class="tree-name" style="color:var(--cyan)">Tool Composition</span>
596
+ <span class="tree-dim">&mdash; combine tools for new goal</span>
597
+ </div>
598
+ <div class="tree-row" style="opacity:1;">
599
+ <span class="tree-branch">&boxur;&boxh;</span>
600
+ <span class="tree-name" style="color:var(--cyan)">Tool Creation</span>
601
+ <span class="tree-dim">&mdash; create new tools for the task</span>
602
+ </div>
603
+ </div>
604
+ <div class="distill-core-sub">Measured by file-system diff. Domain-agnostic. Learned once, applied everywhere.</div>
605
+ </div>
606
+
607
+ <!-- Arrow -->
608
+ <div class="distill-arrow">&rarr;</div>
609
+
610
+ <!-- 4 domain columns -->
611
+ <div class="distill-domains">
612
+ <div class="domain-col d1">
613
+ <div class="domain-title">Hand-Draw</div>
614
+ <div class="hero-tree">
615
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span class="tree-ref">use triangle.js + line.js</span></div>
616
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span style="color:var(--amber)">compose: 2&times;triangle &rarr; hourglass</span></div>
617
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxur;&boxh;</span><span style="color:var(--green)">hourglass.html</span></div>
618
+ </div>
619
+ <div class="domain-mode"><span class="domain-mode-tag visual">visual</span></div>
620
+ </div>
621
+
622
+ <div class="domain-col d4">
623
+ <div class="domain-title">Law</div>
624
+ <div class="hero-tree">
625
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span class="tree-ref">use precedent_template.txt</span></div>
626
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span style="color:var(--amber)">compose: facts + statute &rarr; memo</span></div>
627
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxur;&boxh;</span><span style="color:var(--amber)">legal_memo.txt</span></div>
628
+ </div>
629
+ <div class="domain-mode"><span class="domain-mode-tag text">text-heavy</span></div>
630
+ </div>
631
+
632
+ <div class="domain-col d5">
633
+ <div class="domain-title">Consulting</div>
634
+ <div class="hero-tree">
635
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span class="tree-ref">use framework_template.md</span></div>
636
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span style="color:var(--amber)">compose: framework + data &rarr; deck</span></div>
637
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxur;&boxh;</span><span style="color:var(--amber)">strategy_deck.md</span></div>
638
+ </div>
639
+ <div class="domain-mode"><span class="domain-mode-tag mixed">text + tools</span></div>
640
+ </div>
641
+
642
+ <div class="domain-col d2">
643
+ <div class="domain-title">Investment Banking</div>
644
+ <div class="hero-tree">
645
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span class="tree-ref">use xirr_tool.py + brief.txt</span></div>
646
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxvr;&boxh;</span><span style="color:var(--amber)">compose: cashflows + xirr &rarr; analysis</span></div>
647
+ <div class="tree-row" style="opacity:1;"><span class="tree-branch">&boxur;&boxh;</span><span style="color:var(--cyan)">analysis.txt</span></div>
648
+ </div>
649
+ <div class="domain-mode"><span class="domain-mode-tag tools">tool-heavy</span></div>
650
+ </div>
651
+ </div>
652
+ </div>
653
+ </div>
654
+
655
+ <!-- Part B2: Meta-Strategy Table β€” same structure, different domains -->
656
+ <div class="panel" style="margin-top: 28px;">
657
+ <div class="panel-title">How the environment teaches meta-strategy</div>
658
+ <p style="color:var(--text-dim); font-size:13px; margin-bottom:16px; line-height:1.6;">
659
+ Each domain has a <strong style="color:var(--text-light)">worked example</strong> showing how to compose building blocks into a finished output.
660
+ The agent learns the method &mdash; <em>decompose &rarr; find blocks &rarr; compose</em> &mdash; not the specific answer.
661
+ </p>
662
+ <table style="font-size:12px;">
663
+ <thead>
664
+ <tr>
665
+ <th>Domain</th>
666
+ <th>Worked Example</th>
667
+ <th>Building Blocks</th>
668
+ <th>Meta-Strategy Tip</th>
669
+ </tr>
670
+ </thead>
671
+ <tbody>
672
+ <tr>
673
+ <td style="color:var(--green); font-weight:600;">Hand-Draw</td>
674
+ <td><code style="color:var(--text-light);">diamond.html</code> <span style="color:var(--text-dim)">&mdash; 2 triangles &rarr; diamond</span></td>
675
+ <td><code style="color:var(--cyan);">elements/*.js</code></td>
676
+ <td style="color:var(--text-dim); font-style:italic;">&ldquo;See how illustrations compose from building blocks&rdquo;</td>
677
+ </tr>
678
+ <tr>
679
+ <td style="color:var(--amber); font-weight:600;">Law</td>
680
+ <td><code style="color:var(--text-light);">precedent_memo.txt</code> <span style="color:var(--text-dim)">&mdash; case &rarr; tool &rarr; memo</span></td>
681
+ <td><code style="color:var(--cyan);">tools/royalty_calc.py</code></td>
682
+ <td style="color:var(--text-dim); font-style:italic;">&ldquo;See how memo uses tools and case data&rdquo;</td>
683
+ </tr>
684
+ <tr>
685
+ <td style="color:#c084fc; font-weight:600;">Consulting</td>
686
+ <td><code style="color:var(--text-light);">market_analysis.txt</code> <span style="color:var(--text-dim)">&mdash; data &rarr; framework &rarr; strategy</span></td>
687
+ <td><code style="color:var(--cyan);">tools/tam_tool.py</code></td>
688
+ <td style="color:var(--text-dim); font-style:italic;">&ldquo;See how strategy uses frameworks and market data&rdquo;</td>
689
+ </tr>
690
+ <tr>
691
+ <td style="color:var(--cyan); font-weight:600;">Investment Banking</td>
692
+ <td><code style="color:var(--text-light);">alpha_analysis.txt</code> <span style="color:var(--text-dim)">&mdash; brief &rarr; tool &rarr; result</span></td>
693
+ <td><code style="color:var(--cyan);">tools/xirr_tool.py</code></td>
694
+ <td style="color:var(--text-dim); font-style:italic;">&ldquo;See how analysis uses tools and data&rdquo;</td>
695
+ </tr>
696
+ </tbody>
697
+ </table>
698
+ </div>
699
+
700
+ <!-- Part C: Cross-Domain Leaderboard β€” 4 columns matching domain order -->
701
+ <div class="lb-grid-4">
702
+ <!-- Hand-Draw -->
703
+ <div class="panel lb-panel" style="border-top: 3px solid var(--green);">
704
+ <div class="panel-title" style="color:var(--green); font-size:12px;">Hand-Draw: Hourglass</div>
705
+ <table>
706
+ <thead><tr><th>Model</th><th>Tool Use</th><th>Tool Comp.</th><th>Tool Create</th><th>Reward</th></tr></thead>
707
+ <tbody>
708
+ <tr class="highlight"><td>Claude Sonnet 4</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.700</span><span class="reward-bar" style="width:112px"></span></div></td></tr>
709
+ <tr class="highlight"><td>Qwen3-Coder-30B</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.700</span><span class="reward-bar" style="width:112px"></span></div></td></tr>
710
+ <tr><td>OpenAI GPT-5.4</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.600</span><span class="reward-bar" style="width:96px"></span></div></td></tr>
711
+ <tr><td>OpenAI GPT-4o-mini</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.600</span><span class="reward-bar" style="width:96px"></span></div></td></tr>
712
+ <tr><td>DeepSeek V3</td><td colspan="3" style="color:var(--text-dim); text-align:center;">DNF</td><td style="color:var(--text-dim);">&#8212;</td></tr>
713
+ </tbody>
714
+ </table>
715
+ </div>
716
+ <!-- Law -->
717
+ <div class="panel lb-panel" style="border-top: 3px solid var(--amber);">
718
+ <div class="panel-title" style="color:var(--amber); font-size:12px;">Law: Royalty Dispute</div>
719
+ <table>
720
+ <thead><tr><th>Model</th><th>Tool Use</th><th>Tool Comp.</th><th>Tool Create</th><th>Reward</th></tr></thead>
721
+ <tbody>
722
+ <tr class="highlight"><td>Claude Sonnet 4</td><td class="metric-yes">&#10003;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.730</span><span class="reward-bar" style="width:73px"></span></div></td></tr>
723
+ <tr><td>OpenAI GPT-5.4</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.700</span><span class="reward-bar" style="width:70px"></span></div></td></tr>
724
+ <tr><td>Qwen3-Coder-30B</td><td class="metric-yes">&#10003;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.670</span><span class="reward-bar" style="width:67px"></span></div></td></tr>
725
+ <tr><td>OpenAI GPT-4o-mini</td><td class="metric-no">&#10007;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.210</span><span class="reward-bar" style="width:21px"></span></div></td></tr>
726
+ <tr><td>DeepSeek V3</td><td colspan="3" style="color:var(--text-dim); text-align:center;">DNF</td><td style="color:var(--text-dim);">&#8212;</td></tr>
727
+ </tbody>
728
+ </table>
729
+ </div>
730
+ <!-- Consulting -->
731
+ <div class="panel lb-panel" style="border-top: 3px solid #c084fc;">
732
+ <div class="panel-title" style="color:#c084fc; font-size:12px;">Consulting: Market Entry</div>
733
+ <table>
734
+ <thead><tr><th>Model</th><th>Tool Use</th><th>Tool Comp.</th><th>Tool Create</th><th>Reward</th></tr></thead>
735
+ <tbody>
736
+ <tr class="highlight"><td>Claude Sonnet 4</td><td class="metric-yes">&#10003;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.850</span><span class="reward-bar" style="width:85px"></span></div></td></tr>
737
+ <tr><td>OpenAI GPT-5.4</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.700</span><span class="reward-bar" style="width:70px"></span></div></td></tr>
738
+ <tr><td>Qwen3-Coder-30B</td><td class="metric-yes">&#10003;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.550</span><span class="reward-bar" style="width:55px"></span></div></td></tr>
739
+ <tr><td>OpenAI GPT-4o-mini</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.280</span><span class="reward-bar" style="width:28px"></span></div></td></tr>
740
+ <tr><td>DeepSeek V3</td><td colspan="3" style="color:var(--text-dim); text-align:center;">DNF</td><td style="color:var(--text-dim);">&#8212;</td></tr>
741
+ </tbody>
742
+ </table>
743
+ </div>
744
+ <!-- Investment Banking -->
745
+ <div class="panel lb-panel" style="border-top: 3px solid var(--cyan);">
746
+ <div class="panel-title" style="color:var(--cyan); font-size:12px;">Investment Banking: Financial Analysis</div>
747
+ <table>
748
+ <thead><tr><th>Model</th><th>Tool Use</th><th>Tool Comp.</th><th>Tool Create</th><th>Reward</th></tr></thead>
749
+ <tbody>
750
+ <tr class="highlight"><td>Claude Sonnet 4</td><td class="metric-yes">&#10003;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.741</span><span class="reward-bar" style="width:74px"></span></div></td></tr>
751
+ <tr><td>OpenAI GPT-5.4</td><td class="metric-yes">&#10003;</td><td class="metric-yes">&#10003;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.741</span><span class="reward-bar" style="width:74px"></span></div></td></tr>
752
+ <tr><td>OpenAI GPT-4o-mini</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.327</span><span class="reward-bar" style="width:33px"></span></div></td></tr>
753
+ <tr><td>Qwen3-Coder-30B</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td class="metric-no">&#10007;</td><td><div class="reward-cell"><span class="reward-num">0.327</span><span class="reward-bar" style="width:33px"></span></div></td></tr>
754
+ <tr><td>DeepSeek V3</td><td colspan="3" style="color:var(--text-dim); text-align:center;">DNF</td><td style="color:var(--text-dim);">&#8212;</td></tr>
755
+ </tbody>
756
+ </table>
757
+ </div>
758
+ </div>
759
+
760
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
761
+ <!-- FOOTER -->
762
+ <!-- ═══════════════════════════════════════════════════════════════════ -->
763
+ <div class="footer">
764
+ SuperGeneral &middot; OpenEnv Hackathon 2026 &middot;
765
+ <a href="https://github.com/lilyzhng/OpenEnv">GitHub</a> &middot;
766
+ <a href="https://huggingface.co/spaces/lilyzhng/supergeneral-env">HF Spaces</a>
767
+ </div>
768
+
769
+ </div>
770
+
771
+ <script src="https://unpkg.com/roughjs/bundled/rough.js"></script>
772
+ <script>
773
+ // ══════════════════════════════════════════════════
774
+ // SECTION 1: HERO β€” DECOMPOSITION DEMO
775
+ // ══════════════════════════════════════════════════
776
+ var INK = '#1a1a1a';
777
+ var OLIVE = '#7a8c6e';
778
+
779
+ function heroGrowUp(el, delay, dur) {
780
+ el.style.clipPath = 'inset(100% 0 0 0)';
781
+ el.style.animation = 'hero-grow-up ' + dur + 's ease-out ' + delay + 's forwards';
782
+ }
783
+ function heroDrawIn(el, delay, dur) {
784
+ el.querySelectorAll('path').forEach(function(p) {
785
+ var len = p.getTotalLength();
786
+ p.style.strokeDasharray = len;
787
+ p.style.strokeDashoffset = len;
788
+ p.style.animation = 'hero-draw ' + dur + 's ease-out ' + delay + 's forwards';
789
+ });
790
+ }
791
+ function heroPopIn(el, cx, cy, delay) {
792
+ el.style.opacity = '0';
793
+ el.style.transformOrigin = cx + 'px ' + cy + 'px';
794
+ el.style.animation = 'hero-pop 0.35s cubic-bezier(0.16,1,0.3,1) ' + delay + 's forwards';
795
+ }
796
+
797
+ // Phase groups for reverse animation
798
+ var heroPhases = [];
799
+
800
+ function drawHeroTree() {
801
+ var svg = document.getElementById('svg-hero-tree');
802
+ svg.innerHTML = '';
803
+ heroPhases = [];
804
+ var rc = rough.svg(svg);
805
+ var ns = 'http://www.w3.org/2000/svg';
806
+ var trunkOpts = { stroke: INK, strokeWidth: 4, roughness: 0.6, bowing: 0.3 };
807
+ var branchOpts = { stroke: OLIVE, strokeWidth: 2.5, roughness: 0.7, bowing: 0.4 };
808
+ var nodeOpts = { stroke: OLIVE, strokeWidth: 2.5, fill: OLIVE, fillStyle: 'solid', roughness: 0.6 };
809
+ var darkNodeOpts = { stroke: INK, strokeWidth: 2.5, fill: INK, fillStyle: 'solid', roughness: 0.6 };
810
+
811
+ var sway = document.createElementNS(ns, 'g');
812
+ sway.id = 'hero-sway';
813
+ sway.style.transformOrigin = '150px 275px';
814
+ sway.style.animation = 'hero-sway 4.2s ease-in-out 4.2s infinite';
815
+ svg.appendChild(sway);
816
+
817
+ var el;
818
+
819
+ // Group 0: Trunk
820
+ var gTrunk = document.createElementNS(ns, 'g');
821
+ sway.appendChild(gTrunk);
822
+ heroPhases.push(gTrunk);
823
+
824
+ var trunkMain = document.createElementNS(ns, 'g');
825
+ gTrunk.appendChild(trunkMain);
826
+ trunkMain.appendChild(rc.path('M 150 265 Q 148 205 145 165 Q 142 135 145 110', trunkOpts));
827
+ heroGrowUp(trunkMain, 0, 1.8);
828
+
829
+ el = rc.path('M 150 265 Q 135 270 125 275', trunkOpts);
830
+ gTrunk.appendChild(el); heroDrawIn(el, 0.5, 0.6);
831
+ el = rc.path('M 150 265 Q 165 272 175 277', trunkOpts);
832
+ gTrunk.appendChild(el); heroDrawIn(el, 0.6, 0.6);
833
+
834
+ // Group 1: Primary branches + fork
835
+ var gBranch = document.createElementNS(ns, 'g');
836
+ sway.appendChild(gBranch);
837
+ heroPhases.push(gBranch);
838
+
839
+ el = rc.circle(145, 110, 12, darkNodeOpts);
840
+ gBranch.appendChild(el); heroPopIn(el, 145, 110, 1.6);
841
+
842
+ el = rc.path('M 145 110 Q 175 95 205 80', branchOpts);
843
+ gBranch.appendChild(el); heroDrawIn(el, 1.75, 0.6);
844
+ el = rc.path('M 145 110 Q 160 80 175 55', branchOpts);
845
+ gBranch.appendChild(el); heroDrawIn(el, 1.78, 0.6);
846
+ el = rc.path('M 143 140 Q 175 140 205 135', branchOpts);
847
+ gBranch.appendChild(el); heroDrawIn(el, 1.82, 0.6);
848
+ el = rc.path('M 148 175 Q 178 180 198 190', branchOpts);
849
+ gBranch.appendChild(el); heroDrawIn(el, 1.85, 0.55);
850
+ el = rc.path('M 145 110 Q 112 92 78 78', branchOpts);
851
+ gBranch.appendChild(el); heroDrawIn(el, 1.80, 0.6);
852
+ el = rc.path('M 145 110 Q 128 78 115 52', branchOpts);
853
+ gBranch.appendChild(el); heroDrawIn(el, 1.84, 0.6);
854
+ el = rc.path('M 143 148 Q 108 150 75 158', branchOpts);
855
+ gBranch.appendChild(el); heroDrawIn(el, 1.87, 0.6);
856
+
857
+ // Group 2: Fork nodes + secondary branches
858
+ var gFork = document.createElementNS(ns, 'g');
859
+ sway.appendChild(gFork);
860
+ heroPhases.push(gFork);
861
+
862
+ el = rc.circle(205, 80, 10, darkNodeOpts);
863
+ gFork.appendChild(el); heroPopIn(el, 205, 80, 2.3);
864
+ el = rc.circle(175, 55, 10, darkNodeOpts);
865
+ gFork.appendChild(el); heroPopIn(el, 175, 55, 2.32);
866
+ el = rc.circle(205, 135, 10, darkNodeOpts);
867
+ gFork.appendChild(el); heroPopIn(el, 205, 135, 2.34);
868
+ el = rc.circle(78, 78, 10, darkNodeOpts);
869
+ gFork.appendChild(el); heroPopIn(el, 78, 78, 2.33);
870
+ el = rc.circle(115, 52, 10, darkNodeOpts);
871
+ gFork.appendChild(el); heroPopIn(el, 115, 52, 2.36);
872
+ el = rc.circle(75, 158, 10, darkNodeOpts);
873
+ gFork.appendChild(el); heroPopIn(el, 75, 158, 2.37);
874
+
875
+ el = rc.path('M 205 80 Q 225 70 248 55', branchOpts);
876
+ gFork.appendChild(el); heroDrawIn(el, 2.5, 0.4);
877
+ el = rc.path('M 205 80 Q 230 90 255 95', branchOpts);
878
+ gFork.appendChild(el); heroDrawIn(el, 2.52, 0.4);
879
+ el = rc.path('M 175 55 Q 180 40 190 30', branchOpts);
880
+ gFork.appendChild(el); heroDrawIn(el, 2.52, 0.4);
881
+ el = rc.path('M 175 55 Q 195 50 215 45', branchOpts);
882
+ gFork.appendChild(el); heroDrawIn(el, 2.54, 0.4);
883
+ el = rc.path('M 205 135 Q 235 130 258 140', branchOpts);
884
+ gFork.appendChild(el); heroDrawIn(el, 2.54, 0.4);
885
+ el = rc.path('M 205 135 Q 220 155 235 170', branchOpts);
886
+ gFork.appendChild(el); heroDrawIn(el, 2.56, 0.4);
887
+ el = rc.path('M 78 78 Q 55 62 35 50', branchOpts);
888
+ gFork.appendChild(el); heroDrawIn(el, 2.53, 0.4);
889
+ el = rc.path('M 78 78 Q 48 82 28 92', branchOpts);
890
+ gFork.appendChild(el); heroDrawIn(el, 2.55, 0.4);
891
+ el = rc.path('M 115 52 Q 105 35 95 25', branchOpts);
892
+ gFork.appendChild(el); heroDrawIn(el, 2.57, 0.4);
893
+ el = rc.path('M 75 158 Q 52 168 35 178', branchOpts);
894
+ gFork.appendChild(el); heroDrawIn(el, 2.58, 0.4);
895
+
896
+ // Group 3: Blossoms
897
+ var gBlossom = document.createElementNS(ns, 'g');
898
+ sway.appendChild(gBlossom);
899
+ heroPhases.push(gBlossom);
900
+
901
+ [[248,55,16],[255,95,14],[190,30,14],[215,45,12],
902
+ [258,140,16],[235,170,14],[198,190,12],
903
+ [35,50,15],[28,92,13],[95,25,14],[35,178,14]].forEach(function(p, i) {
904
+ el = rc.circle(p[0], p[1], p[2], nodeOpts);
905
+ gBlossom.appendChild(el);
906
+ heroPopIn(el, p[0], p[1], 3.0 + i * 0.02);
907
+ });
908
+ }
909
+
910
+ // Reverse: time-rewind β€” blossoms β†’ forks/secondary β†’ branches β†’ trunk shrinks into ground
911
+ function reverseHeroTree(cb) {
912
+ // heroPhases: [0:trunk, 1:branches, 2:forks+secondary, 3:blossoms]
913
+ var gap = 600;
914
+ var fadeDur = 0.5;
915
+ var shrinkDur = 1.2; // trunk shrinks slower for dramatic effect
916
+
917
+ for (var i = heroPhases.length - 1; i >= 0; i--) {
918
+ (function(idx) {
919
+ var delay = (heroPhases.length - 1 - idx) * gap;
920
+ setTimeout(function() {
921
+ if (idx === 0) {
922
+ // Trunk: shrink back down into the ground via clip-path
923
+ heroPhases[idx].style.animation = 'hero-shrink-down ' + shrinkDur + 's ease-in forwards';
924
+ } else {
925
+ // Others: fade out
926
+ heroPhases[idx].style.transition = 'opacity ' + fadeDur + 's ease-in';
927
+ heroPhases[idx].style.opacity = '0';
928
+ }
929
+ }, delay);
930
+ })(i);
931
+ }
932
+ // Total: 3 gaps for phases 3β†’2β†’1, then trunk shrink duration
933
+ var totalTime = (heroPhases.length - 1) * gap + shrinkDur * 1000;
934
+ setTimeout(function() { if (cb) cb(); }, totalTime);
935
+ }
936
+
937
+ function typeText(el, text, speed, cb) {
938
+ var i = 0;
939
+ el.textContent = '';
940
+ var cursor = document.createElement('span');
941
+ cursor.className = 'term-cursor';
942
+ el.appendChild(cursor);
943
+ var iv = setInterval(function() {
944
+ if (i < text.length) {
945
+ el.insertBefore(document.createTextNode(text[i]), cursor);
946
+ i++;
947
+ } else {
948
+ clearInterval(iv);
949
+ cursor.remove();
950
+ if (cb) cb();
951
+ }
952
+ }, speed);
953
+ }
954
+
955
+ function runTeaser() {
956
+ var prompt = document.getElementById('heroPrompt');
957
+ var label = document.getElementById('treeLabel');
958
+ var think = document.getElementById('treeThink');
959
+ var root = document.getElementById('treeRoot');
960
+ var rows = [];
961
+ for (var i = 0; i <= 8; i++) rows.push(document.getElementById('tr' + i));
962
+ var render = document.getElementById('heroRender');
963
+
964
+ // Phase 1: Type the prompt
965
+ typeText(prompt, '\u276F draw a growing cherry blossom tree', 50, function() {
966
+
967
+ // Phase 2: Thinking
968
+ setTimeout(function() {
969
+ label.textContent = '\u2234 Thinking\u2026';
970
+ think.innerHTML = '"growing cherry blossom tree" \u2014 new task.<br>= tree (static) + growing (animation)';
971
+ think.classList.add('visible');
972
+
973
+ // Phase 3: Show root + start cherry blossom tree growth + tree rows
974
+ setTimeout(function() {
975
+ root.textContent = 'growing cherry blossom tree';
976
+ root.classList.add('visible');
977
+
978
+ // Start the cherry blossom tree growth animation immediately
979
+ drawHeroTree();
980
+ render.classList.add('visible');
981
+
982
+ // Tree rows appear synced with growth phases
983
+ var delays = [
984
+ 200, // tr0: tree (composition)
985
+ 600, // tr1: trunk β€” syncs with trunk growing
986
+ 1000, // tr2: branches β€” syncs with branches extending
987
+ 1600, // tr3: forks β€” syncs with fork nodes popping
988
+ 2400, // tr4: blossoms β€” syncs with blossoms popping
989
+ 2800, // tr5: growing (animation)
990
+ 3000, // tr6: grow-up
991
+ 3150, // tr7: draw-in
992
+ 3300 // tr8: pop
993
+ ];
994
+ rows.forEach(function(row, i) {
995
+ setTimeout(function() {
996
+ row.classList.add('visible');
997
+ }, delays[i]);
998
+ });
999
+
1000
+ // After full growth + sway pause, reverse
1001
+ setTimeout(function() {
1002
+ // Fade out tree text in reverse order (bottom to top)
1003
+ var rowReverse = [8,7,6,5,4,3,2,1,0];
1004
+ rowReverse.forEach(function(idx, step) {
1005
+ setTimeout(function() {
1006
+ rows[idx].style.transition = 'opacity 0.3s';
1007
+ rows[idx].style.opacity = '0';
1008
+ }, step * 250);
1009
+ });
1010
+ // Simultaneously reverse the cherry blossom tree
1011
+ reverseHeroTree(function() {
1012
+ // Fade out remaining text
1013
+ think.style.transition = 'opacity 0.4s';
1014
+ think.style.opacity = '0';
1015
+ root.style.transition = 'opacity 0.4s';
1016
+ root.style.opacity = '0';
1017
+ label.style.transition = 'opacity 0.4s';
1018
+ label.style.opacity = '0';
1019
+ render.style.transition = 'opacity 0.4s';
1020
+ render.style.opacity = '0';
1021
+ prompt.style.transition = 'opacity 0.4s';
1022
+ prompt.style.opacity = '0';
1023
+
1024
+ // After everything fades, wait 2s then show final state
1025
+ setTimeout(function() {
1026
+ showHeroFinalState();
1027
+ }, 2000);
1028
+ });
1029
+ }, 7000);
1030
+ }, 800);
1031
+ }, 350);
1032
+ });
1033
+ }
1034
+
1035
+ function showHeroFinalState() {
1036
+ var prompt = document.getElementById('heroPrompt');
1037
+ var label = document.getElementById('treeLabel');
1038
+ var think = document.getElementById('treeThink');
1039
+ var root = document.getElementById('treeRoot');
1040
+ var rows = [];
1041
+ for (var i = 0; i <= 8; i++) rows.push(document.getElementById('tr' + i));
1042
+ var render = document.getElementById('heroRender');
1043
+
1044
+ // Reset transitions so everything appears instantly
1045
+ prompt.style.transition = 'none';
1046
+ prompt.style.opacity = '1';
1047
+ prompt.innerHTML = '\u276F draw a growing cherry blossom tree';
1048
+ label.style.transition = 'none'; label.style.opacity = '1';
1049
+ label.textContent = '\u2234 Thinking\u2026';
1050
+ think.style.transition = 'none'; think.style.opacity = '1';
1051
+ think.classList.add('visible');
1052
+ root.style.transition = 'none'; root.style.opacity = '1';
1053
+ root.classList.add('visible');
1054
+ root.textContent = 'growing cherry blossom tree';
1055
+ rows.forEach(function(r) {
1056
+ r.style.transition = 'none';
1057
+ r.style.opacity = '1';
1058
+ r.classList.add('visible');
1059
+ });
1060
+
1061
+ // Redraw the cherry blossom tree in its full state (no animation)
1062
+ drawHeroTree();
1063
+ render.style.transition = 'none';
1064
+ render.style.opacity = '1';
1065
+ render.classList.add('visible');
1066
+
1067
+ // Remove all animations so tree appears fully grown
1068
+ var svg = document.getElementById('svg-hero-tree');
1069
+ svg.querySelectorAll('*').forEach(function(el) {
1070
+ el.style.animation = 'none';
1071
+ el.style.clipPath = 'none';
1072
+ el.style.opacity = '1';
1073
+ el.style.strokeDashoffset = '0';
1074
+ el.style.transform = 'scale(1)';
1075
+ });
1076
+
1077
+ // Fade in smoothly
1078
+ var card = document.querySelector('.hero-card');
1079
+ card.style.transition = 'opacity 0.8s';
1080
+ card.style.opacity = '0';
1081
+ requestAnimationFrame(function() {
1082
+ card.style.opacity = '1';
1083
+ });
1084
+ }
1085
+
1086
+ // ══════════════════════════════════════════════════
1087
+ // SECTION 2: INTERACTIVE MODEL PICKER
1088
+ // ══════════════════════════════════════════════════
1089
+ var modelData = [
1090
+ {
1091
+ name: 'Claude Sonnet 4',
1092
+ result: 'pass',
1093
+ resultLabel: '\u2713 HOURGLASS',
1094
+ shape: 'hourglass',
1095
+ iframe: 'data/handdraw_v1/html/sonnet_hourglass.html',
1096
+ criteria: '5/6',
1097
+ reward: '0.417',
1098
+ method: 'Discovered diamond \u2192 recognized "two triangles" \u2192 adapted orientation.',
1099
+ toolUse: { used: true, label: 'Full analogical reasoning. Reused triangle.js + line.js, adapted diamond pattern.' },
1100
+ blocks: ['triangle', 'line'],
1101
+ phases: [
1102
+ { name: 'Discover', dim: '(explore workspace)', items: [
1103
+ { cmd: 'ls', cls: '' },
1104
+ { cmd: 'cat specs.md', cls: '' },
1105
+ { cmd: 'cat template.html', cls: '' }
1106
+ ]},
1107
+ { name: 'Find Nearest', dim: '(find reference)', items: [
1108
+ { cmd: 'ls elements', cls: '' },
1109
+ { cmd: 'ls examples', cls: '' },
1110
+ { cmd: 'cat examples/diamond.html', cls: 'example' }
1111
+ ]},
1112
+ { name: 'Decompose', dim: '(understand parts)', items: [
1113
+ { cmd: 'cat elements/triangle.js', cls: '' },
1114
+ { cmd: 'cat elements/line.js', cls: '' }
1115
+ ]},
1116
+ { name: 'Recompose', dim: '(adapt & write)', items: [
1117
+ { cmd: 'cat > hourglass.html \u2190 adapted!', cls: 'done' },
1118
+ { cmd: 'rewrites (add caps, sand)...', cls: 'talk' }
1119
+ ]},
1120
+ { name: 'done', dim: '', items: [] }
1121
+ ]
1122
+ },
1123
+ {
1124
+ name: 'OpenAI GPT-5.4',
1125
+ result: 'pass',
1126
+ resultLabel: '\u2713 HOURGLASS',
1127
+ shape: 'hourglass',
1128
+ iframe: 'data/handdraw_v1/html/gpt54_hourglass.html',
1129
+ criteria: '5/6',
1130
+ reward: '0.833',
1131
+ method: 'Read ALL files in one command. Used python3 to generate from internal knowledge.',
1132
+ toolUse: { used: false, label: 'Knowledge-based. No analogical reasoning, no building block reuse.' },
1133
+ blocks: [],
1134
+ phases: [
1135
+ { name: 'Discover', dim: '(explore workspace)', items: [
1136
+ { cmd: 'ls -la', cls: '' },
1137
+ { cmd: 'find . -maxdepth 2 -type f | sort', cls: '' }
1138
+ ]},
1139
+ { name: 'Find Nearest', dim: '(read example)', items: [
1140
+ { cmd: 'cat specs.md template.html', cls: '' },
1141
+ { cmd: 'cat examples/diamond.html', cls: 'example' },
1142
+ { cmd: 'cat elements/*.js notes/*.md', cls: '' }
1143
+ ]},
1144
+ { name: 'Recompose', dim: '(generate)', items: [
1145
+ { cmd: 'python3 > hourglass.html', cls: '' },
1146
+ { cmd: 'grep + review output', cls: 'talk' },
1147
+ { cmd: 'python3 > hourglass.html (rewrite)', cls: 'talk' }
1148
+ ]},
1149
+ { name: 'done', dim: '', items: [] }
1150
+ ]
1151
+ },
1152
+ {
1153
+ name: 'OpenAI GPT-4o-mini',
1154
+ result: 'fail',
1155
+ resultLabel: '\u2717 DIAMOND',
1156
+ shape: 'diamond',
1157
+ iframe: 'data/handdraw_v1/html/gpt4omini_hourglass.html',
1158
+ criteria: '5/6',
1159
+ reward: '0.667',
1160
+ method: 'Wrote output immediately, then explored. Kept rewriting with broken approach.',
1161
+ toolUse: { used: true, label: 'Partial. Read line.js + diamond example, but failed to adapt. Wrong order: wrote before exploring.' },
1162
+ blocks: ['line'],
1163
+ phases: [
1164
+ { name: 'Discover', dim: '(explore workspace)', items: [
1165
+ { cmd: 'ls', cls: '' },
1166
+ { cmd: 'cat specs.md', cls: '' }
1167
+ ]},
1168
+ { name: 'Recompose', dim: '(write too early!)', items: [
1169
+ { cmd: 'template.html > hourglass.html', cls: '' },
1170
+ { cmd: 'echo > hourglass.html (overwrite)', cls: '' }
1171
+ ]},
1172
+ { name: 'Find Nearest', dim: '(too late)', items: [
1173
+ { cmd: 'ls elements/', cls: '' },
1174
+ { cmd: 'cat elements/line.js', cls: '' },
1175
+ { cmd: 'ls examples/', cls: '' },
1176
+ { cmd: 'cat examples/diamond.html', cls: 'example' }
1177
+ ]},
1178
+ { name: 'Recompose', dim: '(retry \u00D7 3)', items: [
1179
+ { cmd: 'echo > hourglass.html (rewrite)', cls: '' },
1180
+ { cmd: 'rewrites \u00D7 3...', cls: 'talk' }
1181
+ ]},
1182
+ { name: 'done', dim: '', items: [] }
1183
+ ]
1184
+ },
1185
+ {
1186
+ name: 'Qwen3-Coder-30B-A3B-Instruct',
1187
+ result: 'unclear',
1188
+ resultLabel: '? UNCLEAR',
1189
+ shape: 'unclear',
1190
+ iframe: 'data/handdraw_v1/html/qwen30b_hourglass_v2.html',
1191
+ criteria: '5/6',
1192
+ reward: '0.667',
1193
+ method: 'Thorough exploration. Read all elements + diamond example, but built from scratch.',
1194
+ toolUse: { used: false, label: 'No analogical reasoning. Read everything but did not reuse any building blocks.' },
1195
+ blocks: [],
1196
+ phases: [
1197
+ { name: 'Discover', dim: '(explore workspace)', items: [
1198
+ { cmd: 'ls -la', cls: '' },
1199
+ { cmd: 'cat specs.md', cls: '' },
1200
+ { cmd: 'cat template.html', cls: '' }
1201
+ ]},
1202
+ { name: 'Decompose', dim: '(read all parts)', items: [
1203
+ { cmd: 'ls -la elements/', cls: '' },
1204
+ { cmd: 'cat elements/*.js', cls: '' }
1205
+ ]},
1206
+ { name: 'Find Nearest', dim: '(find reference)', items: [
1207
+ { cmd: 'ls -la examples/', cls: '' },
1208
+ { cmd: 'cat examples/diamond.html', cls: 'example' }
1209
+ ]},
1210
+ { name: 'Recompose', dim: '(build from scratch)', items: [
1211
+ { cmd: 'cat > hourglass.html', cls: '' },
1212
+ { cmd: 'cat hourglass.html (review)', cls: 'talk' }
1213
+ ]},
1214
+ { name: 'done', dim: '', items: [] }
1215
+ ]
1216
+ },
1217
+ {
1218
+ name: 'DeepSeek V3',
1219
+ result: 'fail',
1220
+ resultLabel: '\u2717 DIAMOND',
1221
+ shape: 'diamond',
1222
+ iframe: 'data/handdraw_v1/html/deepseek_hourglass.html',
1223
+ criteria: '4/6',
1224
+ reward: '0.500',
1225
+ method: 'Read everything thoroughly. Copied diamond structure into output.',
1226
+ toolUse: { used: true, label: 'Read all 5 elements, but copied diamond verbatim. No adaptation \u2014 same orientation = still a diamond.' },
1227
+ blocks: ['triangle', 'rectangle', 'line', 'circle', 'arc'],
1228
+ phases: [
1229
+ { name: 'Discover', dim: '(explore workspace)', items: [
1230
+ { cmd: 'ls', cls: '' },
1231
+ { cmd: 'cat specs.md', cls: '' },
1232
+ { cmd: 'cat template.html', cls: '' }
1233
+ ]},
1234
+ { name: 'Find Nearest', dim: '(find reference)', items: [
1235
+ { cmd: 'cat examples/hourglass.html (404)', cls: 'talk' },
1236
+ { cmd: 'ls examples', cls: '' },
1237
+ { cmd: 'cat examples/diamond.html', cls: 'example' }
1238
+ ]},
1239
+ { name: 'Decompose', dim: '(read all elements)', items: [
1240
+ { cmd: 'ls elements', cls: '' },
1241
+ { cmd: 'cat elements/triangle.js', cls: '' },
1242
+ { cmd: 'cat elements/rectangle.js', cls: '' },
1243
+ { cmd: 'cat elements/line.js', cls: '' },
1244
+ { cmd: 'cat elements/circle.js', cls: '' },
1245
+ { cmd: 'cat elements/arc.js', cls: '' }
1246
+ ]},
1247
+ { name: 'Recompose', dim: '(copy, no adapt)', items: [
1248
+ { cmd: 'template > hourglass.html + script', cls: '' }
1249
+ ]},
1250
+ { name: 'done', dim: '', items: [] }
1251
+ ]
1252
+ }
1253
+ ];
1254
+
1255
+ function drawBlockThumbnails(blocks) {
1256
+ var container = document.getElementById('trajBlocks');
1257
+ if (!blocks || !blocks.length) { container.innerHTML = ''; return; }
1258
+ container.innerHTML = '';
1259
+ var sz = 48;
1260
+ var ink = '#1a1a1a';
1261
+ var opts = { stroke: ink, strokeWidth: 1.8, roughness: 0.8 };
1262
+
1263
+ blocks.forEach(function(name) {
1264
+ var div = document.createElement('div');
1265
+ div.className = 'block-thumb';
1266
+ var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1267
+ svg.setAttribute('viewBox', '0 0 ' + sz + ' ' + sz);
1268
+ svg.setAttribute('width', sz);
1269
+ svg.setAttribute('height', sz);
1270
+ div.appendChild(svg);
1271
+ var label = document.createElement('span');
1272
+ label.className = 'block-thumb-label';
1273
+ label.textContent = name;
1274
+ div.appendChild(label);
1275
+ container.appendChild(div);
1276
+
1277
+ var rc = rough.svg(svg);
1278
+ var m = sz / 2;
1279
+ var p = 8;
1280
+ switch (name) {
1281
+ case 'triangle':
1282
+ svg.appendChild(rc.polygon([[m, p], [sz - p, sz - p], [p, sz - p]], opts));
1283
+ break;
1284
+ case 'rectangle':
1285
+ svg.appendChild(rc.rectangle(p, p + 4, sz - 2*p, sz - 2*p - 8, opts));
1286
+ break;
1287
+ case 'line':
1288
+ svg.appendChild(rc.line(p, sz - p, sz - p, p, opts));
1289
+ break;
1290
+ case 'circle':
1291
+ svg.appendChild(rc.circle(m, m, sz - 2*p, opts));
1292
+ break;
1293
+ case 'arc':
1294
+ svg.appendChild(rc.arc(m, m + 6, sz - 2*p, sz - 2*p, Math.PI, 2 * Math.PI, false, opts));
1295
+ break;
1296
+ case 'polygon':
1297
+ svg.appendChild(rc.polygon([[m, p], [sz - p, sz - p - 4], [p, sz - p - 4]], opts));
1298
+ svg.appendChild(rc.polygon([[p, sz - p - 4], [sz - p, sz - p - 4], [m - 2, p + 2]], { stroke: ink, strokeWidth: 1.2, roughness: 0.6 }));
1299
+ break;
1300
+ }
1301
+ });
1302
+
1303
+ }
1304
+
1305
+ function renderModel(idx) {
1306
+ // Update buttons
1307
+ document.querySelectorAll('.model-btn').forEach(function(btn, i) {
1308
+ btn.classList.toggle('active', i === idx);
1309
+ });
1310
+
1311
+ var m = modelData[idx];
1312
+
1313
+ // Trajectory panel β€” tree structure
1314
+ var trajPanel = document.getElementById('trajPanel');
1315
+ var treeHtml = '';
1316
+ var phases = m.phases;
1317
+ for (var p = 0; p < phases.length; p++) {
1318
+ var phase = phases[p];
1319
+ var isLast = (p === phases.length - 1);
1320
+ var branch = isLast ? '\u2514\u2500' : '\u251C\u2500';
1321
+ // Phase name color
1322
+ var nameColor = 'var(--text-light)';
1323
+ if (phase.name === 'done') nameColor = 'var(--green)';
1324
+ // Phase row
1325
+ treeHtml += '<div class="tree-row" style="opacity:1;">' +
1326
+ '<span class="tree-branch">' + branch + '</span>' +
1327
+ '<span class="tree-name" style="color:' + nameColor + '">' + phase.name + '</span>';
1328
+ if (phase.dim) treeHtml += '<span class="tree-dim">' + phase.dim + '</span>';
1329
+ treeHtml += '</div>';
1330
+ // Child items
1331
+ for (var c = 0; c < phase.items.length; c++) {
1332
+ var item = phase.items[c];
1333
+ var childIsLast = (c === phase.items.length - 1);
1334
+ var childBranch = childIsLast ? '\u2514\u2500' : '\u251C\u2500';
1335
+ var prefix = isLast ? '&nbsp;&nbsp;&nbsp;' : '\u2502&nbsp;&nbsp;';
1336
+ var cmdColor = 'var(--text-dim)';
1337
+ if (item.cls === 'example') cmdColor = 'var(--amber)';
1338
+ else if (item.cls === 'done') cmdColor = 'var(--green)';
1339
+ else if (item.cls === 'talk') cmdColor = '#555';
1340
+ treeHtml += '<div class="tree-row tree-indent" style="opacity:1;">' +
1341
+ '<span class="tree-branch">' + prefix + childBranch + '</span>' +
1342
+ '<span style="color:' + cmdColor + '">' + item.cmd + '</span>' +
1343
+ '</div>';
1344
+ }
1345
+ }
1346
+
1347
+ trajPanel.innerHTML =
1348
+ '<div class="traj-header">' +
1349
+ '<span class="traj-model">Agent Trajectory</span>' +
1350
+ '<span class="traj-result ' + m.result + '">' + m.resultLabel + '</span>' +
1351
+ '</div>' +
1352
+ '<div class="hero-tree" style="margin-bottom:12px;">' + treeHtml + '</div>' +
1353
+ '<div class="traj-summary"><strong>Method:</strong> ' + m.method + '</div>' +
1354
+ '<div class="traj-tool-use">' +
1355
+ '<strong>Tool Use:</strong> ' +
1356
+ (m.toolUse.used
1357
+ ? '<span class="tool-use-yes">\u2713 Yes</span> '
1358
+ : '<span class="tool-use-no">\u2717 None</span> ') +
1359
+ '<span class="tool-use-detail">' + m.toolUse.label + '</span>' +
1360
+ '<div id="trajBlocks" class="traj-blocks-inline"></div>' +
1361
+ '</div>';
1362
+
1363
+ // Draw building block thumbnails
1364
+ drawBlockThumbnails(m.blocks);
1365
+
1366
+ // Render panel
1367
+ var renderPanel = document.getElementById('renderPanel');
1368
+ renderPanel.innerHTML =
1369
+ '<div class="render-header">' + m.name + ' &mdash; Final Render</div>' +
1370
+ '<div class="render-frame"><iframe src="' + m.iframe + '" sandbox="allow-scripts" loading="lazy"></iframe></div>' +
1371
+ '<div style="font-family:var(--font-mono);font-size:11px;color:var(--text-dim);text-align:center;margin-top:12px;">' +
1372
+ 'Criteria: ' + m.criteria + ' &middot; Reward: ' + m.reward +
1373
+ '</div>';
1374
+ }
1375
+
1376
+ // Initialize
1377
+ document.addEventListener('DOMContentLoaded', function() {
1378
+ // Build model buttons
1379
+ var btnContainer = document.getElementById('modelButtons');
1380
+ modelData.forEach(function(m, i) {
1381
+ var btn = document.createElement('button');
1382
+ btn.className = 'model-btn';
1383
+ btn.textContent = m.name;
1384
+ btn.onclick = function() { renderModel(i); };
1385
+ btnContainer.appendChild(btn);
1386
+ });
1387
+
1388
+ // Default to first model
1389
+ renderModel(0);
1390
+
1391
+ // Start hero animation
1392
+ runTeaser();
1393
+ });
1394
+
1395
+ // ══════════════════════════════════════════════════
1396
+ // LIVE AGENT RUN β€” SSE to server space
1397
+ // ══════════════════════════════════════════════════
1398
+ var SERVER_URL = 'https://lilyzhng-apex-env-server.hf.space';
1399
+ var TALK_PREFIXES = ['I ', "I'", 'Let me', 'Now ', 'First', 'Next', 'The ', 'This ',
1400
+ 'Here', 'Sure', 'OK', 'Okay', 'Great', 'Note', 'Since ', 'To ', 'We ', 'My ',
1401
+ 'After', 'Before', 'Based', 'Looking', 'There '];
1402
+
1403
+ function isTalk(s) {
1404
+ s = s.trim();
1405
+ if (!s) return true;
1406
+ for (var i = 0; i < TALK_PREFIXES.length; i++) {
1407
+ if (s.indexOf(TALK_PREFIXES[i]) === 0) return true;
1408
+ }
1409
+ if (s.endsWith('.') && !/[|>&;$`]/.test(s)) return true;
1410
+ return false;
1411
+ }
1412
+
1413
+ function esc(s) { return s.replace(/</g, '&lt;').replace(/>/g, '&gt;'); }
1414
+
1415
+ function runLiveAgent() {
1416
+ var taskId = document.getElementById('tryitTask').value;
1417
+ var model = document.getElementById('tryitModel').value;
1418
+ var btn = document.getElementById('tryitBtn');
1419
+ var grid = document.getElementById('liveGrid');
1420
+ var traj = document.getElementById('liveTrajPanel');
1421
+ var render = document.getElementById('liveRenderPanel');
1422
+
1423
+ btn.disabled = true;
1424
+ btn.innerHTML = 'Running<span class="live-spinner"></span>';
1425
+ grid.style.display = '';
1426
+ traj.innerHTML = '<div class="live-step" style="border-left-color:var(--cyan);"><div class="live-step-label" style="color:var(--cyan);">Running agent on ' + esc(taskId) + '&hellip; this takes 30-90 seconds.</div></div>';
1427
+ render.innerHTML = '<div style="text-align:center; padding:40px; color:var(--text-dim); font-family:var(--font-mono); font-size:12px;">Waiting for agent output&hellip;</div>';
1428
+
1429
+ fetch(SERVER_URL + '/agent_run', {
1430
+ method: 'POST',
1431
+ headers: { 'Content-Type': 'application/json' },
1432
+ body: JSON.stringify({ task_id: taskId, model: model, max_turns: 10 }),
1433
+ }).then(function(response) {
1434
+ if (!response.ok) throw new Error('Server returned ' + response.status);
1435
+ return response.json();
1436
+ }).then(function(data) {
1437
+ btn.disabled = false;
1438
+ btn.innerHTML = '&#9654; Run Agent';
1439
+
1440
+ if (data.error) {
1441
+ traj.innerHTML = '<div class="live-step" style="border-left-color:var(--red);"><div class="live-step-label" style="color:var(--red);">ERROR</div><div class="live-step-cmd" style="color:var(--red);">' + esc(data.error) + '</div></div>';
1442
+ return;
1443
+ }
1444
+
1445
+ // Render all steps
1446
+ traj.innerHTML = '<div class="live-step" style="border-left-color:var(--cyan);"><div class="live-step-label" style="color:var(--cyan);">TASK: ' + esc(data.task_id) + '</div></div>';
1447
+
1448
+ var steps = data.steps || [];
1449
+ for (var i = 0; i < steps.length; i++) {
1450
+ var s = steps[i];
1451
+ var isDone = s.done;
1452
+ var isTalkAction = !isDone && isTalk(s.action);
1453
+ var cls = isDone ? 'done' : (isTalkAction ? 'talk' : '');
1454
+ var labelText = isDone ? '\u2713 DONE' : (isTalkAction ? '\u2022 TALK ' + s.turn : '\u2605 ACTION ' + s.turn);
1455
+ var labelColor = isDone ? 'var(--green)' : (isTalkAction ? '#555' : 'var(--amber)');
1456
+
1457
+ var stepHtml = '<div class="live-step ' + cls + '">' +
1458
+ '<div class="live-step-label" style="color:' + labelColor + ';">' + labelText +
1459
+ ' &nbsp; <span style="color:var(--text-dim);">' + (s.criteria_met||0) + '/' + (s.criteria_total||0) + ' criteria</span></div>' +
1460
+ '<div class="live-step-cmd">$ ' + esc((s.action||'').substring(0, 300)) + '</div>';
1461
+
1462
+ if (s.stdout && !isDone) {
1463
+ stepHtml += '<div class="live-step-obs">' + esc(s.stdout.substring(0, 500)) + '</div>';
1464
+ }
1465
+
1466
+ if (isDone && s.reward !== null && s.reward !== undefined) {
1467
+ var rColor = s.reward > 0.3 ? 'var(--green)' : (s.reward > 0 ? 'var(--amber)' : 'var(--red)');
1468
+ stepHtml += '<div class="live-reward" style="color:' + rColor + ';">REWARD: ' + s.reward.toFixed(3) + '</div>';
1469
+ stepHtml += '<div class="live-step-obs" style="max-height:200px;">' + esc(s.stdout) + '</div>';
1470
+ }
1471
+
1472
+ stepHtml += '</div>';
1473
+ traj.innerHTML += stepHtml;
1474
+ }
1475
+ traj.scrollTop = traj.scrollHeight;
1476
+
1477
+ // Render output HTML if available
1478
+ if (data.output_html) {
1479
+ render.innerHTML = '<div class="render-header">Agent Output &mdash; ' + esc(data.output_filename || 'output.html') + '</div>' +
1480
+ '<div class="render-frame"><iframe srcdoc="' + data.output_html.replace(/"/g, '&quot;') + '" sandbox="allow-scripts" style="width:100%;height:100%;border:none;"></iframe></div>';
1481
+ }
1482
+
1483
+ }).catch(function(err) {
1484
+ traj.innerHTML = '<div class="live-step" style="border-left-color:var(--red);"><div class="live-step-label" style="color:var(--red);">CONNECTION ERROR</div><div class="live-step-cmd" style="color:var(--red);">' + esc(err.message || 'Failed to connect to server') + '</div></div>';
1485
+ btn.disabled = false;
1486
+ btn.innerHTML = '&#9654; Run Agent';
1487
+ });
1488
+ }
1489
+ </script>
1490
+ </body>
1491
+ </html>