Compare commits
8 Commits
e55bc810e6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65a19d7678 | ||
|
|
2f2ec31466 | ||
|
|
c1d278b6e5 | ||
| 5786bcdcf6 | |||
|
|
0291bd26b9 | ||
|
|
64b1c8d703 | ||
|
|
8ebe0632bc | ||
|
|
342504f481 |
178
border-beam.css
Normal file
178
border-beam.css
Normal file
@@ -0,0 +1,178 @@
|
||||
|
||||
@property --beam-angle-bb {
|
||||
syntax: "<angle>";
|
||||
initial-value: 0deg;
|
||||
inherits: true;
|
||||
}
|
||||
|
||||
@property --beam-opacity-bb {
|
||||
syntax: "<number>";
|
||||
initial-value: 0;
|
||||
inherits: true;
|
||||
}
|
||||
|
||||
[data-beam="bb"] {
|
||||
position: relative;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
[data-beam="bb"][data-active] {
|
||||
animation:
|
||||
beam-spin-bb 1.96s linear infinite,
|
||||
beam-fade-in-bb 0.6s ease forwards;
|
||||
}
|
||||
|
||||
[data-beam="bb"][data-active]::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 23px;
|
||||
padding: 1px;
|
||||
clip-path: inset(0 round 24px);
|
||||
background: conic-gradient(
|
||||
from var(--beam-angle-bb),
|
||||
transparent 0%, transparent 54%,
|
||||
rgba(255, 255, 255, 0.1) 57%,
|
||||
rgba(255, 255, 255, 0.3) 60%,
|
||||
rgba(255, 255, 255, 0.6) 63%,
|
||||
rgba(255, 255, 255, 0.75) 66%,
|
||||
rgba(255, 255, 255, 0.6) 69%,
|
||||
rgba(255, 255, 255, 0.3) 72%,
|
||||
rgba(255, 255, 255, 0.1) 75%,
|
||||
transparent 78%, transparent 100%
|
||||
),radial-gradient(ellipse 70px 40px at 33% -7.4%, rgb(255, 50, 100), transparent),
|
||||
radial-gradient(ellipse 60px 35px at 12% -5%, rgb(40, 140, 255), transparent),
|
||||
radial-gradient(ellipse 40px 70px at 2.1% 68.3%, rgb(50, 200, 80), transparent),
|
||||
radial-gradient(ellipse 20px 35px at 2.1% 68.3%, rgb(30, 185, 170), transparent),
|
||||
radial-gradient(ellipse 180px 32px at 74.4% 100%, rgb(100, 70, 255), transparent),
|
||||
radial-gradient(ellipse 85px 26px at 55% 100%, rgb(40, 140, 255), transparent),
|
||||
radial-gradient(ellipse 74px 32px at 93.9% 0%, rgb(255, 120, 40), transparent),
|
||||
radial-gradient(ellipse 26px 42px at 100% 27.1%, rgb(240, 50, 180), transparent),
|
||||
radial-gradient(ellipse 52px 48px at 100% 27.1%, rgb(180, 40, 240), transparent);
|
||||
-webkit-mask:
|
||||
conic-gradient(
|
||||
from var(--beam-angle-bb),
|
||||
transparent 0%, transparent 30%,
|
||||
rgba(255, 255, 255, 0.1) 36%, rgba(255, 255, 255, 0.35) 44%,
|
||||
white 52%, white 80%,
|
||||
rgba(255, 255, 255, 0.35) 86%, rgba(255, 255, 255, 0.1) 92%,
|
||||
transparent 95%, transparent 100%
|
||||
),
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: source-in, xor;
|
||||
mask:
|
||||
conic-gradient(
|
||||
from var(--beam-angle-bb),
|
||||
transparent 0%, transparent 30%,
|
||||
rgba(255, 255, 255, 0.1) 36%, rgba(255, 255, 255, 0.35) 44%,
|
||||
white 52%, white 80%,
|
||||
rgba(255, 255, 255, 0.35) 86%, rgba(255, 255, 255, 0.1) 92%,
|
||||
transparent 95%, transparent 100%
|
||||
),
|
||||
linear-gradient(#fff 0 0) content-box,
|
||||
linear-gradient(#fff 0 0);
|
||||
mask-composite: intersect, exclude;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
opacity: calc(var(--beam-opacity-bb) * 0.26 * var(--beam-stroke-opacity, 1) * var(--beam-strength, 1));
|
||||
animation: beam-hue-shift-bb 12s ease-in-out infinite;
|
||||
}
|
||||
|
||||
[data-beam="bb"][data-active]::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 24px;
|
||||
background: radial-gradient(ellipse 63px 36px at 33% -7.4%, rgba(255, 50, 100, 0.45), transparent),
|
||||
radial-gradient(ellipse 54px 32px at 12% -5%, rgba(40, 140, 255, 0.45), transparent),
|
||||
radial-gradient(ellipse 36px 63px at 2.1% 68.3%, rgba(50, 200, 80, 0.45), transparent),
|
||||
radial-gradient(ellipse 18px 32px at 2.1% 68.3%, rgba(30, 185, 170, 0.45), transparent),
|
||||
radial-gradient(ellipse 162px 29px at 74.4% 100%, rgba(100, 70, 255, 0.45), transparent),
|
||||
radial-gradient(ellipse 77px 23px at 55% 100%, rgba(40, 140, 255, 0.45), transparent),
|
||||
radial-gradient(ellipse 67px 29px at 93.9% 0%, rgba(255, 120, 40, 0.45), transparent),
|
||||
radial-gradient(ellipse 23px 38px at 100% 27.1%, rgba(240, 50, 180, 0.45), transparent),
|
||||
radial-gradient(ellipse 47px 43px at 100% 27.1%, rgba(180, 40, 240, 0.45), transparent);
|
||||
box-shadow: inset 0 0 9px 1px rgba(255, 255, 255, 0.27);
|
||||
-webkit-mask-image:
|
||||
conic-gradient(
|
||||
from var(--beam-angle-bb),
|
||||
transparent 0%, transparent 30%,
|
||||
rgba(255, 255, 255, 0.1) 36%, rgba(255, 255, 255, 0.35) 44%,
|
||||
white 52%, white 80%,
|
||||
rgba(255, 255, 255, 0.35) 86%, rgba(255, 255, 255, 0.1) 92%,
|
||||
transparent 95%, transparent 100%
|
||||
),
|
||||
linear-gradient(white, transparent 28px, transparent calc(100% - 28px), white),
|
||||
linear-gradient(to right, white, transparent 28px, transparent calc(100% - 28px), white);
|
||||
-webkit-mask-composite: source-in, source-over;
|
||||
mask-image:
|
||||
conic-gradient(
|
||||
from var(--beam-angle-bb),
|
||||
transparent 0%, transparent 30%,
|
||||
rgba(255, 255, 255, 0.1) 36%, rgba(255, 255, 255, 0.35) 44%,
|
||||
white 52%, white 80%,
|
||||
rgba(255, 255, 255, 0.35) 86%, rgba(255, 255, 255, 0.1) 92%,
|
||||
transparent 95%, transparent 100%
|
||||
),
|
||||
linear-gradient(white, transparent 28px, transparent calc(100% - 28px), white),
|
||||
linear-gradient(to right, white, transparent 28px, transparent calc(100% - 28px), white);
|
||||
mask-composite: intersect, add;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
opacity: calc(var(--beam-opacity-bb) * 0.42 * var(--beam-inner-opacity, 1) * var(--beam-strength, 1));
|
||||
clip-path: inset(0 round 24px);
|
||||
animation: beam-hue-shift-bb 12s ease-in-out infinite;
|
||||
}
|
||||
|
||||
[data-beam="bb"] [data-beam-bloom] {
|
||||
display: none;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 23px;
|
||||
clip-path: inset(0 round 24px);
|
||||
background: conic-gradient(
|
||||
from var(--beam-angle-bb),
|
||||
transparent 0%, transparent 58%,
|
||||
rgba(255, 255, 255, 0.03) 62%,
|
||||
rgba(255, 255, 255, 0.08) 65%,
|
||||
rgba(255, 255, 255, 0.2) 67%,
|
||||
rgba(255, 255, 255, 0.45) 69%,
|
||||
rgba(255, 255, 255, 0.85) 70%,
|
||||
rgba(255, 255, 255, 0.85) 70.5%,
|
||||
rgba(255, 255, 255, 0.45) 71.5%,
|
||||
rgba(255, 255, 255, 0.2) 73%,
|
||||
rgba(255, 255, 255, 0.08) 75%,
|
||||
rgba(255, 255, 255, 0.03) 78%,
|
||||
transparent 82%
|
||||
);
|
||||
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
-webkit-mask-composite: xor;
|
||||
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
||||
mask-composite: exclude;
|
||||
padding: 1px;
|
||||
filter: blur(8px) brightness(1.30) saturate(1.20);
|
||||
pointer-events: none;
|
||||
z-index: 3;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
[data-beam="bb"][data-active] [data-beam-bloom] {
|
||||
display: block;
|
||||
opacity: calc(var(--beam-opacity-bb) * 0.24 * var(--beam-bloom-opacity, 1) * var(--beam-strength, 1));
|
||||
}
|
||||
|
||||
@keyframes beam-spin-bb {
|
||||
to { --beam-angle-bb: 360deg; }
|
||||
}
|
||||
|
||||
@keyframes beam-fade-in-bb {
|
||||
to { --beam-opacity-bb: 1; }
|
||||
}
|
||||
|
||||
@keyframes beam-hue-shift-bb {
|
||||
0% { filter: hue-rotate(calc(var(--beam-hue-base, 0deg) - 30deg)) brightness(1.30) saturate(1.20); }
|
||||
50% { filter: hue-rotate(calc(var(--beam-hue-base, 0deg) + 30deg)) brightness(1.30) saturate(1.20); }
|
||||
100% { filter: hue-rotate(calc(var(--beam-hue-base, 0deg) - 30deg)) brightness(1.30) saturate(1.20); }
|
||||
}
|
||||
BIN
expo-qr.png
Normal file
BIN
expo-qr.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -5,6 +5,22 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#0a0a0a">
|
||||
<title>BrandLoop – Prototyp</title>
|
||||
<link rel="stylesheet" href="border-beam.css">
|
||||
<script type="module">import('https://esm.sh/@paper-design/shaders').then(function(m){window.__paperShaders=m;var u={u_repetition:4,u_softness:.5,u_shiftRed:.3,u_shiftBlue:.3,u_distortion:0,u_contour:0,u_angle:45,u_scale:8,u_shape:0,u_offsetX:.1,u_offsetY:-.1};setInterval(function(){document.querySelectorAll('.lm-shader:not([data-lm])').forEach(function(el){el.dataset.lm='1';try{new m.ShaderMount(el,m.liquidMetalFragmentShader,u,undefined,0.6)}catch(e){}})},500)}).catch(function(){})</script>
|
||||
<style>
|
||||
/* Liquid-Metal-Buttons (aus BrandLoop.dc.html): Shader-Canvas ueber
|
||||
Metall-Gradient (Fallback ohne WebGL/offline), schwarzer Kern, graues Icon */
|
||||
.lm-shader canvas{width:100%!important;height:100%!important;display:block!important;position:absolute!important;top:0!important;left:0!important;border-radius:100px!important;}
|
||||
.lm-bg{position:absolute; inset:0; border-radius:100px; overflow:hidden;
|
||||
background:linear-gradient(135deg,#e8e8e8,#6f6f6f 35%,#f2f2f2 50%,#5c5c5c 68%,#cfcfcf);}
|
||||
.lm-bg.deg120{background:linear-gradient(120deg,#e8e8e8,#6f6f6f 35%,#f2f2f2 50%,#5c5c5c 68%,#cfcfcf);}
|
||||
.lm-core{position:absolute; inset:2px; border-radius:100px; background:linear-gradient(180deg,#202020,#000);}
|
||||
.lm-ic{position:absolute; inset:0; display:grid; place-items:center;}
|
||||
.lm-btn{position:relative; height:52px; border-radius:100px; cursor:pointer;
|
||||
box-shadow:0 2px 5px rgba(0,0,0,.35), 0 9px 9px rgba(0,0,0,.12);}
|
||||
.lm-label{position:absolute; inset:0; display:flex; align-items:center; justify-content:center; gap:8px;
|
||||
font-size:14.5px; font-weight:700; color:#9a9a9a; text-shadow:0 1px 2px rgba(0,0,0,.5);}
|
||||
</style>
|
||||
<style>
|
||||
:root{
|
||||
--bg:#0a0a0a;
|
||||
@@ -23,6 +39,10 @@
|
||||
}
|
||||
*{box-sizing:border-box; margin:0; padding:0;}
|
||||
html{-webkit-text-size-adjust:100%;}
|
||||
html, body{overscroll-behavior-y:none;}
|
||||
/* Explore ist ein fixer Vollbild-Screen: Seite darf nicht scrollen/wippen */
|
||||
body.noscroll{overflow:hidden; height:100dvh;}
|
||||
body.noscroll .app{padding-bottom:0;}
|
||||
body{
|
||||
background:var(--bg); color:var(--txt);
|
||||
font-family:-apple-system,BlinkMacSystemFont,"Helvetica Neue","Inter",Roboto,system-ui,sans-serif;
|
||||
@@ -178,7 +198,8 @@
|
||||
#explore{padding:0; --xs:max(env(safe-area-inset-top, 0px), 64px);}
|
||||
#explore.active{display:flex; flex-direction:column; height:100dvh; overflow:hidden;}
|
||||
.x-blur{position:absolute; inset:-50px; pointer-events:none; z-index:0;
|
||||
filter:blur(36px) brightness(.78) saturate(1.15); transform:scale(1.08); transition:background .3s;}
|
||||
filter:blur(36px) brightness(.78) saturate(1.15); transform:scale(1.08);
|
||||
transition:background .7s ease, opacity .25s ease;}
|
||||
.x-hood{position:absolute; inset:0; pointer-events:none; z-index:2;}
|
||||
.x-hood svg{position:absolute; top:calc(var(--xs) - 14px); left:0; display:block; width:100%; height:120px;}
|
||||
.x-hood .solid{position:absolute; top:calc(var(--xs) + 105px); left:0; right:0; bottom:0; background:var(--bg);}
|
||||
@@ -216,16 +237,45 @@
|
||||
.x-empty{position:absolute; inset:0; border-radius:26px; background:#141414; border:1px dashed rgba(255,255,255,.15);
|
||||
display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px;}
|
||||
.x-actions{position:relative; z-index:3; display:flex; justify-content:center; align-items:center; gap:22px;
|
||||
padding:6px 0 calc(96px + env(safe-area-inset-bottom));}
|
||||
padding:6px 0 84px;}
|
||||
.x-act{width:56px; height:56px; border-radius:100px; background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.12);
|
||||
display:grid; place-items:center; cursor:pointer; font-size:20px; color:rgba(255,255,255,.8); transition:transform .12s;}
|
||||
.x-act:active{transform:scale(.92);}
|
||||
.x-act.sm{width:44px; height:44px;}
|
||||
.x-act.like{background:var(--accent); border:none; box-shadow:0 0 22px rgba(255,92,57,.27);}
|
||||
.x-act.like{position:relative; background:none; border:none;
|
||||
box-shadow:0 2px 5px rgba(0,0,0,.4), 0 9px 9px rgba(0,0,0,.15);}
|
||||
|
||||
/* ================= DETAIL & CREATE ================= */
|
||||
#detail.active, #create.active{min-height:100dvh;
|
||||
background:radial-gradient(125% 125% at 50% 150%, rgba(241,99,99,.21) 40%, transparent 100%);}
|
||||
/* Create = fixer Vollbild-Screen mit internem Scroll + Fake-Tastatur */
|
||||
#create.active{display:flex; flex-direction:column; height:100dvh; overflow:hidden; position:relative;}
|
||||
.c-scroll{flex:1; overflow-y:auto; min-height:0; margin:0 -20px; padding:8px 18px 110px; scrollbar-width:none;
|
||||
transition:padding-bottom .3s ease;}
|
||||
.c-scroll::-webkit-scrollbar{display:none;}
|
||||
.c-scroll.kb-open{padding-bottom:380px;}
|
||||
.c-optlabel{font-size:11px; font-weight:700; letter-spacing:.12em; color:rgba(255,255,255,.4); margin-bottom:9px;}
|
||||
/* Dithering-Shader-Chips (Testeffekt auf den Modell-Chips) */
|
||||
.chip.dither{position:relative; overflow:hidden; background:#000; color:#fff;
|
||||
border:1px solid rgba(255,255,255,.14);}
|
||||
.chip.dither.on{background:#000; color:#fff; border-color:rgba(255,255,255,.55);}
|
||||
.chip.dither canvas{position:absolute; inset:0; width:100%; height:100%;}
|
||||
.chip.dither > *:not(canvas){position:relative; z-index:1;}
|
||||
.chip.dither span{text-shadow:0 1px 2px rgba(0,0,0,.7);}
|
||||
.c-behind{position:absolute; top:0; left:50%; border-radius:22px; background:#1b1b1b;
|
||||
border:1px solid rgba(255,255,255,.09); transform-origin:top center; z-index:0;}
|
||||
.c-preview{position:relative; border-radius:22px; overflow:hidden; z-index:1;
|
||||
box-shadow:0 18px 44px rgba(0,0,0,.5); transition:width .25s ease, height .25s ease;}
|
||||
.kb{position:fixed; left:0; right:0; bottom:0; z-index:45; max-width:430px; margin:0 auto;
|
||||
transform:translateY(112%); transition:transform .34s cubic-bezier(.22,1,.36,1);}
|
||||
.kb.open{transform:none;}
|
||||
.kb-row{display:flex; gap:5px; margin-bottom:8px;}
|
||||
.kb-key{flex:1; height:38px; border-radius:6px; background:rgba(255,255,255,.16); display:grid; place-items:center;
|
||||
font-size:16px; font-weight:500; color:#fff; cursor:pointer; user-select:none; -webkit-user-select:none; min-width:0;}
|
||||
.kb-key.mod{background:rgba(255,255,255,.28); font-size:15px;}
|
||||
.kb-chip{flex:none; display:flex; align-items:center; gap:7px; padding:8px 13px; border-radius:100px;
|
||||
background:rgba(255,255,255,.12); font-size:12.5px; font-weight:600; cursor:pointer; white-space:nowrap; color:#fff;}
|
||||
.kb-chip .dot{width:8px; height:8px; border-radius:100px; flex:none;}
|
||||
.d-strip{display:flex; gap:10px; overflow-x:auto; margin:0 -18px; padding:0 18px; scrollbar-width:none; scroll-snap-type:x mandatory;}
|
||||
.d-strip::-webkit-scrollbar{display:none;}
|
||||
.d-img{flex:none; width:272px; height:330px; border-radius:20px; position:relative; display:grid; place-items:center; scroll-snap-align:center;}
|
||||
@@ -251,30 +301,28 @@
|
||||
.p-hero p{color:var(--mut); font-size:13px; margin-top:3px;}
|
||||
|
||||
/* ================= Bottom-Navigation ================= */
|
||||
/* Liquid-Glass-Nav (aus BrandLoop.dc.html): Turbulenz-Filter als backdrop,
|
||||
blur(20px) als Fallback falls der Browser url()-backdrop-filter nicht kann */
|
||||
/* Liquid-Glass-Nav (aus BrandLoop.dc.html): echte Refraktion via dynamischer
|
||||
Displacement-Map (bl-glass-refract, RGB-Split) + Blur/Saturate-Backdrop +
|
||||
Weiss-Layer + Kanten-Ring. bottom:14px = exakt die Hoehe aus dem Design. */
|
||||
.nav{position:fixed; bottom:14px; left:50%; transform:translateX(-50%); z-index:30;
|
||||
display:flex; align-items:center; gap:6px; padding:8px 10px; border-radius:100px;
|
||||
margin-bottom:env(safe-area-inset-bottom);}
|
||||
.nav::before{content:''; position:absolute; inset:0; z-index:-1; border-radius:100px;
|
||||
background:rgba(10,10,10,.18);
|
||||
-webkit-backdrop-filter:blur(20px); backdrop-filter:blur(20px);
|
||||
-webkit-backdrop-filter:url(#bl-liquid-glass); backdrop-filter:url(#bl-liquid-glass);}
|
||||
.nav::after{content:''; position:absolute; inset:0; z-index:2; border-radius:100px; pointer-events:none;
|
||||
box-shadow:0 0 8px rgba(0,0,0,.03), 0 2px 6px rgba(0,0,0,.08),
|
||||
inset 3px 3px .5px -3.5px rgba(255,255,255,.09), inset -3px -3px .5px -3.5px rgba(255,255,255,.85),
|
||||
inset 1px 1px 1px -.5px rgba(255,255,255,.6), inset -1px -1px 1px -.5px rgba(255,255,255,.6),
|
||||
inset 0 0 6px 6px rgba(255,255,255,.12), inset 0 0 2px 2px rgba(255,255,255,.06),
|
||||
0 0 12px rgba(0,0,0,.15);}
|
||||
.nav button{display:flex; align-items:center; gap:8px; background:none; border:none; font-family:inherit;
|
||||
box-shadow:0 6px 6px rgba(0,0,0,.2), 0 0 20px rgba(0,0,0,.1);
|
||||
transition:all .7s cubic-bezier(.175,.885,.32,2.2);}
|
||||
.nav-glass{position:absolute; inset:0; border-radius:100px;}
|
||||
.nav-glass.blur{overflow:hidden; -webkit-backdrop-filter:blur(3px) saturate(1.15); backdrop-filter:blur(3px) saturate(1.15);}
|
||||
.nav-glass.refract{overflow:hidden; -webkit-backdrop-filter:url(#bl-glass-refract); backdrop-filter:url(#bl-glass-refract);}
|
||||
.nav-glass.white{background:rgba(255,255,255,.12); z-index:1;}
|
||||
.nav-glass.ring{z-index:2; pointer-events:none;
|
||||
box-shadow:inset 2px 2px 1px 0 rgba(255,255,255,.4), inset -1px -1px 1px 1px rgba(255,255,255,.3);}
|
||||
.nav button{position:relative; z-index:3; display:flex; align-items:center; gap:8px; background:none; border:none; font-family:inherit;
|
||||
width:40px; height:40px; justify-content:center; border-radius:100px; color:rgba(255,255,255,.6);
|
||||
font-size:13.5px; font-weight:600; cursor:pointer; transition:background .2s, color .2s, width .2s;}
|
||||
.nav button svg{width:20px; height:20px; flex:none;}
|
||||
.nav button span{display:none;}
|
||||
.nav button.on{width:auto; padding:9px 16px 9px 12px; background:rgba(255,255,255,.14); color:#fff;}
|
||||
.nav button.on span{display:inline;}
|
||||
.nav button.plus{background:var(--accent); color:#0a0a0a;}
|
||||
.nav button.plus svg{stroke-width:2.4; width:18px; height:18px;}
|
||||
/* Plus-Button = Liquid-Metal (Shader + schwarzer Kern) */
|
||||
.nav button.plus{background:none; box-shadow:0 2px 5px rgba(0,0,0,.35);}
|
||||
.nav button.plus.on{width:40px; padding:0;}
|
||||
.nav button.plus.on span{display:none;}
|
||||
|
||||
@@ -294,17 +342,22 @@
|
||||
.sheet li::before{content:"·"; position:absolute; left:2px; color:var(--accent); font-weight:700;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body class="noscroll">
|
||||
|
||||
<!-- Lucide-Icon-Sprite + Liquid-Glass-Filter -->
|
||||
<svg width="0" height="0" style="position:absolute" aria-hidden="true">
|
||||
<defs>
|
||||
<filter id="bl-liquid-glass" x="0%" y="0%" width="100%" height="100%" color-interpolation-filters="sRGB">
|
||||
<feTurbulence type="fractalNoise" baseFrequency="0.05 0.05" numOctaves="1" seed="1" result="turbulence"/>
|
||||
<feGaussianBlur in="turbulence" stdDeviation="2" result="blurredNoise"/>
|
||||
<feDisplacementMap in="SourceGraphic" in2="blurredNoise" scale="70" xChannelSelector="R" yChannelSelector="B" result="displaced"/>
|
||||
<feGaussianBlur in="displaced" stdDeviation="4" result="finalBlur"/>
|
||||
<feComposite in="finalBlur" in2="finalBlur" operator="over"/>
|
||||
<filter id="bl-glass-refract" color-interpolation-filters="sRGB" x="0%" y="0%" width="100%" height="100%">
|
||||
<feImage id="glassMapImage" x="0" y="0" width="100%" height="100%" preserveAspectRatio="none" href="" result="map"/>
|
||||
<feDisplacementMap in="SourceGraphic" in2="map" scale="-180" xChannelSelector="R" yChannelSelector="G" result="dispRed"/>
|
||||
<feColorMatrix in="dispRed" type="matrix" values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" result="red"/>
|
||||
<feDisplacementMap in="SourceGraphic" in2="map" scale="-170" xChannelSelector="R" yChannelSelector="G" result="dispGreen"/>
|
||||
<feColorMatrix in="dispGreen" type="matrix" values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="green"/>
|
||||
<feDisplacementMap in="SourceGraphic" in2="map" scale="-160" xChannelSelector="R" yChannelSelector="G" result="dispBlue"/>
|
||||
<feColorMatrix in="dispBlue" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" result="blue"/>
|
||||
<feBlend in="red" in2="green" mode="screen" result="rg"/>
|
||||
<feBlend in="rg" in2="blue" mode="screen" result="out"/>
|
||||
<feGaussianBlur in="out" stdDeviation="0.7"/>
|
||||
</filter>
|
||||
<symbol id="i-back" viewBox="0 0 24 24"><path d="m15 18-6-6 6-6"/></symbol>
|
||||
<symbol id="i-chev" viewBox="0 0 24 24"><path d="m9 18 6-6-6-6"/></symbol>
|
||||
@@ -349,7 +402,11 @@
|
||||
<div class="x-actions">
|
||||
<div class="x-act" id="btnSkip" role="button" aria-label="Skip">✕</div>
|
||||
<div class="x-act sm" id="btnDetail" role="button" aria-label="Details / Nachmachen"><svg class="ic" style="width:18px;height:18px;color:rgba(255,255,255,.8)"><use href="#i-refresh"/></svg></div>
|
||||
<div class="x-act like" id="btnLike" role="button" aria-label="Like"><svg width="24" height="24" viewBox="0 0 24 24" fill="#0a0a0a"><path d="M12 21 C5 15.5 2.5 12 2.5 8.5 A4.7 4.7 0 0 1 12 6.2 A4.7 4.7 0 0 1 21.5 8.5 C21.5 12 19 15.5 12 21 Z"/></svg></div>
|
||||
<div class="x-act like" id="btnLike" role="button" aria-label="Like">
|
||||
<div class="lm-shader lm-bg"></div>
|
||||
<div class="lm-core"></div>
|
||||
<div class="lm-ic"><svg width="24" height="24" viewBox="0 0 24 24" fill="#9a9a9a" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 21 C5 15.5 2.5 12 2.5 8.5 A4.7 4.7 0 0 1 12 6.2 A4.7 4.7 0 0 1 21.5 8.5 C21.5 12 19 15.5 12 21 Z"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -374,43 +431,52 @@
|
||||
</div>
|
||||
<div style="font-size:15px; font-weight:800; margin-bottom:10px;">Mit deinem Modell nachmachen</div>
|
||||
<div class="chiprow" id="detailModels"></div>
|
||||
<button class="btn" id="remakeBtn" style="margin-top:16px;"></button>
|
||||
<div class="lm-btn" id="remakeBtn" role="button" style="margin-top:16px;">
|
||||
<div class="lm-shader lm-bg deg120"></div>
|
||||
<div class="lm-core"></div>
|
||||
<div class="lm-label"><svg width="15" height="15" viewBox="0 0 24 24" fill="#9a9a9a" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 2 L14.4 9.6 L22 12 L14.4 14.4 L12 22 L9.6 14.4 L2 12 L9.6 9.6 Z"/></svg><span id="remakeLabel"></span></div>
|
||||
</div>
|
||||
<div style="text-align:center; font-size:11.5px; color:rgba(255,255,255,.4); margin-top:10px;">Prompt + Einstellungen werden übernommen, dein Modell wird eingesetzt</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ POST ERSTELLEN (neu) ============ -->
|
||||
<!-- ============ POST ERSTELLEN (neu, aus BrandLoop.dc.html v4) ============ -->
|
||||
<div class="screen" id="create">
|
||||
<div class="topbar">
|
||||
<button class="backpill" onclick="go('explore')"><span class="ar">‹</span> Zurück</button>
|
||||
<h1 style="flex:1; text-align:center; margin-right:80px;">Neuer KI-Post</h1>
|
||||
</div>
|
||||
<label style="margin:6px 0 2px;">Prompt</label>
|
||||
<textarea id="createPrompt" placeholder="Beschreibe deinen Post … z.B. Sneaker auf Betonboden, goldenes Abendlicht"></textarea>
|
||||
<label>Dein Modell</label>
|
||||
<div class="chiprow" id="createModels" style="margin-top:8px;"></div>
|
||||
<div style="display:flex; gap:24px; margin-top:18px;">
|
||||
<div style="flex:1;">
|
||||
<label style="margin-bottom:8px;">Kette</label>
|
||||
<div class="pill-row" style="margin-top:0;" id="countRow">
|
||||
<div class="pill" data-count="1">1 Bild</div>
|
||||
<div class="pill on" data-count="3">3er</div>
|
||||
<div class="pill" data-count="5">5er</div>
|
||||
<div class="c-scroll" id="cScroll">
|
||||
<div style="display:flex; flex-direction:column; align-items:center; padding:10px 0 4px;">
|
||||
<div id="cStack" onclick="toggleOpts()" style="position:relative; cursor:pointer;"></div>
|
||||
<div onclick="toggleOpts()" style="display:flex; align-items:center; gap:8px; margin-top:14px; padding:9px 10px 9px 16px; border-radius:100px; background:rgba(255,255,255,.08); cursor:pointer;">
|
||||
<span style="font-size:13px; font-weight:600;" id="cSelLabel"></span>
|
||||
<svg id="cChevron" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,.6)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transition:transform .2s;"><path d="M6 9 l6 6 l6 -6"/></svg>
|
||||
</div>
|
||||
<div id="cOpts" style="display:none; width:100%; margin-top:14px; border-radius:20px; background:#161616; border:1px solid rgba(255,255,255,.09); padding:16px; box-sizing:border-box;">
|
||||
<div class="c-optlabel">TYP</div>
|
||||
<div class="pill-row" style="margin:0 0 16px;" id="typeRow"></div>
|
||||
<div class="c-optlabel">FORMAT</div>
|
||||
<div class="pill-row" style="margin:0 0 16px;" id="formatRow"></div>
|
||||
<div class="c-optlabel">KETTE</div>
|
||||
<div class="pill-row" style="margin:0;" id="countRow"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex:1;">
|
||||
<label style="margin-bottom:8px;">Format</label>
|
||||
<div class="pill-row" style="margin-top:0;" id="formatRow">
|
||||
<div class="pill" data-format="1:1">1:1</div>
|
||||
<div class="pill on" data-format="4:5">4:5</div>
|
||||
<div class="pill" data-format="9:16">9:16</div>
|
||||
<label style="margin:22px 0 8px;">Dein Modell</label>
|
||||
<div class="chiprow" id="createModels"></div>
|
||||
<label style="margin:20px 0 8px;">Prompt</label>
|
||||
<div data-beam="bb" data-active="true" style="border-radius:24px;">
|
||||
<div style="border-radius:24px; background:#171717; border:1px solid rgba(255,255,255,.05); box-shadow:0 12px 34px rgba(0,0,0,.4);">
|
||||
<textarea id="createPrompt" inputmode="none" placeholder="Beschreibe deinen Post … z.B. Sneaker auf Betonboden, goldenes Abendlicht" style="display:block; width:100%; box-sizing:border-box; height:104px; resize:none; border:none; border-radius:23px; background:transparent; color:#fff; font-size:13.5px; line-height:1.55; padding:16px 18px; outline:none;"></textarea>
|
||||
</div>
|
||||
<div data-beam-bloom="true"></div>
|
||||
</div>
|
||||
<div class="lm-btn" id="generateBtn" role="button" style="margin-top:22px;">
|
||||
<div class="lm-shader lm-bg deg120"></div>
|
||||
<div class="lm-core"></div>
|
||||
<div class="lm-label"><svg width="15" height="15" viewBox="0 0 24 24" fill="#9a9a9a" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 2 L14.4 9.6 L22 12 L14.4 14.4 L12 22 L9.6 14.4 L2 12 L9.6 9.6 Z"/></svg><span id="generateLabel">Post generieren</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<label style="margin:20px 0 8px;">Vorschau der Kette</label>
|
||||
<div class="frames" id="previewFrames"></div>
|
||||
<button class="btn" id="generateBtn" style="margin-top:22px;">Post generieren</button>
|
||||
|
||||
<h3 style="margin-top:28px;">Mehr erstellen</h3>
|
||||
<h3 style="margin-top:28px;">Mehr erstellen</h3>
|
||||
<div class="card click" onclick="go('tut1')">
|
||||
<div class="cardrow">
|
||||
<div class="ico rose"><svg class="ic"><use href="#i-film"/></svg></div>
|
||||
@@ -425,6 +491,16 @@
|
||||
<svg class="ic chev"><use href="#i-chev"/></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /c-scroll -->
|
||||
|
||||
<!-- Fake-Tastatur (Prototyp): erscheint beim Fokus aufs Prompt-Feld -->
|
||||
<div class="kb" id="kbOverlay">
|
||||
<div style="display:flex; align-items:center; gap:8px; padding:10px 12px; background:rgba(24,24,24,.96); border-top:1px solid rgba(255,255,255,.08);">
|
||||
<div style="display:flex; gap:8px; overflow-x:auto; flex:1; scrollbar-width:none;" id="kbModels"></div>
|
||||
<div id="kbDone" style="flex:none; padding:8px 14px; border-radius:100px; background:rgba(255,255,255,.14); font-size:12px; font-weight:700; cursor:pointer;">Fertig</div>
|
||||
</div>
|
||||
<div style="padding:8px 4px 24px; background:rgba(30,30,32,.98); backdrop-filter:blur(20px); -webkit-backdrop-filter:blur(20px);" id="kbKeys"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ PROFIL / MENSCHLEIN (neu, enthält Knowledge Base) ============ -->
|
||||
@@ -831,10 +907,18 @@ TEXT-OVERLAY: keins (Brand-Stil: clean)</textarea>
|
||||
</div>
|
||||
|
||||
<!-- ============ NAVIGATION (neu: Feed · Profil · Plus · Dev) ============ -->
|
||||
<nav class="nav">
|
||||
<nav class="nav" id="navBar">
|
||||
<div class="nav-glass blur"></div>
|
||||
<div class="nav-glass refract"></div>
|
||||
<div class="nav-glass white"></div>
|
||||
<div class="nav-glass ring"></div>
|
||||
<button id="n-feed" class="on" onclick="go('explore')"><svg class="ic"><use href="#i-home"/></svg><span>Feed</span></button>
|
||||
<button id="n-profile" onclick="go('profile')"><svg class="ic"><use href="#i-user"/></svg><span>Profil</span></button>
|
||||
<button id="n-create" class="plus" onclick="go('create')" aria-label="Neuer KI-Post"><svg class="ic"><use href="#i-plus"/></svg></button>
|
||||
<button id="n-create" class="plus" onclick="go('create')" aria-label="Neuer KI-Post">
|
||||
<div class="lm-shader lm-bg"></div>
|
||||
<div class="lm-core"></div>
|
||||
<div class="lm-ic"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#9a9a9a" stroke-width="2.4" stroke-linecap="round" style="filter:drop-shadow(0 1px 2px rgba(0,0,0,.5))"><path d="M12 5 V19 M5 12 H19"/></svg></div>
|
||||
</button>
|
||||
<button id="n-dev" onclick="go('devmode')" style="opacity:.55;" title="Nur intern sichtbar"><svg class="ic"><use href="#i-gear"/></svg><span>Dev</span></button>
|
||||
</nav>
|
||||
|
||||
@@ -870,6 +954,8 @@ function go(id){
|
||||
};
|
||||
document.querySelectorAll('.nav button').forEach(b=>b.classList.remove('on'));
|
||||
if(navMap[id]) document.getElementById(navMap[id]).classList.add('on');
|
||||
document.body.classList.toggle('noscroll', id==='explore'||id==='create');
|
||||
if(id==='create') requestAnimationFrame(initCreateDither);
|
||||
window.scrollTo(0,0);
|
||||
}
|
||||
function pick(el){
|
||||
@@ -886,20 +972,20 @@ var ACCENT='#ff5c39';
|
||||
var HUES={Produkt:40, Mensch:260, Szene:170};
|
||||
var POSTS=[
|
||||
{id:1, creator:'Lena M.', cat:'Produkt', model:'Sneaker Studio v2', video:true, h:250, imgs:['[ki-video: sneaker spot]'],
|
||||
pics:['uploads/pasted-1784663207742-0.png']},
|
||||
pics:['uploads/pasted-1784663207742-0.jpg']},
|
||||
{id:2, creator:'Mara S.', cat:'Produkt', model:'Glow Serum v3', video:false, h:150, imgs:['Toner im Bogenfenster','Age Decoder Essence','Poster-Ad'],
|
||||
pics:['uploads/pasted-1784643149542-0.png','uploads/pasted-1784643165286-0.png','uploads/pasted-1784643111353-0.png'],
|
||||
avatar:'uploads/pasted-1784663200459-0.png'},
|
||||
pics:['uploads/pasted-1784643149542-0.jpg','uploads/pasted-1784643165286-0.jpg','uploads/pasted-1784643111353-0.jpg'],
|
||||
avatar:'uploads/pasted-1784663200459-0.jpg'},
|
||||
{id:3, creator:'Jonas K.', cat:'Mensch', model:'Coach Avatar', video:true, h:40, imgs:['[ki-video: gym coaching ad]'],
|
||||
pics:['uploads/pasted-1784663200459-0.png']},
|
||||
pics:['uploads/pasted-1784663200459-0.jpg']},
|
||||
{id:4, creator:'Tom B.', cat:'Mensch', model:'Barber Ich v1', video:false, h:90, imgs:['[ki-bild 1/4: portrait]','[ki-bild 2/4: fade cut]','[ki-bild 3/4: shop szene]','[ki-bild 4/4: logo karte]'],
|
||||
pics:['uploads/pasted-1784663261701-0.png','uploads/pasted-1784663207742-0.png','uploads/pasted-1784663200459-0.png','uploads/pasted-1784663233931-0.png']},
|
||||
pics:['uploads/pasted-1784663261701-0.jpg','uploads/pasted-1784663207742-0.jpg','uploads/pasted-1784663200459-0.jpg','uploads/pasted-1784663233931-0.jpg']},
|
||||
{id:5, creator:'Feld & Co',cat:'Szene', model:'Café Interieur', video:false, h:190, imgs:['[ki-bild 1/3: tresen]','[ki-bild 2/3: latte art]','[ki-bild 3/3: fassade]'],
|
||||
pics:['uploads/pasted-1784663233931-0.png','uploads/pasted-1784663383522-0.png','uploads/pasted-1784663261701-0.png']},
|
||||
pics:['uploads/pasted-1784663233931-0.jpg','uploads/pasted-1784663383522-0.jpg','uploads/pasted-1784663261701-0.jpg']},
|
||||
{id:6, creator:'Nina R.', cat:'Produkt', model:'Schmuck Makro', video:false, h:310, imgs:['[ki-bild: ring makro]'],
|
||||
pics:['uploads/pasted-1784663383522-0.png']},
|
||||
pics:['uploads/pasted-1784663383522-0.jpg']},
|
||||
{id:7, creator:'Kai W.', cat:'Szene', model:'Immo Walkthrough', video:true, h:210, imgs:['[ki-video: wohnungs-tour]'],
|
||||
pics:['uploads/pasted-1784663233931-0.png']}
|
||||
pics:['uploads/pasted-1784663233931-0.jpg']}
|
||||
];
|
||||
var X={tab:'posts', idx:0, dx:0, imgIdx:0, liked:[], anim:false, hoodCx:null, hoodHalf:null, hoodRaf:null, centers:null, halves:null};
|
||||
var TAB_CENTERS={videos:40, folge:205, posts:366};
|
||||
@@ -913,7 +999,7 @@ function preloadPics(){
|
||||
POSTS.forEach(function(p){ (p.pics||[]).forEach(function(u){ all[u]=1; }); if(p.avatar) all[p.avatar]=1; });
|
||||
Object.keys(all).forEach(function(u){
|
||||
var im=new Image();
|
||||
im.onload=function(){ PICS_OK[u]=true; renderDeck(); renderDetailStrip(); };
|
||||
im.onload=function(){ PICS_OK[u]=true; renderDeck(); renderDetailStrip(); renderCreateStack(); };
|
||||
im.src=u;
|
||||
});
|
||||
}
|
||||
@@ -1002,7 +1088,12 @@ function renderBlur(){
|
||||
}
|
||||
function esc(s){ return s.replace(/&/g,'&').replace(/</g,'<'); }
|
||||
|
||||
function renderDeck(){
|
||||
function cardTransform(depth){
|
||||
return depth===0 ? 'translateX(0px) rotate(0deg)' : 'scale('+(1-depth*.06)+') translateY('+(-depth*34)+'px)';
|
||||
}
|
||||
/* settle=true: Karten starten eine Position tiefer und gleiten nach vorn
|
||||
(Nachrueck-Animation aus dem Design nach Fling/Tab-Wechsel) */
|
||||
function renderDeck(settle){
|
||||
var host=document.getElementById('xDeck');
|
||||
var d=deck();
|
||||
renderBlur();
|
||||
@@ -1017,16 +1108,17 @@ function renderDeck(){
|
||||
return;
|
||||
}
|
||||
var html='';
|
||||
var slice=d.slice(X.idx, X.idx+3);
|
||||
var slice=d.slice(X.idx, X.idx+4);
|
||||
for(var i=slice.length-1; i>=0; i--){
|
||||
var p=slice[i], top=(i===0);
|
||||
var imgI=top?Math.min(X.imgIdx,p.imgs.length-1):0;
|
||||
var u=pic(p,imgI);
|
||||
var hue=p.h+imgI*25;
|
||||
var tf=top
|
||||
var depth=settle?i+1:i;
|
||||
var tf=(top&&!settle)
|
||||
? 'translateX('+X.dx+'px) rotate('+(X.dx/22)+'deg)'
|
||||
: 'scale('+(1-i*.06)+') translateY('+(-i*34)+'px)';
|
||||
html+='<div class="x-card'+(top?' top':'')+'" data-i="'+i+'" style="z-index:'+(4-i)+'; transform:'+tf+'; transition:transform .28s ease; cursor:'+(top?'grab':'default')+';">';
|
||||
: cardTransform(depth);
|
||||
html+='<div class="x-card'+(top?' top':'')+'" data-i="'+i+'" style="z-index:'+(5-i)+'; transform:'+tf+'; transition:'+(settle?'none':'transform .45s cubic-bezier(.22,1,.36,1)')+'; cursor:'+(top?'grab':'default')+';">';
|
||||
var bg=u ? '#141414 url("'+u+'") center / cover no-repeat' : dummy(hue);
|
||||
html+='<div class="img" style="background:'+bg+';'+(top?'':' filter:brightness(.85);')+'"></div>';
|
||||
if(top){
|
||||
@@ -1054,6 +1146,14 @@ function renderDeck(){
|
||||
host.innerHTML=html;
|
||||
var topEl=host.querySelector('.x-card.top');
|
||||
if(topEl) topEl.addEventListener('pointerdown', onDown);
|
||||
if(settle){
|
||||
requestAnimationFrame(function(){ requestAnimationFrame(function(){
|
||||
host.querySelectorAll('.x-card').forEach(function(el){
|
||||
el.style.transition='transform .45s cubic-bezier(.22,1,.36,1)';
|
||||
el.style.transform=cardTransform(+el.dataset.i);
|
||||
});
|
||||
});});
|
||||
}
|
||||
}
|
||||
|
||||
function fling(dir){
|
||||
@@ -1062,14 +1162,15 @@ function fling(dir){
|
||||
X.anim=true;
|
||||
var topEl=document.querySelector('#xDeck .x-card.top');
|
||||
if(topEl){
|
||||
topEl.style.transition='transform .28s ease';
|
||||
topEl.style.transition='transform .3s cubic-bezier(.4,0,.7,1), opacity .3s ease';
|
||||
topEl.style.transform='translateX('+(dir*640)+'px) rotate('+(dir*640/22)+'deg)';
|
||||
topEl.style.opacity='0';
|
||||
}
|
||||
setTimeout(function(){
|
||||
if(dir>0 && post) X.liked.push(post.id);
|
||||
X.idx++; X.dx=0; X.imgIdx=0; X.anim=false;
|
||||
renderDeck();
|
||||
},280);
|
||||
renderDeck(true);
|
||||
},300);
|
||||
}
|
||||
|
||||
function onDown(e){
|
||||
@@ -1093,7 +1194,7 @@ function onDown(e){
|
||||
var d=ev.clientX-sx;
|
||||
if(Math.abs(d)>110){ fling(d>0?1:-1); return; }
|
||||
X.dx=0;
|
||||
topEl.style.transition='transform .28s ease';
|
||||
topEl.style.transition='transform .45s cubic-bezier(.22,1,.36,1)';
|
||||
topEl.style.transform='translateX(0) rotate(0)';
|
||||
if(likeB) likeB.style.opacity=0;
|
||||
if(skipB) skipB.style.opacity=0;
|
||||
@@ -1108,12 +1209,21 @@ function onDown(e){
|
||||
|
||||
document.querySelectorAll('.x-tab').forEach(function(el){
|
||||
el.addEventListener('click',function(){
|
||||
X.tab=el.dataset.tab; X.idx=0; X.dx=0; X.imgIdx=0;
|
||||
renderTabs(); renderDeck(); animateHood(centerOf(X.tab), halfOf(X.tab));
|
||||
if(X.tab===el.dataset.tab) return;
|
||||
var k=el.dataset.tab;
|
||||
var deckEl=document.getElementById('xDeck'), blurEl=document.getElementById('xBlur');
|
||||
animateHood(centerOf(k), halfOf(k));
|
||||
deckEl.style.transition='opacity .18s ease';
|
||||
deckEl.style.opacity='0'; blurEl.style.opacity='0';
|
||||
setTimeout(function(){
|
||||
X.tab=k; X.idx=0; X.dx=0; X.imgIdx=0;
|
||||
renderTabs(); renderDeck(true);
|
||||
deckEl.style.opacity='1'; blurEl.style.opacity='1';
|
||||
},180);
|
||||
});
|
||||
});
|
||||
window.addEventListener('resize',function(){
|
||||
measureTabs(); setHood(centerOf(X.tab), halfOf(X.tab));
|
||||
measureTabs(); setHood(centerOf(X.tab), halfOf(X.tab)); updateGlassMap();
|
||||
});
|
||||
document.getElementById('btnSkip').onclick=function(){ fling(-1); };
|
||||
document.getElementById('btnLike').onclick=function(){ fling(1); };
|
||||
@@ -1149,9 +1259,8 @@ function renderDetailModels(){
|
||||
host.querySelectorAll('.chip').forEach(function(c){
|
||||
c.onclick=function(){ D.model=+c.dataset.i; D.remade=false; renderDetailModels(); };
|
||||
});
|
||||
var btn=document.getElementById('remakeBtn');
|
||||
btn.textContent=D.remade ? '✓ Übernommen — im Editor geöffnet' : 'Nachmachen mit „'+MODELS[D.model].split(' – ')[1]+'“';
|
||||
btn.classList.toggle('sec', D.remade);
|
||||
document.getElementById('remakeLabel').textContent=
|
||||
D.remade ? '✓ Übernommen — im Editor geöffnet' : 'Nachmachen mit „'+MODELS[D.model].split(' – ')[1]+'“';
|
||||
}
|
||||
document.getElementById('remakeBtn').onclick=function(){
|
||||
if(D.remade) return;
|
||||
@@ -1164,49 +1273,420 @@ document.getElementById('remakeBtn').onclick=function(){
|
||||
},900);
|
||||
};
|
||||
|
||||
/* ---------- Create: Modell / Kette / Format / Vorschau ---------- */
|
||||
var C={model:0, count:3, format:'4:5', generating:0};
|
||||
var RATIOS={'1:1':[130,130],'4:5':[124,155],'9:16':[96,170]};
|
||||
function renderCreateModels(){
|
||||
var host=document.getElementById('createModels');
|
||||
host.innerHTML=MODELS.map(function(m,i){
|
||||
return '<div class="chip'+(i===C.model?' on':'')+'" data-i="'+i+'"><div class="dot"></div>'+m+'</div>';
|
||||
/* ---------- Dithering-Shader (WebGL2-Port von designali-in/dithering-shader) ----------
|
||||
Testweise auf den Modell-Chips im Create-Screen: Sphere/Random,
|
||||
ausgewaehlt = weiss/silber, nicht ausgewaehlt = dunkelgrau. */
|
||||
var DITHER_VERT='#version 300 es\nprecision mediump float;\nlayout(location = 0) in vec4 a_position;\nvoid main(){ gl_Position = a_position; }';
|
||||
var DITHER_FRAG=[
|
||||
'#version 300 es',
|
||||
'precision mediump float;',
|
||||
'uniform float u_time;',
|
||||
'uniform vec2 u_resolution;',
|
||||
'uniform vec4 u_colorBack;',
|
||||
'uniform vec4 u_colorFront;',
|
||||
'uniform float u_shape;',
|
||||
'uniform float u_type;',
|
||||
'uniform float u_pxSize;',
|
||||
'out vec4 fragColor;',
|
||||
'vec3 permute(vec3 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); }',
|
||||
'float snoise(vec2 v) {',
|
||||
' const vec4 C = vec4(0.211324865405187, 0.366025403784439, -0.577350269189626, 0.024390243902439);',
|
||||
' vec2 i = floor(v + dot(v, C.yy));',
|
||||
' vec2 x0 = v - i + dot(i, C.xx);',
|
||||
' vec2 i1;',
|
||||
' i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);',
|
||||
' vec4 x12 = x0.xyxy + C.xxzz;',
|
||||
' x12.xy -= i1;',
|
||||
' i = mod(i, 289.0);',
|
||||
' vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));',
|
||||
' vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);',
|
||||
' m = m * m;',
|
||||
' m = m * m;',
|
||||
' vec3 x = 2.0 * fract(p * C.www) - 1.0;',
|
||||
' vec3 h = abs(x) - 0.5;',
|
||||
' vec3 ox = floor(x + 0.5);',
|
||||
' vec3 a0 = x - ox;',
|
||||
' m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);',
|
||||
' vec3 g;',
|
||||
' g.x = a0.x * x0.x + h.x * x0.y;',
|
||||
' g.yz = a0.yz * x12.xz + h.yz * x12.yw;',
|
||||
' return 130.0 * dot(m, g);',
|
||||
'}',
|
||||
'#define TWO_PI 6.28318530718',
|
||||
'#define PI 3.14159265358979323846',
|
||||
'float hash11(float p) {',
|
||||
' p = fract(p * 0.3183099) + 0.1;',
|
||||
' p *= p + 19.19;',
|
||||
' return fract(p * p);',
|
||||
'}',
|
||||
'float hash21(vec2 p) {',
|
||||
' p = fract(p * vec2(0.3183099, 0.3678794)) + 0.1;',
|
||||
' p += dot(p, p + 19.19);',
|
||||
' return fract(p.x * p.y);',
|
||||
'}',
|
||||
'float getSimplexNoise(vec2 uv, float t) {',
|
||||
' float noise = .5 * snoise(uv - vec2(0., .3 * t));',
|
||||
' noise += .5 * snoise(2. * uv + vec2(0., .32 * t));',
|
||||
' return noise;',
|
||||
'}',
|
||||
'const int bayer2x2[4] = int[4](0, 2, 3, 1);',
|
||||
'const int bayer4x4[16] = int[16](0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5);',
|
||||
'const int bayer8x8[64] = int[64](0, 32, 8, 40, 2, 34, 10, 42, 48, 16, 56, 24, 50, 18, 58, 26, 12, 44, 4, 36, 14, 46, 6, 38, 60, 28, 52, 20, 62, 30, 54, 22, 3, 35, 11, 43, 1, 33, 9, 41, 51, 19, 59, 27, 49, 17, 57, 25, 15, 47, 7, 39, 13, 45, 5, 37, 63, 31, 55, 23, 61, 29, 53, 21);',
|
||||
'float getBayerValue(vec2 uv, int size) {',
|
||||
' ivec2 pos = ivec2(mod(uv, float(size)));',
|
||||
' int index = pos.y * size + pos.x;',
|
||||
' if (size == 2) { return float(bayer2x2[index]) / 4.0; }',
|
||||
' else if (size == 4) { return float(bayer4x4[index]) / 16.0; }',
|
||||
' else if (size == 8) { return float(bayer8x8[index]) / 64.0; }',
|
||||
' return 0.0;',
|
||||
'}',
|
||||
'void main() {',
|
||||
' float t = .5 * u_time;',
|
||||
' vec2 uv = gl_FragCoord.xy / u_resolution.xy;',
|
||||
' uv -= .5;',
|
||||
' float pxSize = u_pxSize;',
|
||||
' vec2 pxSizeUv = gl_FragCoord.xy;',
|
||||
' pxSizeUv -= .5 * u_resolution;',
|
||||
' pxSizeUv /= pxSize;',
|
||||
' vec2 pixelizedUv = floor(pxSizeUv) * pxSize / u_resolution.xy;',
|
||||
' pixelizedUv += .5;',
|
||||
' pixelizedUv -= .5;',
|
||||
' vec2 shape_uv = pixelizedUv;',
|
||||
' vec2 dithering_uv = pxSizeUv;',
|
||||
' vec2 ditheringNoise_uv = uv * u_resolution;',
|
||||
' float shape = 0.;',
|
||||
' if (u_shape < 1.5) {',
|
||||
' shape_uv *= .001;',
|
||||
' shape = 0.5 + 0.5 * getSimplexNoise(shape_uv, t);',
|
||||
' shape = smoothstep(0.3, 0.9, shape);',
|
||||
' } else if (u_shape < 2.5) {',
|
||||
' shape_uv *= .003;',
|
||||
' for (float i = 1.0; i < 6.0; i++) {',
|
||||
' shape_uv.x += 0.6 / i * cos(i * 2.5 * shape_uv.y + t);',
|
||||
' shape_uv.y += 0.6 / i * cos(i * 1.5 * shape_uv.x + t);',
|
||||
' }',
|
||||
' shape = .15 / abs(sin(t - shape_uv.y - shape_uv.x));',
|
||||
' shape = smoothstep(0.02, 1., shape);',
|
||||
' } else if (u_shape < 3.5) {',
|
||||
' shape_uv *= .05;',
|
||||
' float stripeIdx = floor(2. * shape_uv.x / TWO_PI);',
|
||||
' float rand = hash11(stripeIdx * 10.);',
|
||||
' rand = sign(rand - .5) * pow(.1 + abs(rand), .4);',
|
||||
' shape = sin(shape_uv.x) * cos(shape_uv.y - 5. * rand * t);',
|
||||
' shape = pow(abs(shape), 6.);',
|
||||
' } else if (u_shape < 4.5) {',
|
||||
' shape_uv *= 4.;',
|
||||
' float wave = cos(.5 * shape_uv.x - 2. * t) * sin(1.5 * shape_uv.x + t) * (.75 + .25 * cos(3. * t));',
|
||||
' shape = 1. - smoothstep(-1., 1., shape_uv.y + wave);',
|
||||
' } else if (u_shape < 5.5) {',
|
||||
' float dist = length(shape_uv);',
|
||||
' float waves = sin(pow(dist, 1.7) * 7. - 3. * t) * .5 + .5;',
|
||||
' shape = waves;',
|
||||
' } else if (u_shape < 6.5) {',
|
||||
' float l = length(shape_uv);',
|
||||
' float angle = 6. * atan(shape_uv.y, shape_uv.x) + 4. * t;',
|
||||
' float twist = 1.2;',
|
||||
' float offset = pow(l, -twist) + angle / TWO_PI;',
|
||||
' float mid = smoothstep(0., 1., pow(l, twist));',
|
||||
' shape = mix(0., fract(offset), mid);',
|
||||
' } else if (u_shape < 7.5) {',
|
||||
' shape_uv *= 2.;',
|
||||
' float d = 1. - pow(length(shape_uv), 2.);',
|
||||
' vec3 pos = vec3(shape_uv, sqrt(d));',
|
||||
' vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));',
|
||||
' shape = .5 + .5 * dot(lightPos, pos);',
|
||||
' shape *= step(0., d);',
|
||||
' } else {',
|
||||
' float ar = u_resolution.x / u_resolution.y;',
|
||||
' vec2 p = shape_uv * vec2(ar, 1.) * 2.1;',
|
||||
' vec2 q = vec2(sign(p.x) * max(abs(p.x) - (1.05 * ar - 1.), 0.), p.y);',
|
||||
' float d = 1. - dot(q, q);',
|
||||
' vec3 pos = vec3(q, sqrt(max(d, 0.)));',
|
||||
' vec3 lightPos = normalize(vec3(cos(1.5 * t), .8, sin(1.25 * t)));',
|
||||
' shape = .5 + .5 * dot(lightPos, pos);',
|
||||
' shape *= step(0., d);',
|
||||
' }',
|
||||
' int type = int(floor(u_type));',
|
||||
' float dithering = 0.0;',
|
||||
' switch (type) {',
|
||||
' case 1: {',
|
||||
' dithering = step(hash21(ditheringNoise_uv), shape);',
|
||||
' } break;',
|
||||
' case 2:',
|
||||
' dithering = getBayerValue(dithering_uv, 2);',
|
||||
' break;',
|
||||
' case 3:',
|
||||
' dithering = getBayerValue(dithering_uv, 4);',
|
||||
' break;',
|
||||
' default:',
|
||||
' dithering = getBayerValue(dithering_uv, 8);',
|
||||
' break;',
|
||||
' }',
|
||||
' dithering -= .5;',
|
||||
' float res = step(.5, shape + dithering);',
|
||||
' vec3 fgColor = u_colorFront.rgb * u_colorFront.a;',
|
||||
' float fgOpacity = u_colorFront.a;',
|
||||
' vec3 bgColor = u_colorBack.rgb * u_colorBack.a;',
|
||||
' float bgOpacity = u_colorBack.a;',
|
||||
' vec3 color = fgColor * res;',
|
||||
' float opacity = fgOpacity * res;',
|
||||
' color += bgColor * (1. - opacity);',
|
||||
' opacity += bgOpacity * (1. - opacity);',
|
||||
' fragColor = vec4(color, opacity);',
|
||||
'}'
|
||||
].join('\n');
|
||||
function ditherHexToRgba(hex){
|
||||
var m=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
if(!m) return [0,0,0,1];
|
||||
return [parseInt(m[1],16)/255, parseInt(m[2],16)/255, parseInt(m[3],16)/255, 1];
|
||||
}
|
||||
function mountDither(canvas, opts){
|
||||
var gl=canvas.getContext('webgl2');
|
||||
if(!gl) return null;
|
||||
function sh(type,src){
|
||||
var s=gl.createShader(type);
|
||||
gl.shaderSource(s,src); gl.compileShader(s);
|
||||
if(!gl.getShaderParameter(s,gl.COMPILE_STATUS)){ console.error(gl.getShaderInfoLog(s)); return null; }
|
||||
return s;
|
||||
}
|
||||
var vs=sh(gl.VERTEX_SHADER,DITHER_VERT), fs=sh(gl.FRAGMENT_SHADER,DITHER_FRAG);
|
||||
if(!vs||!fs) return null;
|
||||
var prog=gl.createProgram();
|
||||
gl.attachShader(prog,vs); gl.attachShader(prog,fs); gl.linkProgram(prog);
|
||||
if(!gl.getProgramParameter(prog,gl.LINK_STATUS)){ console.error(gl.getProgramInfoLog(prog)); return null; }
|
||||
var L={};
|
||||
['u_time','u_resolution','u_colorBack','u_colorFront','u_shape','u_type','u_pxSize'].forEach(function(n){ L[n]=gl.getUniformLocation(prog,n); });
|
||||
var buf=gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER,buf);
|
||||
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),gl.STATIC_DRAW);
|
||||
gl.enableVertexAttribArray(0);
|
||||
gl.vertexAttribPointer(0,2,gl.FLOAT,false,0,0);
|
||||
var dpr=window.devicePixelRatio||1;
|
||||
var r=canvas.parentElement.getBoundingClientRect();
|
||||
canvas.width=Math.max(2,Math.round((r.width||120)*dpr));
|
||||
canvas.height=Math.max(2,Math.round((r.height||36)*dpr));
|
||||
gl.viewport(0,0,canvas.width,canvas.height);
|
||||
var front=ditherHexToRgba(opts.front||'#ffffff');
|
||||
var back=ditherHexToRgba(opts.back||'#000000');
|
||||
var t0=Date.now();
|
||||
(function frame(){
|
||||
var t=(Date.now()-t0)*.001*(opts.speed||1.5);
|
||||
gl.useProgram(prog);
|
||||
gl.uniform1f(L.u_time,t);
|
||||
gl.uniform2f(L.u_resolution,canvas.width,canvas.height);
|
||||
gl.uniform4fv(L.u_colorBack,back);
|
||||
gl.uniform4fv(L.u_colorFront,front);
|
||||
gl.uniform1f(L.u_shape,opts.shape||7);
|
||||
gl.uniform1f(L.u_type,opts.type||1);
|
||||
gl.uniform1f(L.u_pxSize,opts.pxSize||2);
|
||||
gl.drawArrays(gl.TRIANGLES,0,6);
|
||||
requestAnimationFrame(frame);
|
||||
})();
|
||||
return { setFront:function(hex){ front=ditherHexToRgba(hex); } };
|
||||
}
|
||||
|
||||
/* ---------- Create: Vorschau-Stack / Optionen / Prompt-Beam / Fake-Tastatur ---------- */
|
||||
var C={model:0, count:1, format:'4:5', mediaType:'image', optOpen:false, kbOpen:false, generating:0};
|
||||
var C_MODELS=[
|
||||
{name:'Ich (Avatar)', token:'@Ich', hue:260},
|
||||
{name:'Kerze Studio', token:'@Kerze', hue:40},
|
||||
{name:'Showroom', token:'@Showroom', hue:170}
|
||||
];
|
||||
function renderCreateStack(){
|
||||
var host=document.getElementById('cStack');
|
||||
if(!host) return;
|
||||
var isVideo=C.mediaType==='video';
|
||||
var isChain=!isVideo&&C.count>1;
|
||||
var pr={'1:1':1,'4:5':.8,'9:16':.5625}[C.format];
|
||||
var ph=258, pw=Math.round(ph*pr);
|
||||
var cp=POSTS[1], u=pic(cp,0);
|
||||
var bg=u?'#141414 url("'+u+'") center / cover no-repeat':dummy(150);
|
||||
var html='';
|
||||
var nBehind=isChain?Math.min(C.count-1,2):0;
|
||||
for(var k=nBehind;k>=1;k--){
|
||||
html+='<div class="c-behind" style="width:'+pw+'px; height:'+ph+'px; transform:translateX(-50%) rotate('+(k===1?-6:6)+'deg) translateY('+(4*k)+'px) scale('+(1-.04*k)+');"></div>';
|
||||
}
|
||||
html+='<div class="c-preview" style="width:'+pw+'px; height:'+ph+'px; background:'+bg+';">';
|
||||
if(isVideo){
|
||||
html+='<div style="position:absolute; inset:0; display:grid; place-items:center; pointer-events:none;"><div style="width:62px; height:62px; border-radius:100px; background:rgba(10,10,10,.5); backdrop-filter:blur(8px); display:grid; place-items:center;"><svg width="20" height="20" viewBox="0 0 24 24" fill="#fff"><path d="M8 5 L19 12 L8 19 Z"/></svg></div></div>';
|
||||
html+='<div style="position:absolute; top:12px; left:12px; padding:5px 10px; border-radius:100px; background:rgba(10,10,10,.55); font-size:11px; font-weight:700; letter-spacing:.06em;">VIDEO · 0:08</div>';
|
||||
}
|
||||
if(isChain){
|
||||
html+='<div style="position:absolute; top:12px; right:12px; padding:5px 10px; border-radius:100px; background:rgba(10,10,10,.55); font-size:11px; font-weight:700;">1/'+C.count+'</div>';
|
||||
html+='<div style="position:absolute; left:0; right:0; bottom:14px; display:flex; justify-content:center; align-items:center; gap:5px;">';
|
||||
for(var i=0;i<C.count;i++){
|
||||
html+='<div style="width:'+(i===0?16:6)+'px; height:6px; border-radius:100px; background:'+(i===0?'#fff':'rgba(255,255,255,.45)')+'; transition:width .2s;"></div>';
|
||||
}
|
||||
html+='</div>';
|
||||
}
|
||||
html+='</div>';
|
||||
host.innerHTML=html;
|
||||
document.getElementById('cSelLabel').textContent = isVideo ? ('Video · '+C.format) : ((C.count===1?'Bild':C.count+'er-Kette')+' · '+C.format);
|
||||
document.getElementById('cChevron').style.transform=C.optOpen?'rotate(180deg)':'none';
|
||||
document.getElementById('cOpts').style.display=C.optOpen?'block':'none';
|
||||
}
|
||||
function pills(hostId, items, activeVal, onPick){
|
||||
var host=document.getElementById(hostId);
|
||||
host.innerHTML=items.map(function(it){
|
||||
return '<div class="pill'+(it.v===activeVal?' on':'')+'" data-v="'+it.v+'">'+it.label+'</div>';
|
||||
}).join('');
|
||||
host.querySelectorAll('.chip').forEach(function(c){
|
||||
c.onclick=function(){ C.model=+c.dataset.i; renderCreateModels(); };
|
||||
host.querySelectorAll('.pill').forEach(function(p){
|
||||
p.onclick=function(){ onPick(p.dataset.v); };
|
||||
});
|
||||
}
|
||||
function renderFrames(){
|
||||
var r=RATIOS[C.format], host=document.getElementById('previewFrames'), html='';
|
||||
for(var i=0;i<C.count;i++){
|
||||
html+='<div class="frame" style="width:'+r[0]+'px; height:'+r[1]+'px;"><span>Bild '+(i+1)+'</span></div>';
|
||||
}
|
||||
host.innerHTML=html;
|
||||
function renderCreateOpts(){
|
||||
pills('typeRow',[{v:'image',label:'Bild'},{v:'video',label:'Video'}],C.mediaType,function(v){C.mediaType=v; renderCreateOpts(); renderCreateStack();});
|
||||
pills('formatRow',[{v:'1:1',label:'1:1'},{v:'4:5',label:'4:5'},{v:'9:16',label:'9:16'}],C.format,function(v){C.format=v; renderCreateOpts(); renderCreateStack();});
|
||||
pills('countRow',[{v:'1',label:'1 Bild'},{v:'3',label:'3er'},{v:'5',label:'5er'}],String(C.count),function(v){C.count=+v; renderCreateOpts(); renderCreateStack();});
|
||||
}
|
||||
document.querySelectorAll('#countRow .pill').forEach(function(p){
|
||||
p.onclick=function(){ pick(p); C.count=+p.dataset.count; renderFrames(); };
|
||||
});
|
||||
document.querySelectorAll('#formatRow .pill').forEach(function(p){
|
||||
p.onclick=function(){ pick(p); C.format=p.dataset.format; renderFrames(); };
|
||||
});
|
||||
function toggleOpts(){ C.optOpen=!C.optOpen; renderCreateStack(); }
|
||||
var DCHIPS={built:false, mounted:false, insts:[]};
|
||||
var DITHER_ON='#f2f2f2', DITHER_OFF='#555555';
|
||||
function renderCreateModels(){
|
||||
var host=document.getElementById('createModels');
|
||||
if(!DCHIPS.built){
|
||||
host.innerHTML=C_MODELS.map(function(m,i){
|
||||
return '<div class="chip dither" data-i="'+i+'"><canvas></canvas><div class="dot"></div><span>'+m.name+'</span></div>';
|
||||
}).join('');
|
||||
host.querySelectorAll('.chip').forEach(function(c){
|
||||
c.onclick=function(){ C.model=+c.dataset.i; renderCreateModels(); };
|
||||
});
|
||||
DCHIPS.built=true;
|
||||
}
|
||||
host.querySelectorAll('.chip').forEach(function(c,i){
|
||||
var on=(i===C.model);
|
||||
c.classList.toggle('on',on);
|
||||
c.querySelector('.dot').style.background=on?'var(--accent)':'rgba(255,255,255,.3)';
|
||||
if(DCHIPS.insts[i]) DCHIPS.insts[i].setFront(on?DITHER_ON:DITHER_OFF);
|
||||
});
|
||||
}
|
||||
/* Shader erst mounten, wenn der Create-Screen sichtbar ist (sonst Groesse 0) */
|
||||
function initCreateDither(){
|
||||
if(DCHIPS.mounted) return;
|
||||
var chips=document.querySelectorAll('#createModels .chip.dither');
|
||||
if(!chips.length) return;
|
||||
DCHIPS.mounted=true;
|
||||
chips.forEach(function(c,i){
|
||||
DCHIPS.insts[i]=mountDither(c.querySelector('canvas'), {front:(i===C.model)?DITHER_ON:DITHER_OFF, shape:8, type:1, pxSize:2, speed:1.5});
|
||||
});
|
||||
}
|
||||
/* Prompt-Editing über die Fake-Tastatur (Caret-genau wie im Design) */
|
||||
function editPrompt(mutate){
|
||||
var ta=document.getElementById('createPrompt');
|
||||
var p=ta.value, s=ta.selectionStart, e=ta.selectionEnd;
|
||||
var r=mutate(p,s,e);
|
||||
ta.value=r.val;
|
||||
ta.focus(); ta.setSelectionRange(r.caret,r.caret);
|
||||
}
|
||||
function applyKey(code){
|
||||
editPrompt(function(p,s,e){
|
||||
if(code==='del'){
|
||||
if(s!==e) return {val:p.slice(0,s)+p.slice(e), caret:s};
|
||||
return {val:p.slice(0,Math.max(0,s-1))+p.slice(e), caret:Math.max(0,s-1)};
|
||||
}
|
||||
var ins=code==='space'?' ':code==='ret'?'\n':code;
|
||||
return {val:p.slice(0,s)+ins+p.slice(e), caret:s+ins.length};
|
||||
});
|
||||
}
|
||||
function insertToken(tok){
|
||||
editPrompt(function(p,s,e){
|
||||
var before=p.slice(0,s);
|
||||
var lead=before&&!/\s$/.test(before)?' ':'';
|
||||
var ins=lead+tok+' ';
|
||||
return {val:before+ins+p.slice(e), caret:s+ins.length};
|
||||
});
|
||||
}
|
||||
function setKb(open){
|
||||
C.kbOpen=open;
|
||||
document.getElementById('kbOverlay').classList.toggle('open',open);
|
||||
document.getElementById('cScroll').classList.toggle('kb-open',open);
|
||||
if(open){
|
||||
C.optOpen=false; renderCreateStack();
|
||||
requestAnimationFrame(function(){requestAnimationFrame(function(){
|
||||
var el=document.getElementById('cScroll'); el.scrollTop=el.scrollHeight;
|
||||
});});
|
||||
}
|
||||
}
|
||||
function renderKb(){
|
||||
var mh=document.getElementById('kbModels');
|
||||
mh.innerHTML=C_MODELS.map(function(m,i){
|
||||
return '<div class="kb-chip" data-i="'+i+'"><div class="dot" style="background:oklch(.7 .13 '+m.hue+');"></div>'+m.name+'</div>';
|
||||
}).join('');
|
||||
mh.querySelectorAll('.kb-chip').forEach(function(c){
|
||||
function ins(e){ e.preventDefault(); insertToken(C_MODELS[+c.dataset.i].token); }
|
||||
c.addEventListener('mousedown',ins);
|
||||
c.addEventListener('touchstart',ins,{passive:false});
|
||||
});
|
||||
var rows=[
|
||||
{pad:0, keys:'qwertyuiop'.split('').map(function(l){return {label:l, code:l};})},
|
||||
{pad:16, keys:'asdfghjkl'.split('').map(function(l){return {label:l, code:l};})},
|
||||
{pad:0, keys:[{label:'⇧', code:null, cls:'mod', flex:1.5}].concat('zxcvbnm'.split('').map(function(l){return {label:l, code:l};})).concat([{label:'⌫', code:'del', cls:'mod', flex:1.5}])},
|
||||
{pad:0, keys:[{label:'123', code:null, cls:'mod', flex:1.6, fs:13},{label:'', code:'space', flex:5},{label:'return', code:'ret', flex:1.9, fs:13, bg:'rgba(122,162,255,.9)'}]}
|
||||
];
|
||||
var kh=document.getElementById('kbKeys'); var html='';
|
||||
rows.forEach(function(row,ri){
|
||||
html+='<div class="kb-row" style="padding:0 '+row.pad+'px;">';
|
||||
row.keys.forEach(function(k,ki){
|
||||
var st='';
|
||||
if(k.flex) st+='flex:'+k.flex+';';
|
||||
if(k.fs) st+='font-size:'+k.fs+'px;';
|
||||
if(k.bg) st+='background:'+k.bg+';';
|
||||
html+='<div class="kb-key'+(k.cls?' '+k.cls:'')+'" data-r="'+ri+'" data-k="'+ki+'" style="'+st+'">'+k.label+'</div>';
|
||||
});
|
||||
html+='</div>';
|
||||
});
|
||||
kh.innerHTML=html;
|
||||
kh.querySelectorAll('.kb-key').forEach(function(el){
|
||||
var k=rows[+el.dataset.r].keys[+el.dataset.k];
|
||||
function press(e){ e.preventDefault(); if(k.code) applyKey(k.code); }
|
||||
el.addEventListener('mousedown',press);
|
||||
el.addEventListener('touchstart',press,{passive:false});
|
||||
});
|
||||
function done(e){ e.preventDefault(); document.getElementById('createPrompt').blur(); setKb(false); }
|
||||
document.getElementById('kbDone').addEventListener('mousedown',done);
|
||||
document.getElementById('kbDone').addEventListener('touchstart',done,{passive:false});
|
||||
}
|
||||
(function(){
|
||||
var ta=document.getElementById('createPrompt');
|
||||
ta.addEventListener('focus',function(){ setKb(true); });
|
||||
ta.addEventListener('blur',function(){ setKb(false); });
|
||||
})();
|
||||
document.getElementById('generateBtn').onclick=function(){
|
||||
if(C.generating) return;
|
||||
var btn=this;
|
||||
C.generating=1; btn.classList.add('sec'); btn.textContent='Generiere '+C.count+' Bilder …';
|
||||
setTimeout(function(){ C.generating=2; btn.textContent='✓ In der Warteschlange'; },1400);
|
||||
setTimeout(function(){ C.generating=0; btn.classList.remove('sec'); btn.textContent='Post generieren'; },3200);
|
||||
var lbl=document.getElementById('generateLabel');
|
||||
C.generating=1; lbl.textContent='Generiere '+C.count+' Bilder …';
|
||||
setTimeout(function(){ C.generating=2; lbl.textContent='✓ In der Warteschlange'; },1400);
|
||||
setTimeout(function(){ C.generating=0; lbl.textContent='Post generieren'; },3200);
|
||||
};
|
||||
|
||||
/* ---------- Nav-Glas: dynamische Displacement-Map (aus dem Design) ---------- */
|
||||
function updateGlassMap(){
|
||||
var nav=document.getElementById('navBar'), img=document.getElementById('glassMapImage');
|
||||
if(!nav||!img) return;
|
||||
var w=nav.offsetWidth||286, h=nav.offsetHeight||56;
|
||||
var r=Math.min(100,h/2), e=Math.min(w,h)*0.035;
|
||||
var svg='<svg viewBox="0 0 '+w+' '+h+'" xmlns="http://www.w3.org/2000/svg">'+
|
||||
'<defs><linearGradient id="rg" x1="100%" y1="0%" x2="0%" y2="0%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="red"/></linearGradient>'+
|
||||
'<linearGradient id="bg" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" stop-color="#0000"/><stop offset="100%" stop-color="blue"/></linearGradient></defs>'+
|
||||
'<rect width="'+w+'" height="'+h+'" fill="black"/>'+
|
||||
'<rect width="'+w+'" height="'+h+'" rx="'+r+'" fill="url(#rg)"/>'+
|
||||
'<rect width="'+w+'" height="'+h+'" rx="'+r+'" fill="url(#bg)" style="mix-blend-mode:difference"/>'+
|
||||
'<rect x="'+e+'" y="'+e+'" width="'+(w-e*2)+'" height="'+(h-e*2)+'" rx="'+r+'" fill="hsl(0 0% 50% / 0.93)" style="filter:blur(11px)"/></svg>';
|
||||
img.setAttribute('href','data:image/svg+xml,'+encodeURIComponent(svg));
|
||||
}
|
||||
|
||||
/* ---------- Init ---------- */
|
||||
setHood(centerOf(X.tab), halfOf(X.tab));
|
||||
requestAnimationFrame(function(){ measureTabs(); setHood(centerOf(X.tab), halfOf(X.tab)); });
|
||||
requestAnimationFrame(function(){ measureTabs(); setHood(centerOf(X.tab), halfOf(X.tab)); updateGlassMap(); });
|
||||
renderTabs();
|
||||
renderDeck();
|
||||
renderDetailStrip();
|
||||
preloadPics();
|
||||
renderDetailModels();
|
||||
renderCreateModels();
|
||||
renderFrames();
|
||||
renderCreateOpts();
|
||||
renderCreateStack();
|
||||
renderKb();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
uploads/pasted-1784643111353-0.jpg
Normal file
BIN
uploads/pasted-1784643111353-0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 142 KiB |
BIN
uploads/pasted-1784643165286-0.jpg
Normal file
BIN
uploads/pasted-1784643165286-0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
BIN
uploads/pasted-1784663200459-0.jpg
Normal file
BIN
uploads/pasted-1784663200459-0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
BIN
uploads/pasted-1784663207742-0.jpg
Normal file
BIN
uploads/pasted-1784663207742-0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
BIN
uploads/pasted-1784663261701-0.jpg
Normal file
BIN
uploads/pasted-1784663261701-0.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Reference in New Issue
Block a user