Spaces:
Running on Zero
Running on Zero
Add Karate Wiener title intro overlay
Browse files- .gitattributes +1 -0
- README.md +47 -49
- app.py +352 -16
- assets/karate_wiener_title_overlay.wav +3 -0
- deploy_out2.txt +4 -0
- deploy_space.py +15 -0
.gitattributes
CHANGED
|
@@ -206,3 +206,4 @@ pose_vocab_sheet.png filter=lfs diff=lfs merge=lfs -text
|
|
| 206 |
wiener_proto_card.png filter=lfs diff=lfs merge=lfs -text
|
| 207 |
wiener_session_crab.png filter=lfs diff=lfs merge=lfs -text
|
| 208 |
wiener_session_scorpion.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 206 |
wiener_proto_card.png filter=lfs diff=lfs merge=lfs -text
|
| 207 |
wiener_session_crab.png filter=lfs diff=lfs merge=lfs -text
|
| 208 |
wiener_session_scorpion.png filter=lfs diff=lfs merge=lfs -text
|
| 209 |
+
assets/karate_wiener_title_overlay.wav filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -1,49 +1,47 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
emoji: 🥋
|
| 4 |
-
colorFrom: green
|
| 5 |
-
colorTo: gray
|
| 6 |
-
sdk: gradio
|
| 7 |
-
sdk_version: 6.9.0
|
| 8 |
-
app_file: app.py
|
| 9 |
-
python_version: "3.10"
|
| 10 |
-
suggested_hardware: zero-a10g
|
| 11 |
-
pinned:
|
| 12 |
-
license: apache-2.0
|
| 13 |
-
hf_oauth: true
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
-
|
| 17 |
-
- McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
>
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
`global_quats_xyzw`. Additional rigs can be added to `_CHARACTER_CATALOG` in
|
| 49 |
-
`app.py` as `{ id, label, mapping, glb_b64 }`.
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Kimodo ZeroGPU
|
| 3 |
+
emoji: 🥋
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: gray
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 6.9.0
|
| 8 |
+
app_file: app.py
|
| 9 |
+
python_version: "3.10"
|
| 10 |
+
suggested_hardware: zero-a10g
|
| 11 |
+
pinned: false
|
| 12 |
+
license: apache-2.0
|
| 13 |
+
hf_oauth: true
|
| 14 |
+
models:
|
| 15 |
+
- nvidia/Kimodo-SMPLX-RP-v1
|
| 16 |
+
- McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp
|
| 17 |
+
- McGill-NLP/LLM2Vec-Meta-Llama-3-8B-Instruct-mntp-supervised
|
| 18 |
+
---
|
| 19 |
+
|
| 20 |
+
# Kimodo ZeroGPU
|
| 21 |
+
|
| 22 |
+
Viewer-first ZeroGPU Space for Kimodo text-to-motion generation.
|
| 23 |
+
|
| 24 |
+
Generated animations are saved into the configured Hugging Face Dataset store so
|
| 25 |
+
they survive Space rebuilds and can be reused by the kata maker. Animation IDs
|
| 26 |
+
are deterministic from the normalized prompt, model, seconds, denoising steps,
|
| 27 |
+
seed, and generation schema; regenerating with the same settings returns the
|
| 28 |
+
cached animation instead of spending GPU time again.
|
| 29 |
+
|
| 30 |
+
## Generation model
|
| 31 |
+
|
| 32 |
+
The Space generates on the **SMPL-X 22-joint** skeleton via `kimodo-smplx-rp`
|
| 33 |
+
(set `KIMODO_MODEL` to override). This matches the skeleton used by the kimodo
|
| 34 |
+
web/kata viewers, so generated clips can be retargeted directly onto skinned
|
| 35 |
+
display characters with no joint remapping.
|
| 36 |
+
|
| 37 |
+
> Note: `nvidia/Kimodo-SMPLX-RP-v1` is distributed under NVIDIA's research/R&D
|
| 38 |
+
> model license, which is more restrictive than the NVIDIA Open Model license
|
| 39 |
+
> used by the SOMA models. Review it before public/commercial use.
|
| 40 |
+
|
| 41 |
+
## Display characters
|
| 42 |
+
|
| 43 |
+
The 3D viewer can play a clip as the procedural skeleton or retarget it onto a
|
| 44 |
+
skinned rig (an s&box Citizen ships in `assets/`). The picker in the viewer HUD
|
| 45 |
+
switches between them; retargeting is rest-pose alignment driven by each clip's
|
| 46 |
+
`global_quats_xyzw`. Additional rigs can be added to `_CHARACTER_CATALOG` in
|
| 47 |
+
`app.py` as `{ id, label, mapping, glb_b64 }`.
|
|
|
|
|
|
app.py
CHANGED
|
@@ -129,8 +129,9 @@ CLOTHING_CATALOG = [
|
|
| 129 |
# it's still in the catalog so it can be added from the wardrobe.)
|
| 130 |
DEFAULT_CLOTHING = {"face": "nerdy_glasses",
|
| 131 |
"torso_over": "kimono", "legs": "kimono_trousers"}
|
| 132 |
-
_DEFAULT_SCENE_PATH = Path(__file__).parent / "assets" / "default_scene.webp"
|
| 133 |
-
|
|
|
|
| 134 |
KLEIN_SPACE = os.environ.get("KIMODO_KLEIN_SPACE", "polats/tiny-army-klein-zerogpu").strip()
|
| 135 |
TRIPOSPLAT_SPACE = os.environ.get("KIMODO_TRIPOSPLAT_SPACE", "polats/kimodo-triposplat-zerogpu").strip()
|
| 136 |
# tiny-aya (Cohere Tiny Aya) text model — used to suggest/improve dojo scene prompts.
|
|
@@ -155,10 +156,18 @@ TINY_AYA_SPACE = os.environ.get("KIMODO_TINY_AYA_SPACE", "polats/tiny-army-tiny-
|
|
| 155 |
# the "NEW-TAB BACKEND EXTENSION POINT" marker near the compose wiring.
|
| 156 |
# See tabs/README.md + tabs/templates/ for a complete copy-paste example.
|
| 157 |
_TABS_DIR = Path(__file__).parent / "tabs"
|
| 158 |
-
def _read_tabs(pattern: str) -> str:
|
| 159 |
-
if not _TABS_DIR.is_dir():
|
| 160 |
-
return ""
|
| 161 |
-
return "".join(p.read_text(encoding="utf-8") for p in sorted(_TABS_DIR.glob(pattern)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 162 |
|
| 163 |
APP_CSS = """
|
| 164 |
#main-preview {
|
|
@@ -1792,7 +1801,7 @@ def _render_preview_html(
|
|
| 1792 |
fill.position.set(-2, 3, 5);
|
| 1793 |
scene.add(fill);
|
| 1794 |
|
| 1795 |
-
const floor = new THREE.GridHelper(1, 20,
|
| 1796 |
floor.position.y = dojoFloorSurfaceY;
|
| 1797 |
floor.scale.set(dojoRoomSize, 1, dojoRoomSize);
|
| 1798 |
scene.add(floor);
|
|
@@ -5963,8 +5972,8 @@ _ACCT_JS = r"""
|
|
| 5963 |
# Pluggable side-tab behavior, concatenated into the drawer-JS scope (see _read_tabs).
|
| 5964 |
_EXTRA_TABS_JS = _read_tabs("*.tab.js")
|
| 5965 |
|
| 5966 |
-
DRAWER_JS = f"""
|
| 5967 |
-
(() => {{
|
| 5968 |
// Lift the SSR boot splash (the body::before/::after overlay in _BLOCKS_CSS) by
|
| 5969 |
// tagging <body>. Called on the viewer's first preview-ready / viewer-error, plus a
|
| 5970 |
// safety timeout so a slow/blocked CDN never traps the user behind the spinner.
|
|
@@ -6254,9 +6263,335 @@ DRAWER_JS = f"""
|
|
| 6254 |
}}
|
| 6255 |
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
|
| 6256 |
else boot();
|
| 6257 |
-
}})();
|
| 6258 |
-
"""
|
| 6259 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6260 |
# Warm the CDNs the viewer iframe pulls three.js (+ lazy spark) from. (head= is
|
| 6261 |
# injected at hydration, so this is a best-effort warm-up; the boot splash that
|
| 6262 |
# hides the pre-hydration flash lives in the SSR'd css= block instead — see
|
|
@@ -6264,10 +6599,11 @@ APP_HEAD = (
|
|
| 6264 |
'<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>'
|
| 6265 |
'<link rel="dns-prefetch" href="https://cdn.jsdelivr.net">'
|
| 6266 |
'<link rel="preconnect" href="https://unpkg.com" crossorigin>'
|
| 6267 |
-
'<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>'
|
| 6268 |
-
# APP_CSS + any pluggable-tab styles (tabs/<name>.tab.css), then the drawer JS.
|
| 6269 |
-
f"<style>{APP_CSS}{_read_tabs('*.tab.css')}
|
| 6270 |
-
|
|
|
|
| 6271 |
|
| 6272 |
|
| 6273 |
def generate(
|
|
|
|
| 129 |
# it's still in the catalog so it can be added from the wardrobe.)
|
| 130 |
DEFAULT_CLOTHING = {"face": "nerdy_glasses",
|
| 131 |
"torso_over": "kimono", "legs": "kimono_trousers"}
|
| 132 |
+
_DEFAULT_SCENE_PATH = Path(__file__).parent / "assets" / "default_scene.webp"
|
| 133 |
+
_TITLE_OVERLAY_AUDIO_PATH = Path(__file__).parent / "assets" / "karate_wiener_title_overlay.wav"
|
| 134 |
+
DIT360_SPACE = os.environ.get("KIMODO_DIT360_SPACE", "Insta360-Research/DiT360").strip()
|
| 135 |
KLEIN_SPACE = os.environ.get("KIMODO_KLEIN_SPACE", "polats/tiny-army-klein-zerogpu").strip()
|
| 136 |
TRIPOSPLAT_SPACE = os.environ.get("KIMODO_TRIPOSPLAT_SPACE", "polats/kimodo-triposplat-zerogpu").strip()
|
| 137 |
# tiny-aya (Cohere Tiny Aya) text model — used to suggest/improve dojo scene prompts.
|
|
|
|
| 156 |
# the "NEW-TAB BACKEND EXTENSION POINT" marker near the compose wiring.
|
| 157 |
# See tabs/README.md + tabs/templates/ for a complete copy-paste example.
|
| 158 |
_TABS_DIR = Path(__file__).parent / "tabs"
|
| 159 |
+
def _read_tabs(pattern: str) -> str:
|
| 160 |
+
if not _TABS_DIR.is_dir():
|
| 161 |
+
return ""
|
| 162 |
+
return "".join(p.read_text(encoding="utf-8") for p in sorted(_TABS_DIR.glob(pattern)))
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
def _load_b64(path: Path) -> str:
|
| 166 |
+
try:
|
| 167 |
+
return base64.b64encode(path.read_bytes()).decode("ascii")
|
| 168 |
+
except Exception as exc: # pragma: no cover - optional startup flourish
|
| 169 |
+
print(f"Could not load {path}: {exc}")
|
| 170 |
+
return ""
|
| 171 |
|
| 172 |
APP_CSS = """
|
| 173 |
#main-preview {
|
|
|
|
| 1801 |
fill.position.set(-2, 3, 5);
|
| 1802 |
scene.add(fill);
|
| 1803 |
|
| 1804 |
+
const floor = new THREE.GridHelper(1, 20, 0x42f6ff, 0x1aa6b8);
|
| 1805 |
floor.position.y = dojoFloorSurfaceY;
|
| 1806 |
floor.scale.set(dojoRoomSize, 1, dojoRoomSize);
|
| 1807 |
scene.add(floor);
|
|
|
|
| 5972 |
# Pluggable side-tab behavior, concatenated into the drawer-JS scope (see _read_tabs).
|
| 5973 |
_EXTRA_TABS_JS = _read_tabs("*.tab.js")
|
| 5974 |
|
| 5975 |
+
DRAWER_JS = f"""
|
| 5976 |
+
(() => {{
|
| 5977 |
// Lift the SSR boot splash (the body::before/::after overlay in _BLOCKS_CSS) by
|
| 5978 |
// tagging <body>. Called on the viewer's first preview-ready / viewer-error, plus a
|
| 5979 |
// safety timeout so a slow/blocked CDN never traps the user behind the spinner.
|
|
|
|
| 6263 |
}}
|
| 6264 |
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
|
| 6265 |
else boot();
|
| 6266 |
+
}})();
|
| 6267 |
+
"""
|
| 6268 |
+
|
| 6269 |
+
TITLE_OVERLAY_CSS = """
|
| 6270 |
+
#kw-title-overlay {
|
| 6271 |
+
position: fixed; inset: 0; z-index: 100020; overflow: hidden;
|
| 6272 |
+
display: grid; place-items: center; background: transparent;
|
| 6273 |
+
font-family: Impact, Haettenschweiler, "Arial Black", system-ui, sans-serif;
|
| 6274 |
+
pointer-events: none;
|
| 6275 |
+
}
|
| 6276 |
+
#kw-title-overlay.kw-ready { pointer-events: auto; }
|
| 6277 |
+
#kw-title-overlay.kw-done { pointer-events: none; }
|
| 6278 |
+
#kw-title-overlay::before {
|
| 6279 |
+
content: ""; position: absolute; inset: 0; pointer-events: none;
|
| 6280 |
+
background:
|
| 6281 |
+
radial-gradient(circle at 50% 50%, transparent 0 24%, rgba(0,0,0,.08) 62%, rgba(0,0,0,.22) 100%),
|
| 6282 |
+
linear-gradient(90deg, rgba(255,42,163,.08), transparent 25% 75%, rgba(66,246,255,.08));
|
| 6283 |
+
}
|
| 6284 |
+
.kw-sun {
|
| 6285 |
+
position: absolute; z-index: 3; left: 50%; top: 45%; width: min(42vw, 460px);
|
| 6286 |
+
aspect-ratio: 1; border-radius: 50%; opacity: 0; pointer-events: none;
|
| 6287 |
+
transform: translate(-50%, -58%) scale(.72);
|
| 6288 |
+
background:
|
| 6289 |
+
repeating-linear-gradient(0deg, transparent 0 18px, rgba(7,2,15,.78) 19px 26px),
|
| 6290 |
+
linear-gradient(180deg, #ffe96c, #ff8a26 46%, #ef2a7a 100%);
|
| 6291 |
+
}
|
| 6292 |
+
#kw-title-overlay.kw-exploded .kw-sun { animation: kwSunReveal .55s ease-out forwards; }
|
| 6293 |
+
#kw-title-overlay.kw-vanish .kw-sun { animation: kwSunVanish .48s ease-in forwards; }
|
| 6294 |
+
.kw-card {
|
| 6295 |
+
position: relative; z-index: 6; width: min(94vw, 1080px); text-align: center;
|
| 6296 |
+
transform: translateY(-1vh); overflow: visible;
|
| 6297 |
+
}
|
| 6298 |
+
.kw-logo {
|
| 6299 |
+
position: relative; transform: translateX(-145vw) rotate(-1080deg) scale(.18);
|
| 6300 |
+
opacity: 0; transform-origin: 50% 52%; overflow: visible;
|
| 6301 |
+
}
|
| 6302 |
+
#kw-title-overlay.kw-running .kw-logo { animation: kwLogoSpinIn .95s linear forwards; }
|
| 6303 |
+
#kw-title-overlay.kw-vanish .kw-logo { animation: kwLogoVanish .48s cubic-bezier(.62,0,.9,.42) forwards; }
|
| 6304 |
+
.kw-title {
|
| 6305 |
+
margin: 0; display: flex; flex-direction: column; align-items: center;
|
| 6306 |
+
text-transform: uppercase; line-height: .78; letter-spacing: 0;
|
| 6307 |
+
font-size: clamp(72px, 15vw, 184px); color: #ffd84a;
|
| 6308 |
+
-webkit-text-stroke: clamp(2px, .45vw, 6px) #2a032a;
|
| 6309 |
+
text-shadow:
|
| 6310 |
+
5px 5px 0 #8f143f,
|
| 6311 |
+
10px 10px 0 #2a032a,
|
| 6312 |
+
0 0 18px rgba(255,216,74,.65),
|
| 6313 |
+
0 0 44px rgba(255,42,163,.85);
|
| 6314 |
+
transform: rotate(-7deg) scale(1);
|
| 6315 |
+
}
|
| 6316 |
+
.kw-title span:last-child {
|
| 6317 |
+
color: #ff5d2c;
|
| 6318 |
+
text-shadow:
|
| 6319 |
+
5px 5px 0 #7021a8,
|
| 6320 |
+
10px 10px 0 #22022d,
|
| 6321 |
+
0 0 18px rgba(255,107,25,.75),
|
| 6322 |
+
0 0 46px rgba(66,246,255,.46);
|
| 6323 |
+
}
|
| 6324 |
+
#kw-title-overlay.kw-exploded .kw-title { animation: kwTitleImpact .82s ease-out forwards; }
|
| 6325 |
+
.kw-blast { position: absolute; inset: 0; z-index: 4; width: 100%; height: 100%; pointer-events: none; }
|
| 6326 |
+
.kw-grain, .kw-scanlines { position: absolute; inset: 0; z-index: 7; pointer-events: none; }
|
| 6327 |
+
.kw-play {
|
| 6328 |
+
position: absolute; z-index: 6; left: 50%; top: 50%;
|
| 6329 |
+
transform: translate(-50%, -50%); display: none; align-items: center; justify-content: center;
|
| 6330 |
+
width: clamp(78px, 19vw, 110px); aspect-ratio: 1; padding: 0; border: 0;
|
| 6331 |
+
border-radius: 999px;
|
| 6332 |
+
background:
|
| 6333 |
+
linear-gradient(rgba(7,2,15,.14), rgba(7,2,15,.14)) padding-box,
|
| 6334 |
+
linear-gradient(180deg, rgba(255,233,108,.58) 0%, rgba(255,155,47,.52) 43%, rgba(239,42,122,.5) 100%) border-box;
|
| 6335 |
+
border: 4px solid transparent; backdrop-filter: blur(1px);
|
| 6336 |
+
box-shadow: 0 0 0 1px rgba(42,3,42,.38), 0 0 18px rgba(239,42,122,.18), inset 0 0 20px rgba(255,155,47,.06);
|
| 6337 |
+
cursor: pointer;
|
| 6338 |
+
}
|
| 6339 |
+
.kw-play::before {
|
| 6340 |
+
content: ""; width: 0; height: 0; margin-left: 7%;
|
| 6341 |
+
border-top: clamp(13px, 3.2vw, 18px) solid transparent;
|
| 6342 |
+
border-bottom: clamp(13px, 3.2vw, 18px) solid transparent;
|
| 6343 |
+
border-left: clamp(20px, 5vw, 29px) solid rgba(255,138,38,.58);
|
| 6344 |
+
filter: drop-shadow(0 0 6px rgba(255,138,38,.22)) drop-shadow(0 0 12px rgba(239,42,122,.16));
|
| 6345 |
+
}
|
| 6346 |
+
.kw-play:active { transform: translate(-50%, -50%) scale(.94); filter: brightness(1.18); }
|
| 6347 |
+
#kw-title-overlay.kw-ready .kw-play { display: inline-flex; animation: kwPlayIdle 1.45s ease-in-out infinite; }
|
| 6348 |
+
#kw-title-overlay.kw-pressed .kw-play { display: inline-flex; animation: kwPlayPressed .22s ease-in forwards; }
|
| 6349 |
+
#kw-title-overlay.kw-running .kw-play,
|
| 6350 |
+
#kw-title-overlay.kw-vanish .kw-play,
|
| 6351 |
+
#kw-title-overlay.kw-done .kw-play { display: none; }
|
| 6352 |
+
.kw-grain {
|
| 6353 |
+
opacity: .12;
|
| 6354 |
+
background-image:
|
| 6355 |
+
radial-gradient(circle at 15% 35%, #fff 0 1px, transparent 1px),
|
| 6356 |
+
radial-gradient(circle at 68% 22%, #fff 0 1px, transparent 1px),
|
| 6357 |
+
radial-gradient(circle at 45% 71%, #fff 0 1px, transparent 1px);
|
| 6358 |
+
background-size: 37px 31px, 53px 47px, 71px 61px;
|
| 6359 |
+
animation: kwGrain .3s steps(2,end) infinite;
|
| 6360 |
+
}
|
| 6361 |
+
.kw-scanlines { background: repeating-linear-gradient(0deg, rgba(255,255,255,.035) 0 1px, transparent 1px 4px); mix-blend-mode: screen; }
|
| 6362 |
+
#kw-title-overlay.kw-filters-out .kw-grain,
|
| 6363 |
+
#kw-title-overlay.kw-filters-out .kw-scanlines { opacity: 0; transition: opacity 1.8s ease; }
|
| 6364 |
+
#kw-title-overlay.kw-flash { animation: kwScreenFlash .82s ease-out; }
|
| 6365 |
+
@keyframes kwLogoSpinIn {
|
| 6366 |
+
0% { opacity: 0; transform: translateX(-145vw) rotate(-1260deg) scale(.16); }
|
| 6367 |
+
66% { opacity: 1; transform: translateX(-26vw) rotate(-520deg) scale(.82); }
|
| 6368 |
+
91% { opacity: 1; transform: translateX(0) rotate(-94deg) scale(1.18); }
|
| 6369 |
+
97% { opacity: 1; transform: translateX(0) rotate(-24deg) scale(1.24); }
|
| 6370 |
+
100% { opacity: 1; transform: translateX(0) rotate(0deg) scale(1.18); }
|
| 6371 |
+
}
|
| 6372 |
+
@keyframes kwLogoVanish {
|
| 6373 |
+
0% { opacity: 1; transform: translateX(0) rotate(0deg) scale(1.18); filter: brightness(1.15); }
|
| 6374 |
+
100% { opacity: 0; transform: translateX(0) rotate(0deg) scale(.03); filter: brightness(2.4) blur(8px); }
|
| 6375 |
+
}
|
| 6376 |
+
@keyframes kwSunReveal {
|
| 6377 |
+
0% { opacity: 0; transform: translate(-50%, -58%) scale(.72); }
|
| 6378 |
+
22% { opacity: .95; transform: translate(-50%, -58%) scale(1.08); }
|
| 6379 |
+
100% { opacity: .88; transform: translate(-50%, -58%) scale(1); }
|
| 6380 |
+
}
|
| 6381 |
+
@keyframes kwSunVanish {
|
| 6382 |
+
from { opacity: .88; transform: translate(-50%, -58%) scale(1); }
|
| 6383 |
+
to { opacity: 0; transform: translate(-50%, -58%) scale(.25); }
|
| 6384 |
+
}
|
| 6385 |
+
@keyframes kwTitleImpact {
|
| 6386 |
+
0% { transform: rotate(-7deg) scale(1); filter: brightness(1) saturate(1.4); }
|
| 6387 |
+
18% { transform: rotate(-4deg) scale(1.1); filter: brightness(3.2) saturate(2.2); }
|
| 6388 |
+
34% { transform: rotate(-10deg) scale(1.03); filter: brightness(1.55) saturate(1.7); }
|
| 6389 |
+
100% { transform: rotate(-7deg) scale(1); filter: brightness(1.16) saturate(1.48); }
|
| 6390 |
+
}
|
| 6391 |
+
@keyframes kwScreenFlash {
|
| 6392 |
+
0% { box-shadow: inset 0 0 0 100vmax rgba(255,247,196,.82); }
|
| 6393 |
+
18% { box-shadow: inset 0 0 0 100vmax rgba(255,88,24,.42); }
|
| 6394 |
+
100% { box-shadow: inset 0 0 0 100vmax rgba(255,88,24,0); }
|
| 6395 |
+
}
|
| 6396 |
+
@keyframes kwPlayIdle {
|
| 6397 |
+
0%, 100% { opacity: .54; transform: translate(-50%, -50%) scale(1); filter: saturate(1.02) brightness(.96); }
|
| 6398 |
+
50% { opacity: .7; transform: translate(-50%, -50%) scale(1.06); filter: saturate(1.12) brightness(1.06); }
|
| 6399 |
+
}
|
| 6400 |
+
@keyframes kwPlayPressed {
|
| 6401 |
+
0% { opacity: 1; transform: translate(-50%, -50%) scale(1); filter: brightness(1); }
|
| 6402 |
+
42% { opacity: .96; transform: translate(-50%, -50%) scale(1.18); filter: brightness(1.45); }
|
| 6403 |
+
100% { opacity: 0; transform: translate(-50%, -50%) scale(.08); filter: brightness(2) blur(3px); }
|
| 6404 |
+
}
|
| 6405 |
+
@keyframes kwGrain { from { transform: translate(0,0); } to { transform: translate(-18px,11px); } }
|
| 6406 |
+
@media (max-width: 620px) {
|
| 6407 |
+
.kw-title { font-size: clamp(58px, 21vw, 112px); }
|
| 6408 |
+
.kw-sun { width: 76vw; }
|
| 6409 |
+
}
|
| 6410 |
+
"""
|
| 6411 |
+
|
| 6412 |
+
_TITLE_OVERLAY_AUDIO_B64 = _load_b64(_TITLE_OVERLAY_AUDIO_PATH)
|
| 6413 |
+
_TITLE_OVERLAY_AUDIO_DATA = (
|
| 6414 |
+
"data:audio/wav;base64," + _TITLE_OVERLAY_AUDIO_B64
|
| 6415 |
+
if _TITLE_OVERLAY_AUDIO_B64 else ""
|
| 6416 |
+
)
|
| 6417 |
+
|
| 6418 |
+
TITLE_OVERLAY_JS = f"""
|
| 6419 |
+
(() => {{
|
| 6420 |
+
const AUDIO_SRC = {json.dumps(_TITLE_OVERLAY_AUDIO_DATA)};
|
| 6421 |
+
if (!AUDIO_SRC || window.__kwTitleOverlayInstalled) return;
|
| 6422 |
+
window.__kwTitleOverlayInstalled = true;
|
| 6423 |
+
|
| 6424 |
+
function install() {{
|
| 6425 |
+
if (document.getElementById('kw-title-overlay')) return;
|
| 6426 |
+
const root = document.createElement('div');
|
| 6427 |
+
root.id = 'kw-title-overlay';
|
| 6428 |
+
root.innerHTML = `
|
| 6429 |
+
<canvas class="kw-blast" aria-hidden="true"></canvas>
|
| 6430 |
+
<div class="kw-sun" aria-hidden="true"></div>
|
| 6431 |
+
<section class="kw-card" aria-label="Karate Wiener title card">
|
| 6432 |
+
<div class="kw-logo">
|
| 6433 |
+
<h1 class="kw-title"><span>Karate</span><span>Wiener</span></h1>
|
| 6434 |
+
</div>
|
| 6435 |
+
</section>
|
| 6436 |
+
<button class="kw-play" type="button" aria-label="Start Karate Wiener intro"></button>
|
| 6437 |
+
<div class="kw-grain" aria-hidden="true"></div>
|
| 6438 |
+
<div class="kw-scanlines" aria-hidden="true"></div>
|
| 6439 |
+
<audio class="kw-audio" preload="auto"></audio>
|
| 6440 |
+
`;
|
| 6441 |
+
document.body.appendChild(root);
|
| 6442 |
+
|
| 6443 |
+
const audio = root.querySelector('.kw-audio');
|
| 6444 |
+
const canvas = root.querySelector('.kw-blast');
|
| 6445 |
+
const ctx = canvas.getContext('2d');
|
| 6446 |
+
const mobile = window.matchMedia('(max-width: 700px), (pointer: coarse)').matches;
|
| 6447 |
+
let particles = [];
|
| 6448 |
+
let sparks = [];
|
| 6449 |
+
let raf = 0;
|
| 6450 |
+
let active = false;
|
| 6451 |
+
let starting = false;
|
| 6452 |
+
audio.src = AUDIO_SRC;
|
| 6453 |
+
|
| 6454 |
+
function resize() {{
|
| 6455 |
+
const dpr = Math.min(mobile ? 1.35 : 2, window.devicePixelRatio || 1);
|
| 6456 |
+
canvas.width = Math.floor(window.innerWidth * dpr);
|
| 6457 |
+
canvas.height = Math.floor(window.innerHeight * dpr);
|
| 6458 |
+
canvas.style.width = `${{window.innerWidth}}px`;
|
| 6459 |
+
canvas.style.height = `${{window.innerHeight}}px`;
|
| 6460 |
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
| 6461 |
+
}}
|
| 6462 |
+
function rand(min, max) {{ return min + Math.random() * (max - min); }}
|
| 6463 |
+
function makeExplosion() {{
|
| 6464 |
+
const cx = window.innerWidth / 2;
|
| 6465 |
+
const cy = window.innerHeight * 0.45;
|
| 6466 |
+
particles = [];
|
| 6467 |
+
sparks = [];
|
| 6468 |
+
const pc = mobile ? 58 : 96;
|
| 6469 |
+
const sc = mobile ? 96 : 170;
|
| 6470 |
+
for (let i = 0; i < pc; i += 1) {{
|
| 6471 |
+
const a = rand(0, Math.PI * 2);
|
| 6472 |
+
const speed = rand(5, 24);
|
| 6473 |
+
particles.push({{
|
| 6474 |
+
x: cx + Math.cos(a) * rand(0, 56),
|
| 6475 |
+
y: cy + Math.sin(a) * rand(0, 38),
|
| 6476 |
+
vx: Math.cos(a) * speed,
|
| 6477 |
+
vy: Math.sin(a) * speed - rand(0, 5),
|
| 6478 |
+
r: rand(10, 54),
|
| 6479 |
+
life: rand(.85, 1.55),
|
| 6480 |
+
max: 1,
|
| 6481 |
+
hue: rand(22, 58),
|
| 6482 |
+
}});
|
| 6483 |
+
}}
|
| 6484 |
+
for (let i = 0; i < sc; i += 1) {{
|
| 6485 |
+
const a = rand(-Math.PI * .95, Math.PI * 1.95);
|
| 6486 |
+
const speed = rand(7, 38);
|
| 6487 |
+
sparks.push({{
|
| 6488 |
+
x: cx, y: cy,
|
| 6489 |
+
vx: Math.cos(a) * speed,
|
| 6490 |
+
vy: Math.sin(a) * speed,
|
| 6491 |
+
life: rand(.4, 1.1),
|
| 6492 |
+
len: rand(8, 30),
|
| 6493 |
+
hue: rand(35, 62),
|
| 6494 |
+
}});
|
| 6495 |
+
}}
|
| 6496 |
+
root.classList.add('kw-flash', 'kw-exploded');
|
| 6497 |
+
window.setTimeout(() => root.classList.remove('kw-flash'), 900);
|
| 6498 |
+
animateExplosion();
|
| 6499 |
+
}}
|
| 6500 |
+
function drawExplosion() {{
|
| 6501 |
+
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
|
| 6502 |
+
ctx.globalCompositeOperation = 'lighter';
|
| 6503 |
+
particles.forEach((p) => {{
|
| 6504 |
+
const alpha = Math.max(0, p.life / p.max);
|
| 6505 |
+
const grad = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.r);
|
| 6506 |
+
grad.addColorStop(0, `hsla(${{p.hue}},100%,72%,${{.8 * alpha}})`);
|
| 6507 |
+
grad.addColorStop(.38, `hsla(${{p.hue - 18}},100%,50%,${{.45 * alpha}})`);
|
| 6508 |
+
grad.addColorStop(1, 'hsla(3,94%,30%,0)');
|
| 6509 |
+
ctx.fillStyle = grad;
|
| 6510 |
+
ctx.beginPath();
|
| 6511 |
+
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
|
| 6512 |
+
ctx.fill();
|
| 6513 |
+
}});
|
| 6514 |
+
ctx.lineCap = 'round';
|
| 6515 |
+
sparks.forEach((s) => {{
|
| 6516 |
+
const alpha = Math.max(0, s.life);
|
| 6517 |
+
ctx.strokeStyle = `hsla(${{s.hue}},100%,70%,${{alpha}})`;
|
| 6518 |
+
ctx.lineWidth = 2.4 * alpha;
|
| 6519 |
+
ctx.beginPath();
|
| 6520 |
+
ctx.moveTo(s.x, s.y);
|
| 6521 |
+
ctx.lineTo(s.x - s.vx * .7, s.y - s.vy * .7 + s.len);
|
| 6522 |
+
ctx.stroke();
|
| 6523 |
+
}});
|
| 6524 |
+
ctx.globalCompositeOperation = 'source-over';
|
| 6525 |
+
}}
|
| 6526 |
+
function animateExplosion() {{
|
| 6527 |
+
window.cancelAnimationFrame(raf);
|
| 6528 |
+
let last = performance.now();
|
| 6529 |
+
function tick(now) {{
|
| 6530 |
+
const dt = Math.min(.033, (now - last) / 1000);
|
| 6531 |
+
last = now;
|
| 6532 |
+
particles.forEach((p) => {{
|
| 6533 |
+
p.x += p.vx; p.y += p.vy;
|
| 6534 |
+
p.vx *= .964; p.vy = p.vy * .96 + .22;
|
| 6535 |
+
p.r *= 1.012; p.life -= dt;
|
| 6536 |
+
}});
|
| 6537 |
+
sparks.forEach((s) => {{
|
| 6538 |
+
s.x += s.vx; s.y += s.vy;
|
| 6539 |
+
s.vx *= .982; s.vy = s.vy * .98 + .5;
|
| 6540 |
+
s.life -= dt * 1.18;
|
| 6541 |
+
}});
|
| 6542 |
+
particles = particles.filter((p) => p.life > 0);
|
| 6543 |
+
sparks = sparks.filter((s) => s.life > 0);
|
| 6544 |
+
drawExplosion();
|
| 6545 |
+
if (particles.length || sparks.length) raf = window.requestAnimationFrame(tick);
|
| 6546 |
+
else ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
|
| 6547 |
+
}}
|
| 6548 |
+
raf = window.requestAnimationFrame(tick);
|
| 6549 |
+
}}
|
| 6550 |
+
async function run() {{
|
| 6551 |
+
if (active) return;
|
| 6552 |
+
active = true;
|
| 6553 |
+
root.classList.remove('kw-ready', 'kw-pressed', 'kw-exploded', 'kw-flash', 'kw-vanish', 'kw-filters-out', 'kw-done');
|
| 6554 |
+
void root.offsetWidth;
|
| 6555 |
+
root.classList.add('kw-running');
|
| 6556 |
+
window.setTimeout(async () => {{
|
| 6557 |
+
makeExplosion();
|
| 6558 |
+
try {{
|
| 6559 |
+
audio.muted = false;
|
| 6560 |
+
audio.volume = 1;
|
| 6561 |
+
audio.currentTime = 0;
|
| 6562 |
+
await audio.play();
|
| 6563 |
+
}} catch (error) {{
|
| 6564 |
+
console.warn('Karate Wiener audio blocked:', error);
|
| 6565 |
+
}}
|
| 6566 |
+
}}, 950);
|
| 6567 |
+
window.setTimeout(() => root.classList.add('kw-vanish'), 3450);
|
| 6568 |
+
window.setTimeout(() => root.classList.add('kw-filters-out'), 3950);
|
| 6569 |
+
window.setTimeout(() => {{
|
| 6570 |
+
root.classList.add('kw-done');
|
| 6571 |
+
root.remove();
|
| 6572 |
+
}}, 5600);
|
| 6573 |
+
}}
|
| 6574 |
+
resize();
|
| 6575 |
+
window.addEventListener('resize', resize, {{ passive: true }});
|
| 6576 |
+
root.addEventListener('click', async (event) => {{
|
| 6577 |
+
if (!root.classList.contains('kw-ready') || starting) return;
|
| 6578 |
+
starting = true;
|
| 6579 |
+
event.preventDefault();
|
| 6580 |
+
root.classList.add('kw-pressed');
|
| 6581 |
+
window.setTimeout(run, 180);
|
| 6582 |
+
}});
|
| 6583 |
+
if (mobile) {{
|
| 6584 |
+
root.classList.add('kw-ready');
|
| 6585 |
+
}} else {{
|
| 6586 |
+
window.setTimeout(run, 350);
|
| 6587 |
+
}}
|
| 6588 |
+
}}
|
| 6589 |
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', install);
|
| 6590 |
+
else install();
|
| 6591 |
+
}})();
|
| 6592 |
+
"""
|
| 6593 |
+
|
| 6594 |
+
APP_HEAD = (
|
| 6595 |
# Warm the CDNs the viewer iframe pulls three.js (+ lazy spark) from. (head= is
|
| 6596 |
# injected at hydration, so this is a best-effort warm-up; the boot splash that
|
| 6597 |
# hides the pre-hydration flash lives in the SSR'd css= block instead — see
|
|
|
|
| 6599 |
'<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin>'
|
| 6600 |
'<link rel="dns-prefetch" href="https://cdn.jsdelivr.net">'
|
| 6601 |
'<link rel="preconnect" href="https://unpkg.com" crossorigin>'
|
| 6602 |
+
'<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>'
|
| 6603 |
+
# APP_CSS + any pluggable-tab styles (tabs/<name>.tab.css), then the drawer JS.
|
| 6604 |
+
f"<style>{APP_CSS}{_read_tabs('*.tab.css')}{TITLE_OVERLAY_CSS}</style>"
|
| 6605 |
+
f"<script>{DRAWER_JS}</script><script>{TITLE_OVERLAY_JS}</script>"
|
| 6606 |
+
)
|
| 6607 |
|
| 6608 |
|
| 6609 |
def generate(
|
assets/karate_wiener_title_overlay.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:dcd9c57314a80c1e1ee4f95f95823a7171abdcac03508e96edfc4d765d474046
|
| 3 |
+
size 783404
|
deploy_out2.txt
CHANGED
|
@@ -802,3 +802,7 @@ variables + HF_TOKEN secret set
|
|
| 802 |
|
| 803 |
...ace\comic_koma_sample.png: 100%|##########| 365kB / 365kB
|
| 804 |
|
| 805 |
...raw_lora-minimal_1234.png: 100%|##########| 490kB / 490kB
|
| 806 |
|
| 807 |
[+ 167 files] : 100%|##########| 285MB / 285MB
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 802 |
|
| 803 |
...ace\comic_koma_sample.png: 100%|##########| 365kB / 365kB
|
| 804 |
|
| 805 |
...raw_lora-minimal_1234.png: 100%|##########| 490kB / 490kB
|
| 806 |
|
| 807 |
[+ 167 files] : 100%|##########| 285MB / 285MB
|
| 808 |
+
No files have been modified since last commit. Skipping to prevent empty commit.
|
| 809 |
+
Uploaded: https://huggingface.co/spaces/build-small-hackathon/karate-wiener/commit/be2c1ca83c0c7fd01bc453c629c1bface7121a4f
|
| 810 |
+
Space URL: https://huggingface.co/spaces/build-small-hackathon/karate-wiener
|
| 811 |
+
restarting local gradio -> http://127.0.0.1:7860 (log: C:\Users\paulg\AppData\Local\Temp\kimodo_local_gradio.log)
|
deploy_space.py
CHANGED
|
@@ -43,6 +43,21 @@ def main() -> None:
|
|
| 43 |
".kimodo-animations/**",
|
| 44 |
# Local headless probes / checks (never part of the Space).
|
| 45 |
"_*.py",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
],
|
| 47 |
)
|
| 48 |
runtime = api.request_space_hardware(repo_id=args.repo_id, hardware=SpaceHardware.ZERO_A10G)
|
|
|
|
| 43 |
".kimodo-animations/**",
|
| 44 |
# Local headless probes / checks (never part of the Space).
|
| 45 |
"_*.py",
|
| 46 |
+
# Experiment line + LAN-only lab/prototype servers (never deployed).
|
| 47 |
+
"experiments/**",
|
| 48 |
+
"kimodo_lab.py",
|
| 49 |
+
"flux_lab.py",
|
| 50 |
+
"wiener_dojo.py",
|
| 51 |
+
"wiener_dojo_web.py",
|
| 52 |
+
".comic-cache/**",
|
| 53 |
+
"comic_klein_out/**",
|
| 54 |
+
"weiner_dataset_raw/**",
|
| 55 |
+
"weiner_lora_train/**",
|
| 56 |
+
"weiner_lora_train.zip",
|
| 57 |
+
"*.task",
|
| 58 |
+
"*.obj",
|
| 59 |
+
"dojo_*",
|
| 60 |
+
".gitignore",
|
| 61 |
],
|
| 62 |
)
|
| 63 |
runtime = api.request_space_hardware(repo_id=args.repo_id, hardware=SpaceHardware.ZERO_A10G)
|