PageSourceSearch

https://yeolj00.github.io/research/vector-prism/

html yeolj00.github.io collected 2026-10-03 10:12:38 UTC 34,239 bytes, 791 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3
4<head>
5    <meta charset="utf-8">
6    <meta name="viewport" content="width=device-width, initial-scale=1">
7    <meta property="og:image" content="https://yeolj00.github.io/research/vector-prism/assets/og_image.png">
8    <title>Vector Prism: Animating Vector Graphics by Stratifying Semantic Structure</title>
9    <link rel="icon" href="assets/favicon_davian.png" type="image/png">
10    <link rel="stylesheet" href="afterglow-bootstrap.css">
11    <style>
12        /* Hero video grid */
13        .teaser-grid {
14            display: grid;
15            grid-template-columns: repeat(4, 1fr);
16            gap: 15px;
17            margin: 30px 0;
18        }
19        
20        .teaser-item {
21            text-align: center;
22        }
23        
24        /* Styled iframe container for animations */
25        .animation-frame {
26            position: relative;
27            width: 100%;
28            aspect-ratio: 1 / 1;
29            border-radius: var(--border-radius-lg);
30            overflow: hidden;
31            box-shadow: var(--box-sha
31dow);
32            background: white;
33            display: flex;
34            align-items: center;
35            justify-content: center;
36        }
37        
38        /* SVG will scale to fit container */
39        .animation-frame svg {
40            width: 100%;
41            height: 100%;
42            display: block;
43        }
44        
45        /* Loading state */
46        .animation-frame.loading::after {
47            content: "Loading...";
48            color: var(--gray-400);
49            font-size: 0.85rem;
50        }
51        
52        /* Hover effect for teaser animations */
53        .teaser-item .animation-frame {
54            transition: transform 0.3s ease, box-shadow 0.3s ease;
55        }
56        
57        .teaser-item .animation-frame:hover {
58            transform: translateY(-5px);
59            box-shadow: var(--box-shadow-lg);
60        }
61        
62        .teaser-item figcaption {
63            font-size: 0.85rem;
64            margin-top: 12px;
65            color: var(--gray-600);
66            font-style: italic;
67            line-height: 1.4;
68        }
69
70        /* Interactive scaling demo */
71        .scalable-demo-container {
72            max-width: 300px;
73            margin: 0 auto 3rem;
74            cursor: pointer;
75            transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
76        }
77        
78        .scalable-demo-container:hover {
79            max-width: 600px;
80            transform: translateY(-10px);
81        }
82        
83        .scalable-demo-container .animation-frame {
84            overflow: visible;
85            border: 2px solid rgba(255, 106, 138, 0.3);
86            transition: all 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
87        }
88        
89        .scalable-demo-container:hover .animation-frame {
90            border-color: rgba(255, 106, 138, 0.8);
91            box-shadow: 0 20px 60px rgba(255, 106, 138, 0.3);
92        }
93        
94        .scale-hint {
95            font-style: italic;
96            color: #666;
97            margin-top: 1rem;
98            font-size: 0.9rem;
99            transition: all 0.3s ease;
100        }
101        
102        .scalable-demo-container:hover + .scale-hint {
103            color: #ff6a8a;
104            font-weight: 600;
105            transform: scale(1.05);
106        }
107        
108        /* Comparison section */
109        .comparison-section {
110            background: var(--gray-100);
111            padding: 3rem 0;
112            margin: 3rem 0;
113        }
114        
115        .comparison-grid {
116            display: grid;
117            grid-template-columns: repeat(5, 1fr);
118            gap: 12px;
119            margin: 20px 0;
120        }
121        
122        .comparison-item {
123            text-align: center;
124        }
125        
126        /* Comparison iframe styling */
127        .comparison-item .animation-frame {
128            border-radius: var(--border-radius);
129            box-shadow: none;
130            border: 1px solid var(--gray-300);
131        }
132        
133        .comparison-item.ours .animation-frame {
134            border: 2px solid var(--primary);
135            box-shadow: 0 0 0 3px rgba(255, 106, 138, 0.2);
136        }
137        
138        /* Video styling for baselines */
139        .comparison-item video {
140            width: 100%;
141            aspect-ratio: 1 / 1;
142            object-fit: cover;
143            border-radius: var(--border-radius);
144            border: 1px solid var(--gray-300);
145            background: #000;
146        }
147        
148        .comparison-item .method-label {
149            font-size: 0.85rem;
150            font-weight: 600;
151            margin-top: 8px;
152            color: var(--gray-700);
153        }
154        
155        .comparison-item.ours .method-label {
156            color: var(--primary);
157        }
158        
159        .refresh-btn {
160            display: inline-block;
161            margin-left: 8px;
162            cursor: pointer;
163            font-size: 1rem;
164            opacity: 0.7;
165            transition: all 0.2s ease;
166            user-select: none;
167        }
168        
169        .refresh-btn:hover {
170            opacity: 1;
171            transform: rotate(180deg);
172        }
173        
174        .refresh-btn:active {
175            transform: rotate(180deg) scale(0.9);
176        }
177        
178        .instruction-text {
179            font-weight: 500;
180            text-align: center;
181            padding: 1rem 2rem;
182            background: linear-gradient(135deg, rgba(255, 167, 166, 0.15) 0%, rgba(157, 79, 255, 0.15) 100%);
183            border-radius: var(--border-radius-lg);
184            margin-bottom: 1.5rem;
185            font-size: 1.1rem;
186            color: var(--gray-800);
187        }
188
189        /* Stats section */
190        .stats-grid {
191            display: flex;
192            justify-content: center;
193            gap: 2rem;
194            margin: 2rem 0;
195            flex-wrap: wrap;
196        }
197        
198        .stat-card {
199            flex: 0 0 calc(33.333% - 2rem);
200            max-width: 350px;
201            text-align: center;
202            padding: 2rem;
203            background: white;
204            border-radius: var(--border-radius-lg);
205            box-shadow: var(--box-shadow-sm);
206            border-top: 4px solid;
207            border-image: var(--gradient-afterglow) 1;
208        }
209        
210        .stat-card .number {
211            font-size: 3rem;
212            font-weight: 700;
213            background: var(--gradient-afterglow);
214            -webkit-background-clip: text;
215            -webkit-text-fill-color: transparent;
216            background-clip: text;
217        }
218        
219        .stat-card .label {
220            color: var(--gray-600);
221            font-size: 1rem;
222        }
223        
224        /* No video placeholder */
225        .no-video {
226            width: 100%;
227            aspect-ratio: 1;
228            background: var(--gray-200);
229            border-radius: var(--border-radius);
230            display: flex;
231            align-items: center;
232            justify-content: center;
233            color: var(--gray-500);
234            font-size: 0.8rem;
235        }
236        
237        /* No video placeholder */
238        .no-video {
239            width: 100%;
240            aspect-ratio: 1;
241            background: var(--gray-200);
242            border-radius: var(--border-radius);
243            display: flex;
244            align-items: center;
245            justify-content: center;
246            color: var(--gray-500);
247            font-size: 0.8rem;
248        }
249        
250        /* CVPR Badge */
251        .conference-badge {
252            display: inline-block;
253            font-size: 1.3rem;
254            font-weight: 600;
255            letter-spacing: 0.5px;
256            margin: 1rem 0 1.5rem;
257            background: linear-gradient(135deg, #FF6A8A 0%, #9D4FFF 100%);
258            -webkit-background-clip: text;
259            -webkit-text-fill-color: transparent;
260            background-clip: text;
261        }
262
263        /* Responsive */
264        @media (max-width: 992px) {
265            .teaser-grid {
266                grid-template-columns: repeat(2, 1fr);
267            }
268            .comparison-grid {
269                grid-template-columns: repeat(3, 1fr);
270            }
271            .stats-grid {
272                gap: 1rem;
273            }
274            .stat-card {
275                flex: 0 0 calc(50% - 1rem);
276            }
277        }
278
279        @media (max-width: 768px) {
280            h1.text-gradient {
281                font-size: 2.4rem !important;
282            }
283            h4.text-muted {
284                font-size: 1.1rem !important;
285            }
286            .comparison-grid {
287                grid-template-columns: repeat(2, 1fr);
288            }
289            .instruction-text {
290                font-size: 0.95rem;
291                padding: 0.75rem 1rem;
292            }
293            .stat-card {
294                flex: 0 0 100%;
295                max-width: 100%;
296            }
297            .stat-card .number {
298                font-size: 2.2rem;
299            }
300            pre code {
301                font-size: 0.75rem;
302            }
303            .scalable-demo-container:hover {
304                max-width: 100%;
305                transform: none;
306            }
307        }
308
309        @media (max-width: 576px) {
310            .teaser-grid {
311                grid-template-columns: repeat(2, 1fr);
312                gap: 10px;
313            }
314            .comparison-grid {
315                grid-template-columns: repeat(2, 1fr);
316            }
317            .pipeline-visual {
318                flex-direction: column;
319            }
320            .pipeline-arrow {
321                transform: rotate(90deg);
322            }
323            h1.text-gradient {
324                font-size: 2rem !important;
325            }
326            .container {
327                padding-left: 12px;
328                padding-right: 12px;
329            }
330            .col-1 {
331                display: none;
332            }
333            .col-10 {
334                flex: 0 0 100%;
335                max-width: 100%;
336            }
337            .btn-lg {
338                padding: 0.6rem 1.2rem;
339                font-size: 1rem;
340            }
341            img[src="assets/exp_user_study.png"] {
342                max-width: 100% !important;
343            }
344.row.justify-content-center .col-3 {
345                flex: 0 0 50%;
346                max-width: 50%;
347            }
348        }
349    </style>
350</head>
351
352<body>
353    <div class="container" style="margin-top: 40px; margin-bottom: 60px;">
354        <div class="row">
355            <div class="col-1"></div>
356            <div class="col-10">
357
358                <!-- Title and Authors -->
359                <div class="text-center">
360                    <h1 class="text-gradient"
361                        style="margin-top: 20px; margin-bottom: 20px; line-height: 1.2em; font-weight: 600; font-size: 3.5rem;">
362                        Vector Prism
363                    </h1>
364                    <h4 class="text-muted mb-4" style="font-weight: 400; font-size: 1.5rem;">
365                        Animating Vector Graphics by Stratifying Semantic Structure
366                    </h4>
367
368                    <!-- Authors - FIXED LAYOUT -->
369                    <div class="row justify-content-center mt-4 mb-4">
370                        <div class="col-3 col-md-3 mb-3">
371                            <a href="https://yeolj00.github.io/" style="text-decoration: none;">
372                                <h5 class="text-dark mb-1">Jooyeol Yun</h5>
373                            </a>
374                            <p class="text-primary mb-0" style="font-size: 0.85rem;">[email protected]</p>
375                        </div>
376                        <div class="col-3 col-md-3 mb-3">
377                            <h5 class="text-dark mb-1">Jaegul Choo</h5>
378                            <p class="text-primary mb-0" style="font-size: 0.85rem;">
378[email protected]</p>
379                        </div>
380                    </div>
381                    <div class="row justify-content-center mt-4 mb-2">
382                        <img src="assets/logo_kaist.svg" class="figure-img img-fluid" style="margin: 0px 50px" width="20%">
383                    </div>
384
385                    <!-- Conference Badge -->
386                    <div class="mt-3 mb-2">
387                        <span class="conference-badge">CVPR 2026 · Highlight</span>
388                    </div>
389                </div>
390
391                <!-- Teaser Videos -->
392                <div class="teaser-grid">
393                    <div class="teaser-item">
394                        <div class="animation-frame loading" data-src="assets/19-1-cool.html" id="teaser-emoji"></div>
395                        <figcaption>"Make the emoji look left and right"<span class="refresh-btn" onclick="reloadAnimation('teaser-emoji')" title="Reload animation">🔄</span></figcaption>
396                    </div>
397                    <div class="teaser-item">
398                        <div class="animation-frame loading" data-src="assets/6-1-rainbow.html" id="teaser-rainbow"></div>
399                        <figcaption>"Elements smoothly pop up in a lively manner"<span class="refresh-btn" onclick="reloadAnimation('teaser-rainbow')" title="Reload animation">🔄</span></figcaption>
400                    </div>
401                    <div class="teaser-item">
402                        <div class="animation-frame loading" data-src="assets/18-2-compass.html" id="teaser-compass"></div>
403                        <figcaption>"Compass needle quickly spins around once"<span class="refresh-btn" onclick="reloadAnimation('teaser-compass')" title="Reload animation">🔄</span></figcaption>
404                    </div>
405                    <div class="teaser-item">
406                        <div class="animation-frame loading" data-src="assets/8-2-calculator.html" id="teaser-calculator"></div>
407                        <figcaption>"Buttons bounce in one by one"<span class="refresh-btn" onclick="reloadAnimation('teaser-calculator')" title="Reload animation">🔄</span></figcaption>
408                    </div>
409                </div>
410
411                <div class="teaser-grid">
412                    <div class="teaser-item">
413                        <div class="animation-frame loading" data-src="assets/3-2-architecture.html" id="teaser-architecture"></div>
414                        <figcaption>"Turn the scene to night"<span class="refresh-btn" onclick="reloadAnimation('teaser-architecture')" title="Reload animation">🔄</span></figcaption>
415                    </div>
416                    <div class="teaser-item">
417                        <div class="animation-frame loading" data-src="assets/42-1-python.html" id="teaser-python"></div>
418                        <figcaption>"Python logo bounces in and meets in the middle"<span class="refresh-btn" onclick="reloadAnimation('teaser-python')" title="Reload animation">🔄</span></figcaption>
419                    </div>
420                    <div class="teaser-item">
421                        <div class="animation-frame loading" data-src="assets/43-2-pytorch.html" id="teaser-pytorch"></div>
422                        <figcaption>"PyTorch logo bounces and changes colors"<span class="refresh-btn" onclick="reloadAnimation('teaser-pytorch')" title="Reload animation">🔄</span></figcaption>
423                    </div>
424                    <div class="teaser-item">
425                        <div class="animation-frame loading" data-src="assets/24-1-doughnut.html" id="teaser-doughnut"></div>
426                        <figcaption>"Doughnut bounces up, sprinkles fall in"<span class="refresh-btn" onclick="reloadAnimation('teaser-doughnut')" title="Reload animation">🔄</span></figcaption>
427                    </div>
428                </div>
429
430                <!-- Action Buttons -->
431                <div class="text-center mt-5">
432                    <a href="https://arxiv.org/abs/2512.14336" class="btn btn-gradient btn-lg mr-2 mb-2">📄 Paper</a>
433                    <a href="https://github.com/YeolJ00/vector-prism" class="btn btn-outline-primary btn-lg mr-2 mb-2">💻 Code</a>
434                </div>
435
436                <hr class="my-5">
437
438                <!-- TL;DR -->
439                <div class="text-center">
440                    <h2 class="text-gradient mb-5" style="font-weight: 600;">Why Animate Vector Graphics?</h2>
441                    <div class="scalable-demo-container">
442                        <div class="animation-frame loading" data-src="assets/54-1-rocket.html" id="teaser-rocket"></div>
443                    </div>
444                    <p class="scale-hint">
445                        "The rocket exhaust to glow softly as if traveling through space."<br>
446                        <span style="font-size: 0.85rem; color: #999;">💡 Hover to see infinite scalability</span>
447                    </p>
448                    
449                </div>
450                <div style="max-width: 950px; margin: 0 auto;">
451                    <p class="lead" style="font-size: 1rem; margin-bottom: 2.5rem; line-height: 1.8; color: #333;">
452                        Vector graphics (SVGs) power the modern web. They are <strong>infinitely scalable</strong> with 
453                        perfect clarity at any resolution, <strong>54× smaller</strong> than video files, 
454                        <strong>editable</strong> with CSS and code, and <strong>portable</strong> across any device.
455                        Yet animating them meaningfully is incredibly difficult, even for LLMs. This is because SVGs
456                        are made of thousands of <strong>low-level elements</strong> (paths, groups, shapes) that lack
457                        semantic structure. Naively animating these elements leads to <strong>chaotic, incoherent results</strong>.
458                    </p>
459                    
460                    <div style="background: linear-gradient(135deg, rgba(255, 167, 166, 0.1) 0%, rgba(157, 79, 255, 0.1) 100%); 
461                                padding: 1rem 2.5rem; border-radius: 16px; margin: 2.5rem 0;">
462                        <p class="lead" style="font-size: 1.1rem; margin: 0; line-height: 1.8; color: #1a1a1a;">
463                            Vector Prism 
464                            <strong>re-organizing vector graphics to have a semantically meaningful structure</strong>
465                            before animating them, enabling high-quality, user-controllable animations
466                            that were previously impossible.
467                        </p>
468                    </div>
469                </div>
470
471                <!-- How Do We Do It Section -->
472                <div class="text-center">
473                    <h2 class="text-gradient mb-5" style="font-weight: 600;">How Do We Do It?</h2>
474                </div>
475                <p style="font-size: 1rem; line-height: 1.8; color: #333; margin-bottom: 2.5rem;">
476                    When you say "make the buttons bounce," there is no "buttons" in the code, but just scattered <code>&lt;path&gt;</code> elements with no semantic structure.
477                    We need to identify which elements correspond to "buttons" first. 
478                </p>
479                
480                <!-- First Image - Properly Centered -->
481                <div class="text-center mt-4 mb-4">
482                    <img src="assets/method_main.png" alt="Semantic Structure Visualization"
483                    style="max-width: 100%; height: auto; border-radius: var(--border-radius-lg);
483 box-shadow: var(--box-shadow);">
484                </div>
485                <p class="method-intro" style="margin-bottom: 3rem;">
486                We render each SVG element multiple ways (highlighted, isolated, zoomed), 
487                collect (possibly incorrect) predictions from a vision-language model, then use Dawid-Skene model to aggregate these noisy predictions into reliable semantic labels. 
488                This turns weak, contradictory signals into robust semantic decisions.
489                </p>
490
491                <hr class="my-5">
492
493                <!-- Stats -->
494                <h2 class="text-gradient text-center mb-4" style="font-weight: 600; margin-bottom: 1rem;">Results at a glance</h2>
495                <div class="stats-grid">
496                    <div class="stat-card">
497                        <div class="number">76.1</div>
498                        <div class="label">GPT-T2V Score<br><small class="text-muted">vs. Sora 2's 69.1</small></div>
499                    </div>
500                    <div class="stat-card">
501                        <div class="number">54×</div>
502                        <div class="label">Smaller Files<br><small class="text-muted">vs. video formats</small></div>
503                    </div>
504                </div>
505                
506                <!-- Second Image - Properly Centered Below Stats -->
507                <div class="text-center mt-5 mb-4">
508                    <img src="assets/exp_user_study.png" alt="User Study Results"
509                        style="max-width: 60%; height: auto; border-radius: var(--border-radius-lg);
509 box-shadow: var(--box-shadow);">
510                </div>
511                <p class="method-intro" style="margin-bottom: 3rem;">
512                Vector Prism achieves state-of-the-art performance across both instruction-following metrics and file efficiency, demonstrating that proper semantic structure unlocks superior animation quality. 
513                </p>
514                
515            </div>
516            <div class="col-1"></div>
517        </div>
518    </div>
519
520    <!-- Comparisons Section (Full Width Background) -->
521    <div class="comparison-section">
522        <div class="container">
523            <div class="row">
524                <div class="col-1"></div>
525                <div class="col-10">
526
527                    <h2 class="text-gradient text-center mb-5" style="font-weight: 600;">Side-by-Side Comparisons</h2>
528
529                    <!-- Comparison 1 -->
530                    <div class="instruction-text">
531                        "I want an opening animation, starting from the bottom and moving up."
532                    </div>
533                    <div class="comparison-grid">
534                        <div class="comparison-item">
535                            <video controls loop muted playsinline>
536                                <source src="assets/videos/57-2-aniclip/video.mp4" type="video/mp4">
537                            </video>
538                            <div class="method-label">AniClipart</div>
539                        </div>
540                        <div class="comparison-item">
541                            <video controls loop muted playsinline>
542                                <source src="assets/videos/57-2-gpt/video.mp4" type="video/mp4">
543                            </video>
544                            <div class="method-label">GPT-5</div>
545                        </div>
546                        <div class="comparison-item">
547                            <video controls loop muted playsinline>
548                                <source src="assets/videos/57-2-wan/video.mp4" type="video/mp4">
549                            </video>
550                            <div class="method-label">Wan 2.2</div>
551                        </div>
552                        <div class="comparison-item">
553                            <video controls loop muted playsinline>
554                                <source src="assets/videos/57-2-sora/video.mp4" type="video/mp4">
555                            </video>
556                            <div class="method-label">Sora 2</div>
557                        </div>
558                        <div class="comparison-item ours">
559                            <div class="animation-frame loading" data-src="assets/57-2-windmill.html" id="anim-windmill"></div>
560                            <div class="method-label">Ours ✨<span class="refresh-btn" onclick="reloadAnimation('anim-windmill')" title="Reload animation">🔄</span></div>
561                        </div>
562                    </div>
563
564                    <!-- Comparison 2 -->
565                    <div class="instruction-text mt-5">
566                        "I want the lightning bolt to glow softly and raindrops to fade in and out."
567                    </div>
568                    <div class="comparison-grid">
569                        <div class="comparison-item">
570                            <video controls loop muted playsinline>
571                                <source src="assets/videos/16-2-aniclip/video.mp4" type="video/mp4">
572                            </video>
573                            <div class="method-label">AniClipart</div>
574                        </div>
575                        <div class="comparison-item">
576                            <video controls loop muted playsinline>
577                                <source src="assets/videos/16-2-gpt/video.mp4" type="video/mp4">
578                            </video>
579                            <div class="method-label">GPT-5</div>
580                        </div>
581                        <div class="comparison-item">
582                            <video controls loop muted playsinline>
583                                <source src="assets/videos/16-2-wan/video.mp4" type="video/mp4">
584                            </video>
585                            <div class="method-label">Wan 2.2</div>
586                        </div>
587                        <div class="comparison-item">
588                            <video controls loop muted playsinline>
589                                <source src="assets/videos/16-2-sora/video.mp4" type="video/mp4">
590                            </video>
591                            <div class="method-label">Sora 2</div>
592                        </div>
593                        <div class="comparison-item ours">
594                            <div class="animation-frame loading" data-src="assets/16-2-lightning.html" id="anim-lightning"></div>
595                            <div class="method-label">Ours ✨<span class="refresh-btn" onclick="reloadAnimation('anim-lightning')" title="Reload animation">🔄</span></div>
596                        </div>
597                    </div>
598
599                    <!-- Comparison 4 -->
600                    <div class="instruction-text mt-5">
601                        "I want the hexagon to appear first, then the X sign enters by spinning in."
602                    </div>
603                    <div class="comparison-grid">
604                        <div class="comparison-item">
605                            <div class="no-video">No output</div>
606                            <div class="method-label">AniClipart</div>
607                        </div>
608                        <div class="comparison-item">
609                            <video controls loop muted playsinline>
610                                <source src="assets/videos/12-1-gpt/video.mp4" type="video/mp4">
611                            </video>
612                            <div class="method-label">GPT-5</div>
613                        </div>
614                        <div class="comparison-item">
615                            <video controls loop muted playsinline>
616                                <source src="assets/videos/12-1-wan/video.mp4" type="video/mp4">
617                            </video>
618                            <div class="method-label">Wan 2.2</div>
619                        </div>
620                        <div class="comparison-item">
621                            <video controls loop muted playsinline>
622                                <source src="assets/videos/12-1-sora/video.mp4" type="video/mp4">
623                            </video>
624                            <div class="method-label">Sora 2</div>
625                        </div>
626                        <div class="comparison-item ours">
627                            <div class="animation-frame loading" data-src="assets/12-1-cancel.html" id="anim-cancel"></div>
628                            <div class="method-label">Ours ✨<span class="refresh-btn" onclick="reloadAnimation('anim-cancel')" title="Reload animation">🔄</span></div>
629                        </div>
630                    </div>
631
632                </div>
633                <div class="col-1"></div>
634            </div>
635        </div>
636    </div>
637
638    <!-- Back to container -->
639    <div class="container">
640        <div class="row">
641            <div class="col-1"></div>
642            <div class="col-10">
643
644                <hr class="my-5">
645
646                <!-- Citation -->
647                <h2 class="text-gradient mb-4">Citation</h2>
648                <pre class="border rounded p-3 bg-light" style="font-size: 0.85rem;"><code>@article{yun2026vectorprism,
649  title={Vector Prism: Animating Vector Graphics by Stratifying Semantic Structure},
650  author={Yun, Jooyeol and Choo, Jaegul},
651  journal={arXiv preprint arXiv:2512.14336},
652  year={2026}
653}</code></pre>
654
655                <hr class="my-5">
656
657            </div>
658            <div class="col-1"></div>
659        </div>
660    </div>
661
662    <!-- Footer -->
663    <div class="footer">
664        <div class="container text-center">
665            <p>© 2026 KAIST AI. All rights reserved.</p>
666            <p class="text-muted" style="font-size: 0.9rem;">
667                Made with the Firefox Afterglow color palette 🦊✨
668            </p>
669        </div>
670    </div>
671</body>
672    <!-- JavaScript to load SVG animations -->
673    
673<script>
674        function reloadAnimation(elementId) {
675            const frame = document.getElementById(elementId);
676            if (!frame) return;
677            
678            const src = frame.getAttribute('data-src');
679            if (!src) return;
680            
681            // Clear the frame
682            frame.innerHTML = '';
683            frame.classList.add('loading');
684            
685            // Reload the animation
686            fetch(src)
687                .then(response => {
688                    if (!response.ok) throw new Error('Failed to load: ' + src);
689                    return response.text();
690                })
691                .then(html => {
692                    // Parse the HTML
693                    const parser = new DOMParser();
694                    const doc = parser.parseFromString(html, 'text/html');
695                    
696                    // Extract SVG
697                    const svg = doc.querySelector('svg');
698                    
699                    // Extract all style tags
700                    const styles = doc.querySelectorAll('style');
701                    
702                    if (svg) {
703                        // Create a unique ID for scoping
704                        const uniqueId = elementId + '-reload-' + Date.now();
705                        
706                        // Add unique class to SVG for scoping
707                        svg.classList.add(uniqueId);
708                        
709                        // Process styles to scope them
710                        styles.forEach(style => {
711                            let css = style.textContent;
712                            
713                            // Create a new scoped style element
714                            const scopedStyle = document.createElement('style');
715                            scopedStyle.textContent = css;
716                            frame.appendChild(scopedStyle);
717                        });
718                        
719                        // Add SVG to frame
720                        frame.appendChild(svg);
721                        
722                        // Remove loading state
723                        frame.classList.remove('loading');
724                    }
725                })
726                .catch(error => {
727                    console.error(error);
728                    frame.innerHTML = '<span style="color: #999; font-size: 0.8rem;">Failed to load</span>';
729                    frame.classList.remove('loading');
730                });
731        }
732        
733        document.addEventListener('DOMContentLoaded', function() {
734            // Find all animation frames with data-src
735            const frames = document.querySelectorAll('.animation-frame[data-src]');
736            
737            frames.forEach((frame, index) => {
738                const src = frame.getAttribute('data-src');
739                
740                fetch(src)
741                    .then(response => {
742                        if (!response.ok) throw new Error('Failed to load: ' + src);
743                        return response.text();
744                    })
745                    .then(html => {
746                        // Parse the HTML
747                        const parser = new DOMParser();
748                        const doc = parser.parseFromString(html, 'text/html');
749                        
750                        // Extract SVG
751                        const svg = doc.querySelector('svg');
752                        
753                        // Extract all style tags
754                        const styles = doc.querySelectorAll('style');
755                        
756                        if (svg) {
757                            // Create a unique ID for scoping
758                            const uniqueId = 'anim-' + index;
759                            
760                            // Add unique class to SVG for scoping
761                            svg.classList.add(uniqueId);
762                            
763                            // Process styles to scope them
764                            styles.forEach(style => {
765                                // Optionally scope CSS - prepend unique class
766                                // This helps avoid conflicts between animations
767                                let css = style.textContent;
768                                
769                                // Create a new scoped style element
770                                const scopedStyle = document.createElement('style');
771                                scopedStyle.textContent = css;
772                                frame.appendChild(scopedStyle);
773                            });
774                            
775                            // Add SVG to frame
776                            frame.appendChild(svg);
777                            
778                            // Remove loading state
779                            frame.classList.remove('loading');
780                        }
781                    })
782                    .catch(error => {
783                        console.error(error);
784                        frame.innerHTML = '<span style="color: #999; font-size: 0.8rem;">Failed to load</span>';
785                        frame.classList.remove('loading');
786                    });
787            });
788        });
789    </script>
789
790
791</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.