Delanoe Pirard
Deploy to HuggingFace Spaces
18b382b
# flake8: noqa: E501
# Copyright (c) 2025 ByteDance Ltd. and/or its affiliates
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
CSS and HTML content for the Depth Anything 3 Gradio application.
This module contains all the CSS styles and HTML content blocks
used in the Gradio interface.
"""
# CSS Styles for the Gradio interface
# Color palette:
# - Primary: #2563EB (Modern Blue)
# - Secondary: #14B8A6 (Vibrant Teal)
# - Accent: #F97316 (Electric Orange)
# - Neutrals: #F9FAFB to #111827
GRADIO_CSS = """
/* Add Font Awesome CDN with all styles including brands and colors */
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css');
/* Force light mode */
html, body, .gradio-container {
color-scheme: light !important;
}
/* CSS Custom Properties for theming */
:root {
--primary: #2563EB;
--primary-light: #3B82F6;
--primary-dark: #1D4ED8;
--secondary: #14B8A6;
--secondary-light: #2DD4BF;
--secondary-dark: #0D9488;
--accent: #F97316;
--accent-light: #FB923C;
--accent-dark: #EA580C;
--neutral-50: #F9FAFB;
--neutral-100: #F3F4F6;
--neutral-200: #E5E7EB;
--neutral-300: #D1D5DB;
--neutral-400: #9CA3AF;
--neutral-500: #6B7280;
--neutral-600: #4B5563;
--neutral-700: #374151;
--neutral-800: #1F2937;
--neutral-900: #111827;
}
/* Add custom styles for colored icons */
.fa-color-blue {
color: var(--primary);
}
.fa-color-purple {
color: #8B5CF6;
}
.fa-color-cyan {
color: var(--secondary);
}
.fa-color-green {
color: #10B981;
}
.fa-color-yellow {
color: var(--accent);
}
.fa-color-red {
color: #EF4444;
}
.link-btn {
display: inline-flex;
align-items: center;
gap: 8px;
text-decoration: none;
padding: 12px 24px;
border-radius: 50px;
font-weight: 500;
transition: all 0.3s ease;
}
/* Dark mode theme */
@media (prefers-color-scheme: dark) {
html, body {
background: var(--neutral-800);
color: var(--neutral-50);
}
.gradio-container {
background: var(--neutral-800);
color: var(--neutral-50);
}
.link-btn {
background: rgba(20, 184, 166, 0.2);
color: white;
border: 1px solid rgba(20, 184, 166, 0.4);
}
.link-btn:hover {
background: rgba(20, 184, 166, 0.35);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(20, 184, 166, 0.25);
}
.tech-bg {
background: linear-gradient(135deg, var(--neutral-900), var(--neutral-800));
position: relative;
overflow: hidden;
}
.tech-bg::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 20% 80%, rgba(37, 99, 235, 0.15) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(20, 184, 166, 0.15) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(249, 115, 22, 0.1) 0%, transparent 50%);
animation: techPulse 8s ease-in-out infinite;
}
.gradio-container .panel,
.gradio-container .block,
.gradio-container .form {
background: rgba(0, 0, 0, 0.3);
border: 1px solid rgba(20, 184, 166, 0.2);
border-radius: 10px;
}
.gradio-container * {
color: var(--neutral-50);
}
.gradio-container label {
color: var(--neutral-200);
}
.gradio-container .markdown {
color: var(--neutral-200);
}
}
/* Light mode theme */
@media (prefers-color-scheme: light) {
html, body {
background: var(--neutral-50);
color: var(--neutral-800);
}
.gradio-container {
background: var(--neutral-50);
color: var(--neutral-800);
}
.tech-bg {
background: linear-gradient(135deg, var(--neutral-50), var(--neutral-100));
position: relative;
overflow: hidden;
}
.link-btn {
background: rgba(20, 184, 166, 0.12);
color: var(--neutral-700);
border: 1px solid rgba(20, 184, 166, 0.3);
}
.link-btn:hover {
background: rgba(20, 184, 166, 0.2);
transform: translateY(-2px);
box-shadow: 0 8px 25px rgba(20, 184, 166, 0.2);
}
.tech-bg::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 20% 80%, rgba(37, 99, 235, 0.08) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(20, 184, 166, 0.08) 0%, transparent 50%),
radial-gradient(circle at 40% 40%, rgba(249, 115, 22, 0.06) 0%, transparent 50%);
animation: techPulse 8s ease-in-out infinite;
}
.gradio-container .panel,
.gradio-container .block,
.gradio-container .form {
background: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(20, 184, 166, 0.2);
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
}
.gradio-container * {
color: var(--neutral-800);
}
.gradio-container label {
color: var(--neutral-600);
}
.gradio-container .markdown {
color: var(--neutral-600);
}
}
@keyframes techPulse {
0%, 100% { opacity: 0.5; }
50% { opacity: 0.8; }
}
/* Custom log with tech gradient */
.custom-log * {
font-style: italic;
font-size: 22px !important;
background: linear-gradient(135deg, var(--primary), var(--secondary));
background-size: 400% 400%;
-webkit-background-clip: text;
background-clip: text;
font-weight: bold !important;
color: transparent !important;
text-align: center !important;
animation: techGradient 3s ease infinite;
}
@keyframes techGradient {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
@keyframes metricPulse {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes pointcloudPulse {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes camerasPulse {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes gaussiansPulse {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
/* Special colors for key terms - Global styles with gradient animations */
.metric-text {
background: linear-gradient(135deg, #10B981, #059669);
background-size: 200% 200%;
-webkit-background-clip: text;
background-clip: text;
color: transparent !important;
font-weight: 700;
animation: metricPulse 3s ease infinite;
}
.pointcloud-text {
background: linear-gradient(135deg, #10B981, #059669);
background-size: 200% 200%;
-webkit-background-clip: text;
background-clip: text;
color: transparent !important;
font-weight: 700;
animation: pointcloudPulse 3s ease infinite;
}
.cameras-text {
background: linear-gradient(135deg, #F97316, #EA580C);
background-size: 200% 200%;
-webkit-background-clip: text;
background-clip: text;
color: transparent !important;
font-weight: 700;
animation: camerasPulse 3s ease infinite;
}
.gaussians-text {
background: linear-gradient(135deg, #2563EB, #1D4ED8);
background-size: 200% 200%;
-webkit-background-clip: text;
background-clip: text;
color: transparent !important;
font-weight: 700;
animation: gaussiansPulse 3s ease infinite;
}
.example-log * {
font-style: italic;
font-size: 16px !important;
background: linear-gradient(135deg, var(--primary), var(--secondary));
-webkit-background-clip: text;
background-clip: text;
color: transparent !important;
}
#my_radio .wrap {
display: flex;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
}
#my_radio .wrap label {
display: flex;
width: 50%;
justify-content: center;
align-items: center;
margin: 0;
padding: 10px 0;
box-sizing: border-box;
}
/* Align navigation buttons with dropdown bottom */
.navigation-row {
display: flex !important;
align-items: flex-end !important;
gap: 8px !important;
}
.navigation-row > div:nth-child(1),
.navigation-row > div:nth-child(3) {
align-self: flex-end !important;
}
.navigation-row > div:nth-child(2) {
flex: 1 !important;
}
/* Make thumbnails clickable with pointer cursor */
.clickable-thumbnail img {
cursor: pointer !important;
}
.clickable-thumbnail:hover img {
cursor: pointer !important;
opacity: 0.8;
transition: opacity 0.3s ease;
}
/* Make thumbnail containers narrower horizontally */
.clickable-thumbnail {
padding: 5px 2px !important;
margin: 0 2px !important;
}
.clickable-thumbnail .image-container {
margin: 0 !important;
padding: 0 !important;
}
.scene-info {
text-align: center !important;
padding: 5px 2px !important;
margin: 0 !important;
}
"""
def get_header_html(logo_base64=None):
"""
Generate the main header HTML with logo and title.
Args:
logo_base64 (str, optional): Base64 encoded logo image
Returns:
str: HTML string for the header
"""
return """
<div class="tech-bg" style="text-align: center; margin-bottom: 5px; padding: 40px 20px; border-radius: 15px; position: relative; overflow: hidden;">
<div style="position: relative; z-index: 2;">
<h1 style="margin: 0; font-size: 3.5em; font-weight: 700;
background: linear-gradient(135deg, #2563EB, #14B8A6);
background-size: 400% 400%;
-webkit-background-clip: text;
background-clip: text;
color: transparent;
animation: techGradient 3s ease infinite;
text-shadow: 0 0 30px rgba(20, 184, 166, 0.4);
letter-spacing: 2px;">
Depth Anything 3
</h1>
<p style="margin: 15px 0 0 0; font-size: 2.16em; font-weight: 300;" class="header-subtitle">
Recovering the Visual Space from Any Views
</p>
<div style="margin-top: 20px;">
<a href="https://depth-anything-3.github.io" target="_blank" class="link-btn" style="margin: 0.5em;">
<i class="fas fa-globe" style="margin-right: 8px;"></i> Project Page
</a>
<a href="https://arxiv.org/abs/2406.09414" target="_blank" class="link-btn" style="margin: 0.5em;">
<i class="fas fa-file-pdf" style="margin-right: 8px;"></i> Paper
</a>
<a href="https://github.com/Aedelon/awesome-depth-anything-3" target="_blank" class="link-btn" style="margin: 0.5em; background: var(--secondary); color: white; border: none; font-weight: 600;">
<i class="fab fa-github" style="margin-right: 8px;"></i> Awesome Optimized Fork
</a>
<a href="https://github.com/ByteDance-Seed/Depth-Anything-3" target="_blank" class="link-btn" style="margin: 0.5em;">
<i class="fab fa-github" style="margin-right: 8px;"></i> Original
</a>
</div>
</div>
</div>
<style>
.header-subtitle {
color: #4B5563;
}
.tech-bg {
background: linear-gradient(135deg, rgba(20, 184, 166, 0.08) 0%, rgba(37, 99, 235, 0.08) 100%) !important;
}
</style>
<script>
document.body.classList.add('light');
document.documentElement.classList.add('light');
</script>
"""
def get_description_html():
"""
Generate the main description and getting started HTML.
Returns:
str: HTML string for the description
"""
return """
<div class="description-container" style="padding: 25px; border-radius: 15px; margin: 0 0 20px 0;">
<h2 class="description-title" style="margin-top: 0; font-size: 1.6em; text-align: center;">
<i class="fas fa-bullseye fa-color-red" style="margin-right: 8px;"></i> What This Demo Does
</h2>
<div class="description-content" style="padding: 20px; border-radius: 10px; margin: 15px 0; text-align: center;">
<p class="description-main" style="line-height: 1.6; margin: 0; font-size: 1.45em;">
<strong>Upload images or videos</strong> → <strong>Get <span class="metric-text">Metric</span> <span class="pointcloud-text">Point Clouds</span>, <span class="cameras-text">Cameras</span> and <span class="gaussians-text">Novel Views</span></strong> → <strong>Explore in 3D</strong>
</p>
</div>
<div style="text-align: center; margin-top: 15px;">
<p class="description-tip" style="font-style: italic; margin: 0;">
<i class="fas fa-lightbulb fa-color-yellow" style="margin-right: 8px;"></i> <strong>Tip:</strong> Landscape-oriented images or videos are preferred for best 3D recovering.
</p>
</div>
</div>
<style>
@media (prefers-color-scheme: dark) {
.description-container {
background: linear-gradient(135deg, rgba(20, 184, 166, 0.08) 0%, rgba(37, 99, 235, 0.08) 100%);
border: 1px solid rgba(20, 184, 166, 0.2);
}
.description-title { color: #14B8A6; }
.description-content { background: rgba(0, 0, 0, 0.3); }
.description-main { color: #E5E7EB; }
.description-text { color: #D1D5DB; }
.description-tip { color: #D1D5DB; }
}
@media (prefers-color-scheme: light) {
.description-container {
background: linear-gradient(135deg, rgba(20, 184, 166, 0.05) 0%, rgba(37, 99, 235, 0.05) 100%);
border: 1px solid rgba(20, 184, 166, 0.2);
}
.description-title { color: #14B8A6; }
.description-content { background: transparent; }
.description-main { color: #1F2937; }
.description-text { color: #4B5563; }
.description-tip { color: #4B5563; }
}
</style>
"""
def get_acknowledgements_html():
"""
Generate the acknowledgements section HTML.
Returns:
str: HTML string for the acknowledgements
"""
return """
<div style="background: linear-gradient(135deg, rgba(20, 184, 166, 0.08) 0%, rgba(37, 99, 235, 0.08) 100%);
padding: 25px; border-radius: 15px; margin: 20px 0; border: 1px solid rgba(20, 184, 166, 0.2);">
<h3 style="color: #14B8A6; margin-top: 0; text-align: center; font-size: 1.4em;">
<i class="fas fa-trophy fa-color-yellow" style="margin-right: 8px;"></i> Research Credits & Acknowledgments
</h3>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin: 15px 0;">
<!-- Original Research Section (Left) -->
<div style="text-align: center;">
<h4 style="color: #2563EB; margin: 10px 0;"><i class="fas fa-flask fa-color-green" style="margin-right: 8px;"></i> Original Research</h4>
<p style="color: #9CA3AF; margin: 5px 0;">
<a href="https://depth-anything-3.github.io" target="_blank"
style="color: #14B8A6; text-decoration: none; font-weight: 600;">
Depth Anything 3
</a>
</p>
</div>
<!-- Previous Versions Section (Right) -->
<div style="text-align: center;">
<h4 style="color: #2563EB; margin: 10px 0;"><i class="fas fa-history fa-color-blue" style="margin-right: 8px;"></i> Previous Versions</h4>
<div style="display: flex; flex-direction: row; gap: 15px; justify-content: center; align-items: center;">
<p style="color: #9CA3AF; margin: 0;">
<a href="https://huggingface.co/spaces/LiheYoung/Depth-Anything" target="_blank"
style="color: #14B8A6; text-decoration: none; font-weight: 600;">
Depth-Anything
</a>
</p>
<span style="color: #9CA3AF;">•</span>
<p style="color: #9CA3AF; margin: 0;">
<a href="https://huggingface.co/spaces/depth-anything/Depth-Anything-V2" target="_blank"
style="color: #14B8A6; text-decoration: none; font-weight: 600;">
Depth-Anything-V2
</a>
</p>
</div>
</div>
</div>
<!-- HF Demo Adapted from - Centered at the bottom of the whole block -->
<div style="margin-top: 20px; padding-top: 15px; border-top: 1px solid rgba(20, 184, 166, 0.2); text-align: center;">
<p style="color: #6B7280; font-size: 0.9em; margin: 0;">
<i class="fas fa-code-branch" style="margin-right: 5px; color: #9CA3AF;"></i> HF demo adapted from <a href="https://huggingface.co/spaces/facebook/map-anything" target="_blank" style="color: inherit; text-decoration: none;">Map Anything</a>
</p>
</div>
</div>
"""
def get_gradio_theme():
"""
Get the configured Gradio theme with modern teal/blue colors.
Color palette:
- Primary: Teal (#14B8A6)
- Secondary: Blue (#2563EB)
- Accent: Orange (#F97316)
- Neutrals: Clean grays (#F9FAFB to #111827)
Returns:
gr.themes.Base: Configured Gradio theme
"""
import gradio as gr
return gr.themes.Base(
# Primary hue: Teal
primary_hue=gr.themes.Color(
c50="#F0FDFA",
c100="#CCFBF1",
c200="#99F6E4",
c300="#5EEAD4",
c400="#2DD4BF",
c500="#14B8A6",
c600="#0D9488",
c700="#0F766E",
c800="#115E59",
c900="#134E4A",
c950="#042F2E",
),
# Secondary hue: Blue
secondary_hue=gr.themes.Color(
c50="#EFF6FF",
c100="#DBEAFE",
c200="#BFDBFE",
c300="#93C5FD",
c400="#60A5FA",
c500="#3B82F6",
c600="#2563EB",
c700="#1D4ED8",
c800="#1E40AF",
c900="#1E3A8A",
c950="#172554",
),
# Neutral hue: Clean grays
neutral_hue=gr.themes.Color(
c50="#F9FAFB",
c100="#F3F4F6",
c200="#E5E7EB",
c300="#D1D5DB",
c400="#9CA3AF",
c500="#6B7280",
c600="#4B5563",
c700="#374151",
c800="#1F2937",
c900="#111827",
c950="#030712",
),
)
# Measure tab instructions HTML
MEASURE_INSTRUCTIONS_HTML = """
### Click points on the image to compute distance.
> <i class="fas fa-triangle-exclamation fa-color-red" style="margin-right: 5px;"></i> Metric scale estimation is difficult on aerial/drone images.
"""