Initial commit for OmniLottie project page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
i-yangyiying
2026-02-12 21:31:55 +08:00
co-authored by Claude Opus 4.6
commit 3261cc21c6
19 changed files with 3675 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
venv/
ENV/
*.py
# OS
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Logs
*.log
# Temporary files
*.tmp
*.bak
*.swp
# Documentation and scripts (不上传到GitHub Pages)
*.md
*.sh
# Backup
.git.bak/
# Don't ignore these important files
!static/css/index.css
!static/js/index.js
View File
+571
View File
@@ -0,0 +1,571 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="OmniLottie: Generating Vector Animations via Parameterized Lottie Tokens">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>OmniLottie: Generating Vector Animations via Parameterized Lottie Tokens</title>
<link href="https://fonts.googleapis.com/css?family=Google+Sans|Noto+Sans|Castoro" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"/>
<link rel="stylesheet" href="./static/css/bulma.min.css">
<link rel="stylesheet" href="./static/css/bulma-carousel.min.css">
<link rel="stylesheet" href="./static/css/bulma-slider.min.css">
<link rel="stylesheet" href="./static/css/fontawesome.all.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jpswalsh/academicons@1/css/academicons.min.css">
<link rel="stylesheet" href="./static/css/index.css">
<link rel="icon" href="./static/images/lottie_icon.png"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script defer src="./static/js/fontawesome.all.min.js"></script>
<script src="./static/js/bulma-slider.min.js"></script>
<script src="./static/js/index.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<style>
body {
margin: auto;
font-family: Arial, sans-serif;
}
nav {
position: auto;
top: 0;
left: 0;
width: 100%;
background-color: ghostwhite;
z-index: 100;
box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.3);
}
nav ul {
padding: 0;
margin: auto;
list-style: none;
display: flex;
justify-content: center;
}
nav ul li {
margin: auto;
}
nav ul li a {
display: block;
padding: 5px;
text-decoration: none;
transition: background-color 0.3s;
}
nav ul li a:hover {
background-color: #555;
}
.title {
font-size: 41px;
}
.teaserTitle {
font-size: 76px;
}
.subTeaserTitle {
font-size: 15px;
}
.carousel-indicators {
bottom: -26px;
}
.carousel-control.left,
.carousel-control.right {
background-image: none !important;
filter: none !important;
width: 20px;
}
.columns {
display: flex;
flex-wrap: wrap;
}
.column {
flex: 1;
min-width: 150px;
}
.carousel-indicators ol {
width: 100%;
}
.carousel-indicators li {
height: 3px !important;
border-radius: 0px !important;
width: 25%;
}
.render_wrapper {
position: relative;
height: 300px;
}
.render_wrapper_small {
position: relative;
height: 200px;
}
.render_div {
position: absolute;
top: 0;
left: 0;
}
#interpolation-image-wrapper-car {
text-align: center;
}
#interpolation-image-wrapper-chair {
text-align: center;
}
.nested-columns {
margin-bottom: 0 !important;
}
.task-icon {
font-size: 1.2em;
margin-right: 8px;
}
.highlight-box {
background: linear-gradient(135deg, #b39ddb 0%, #9575cd 100%);
border-radius: 10px;
padding: 20px;
margin: 10px 0;
color: white;
}
.feature-card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 15px;
margin: 10px;
transition: box-shadow 0.3s;
}
.feature-card:hover {
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body>
<section class="hero">
<div class="hero-body">
<div class="container is-max-desktop">
<div class="columns is-centered">
<div class="column has-text-centered">
<h1 class="title is-0 publication-title">
OmniLottie: Generating Vector Animations via Parameterized Lottie Tokens <br/>
</h1>
<style>
.neurips-text {
color: #b39ddb; /* 浅紫色 - 与OmniSVG一致 */
font-size: 30px;
font-weight: bold;
text-align: center;
margin-top: 10px;
}
</style>
<div class="neurips-text">
NeurIPS 2025
</div>
<div class="is-size-4 publication-authors">
<span class="author-block">
<a href="#">Author 1</a><sup>1,2*</sup>,</span>
<span class="author-block">
<a href="#">Author 2</a><sup>2*</sup>,</span>
<span class="author-block">
<a href="#">Author 3</a><sup>1</sup>,</span>
<span class="author-block">
<a href="#">Author 4</a><sup>2</sup>,</span>
<span class="author-block">
<a href="#">Author 5</a><sup>1</sup>,</span>
</div>
<div class="is-size-4 publication-authors">
<span class="author-block">
<a href="#">Author 6</a><sup>2</sup>,</span>
<span class="author-block">
<a href="#">Author 7</a><sup>2</sup>,</span>
<span class="author-block">
<a href="#">Author 8</a><sup>2&ddagger;</sup>,</span>
<span class="author-block">
<a href="#">Author 9</a><sup>1&ddagger;</sup>,</span>
<span class="author-block">
<a href="#">Author 10</a><sup>1</sup></span>
</div>
<div class="is-size-5 publication-authors">
<span class="author-block"><sup>*</sup>Equal Contribution,</span>
<span class="author-block"><sup>&ddagger;</sup>Correspondence Authors</span>
</div>
<div class="is-size-5 publication-authors">
<span class="author-block"><sup>1</sup>Fudan University,</span>
<span class="author-block"><sup>2</sup>StepFun</span>
</div>
<div class="column has-text-centered">
<div class="publication-links">
<!-- arXiv Link -->
<span class="link-block">
<a class="external-link button is-normal is-rounded is-dark" href="#">
<span class="icon">
<i class="ai ai-arxiv"></i>
</span>
<span>arXiv</span>
</a>
</span>
<!-- Github Link -->
<span class="link-block">
<a href="#" class="external-link button is-normal is-rounded is-dark">
<span class="icon">
<i class="fab fa-github" style="color: white;"></i>
</span>
<span>Code</span>
</a>
</span>
<!-- Weights Link -->
<span class="link-block">
<a href="#" class="external-link button is-normal is-rounded is-dark">
<span class="icon">
<img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face Logo" style="width: 20px; height: 20px;">
</span>
<span>Weights</span>
</a>
</span>
<!-- Dataset Link -->
<span class="link-block">
<a href="#" class="external-link button is-normal is-rounded is-dark">
<span class="icon">
<img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face Logo" style="width: 20px; height: 20px;">
</span>
<span>MMLottie-2M Dataset</span>
</a>
</span>
<!-- Demo Link -->
<span class="link-block">
<a href="#" class="external-link button is-normal is-rounded is-dark">
<span class="icon">
<i class="fas fa-play"></i>
</span>
<span>Demo</span>
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Banner Video -->
<section class="section">
<div class="container is-max-desktop">
<div class="columns is-centered has-text-centered" style="margin-top: -20px">
<video src="./assets/OmniLottie-main-demo.mp4" width="100%" autoplay loop muted playsinline></video>
</div>
</div>
</section>
<!-- Abstract -->
<section class="section">
<div class="container is-max-desktop">
<div class="columns is-centered has-text-centered" style="margin-top: -80px">
<div class="column is-four-fifths">
<h2 class="title is-2">Abstract</h2>
<div class="content has-text-justified">
<p>
<b>OmniLottie</b> is a versatile framework that generates high-quality vector animations from multi-modal instructions.
For flexible motion and visual content control, we focus on Lottie, a light-weight JSON formatting for both shapes and animation behaviors representation.
However, the raw Lottie JSON files contain extensive invariant structural metadata and formatting tokens, posing significant challenges for learning vector animation generation.
Therefore, we introduce a well-designed <b>Lottie tokenizer</b> that transforms JSON files into structured sequences of commands and parameters representing shapes, animation functions and control parameters.
Such tokenizer enables us to build OmniLottie upon pretrained visionlanguage models to follow multi-modal interleaved instructions and generate high-quality vector animations.
To further advance research in vector animation generation, we curate <b>MMLottie-2M</b>, a large-scale dataset of professionally designed vector animations paired with textual and visual annotations.
With extensive experiments, we validate that OmniLottie can produce vivid and semantically aligned vector animations that adhere closely to multi-modal human instructions.
</p>
</div>
</div>
</div>
</div>
</section>
<!-- Highlights -->
<section class="hero" id="teaser" style="margin-bottom: 50px; margin-top: 50px;">
<div class="container is-max-desktop">
<div class="columns is-centered" style="margin-top: 15px">
<div class="column is-full-width">
<h2 class="title is-4">Highlights</h2>
<div class="columns is-centered" style="text-align: center">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-teaser.jpg" alt="OmniLottie Teaser">
</div>
</div>
<div class="content has-text-justified" style="padding-top: 15px">
OmniLottie is capable of generating high-quality vector animations across a wide spectrum of complexity — from simple icons to intricate animated illustrations.
It demonstrates remarkable versatility through multiple generation modalities, including <b>Text-to-Lottie</b>, <b>Text-Image-to-Lottie</b>, and <b>Video-to-Lottie</b>,
making it a powerful and flexible solution for diverse creative and professional animation tasks.
</div>
</div>
</div>
<!-- Method Overview -->
<div class="columns is-centered" style="margin-top: 15px">
<div class="column is-full-width">
<h2 class="title is-4">Method Overview</h2>
<div class="columns is-centered" style="text-align: center">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-pipeline.jpg" alt="OmniLottie Pipeline">
</div>
</div>
<div class="content has-text-justified" style="padding-top: 15px">
OmniLottie is built on a pre-trained vision-language model (Qwen2.5-VL) and incorporates a Lottie tokenizer.
The model tokenizes both text and image/video inputs as prefix tokens, while the Lottie tokenizer encodes vector animation commands into a unified representation space.
The Lottie tokenizer abstracts Lottie animations into compact sequences of animation commands and control parameters, removing redundant metadata while preserving full generative flexibility.
</div>
</div>
</div>
<!-- Lottie Tokenizer Details -->
<div class="columns is-centered" style="margin-top: 15px">
<div class="column is-full-width">
<h2 class="title is-4">Lottie Tokenizer</h2>
<div class="columns is-centered" style="text-align: center">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-tokenizer.jpg" alt="Lottie Tokenizer">
</div>
</div>
<div class="content has-text-justified" style="padding-top: 15px">
Our Lottie tokenizer converts raw JSON files into compact sequences of shape, effect, and animation commands with their associated parameters.
This representation substantially shortens sequence lengths (81% reduction compared to raw JSON), improves token efficiency, and enables OmniLottie to learn a clean distribution over animation primitives.
The tokenizer supports five fundamental layer types: Precomposition, Solid, Null, Shape, and Text layers, each identified by a unique type parameter.
</div>
</div>
</div>
</div>
</section>
<!-- Generation Process -->
<section class="section">
<div class="container is-max-desktop" style="margin-top: 30px;">
<h3 class="title is-4">Generation Process of OmniLottie</h3>
<div>
<section class="section" style="overflow:hidden">
<div class="container">
<div id="post_images" class="carousel">
<div class="item-1">
<video poster="" autoplay="" muted loop="" style="pointer-events: none;">
<source src="./assets/OmniLottie-demo-text2lottie.mp4" type="video/mp4">
</video>
<p class="has-text-centered"><b>Text-to-Lottie Generation</b></p>
</div>
<div class="item-2">
<video poster="" autoplay="" muted loop="" style="pointer-events: none;">
<source src="./assets/OmniLottie-demo-image2lottie.mp4" type="video/mp4">
</video>
<p class="has-text-centered"><b>Text-Image-to-Lottie Generation</b></p>
</div>
<div class="item-3">
<video poster="" autoplay="" muted loop="" style="pointer-events: none;">
<source src="./assets/OmniLottie-demo-video2lottie.mp4" type="video/mp4">
</video>
<p class="has-text-centered"><b>Video-to-Lottie Generation</b></p>
</div>
</div>
</div>
</section>
<script src="https://cdn.jsdelivr.net/npm/bulma-carousel@4.0.3/dist/js/bulma-carousel.min.js"></script>
<script>
bulmaCarousel.attach('#post_images', {
slidesToScroll: 1,
slidesToShow: 1,
loop: true,
});
</script>
</div>
<!-- Comparison Results -->
<div class="columns is-centered" style="margin-top: 20px">
<div class="column is-full-width">
<h2 class="title is-4">Comparison with SOTA Methods</h2>
<h3 class="title is-5">Text-to-Lottie</h3>
<div class="content has-text-justified">
<p>OmniLottie achieves near-perfect success rates, the best FVD, and the strongest motion alignment compared to baselines including DeepSeek, GPT-4o, and Recraft.</p>
</div>
<div class="columns is-centered">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-t2lottie.jpg" alt="Text-to-Lottie Comparison">
</div>
</div>
<h3 class="title is-5">Text-Image-to-Lottie</h3>
<div class="content has-text-justified">
<p>OmniLottie ranks first in FVD, object alignment, and motion alignment while maintaining high reliability. Methods such as AniClipart and LiveSketch exhibit low success rates and significantly longer runtimes.</p>
</div>
<div class="columns is-centered">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-ti2lottie.jpg" alt="Text-Image-to-Lottie Comparison">
</div>
</div>
<h3 class="title is-5">Video-to-Lottie</h3>
<div class="content has-text-justified">
<p>OmniLottie preserves temporal and structural fidelity most effectively, achieving the best FVD, PSNR, SSIM, and DINO scores.</p>
</div>
<div class="columns is-centered">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-v2lottie.jpg" alt="Video-to-Lottie Comparison">
</div>
</div>
</div>
</div>
<!-- Quantitative Results Table -->
<div class="columns is-centered" style="margin-top: 20px">
<div class="column is-full-width">
<h2 class="title is-4">Quantitative Results</h2>
<div class="columns is-centered">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-quantitative-table.jpg" alt="Quantitative Results">
</div>
</div>
<div class="content has-text-justified" style="padding-top: 15px">
OmniLottie achieves 97.3%, 92.0%, and 90.7% success rates for Text-to-Lottie, Text-Image-to-Lottie, and Video-to-Lottie tasks respectively,
substantially outperforming all baselines while producing richer token sequences that enable more expressive and detailed vector animation generation.
</div>
</div>
</div>
<!-- Dataset Section -->
<div class="columns is-centered" style="margin-top: 20px">
<div class="column is-full-width">
<h3 class="title is-4">MMLottie-2M Dataset</h3>
<div class="columns is-centered">
<div class="column" style="align-self: center">
<img src="./assets/MMLottie-dataset.jpg" alt="MMLottie-2M Dataset">
</div>
</div>
<div class="content has-text-justified" style="padding-top: 15px">
The MMLottie-2M dataset consists of two million Lottie animations paired with multi-modal annotations including text descriptions, keyframe images, and rendered videos.
Data is collected from major online platforms (LottieFiles, IconScout, Flaticon, Iconfont, Icons8) and augmented with SVG-derived animations.
The dataset undergoes comprehensive processing including Lottie cleaning, spatial-temporal normalization, video rendering, and coarse-to-fine captioning using VLMs.
</div>
</div>
</div>
<!-- Data Pipeline -->
<div class="columns is-centered" style="margin-top: 20px">
<div class="column is-full-width">
<h3 class="title is-4">Data Processing Pipeline</h3>
<div class="columns is-centered">
<div class="column" style="align-self: center">
<img src="./assets/OmniLottie-data-pipeline.jpg" alt="Data Processing Pipeline">
</div>
</div>
<div class="content has-text-justified" style="padding-top: 15px">
Our data processing pipeline includes five stages: (1) Data collection from web sources and SVG conversion,
(2) Lottie cleaning to remove non-visual and non-parameterizable layers,
(3) Spatial-temporal normalization to 512×512 canvas and unified timeline,
(4) Video rendering with random backgrounds, and
(5) Multi-modal annotation using a coarse-to-fine VLM captioning strategy.
</div>
</div>
</div>
<br>
<!-- Related Links -->
<div class="columns is-centered">
<div class="column is-full-width">
<h2 class="title is-3">Related Links</h2>
<div class="content has-text-justified">
<p>
<b>We thank the following excellent open-source works:</b>
</p>
<p>
<a href="https://omnisvg.github.io/"><b>OmniSVG</b></a>: A unified framework for SVG generation that leverages pre-trained VLMs. We build upon its methodology for vector graphics generation.
</p>
<p>
<a href="https://icon-shop.github.io/"><b>IconShop</b></a>: The first work leveraging LLMs to generate monochrome, icon-level SVGs. We referred to its parametric implementation.
</p>
<p>
<b>Concurrent Works:</b>
</p>
<p>
<a href="https://aniclipart.github.io/"><b>AniClipart</b></a>: Animates static clipart using text-to-video diffusion priors.
</p>
<p>
<a href="#"><b>LiveSketch</b></a>: Generates sketch animations through optimization-based approaches.
</p>
<p>
<a href="https://starvector.github.io/"><b>StarVector</b></a>: Equips LLM with an image encoder for Image-to-SVG generation.
</p>
</div>
</div>
</div>
<!-- Acknowledgements -->
<div class="columns is-centered">
<div class="column is-full-width">
<h2 class="title is-3">Acknowledgements</h2>
<div class="content has-text-justified">
<p>
We thank all the contributors for dataset construction and valuable discussions.
</p>
</div>
</div>
</div>
</div>
</section>
<!-- BibTeX -->
<section class="section" id="BibTeX">
<div class="container is-max-desktop content">
<h2 class="title">BibTeX</h2>
<pre><code>@article{omnilottie2025,
title={OmniLottie: A Unified Scalable Vector Animation Generation Model},
author={Author1 and Author2 and Author3 and Author4 and Author5 and Author6 and Author7 and Author8 and Author9 and Author10},
journal={arXiv preprint arXiv:XXXX.XXXXX},
year={2025}
}</code></pre>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="columns is-centered">
<div class="column is-8">
<div class="content">
<p style="text-align:center">
Source code mainly borrowed from <a href="https://keunhong.com/">Keunhong Park</a>'s <a href="https://nerfies.github.io/">Nerfies website</a>.
</p>
</div>
</div>
</div>
</div>
</footer>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
@-webkit-keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes spinAround{from{-webkit-transform:rotate(0);transform:rotate(0)}to{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.slider{position:relative;width:100%}.slider-container{display:flex;flex-wrap:nowrap;flex-direction:row;overflow:hidden;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);min-height:100%}.slider-container.is-vertical{flex-direction:column}.slider-container .slider-item{flex:none}.slider-container .slider-item .image.is-covered img{-o-object-fit:cover;object-fit:cover;-o-object-position:center center;object-position:center center;height:100%;width:100%}.slider-container .slider-item .video-container{height:0;padding-bottom:0;padding-top:56.25%;margin:0;position:relative}.slider-container .slider-item .video-container.is-1by1,.slider-container .slider-item .video-container.is-square{padding-top:100%}.slider-container .slider-item .video-container.is-4by3{padding-top:75%}.slider-container .slider-item .video-container.is-21by9{padding-top:42.857143%}.slider-container .slider-item .video-container embed,.slider-container .slider-item .video-container iframe,.slider-container .slider-item .video-container object{position:absolute;top:0;left:0;width:100%!important;height:100%!important}.slider-navigation-next,.slider-navigation-previous{display:flex;justify-content:center;align-items:center;position:absolute;width:42px;height:42px;background:#fff center center no-repeat;background-size:20px 20px;border:1px solid #fff;border-radius:25091983px;box-shadow:0 2px 5px #3232321a;top:50%;margin-top:-20px;left:0;cursor:pointer;transition:opacity .3s,-webkit-transform .3s;transition:transform .3s,opacity .3s;transition:transform .3s,opacity .3s,-webkit-transform .3s}.slider-navigation-next:hover,.slider-navigation-previous:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.slider-navigation-next.is-hidden,.slider-navigation-previous.is-hidden{display:none;opacity:0}.slider-navigation-next svg,.slider-navigation-previous svg{width:25%}.slider-navigation-next{left:auto;right:0;background:#fff center center no-repeat;background-size:20px 20px}.slider-pagination{display:none;justify-content:center;align-items:center;position:absolute;bottom:0;left:0;right:0;padding:.5rem 1rem;text-align:center}.slider-pagination .slider-page{background:#fff;width:10px;height:10px;border-radius:25091983px;display:inline-block;margin:0 3px;box-shadow:0 2px 5px #3232321a;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;cursor:pointer}.slider-pagination .slider-page.is-active,.slider-pagination .slider-page:hover{-webkit-transform:scale(1.4);transform:scale(1.4)}@media screen and (min-width:800px){.slider-pagination{display:flex}}.hero.has-carousel{position:relative}.hero.has-carousel+.hero-body,.hero.has-carousel+.hero-footer,.hero.has-carousel+.hero-head{z-index:10;overflow:hidden}.hero.has-carousel .hero-carousel{position:absolute;top:0;left:0;bottom:0;right:0;height:auto;border:none;margin:auto;padding:0;z-index:0}.hero.has-carousel .hero-carousel .slider{width:100%;max-width:100%;overflow:hidden;height:100%!important;max-height:100%;z-index:0}.hero.has-carousel .hero-carousel .slider .has-background{max-height:100%}.hero.has-carousel .hero-carousel .slider .has-background .is-background{-o-object-fit:cover;object-fit:cover;-o-object-position:center center;object-position:center center;height:100%;width:100%}.hero.has-carousel .hero-body{margin:0 3rem;z-index:10}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+157
View File
@@ -0,0 +1,157 @@
body {
font-family: 'Noto Sans', sans-serif;
}
.footer .icon-link {
font-size: 25px;
color: #000;
}
.link-block a {
margin-top: 5px;
margin-bottom: 5px;
}
.dnerf {
font-variant: small-caps;
}
.teaser .hero-body {
padding-top: 0;
padding-bottom: 3rem;
}
.teaser {
font-family: 'Google Sans', sans-serif;
}
.publication-title {
}
.publication-banner {
max-height: parent;
}
.publication-banner video {
position: relative;
left: auto;
top: auto;
transform: none;
object-fit: fit;
}
.publication-header .hero-body {
}
.publication-title {
font-family: 'Google Sans', sans-serif;
}
.publication-authors {
font-family: 'Google Sans', sans-serif;
}
.publication-venue {
color: #555;
width: fit-content;
font-weight: bold;
}
.publication-awards {
color: #ff3860;
width: fit-content;
font-weight: bolder;
}
.publication-authors {
}
.publication-authors a {
color: hsl(204, 86%, 53%) !important;
}
.publication-authors a:hover {
text-decoration: underline;
}
.author-block {
display: inline-block;
}
.publication-banner img {
}
.publication-authors {
/*color: #4286f4;*/
}
.publication-video {
position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%;
overflow: hidden;
border-radius: 10px !important;
}
.publication-video iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.publication-body img {
}
.results-carousel {
overflow: hidden;
}
.results-carousel .item {
margin: 5px;
overflow: hidden;
border: 1px solid #bbb;
border-radius: 10px;
padding: 0;
font-size: 0;
}
.results-carousel video {
margin: 0;
}
.interpolation-panel {
background: #f5f5f5;
border-radius: 10px;
}
.interpolation-panel .interpolation-image {
width: 100%;
border-radius: 5px;
}
.interpolation-video-column {
}
.interpolation-panel .slider {
margin: 0 !important;
}
.interpolation-panel .slider {
margin: 0 !important;
}
#interpolation-image-wrapper {
width: 100%;
}
#interpolation-image-wrapper img {
border-radius: 5px;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+461
View File
@@ -0,0 +1,461 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["bulmaSlider"] = factory();
else
root["bulmaSlider"] = factory();
})(typeof self !== 'undefined' ? self : this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isString", function() { return isString; });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__events__ = __webpack_require__(1);
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var isString = function isString(unknown) {
return typeof unknown === 'string' || !!unknown && (typeof unknown === 'undefined' ? 'undefined' : _typeof(unknown)) === 'object' && Object.prototype.toString.call(unknown) === '[object String]';
};
var bulmaSlider = function (_EventEmitter) {
_inherits(bulmaSlider, _EventEmitter);
function bulmaSlider(selector) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, bulmaSlider);
var _this = _possibleConstructorReturn(this, (bulmaSlider.__proto__ || Object.getPrototypeOf(bulmaSlider)).call(this));
_this.element = typeof selector === 'string' ? document.querySelector(selector) : selector;
// An invalid selector or non-DOM node has been provided.
if (!_this.element) {
throw new Error('An invalid selector or non-DOM node has been provided.');
}
_this._clickEvents = ['click'];
/// Set default options and merge with instance defined
_this.options = _extends({}, options);
_this.onSliderInput = _this.onSliderInput.bind(_this);
_this.init();
return _this;
}
/**
* Initiate all DOM element containing selector
* @method
* @return {Array} Array of all slider instances
*/
_createClass(bulmaSlider, [{
key: 'init',
/**
* Initiate plugin
* @method init
* @return {void}
*/
value: function init() {
this._id = 'bulmaSlider' + new Date().getTime() + Math.floor(Math.random() * Math.floor(9999));
this.output = this._findOutputForSlider();
this._bindEvents();
if (this.output) {
if (this.element.classList.contains('has-output-tooltip')) {
// Get new output position
var newPosition = this._getSliderOutputPosition();
// Set output position
this.output.style['left'] = newPosition.position;
}
}
this.emit('bulmaslider:ready', this.element.value);
}
}, {
key: '_findOutputForSlider',
value: function _findOutputForSlider() {
var _this2 = this;
var result = null;
var outputs = document.getElementsByTagName('output') || [];
Array.from(outputs).forEach(function (output) {
if (output.htmlFor == _this2.element.getAttribute('id')) {
result = output;
return true;
}
});
return result;
}
}, {
key: '_getSliderOutputPosition',
value: function _getSliderOutputPosition() {
// Update output position
var newPlace, minValue;
var style = window.getComputedStyle(this.element, null);
// Measure width of range input
var sliderWidth = parseInt(style.getPropertyValue('width'), 10);
// Figure out placement percentage between left and right of input
if (!this.element.getAttribute('min')) {
minValue = 0;
} else {
minValue = this.element.getAttribute('min');
}
var newPoint = (this.element.value - minValue) / (this.element.getAttribute('max') - minValue);
// Prevent bubble from going beyond left or right (unsupported browsers)
if (newPoint < 0) {
newPlace = 0;
} else if (newPoint > 1) {
newPlace = sliderWidth;
} else {
newPlace = sliderWidth * newPoint;
}
return {
'position': newPlace + 'px'
};
}
/**
* Bind all events
* @method _bindEvents
* @return {void}
*/
}, {
key: '_bindEvents',
value: function _bindEvents() {
if (this.output) {
// Add event listener to update output when slider value change
this.element.addEventListener('input', this.onSliderInput, false);
}
}
}, {
key: 'onSliderInput',
value: function onSliderInput(e) {
e.preventDefault();
if (this.element.classList.contains('has-output-tooltip')) {
// Get new output position
var newPosition = this._getSliderOutputPosition();
// Set output position
this.output.style['left'] = newPosition.position;
}
// Check for prefix and postfix
var prefix = this.output.hasAttribute('data-prefix') ? this.output.getAttribute('data-prefix') : '';
var postfix = this.output.hasAttribute('data-postfix') ? this.output.getAttribute('data-postfix') : '';
// Update output with slider value
this.output.value = prefix + this.element.value + postfix;
this.emit('bulmaslider:ready', this.element.value);
}
}], [{
key: 'attach',
value: function attach() {
var _this3 = this;
var selector = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'input[type="range"].slider';
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var instances = new Array();
var elements = isString(selector) ? document.querySelectorAll(selector) : Array.isArray(selector) ? selector : [selector];
elements.forEach(function (element) {
if (typeof element[_this3.constructor.name] === 'undefined') {
var instance = new bulmaSlider(element, options);
element[_this3.constructor.name] = instance;
instances.push(instance);
} else {
instances.push(element[_this3.constructor.name]);
}
});
return instances;
}
}]);
return bulmaSlider;
}(__WEBPACK_IMPORTED_MODULE_0__events__["a" /* default */]);
/* harmony default export */ __webpack_exports__["default"] = (bulmaSlider);
/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var EventEmitter = function () {
function EventEmitter() {
var listeners = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
_classCallCheck(this, EventEmitter);
this._listeners = new Map(listeners);
this._middlewares = new Map();
}
_createClass(EventEmitter, [{
key: "listenerCount",
value: function listenerCount(eventName) {
if (!this._listeners.has(eventName)) {
return 0;
}
var eventListeners = this._listeners.get(eventName);
return eventListeners.length;
}
}, {
key: "removeListeners",
value: function removeListeners() {
var _this = this;
var eventName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var middleware = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
if (eventName !== null) {
if (Array.isArray(eventName)) {
name.forEach(function (e) {
return _this.removeListeners(e, middleware);
});
} else {
this._listeners.delete(eventName);
if (middleware) {
this.removeMiddleware(eventName);
}
}
} else {
this._listeners = new Map();
}
}
}, {
key: "middleware",
value: function middleware(eventName, fn) {
var _this2 = this;
if (Array.isArray(eventName)) {
name.forEach(function (e) {
return _this2.middleware(e, fn);
});
} else {
if (!Array.isArray(this._middlewares.get(eventName))) {
this._middlewares.set(eventName, []);
}
this._middlewares.get(eventName).push(fn);
}
}
}, {
key: "removeMiddleware",
value: function removeMiddleware() {
var _this3 = this;
var eventName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
if (eventName !== null) {
if (Array.isArray(eventName)) {
name.forEach(function (e) {
return _this3.removeMiddleware(e);
});
} else {
this._middlewares.delete(eventName);
}
} else {
this._middlewares = new Map();
}
}
}, {
key: "on",
value: function on(name, callback) {
var _this4 = this;
var once = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (Array.isArray(name)) {
name.forEach(function (e) {
return _this4.on(e, callback);
});
} else {
name = name.toString();
var split = name.split(/,|, | /);
if (split.length > 1) {
split.forEach(function (e) {
return _this4.on(e, callback);
});
} else {
if (!Array.isArray(this._listeners.get(name))) {
this._listeners.set(name, []);
}
this._listeners.get(name).push({ once: once, callback: callback });
}
}
}
}, {
key: "once",
value: function once(name, callback) {
this.on(name, callback, true);
}
}, {
key: "emit",
value: function emit(name, data) {
var _this5 = this;
var silent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
name = name.toString();
var listeners = this._listeners.get(name);
var middlewares = null;
var doneCount = 0;
var execute = silent;
if (Array.isArray(listeners)) {
listeners.forEach(function (listener, index) {
// Start Middleware checks unless we're doing a silent emit
if (!silent) {
middlewares = _this5._middlewares.get(name);
// Check and execute Middleware
if (Array.isArray(middlewares)) {
middlewares.forEach(function (middleware) {
middleware(data, function () {
var newData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
if (newData !== null) {
data = newData;
}
doneCount++;
}, name);
});
if (doneCount >= middlewares.length) {
execute = true;
}
} else {
execute = true;
}
}
// If Middleware checks have been passed, execute
if (execute) {
if (listener.once) {
listeners[index] = null;
}
listener.callback(data);
}
});
// Dirty way of removing used Events
while (listeners.indexOf(null) !== -1) {
listeners.splice(listeners.indexOf(null), 1);
}
}
}
}]);
return EventEmitter;
}();
/* harmony default export */ __webpack_exports__["a"] = (EventEmitter);
/***/ })
/******/ ])["default"];
});
+1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+54
View File
@@ -0,0 +1,54 @@
window.HELP_IMPROVE_VIDEOJS = false;
window.HELP_IMPROVE_VIDEOJS = false;
$(document).ready(function() {
// Check for click events on the navbar burger icon
$(".navbar-burger").click(function() {
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
$(".navbar-burger").toggleClass("is-active");
$(".navbar-menu").toggleClass("is-active");
});
let options = {
slidesToScroll: 1,
slidesToShow: 4,
loop: false,
infinite: false,
pagination: false,
autoplay: false,
autoplaySpeed: 3000,
}
// Initialize all div with carousel class
let carousels = bulmaCarousel.attach('.carousel', options);
// Loop on each carousel initialized
for(let i = 0; i < carousels.length; i++) {
// Add listener to event
carousels[i].on('before:show', state => {
console.log(state);
});
}
// Access to bulmaCarousel instance of an element
let element = document.querySelector('#my-element');
if (element && element.bulmaCarousel) {
// bulmaCarousel instance is available as element.bulmaCarousel
element.bulmaCarousel.on('before-show', function(state) {
console.log(state);
});
}
/*
let player = document.getElementById('interpolation-video');
player.addEventListener('loadedmetadata', function() {
$('#interpolation-slider').on('input', function(event) {
console.log(this.value, player.duration);
player.currentTime = player.duration / 100 * this.value;
})
}, false);
*/
bulmaSlider.attach();
})
Binary file not shown.
Binary file not shown.
Binary file not shown.