Spaces:
Running
Running
| <html lang="de"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
| <title>Film Cam – Vintage Analogkamera</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;700;900&family=DM+Sans:wght@300;400;500;700&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> | |
| <style> | |
| :root { | |
| --bg: #0a0a0a; | |
| --fg: #f0ebe3; | |
| --muted: #6b6560; | |
| --accent: #c8956c; | |
| --accent2: #e8b88a; | |
| --card: #161412; | |
| --card2: #1e1b18; | |
| --border: #2a2520; | |
| --glass: rgba(22,20,18,0.85); | |
| --gold: #d4a855; | |
| --chrome: #c0c0c0; | |
| --film-red: #b33a3a; | |
| --film-teal: #3a8a8a; | |
| } | |
| * { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; } | |
| html, body { | |
| height:100%; width:100%; | |
| overflow:hidden; | |
| background: var(--bg); | |
| color: var(--fg); | |
| font-family: 'DM Sans', sans-serif; | |
| } | |
| /* Scrollbar */ | |
| ::-webkit-scrollbar { width:4px; height:4px; } | |
| ::-webkit-scrollbar-track { background:transparent; } | |
| ::-webkit-scrollbar-thumb { background:var(--muted); border-radius:4px; } | |
| .app { | |
| display:flex; flex-direction:column; | |
| height:100vh; width:100vw; | |
| position:relative; | |
| overflow:hidden; | |
| } | |
| /* HEADER */ | |
| .header { | |
| position:absolute; top:0; left:0; right:0; | |
| z-index:100; | |
| display:flex; align-items:center; justify-content:space-between; | |
| padding:12px 16px; | |
| background: linear-gradient(180deg, rgba(10,10,10,0.95) 0%, transparent 100%); | |
| pointer-events:none; | |
| } | |
| .header > * { pointer-events:auto; } | |
| .header-left { display:flex; align-items:center; gap:10px; } | |
| .header-logo { | |
| font-family:'Playfair Display',serif; | |
| font-weight:900; font-size:20px; | |
| background: linear-gradient(135deg, var(--accent), var(--gold)); | |
| -webkit-background-clip:text; -webkit-text-fill-color:transparent; | |
| letter-spacing:1px; | |
| } | |
| .header-sub { | |
| font-size:9px; color:var(--muted); | |
| text-transform:uppercase; letter-spacing:2px; | |
| } | |
| .header-right { display:flex; gap:16px; align-items:center; } | |
| .header-right a { | |
| color:var(--muted); font-size:11px; | |
| text-decoration:none; transition:color .3s; | |
| font-weight:500; | |
| } | |
| .header-right a:hover { color:var(--accent); } | |
| .hdr-btn { | |
| background:none; border:none; color:var(--fg); | |
| font-size:18px; cursor:pointer; opacity:.7; | |
| transition:opacity .3s; | |
| } | |
| .hdr-btn:hover { opacity:1; } | |
| /* VIEWFINDER */ | |
| .viewfinder { | |
| flex:1; position:relative; | |
| display:flex; align-items:center; justify-content:center; | |
| background:#000; | |
| overflow:hidden; | |
| } | |
| .vf-canvas-wrap { | |
| position:relative; | |
| width:100%; height:100%; | |
| display:flex; align-items:center; justify-content:center; | |
| } | |
| #mainCanvas { | |
| max-width:100%; max-height:100%; | |
| object-fit:contain; | |
| } | |
| .vf-overlay { | |
| position:absolute; inset:0; | |
| pointer-events:none; | |
| z-index:10; | |
| } | |
| /* Film grain overlay */ | |
| .vf-grain { | |
| position:absolute; inset:0; | |
| opacity:0.04; | |
| background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); | |
| background-size:128px 128px; | |
| mix-blend-mode:overlay; | |
| animation: grainShift 0.3s steps(3) infinite; | |
| pointer-events:none; z-index:11; | |
| } | |
| @keyframes grainShift { | |
| 0% { transform:translate(0,0); } | |
| 33% { transform:translate(-2px,1px); } | |
| 66% { transform:translate(1px,-2px); } | |
| 100% { transform:translate(2px,2px); } | |
| } | |
| /* Vignette */ | |
| .vf-vignette { | |
| position:absolute; inset:0; | |
| background: radial-gradient(ellipse at center, transparent 50%, rgba(0,0,0,0.6) 100%); | |
| pointer-events:none; z-index:12; | |
| } | |
| /* Light leak */ | |
| .vf-lightleak { | |
| position:absolute; inset:0; | |
| pointer-events:none; z-index:13; | |
| opacity:0; | |
| transition: opacity 0.5s; | |
| mix-blend-mode:screen; | |
| } | |
| .vf-lightleak.active { opacity:1; } | |
| .vf-lightleak-warm { | |
| background: linear-gradient(135deg, rgba(255,180,80,0.15) 0%, transparent 40%, rgba(255,100,50,0.1) 100%); | |
| } | |
| .vf-lightleak-cool { | |
| background: linear-gradient(225deg, rgba(80,150,255,0.12) 0%, transparent 40%, rgba(150,80,255,0.08) 100%); | |
| } | |
| .vf-lightleak-rainbow { | |
| background: linear-gradient(135deg, rgba(255,80,80,0.08) 0%, rgba(255,200,80,0.06) 25%, rgba(80,255,80,0.05) 50%, rgba(80,80,255,0.08) 75%, rgba(200,80,255,0.06) 100%); | |
| } | |
| /* Corner info */ | |
| .vf-info-tl, .vf-info-tr, .vf-info-bl, .vf-info-br { | |
| position:absolute; z-index:20; | |
| font-size:10px; color:rgba(240,235,227,0.5); | |
| font-family:'DM Sans',monospace; | |
| letter-spacing:1px; | |
| } | |
| .vf-info-tl { top:60px; left:16px; } | |
| .vf-info-tr { top:60px; right:16px; text-align:right; } | |
| .vf-info-bl { bottom:100px; left:16px; } | |
| .vf-info-br { bottom:100px; right:16px; text-align:right; } | |
| /* Timestamp */ | |
| .vf-timestamp { | |
| position:absolute; bottom:108px; right:16px; | |
| font-family:'DM Sans',monospace; | |
| font-size:13px; color:rgba(255,120,80,0.8); | |
| z-index:20; letter-spacing:1px; | |
| text-shadow: 0 0 4px rgba(255,120,80,0.3); | |
| display:none; | |
| } | |
| .vf-timestamp.active { display:block; } | |
| /* FRAME OVERLAY */ | |
| .vf-frame { | |
| position:absolute; inset:0; | |
| pointer-events:none; z-index:15; | |
| display:none; | |
| } | |
| .vf-frame.active { display:block; } | |
| /* DOUBLE EXPOSURE INDICATOR */ | |
| .dx-indicator { | |
| position:absolute; top:56px; left:50%; | |
| transform:translateX(-50%); | |
| background:rgba(200,149,108,0.2); | |
| border:1px solid rgba(200,149,108,0.4); | |
| border-radius:20px; | |
| padding:4px 14px; | |
| font-size:10px; color:var(--accent); | |
| z-index:25; | |
| display:none; | |
| backdrop-filter:blur(8px); | |
| } | |
| .dx-indicator.active { display:flex; align-items:center; gap:6px; } | |
| /* BOTTOM CONTROLS */ | |
| .bottom-controls { | |
| position:absolute; bottom:0; left:0; right:0; | |
| z-index:50; | |
| background: linear-gradient(0deg, rgba(10,10,10,0.98) 0%, rgba(10,10,10,0.9) 70%, transparent 100%); | |
| padding:8px 0 12px; | |
| } | |
| /* Camera selector carousel */ | |
| .camera-carousel { | |
| display:flex; gap:10px; | |
| overflow-x:auto; | |
| padding:0 16px 8px; | |
| scroll-snap-type:x mandatory; | |
| scrollbar-width:none; | |
| } | |
| .camera-carousel::-webkit-scrollbar { display:none; } | |
| .cam-chip { | |
| flex-shrink:0; | |
| scroll-snap-align:center; | |
| display:flex; flex-direction:column; align-items:center; | |
| gap:4px; cursor:pointer; | |
| padding:8px 12px; | |
| border-radius:12px; | |
| border:1.5px solid transparent; | |
| transition: all .3s; | |
| min-width:72px; | |
| } | |
| .cam-chip:hover { background:rgba(200,149,108,0.08); } | |
| .cam-chip.active { | |
| border-color:var(--accent); | |
| background:rgba(200,149,108,0.12); | |
| } | |
| .cam-chip-icon { | |
| width:36px; height:36px; | |
| border-radius:8px; | |
| display:flex; align-items:center; justify-content:center; | |
| font-size:14px; font-weight:700; | |
| font-family:'Playfair Display',serif; | |
| position:relative; overflow:hidden; | |
| } | |
| .cam-chip-name { | |
| font-size:9px; color:var(--muted); | |
| text-transform:uppercase; letter-spacing:1px; | |
| white-space:nowrap; | |
| } | |
| .cam-chip.active .cam-chip-name { color:var(--accent); } | |
| /* Shutter row */ | |
| .shutter-row { | |
| display:flex; align-items:center; justify-content:center; | |
| gap:32px; padding:8px 0 4px; | |
| } | |
| .shutter-side-btn { | |
| background:none; border:none; | |
| color:var(--fg); font-size:22px; | |
| cursor:pointer; opacity:.6; | |
| transition:all .3s; | |
| width:44px; height:44px; | |
| display:flex; align-items:center; justify-content:center; | |
| border-radius:50%; | |
| } | |
| .shutter-side-btn:hover { opacity:1; background:rgba(255,255,255,0.05); } | |
| .shutter-btn { | |
| width:68px; height:68px; | |
| border-radius:50%; | |
| border:3px solid var(--fg); | |
| background:transparent; | |
| cursor:pointer; | |
| position:relative; | |
| transition:all .15s; | |
| } | |
| .shutter-btn::after { | |
| content:''; | |
| position:absolute; | |
| inset:4px; | |
| border-radius:50%; | |
| background:var(--fg); | |
| transition:all .15s; | |
| } | |
| .shutter-btn:hover::after { background:var(--accent); } | |
| .shutter-btn:active { transform:scale(0.92); } | |
| .shutter-btn:active::after { background:#e8e0d8; } | |
| .shutter-btn.recording { border-color:#e84040; } | |
| .shutter-btn.recording::after { | |
| background:#e84040; | |
| border-radius:6px; | |
| inset:20px; | |
| animation: recPulse 1s infinite; | |
| } | |
| @keyframes recPulse { 0%,100%{opacity:1;} 50%{opacity:.6;} } | |
| /* Mode tabs */ | |
| .mode-tabs { | |
| display:flex; justify-content:center; gap:20px; | |
| padding:6px 0 2px; | |
| } | |
| .mode-tab { | |
| background:none; border:none; | |
| color:var(--muted); font-size:11px; | |
| cursor:pointer; text-transform:uppercase; | |
| letter-spacing:2px; font-weight:500; | |
| transition:color .3s; | |
| position:relative; | |
| padding-bottom:4px; | |
| } | |
| .mode-tab::after { | |
| content:''; | |
| position:absolute; bottom:0; left:50%; transform:translateX(-50%); | |
| width:0; height:2px; | |
| background:var(--accent); | |
| border-radius:1px; | |
| transition:width .3s; | |
| } | |
| .mode-tab.active { color:var(--fg); } | |
| .mode-tab.active::after { width:100%; } | |
| /* PANELS */ | |
| .panel { | |
| position:absolute; inset:0; | |
| z-index:200; | |
| background:var(--bg); | |
| transform:translateX(100%); | |
| transition:transform .4s cubic-bezier(0.4,0,0.2,1); | |
| display:flex; flex-direction:column; | |
| } | |
| .panel.open { transform:translateX(0); } | |
| .panel-header { | |
| display:flex; align-items:center; justify-content:space-between; | |
| padding:16px 20px; | |
| border-bottom:1px solid var(--border); | |
| } | |
| .panel-title { | |
| font-family:'Playfair Display',serif; | |
| font-size:20px; font-weight:700; | |
| } | |
| .panel-close { | |
| background:none; border:none; | |
| color:var(--fg); font-size:20px; | |
| cursor:pointer; | |
| } | |
| .panel-body { | |
| flex:1; overflow-y:auto; | |
| padding:16px 20px; | |
| } | |
| /* EFFECTS PANEL */ | |
| .effect-category { | |
| margin-bottom:24px; | |
| } | |
| .effect-category-title { | |
| font-size:11px; text-transform:uppercase; | |
| letter-spacing:3px; color:var(--muted); | |
| margin-bottom:12px; | |
| display:flex; align-items:center; gap:8px; | |
| } | |
| .effect-category-title::after { | |
| content:''; flex:1; height:1px; | |
| background:var(--border); | |
| } | |
| .effect-grid { | |
| display:grid; | |
| grid-template-columns:repeat(auto-fill, minmax(80px,1fr)); | |
| gap:10px; | |
| } | |
| .effect-item { | |
| aspect-ratio:1; | |
| border-radius:12px; | |
| overflow:hidden; | |
| cursor:pointer; | |
| position:relative; | |
| border:2px solid transparent; | |
| transition:all .3s; | |
| } | |
| .effect-item:hover { transform:scale(1.05); } | |
| .effect-item.active { border-color:var(--accent); } | |
| .effect-item-inner { | |
| width:100%; height:100%; | |
| display:flex; align-items:center; justify-content:center; | |
| font-size:10px; text-transform:uppercase; | |
| letter-spacing:1px; color:rgba(255,255,255,0.8); | |
| text-shadow:0 1px 3px rgba(0,0,0,0.5); | |
| } | |
| .effect-item-label { | |
| position:absolute; bottom:4px; left:0; right:0; | |
| text-align:center; font-size:8px; | |
| color:rgba(255,255,255,0.7); | |
| text-transform:uppercase; letter-spacing:1px; | |
| } | |
| /* DOUBLE EXPOSURE PANEL */ | |
| .dx-panel { | |
| position:absolute; bottom:0; left:0; right:0; | |
| z-index:180; | |
| background:var(--glass); | |
| backdrop-filter:blur(20px); | |
| border-top:1px solid var(--border); | |
| border-radius:20px 20px 0 0; | |
| transform:translateY(100%); | |
| transition:transform .4s cubic-bezier(0.4,0,0.2,1); | |
| max-height:70vh; | |
| display:flex; flex-direction:column; | |
| } | |
| .dx-panel.open { transform:translateY(0); } | |
| .dx-handle { | |
| width:36px; height:4px; | |
| background:var(--muted); | |
| border-radius:2px; | |
| margin:10px auto 6px; | |
| } | |
| .dx-header { | |
| display:flex; align-items:center; justify-content:space-between; | |
| padding:0 20px 12px; | |
| } | |
| .dx-title { | |
| font-family:'Playfair Display',serif; | |
| font-size:16px; font-weight:700; | |
| } | |
| .dx-body { | |
| flex:1; overflow-y:auto; | |
| padding:0 20px 20px; | |
| } | |
| /* Slider */ | |
| .dx-slider-wrap { | |
| margin:16px 0; | |
| } | |
| .dx-slider-label { | |
| display:flex; justify-content:space-between; | |
| font-size:10px; color:var(--muted); | |
| text-transform:uppercase; letter-spacing:1px; | |
| margin-bottom:8px; | |
| } | |
| .dx-slider { | |
| -webkit-appearance:none; | |
| width:100%; height:6px; | |
| border-radius:3px; | |
| background:linear-gradient(90deg, var(--accent), var(--border) 50%, var(--film-teal)); | |
| outline:none; | |
| cursor:pointer; | |
| } | |
| .dx-slider::-webkit-slider-thumb { | |
| -webkit-appearance:none; | |
| width:22px; height:22px; | |
| border-radius:50%; | |
| background:var(--fg); | |
| border:3px solid var(--accent); | |
| cursor:pointer; | |
| box-shadow:0 2px 8px rgba(0,0,0,0.4); | |
| } | |
| /* Blend mode selector */ | |
| .blend-modes { | |
| display:flex; gap:8px; flex-wrap:wrap; | |
| margin:12px 0; | |
| } | |
| .blend-mode-btn { | |
| padding:6px 14px; | |
| border-radius:20px; | |
| border:1px solid var(--border); | |
| background:transparent; | |
| color:var(--muted); | |
| font-size:10px; text-transform:uppercase; | |
| letter-spacing:1px; | |
| cursor:pointer; | |
| transition:all .3s; | |
| } | |
| .blend-mode-btn.active { | |
| border-color:var(--accent); | |
| color:var(--accent); | |
| background:rgba(200,149,108,0.1); | |
| } | |
| /* Texture grid in DX */ | |
| .texture-grid { | |
| display:grid; | |
| grid-template-columns:repeat(4,1fr); | |
| gap:8px; | |
| margin:12px 0; | |
| } | |
| .texture-item { | |
| aspect-ratio:1; | |
| border-radius:10px; | |
| cursor:pointer; | |
| border:2px solid transparent; | |
| transition:all .3s; | |
| overflow:hidden; | |
| position:relative; | |
| } | |
| .texture-item.active { border-color:var(--accent); } | |
| .texture-item-label { | |
| position:absolute; bottom:2px; left:0; right:0; | |
| text-align:center; font-size:7px; | |
| color:rgba(255,255,255,0.8); | |
| text-transform:uppercase; letter-spacing:0.5px; | |
| } | |
| /* SETTINGS PANEL */ | |
| .setting-row { | |
| display:flex; align-items:center; justify-content:space-between; | |
| padding:14px 0; | |
| border-bottom:1px solid var(--border); | |
| } | |
| .setting-label { | |
| font-size:13px; color:var(--fg); | |
| } | |
| .setting-control { | |
| display:flex; align-items:center; gap:8px; | |
| } | |
| .setting-slider { | |
| -webkit-appearance:none; | |
| width:100px; height:4px; | |
| border-radius:2px; | |
| background:var(--border); | |
| outline:none; | |
| } | |
| .setting-slider::-webkit-slider-thumb { | |
| -webkit-appearance:none; | |
| width:16px; height:16px; | |
| border-radius:50%; | |
| background:var(--accent); | |
| cursor:pointer; | |
| } | |
| .setting-val { | |
| font-size:11px; color:var(--muted); | |
| min-width:28px; text-align:right; | |
| } | |
| .setting-toggle { | |
| width:44px; height:24px; | |
| border-radius:12px; | |
| background:var(--border); | |
| border:none; | |
| cursor:pointer; | |
| position:relative; | |
| transition:background .3s; | |
| } | |
| .setting-toggle.on { background:var(--accent); } | |
| .setting-toggle::after { | |
| content:''; | |
| position:absolute; | |
| top:2px; left:2px; | |
| width:20px; height:20px; | |
| border-radius:50%; | |
| background:#fff; | |
| transition:transform .3s; | |
| } | |
| .setting-toggle.on::after { transform:translateX(20px); } | |
| /* FRAMES PANEL */ | |
| .frame-grid { | |
| display:grid; | |
| grid-template-columns:repeat(3,1fr); | |
| gap:10px; | |
| } | |
| .frame-item { | |
| aspect-ratio:3/4; | |
| border-radius:10px; | |
| cursor:pointer; | |
| border:2px solid transparent; | |
| transition:all .3s; | |
| overflow:hidden; | |
| position:relative; | |
| background:var(--card); | |
| } | |
| .frame-item.active { border-color:var(--accent); } | |
| .frame-item-label { | |
| position:absolute; bottom:6px; left:0; right:0; | |
| text-align:center; font-size:8px; | |
| color:var(--muted); text-transform:uppercase; | |
| letter-spacing:1px; | |
| } | |
| .frame-preview { | |
| width:100%; height:100%; | |
| display:flex; align-items:center; justify-content:center; | |
| } | |
| /* GALLERY */ | |
| .gallery-grid { | |
| display:grid; | |
| grid-template-columns:repeat(3,1fr); | |
| gap:4px; | |
| } | |
| .gallery-thumb { | |
| aspect-ratio:1; | |
| border-radius:4px; | |
| overflow:hidden; | |
| cursor:pointer; | |
| transition:transform .2s; | |
| } | |
| .gallery-thumb:hover { transform:scale(1.02); } | |
| .gallery-thumb img, .gallery-thumb canvas { | |
| width:100%; height:100%; | |
| object-fit:cover; | |
| } | |
| /* CAMERA DETAIL PAGE */ | |
| .cam-detail { | |
| position:absolute; inset:0; | |
| z-index:250; | |
| background:var(--bg); | |
| transform:translateY(100%); | |
| transition:transform .5s cubic-bezier(0.4,0,0.2,1); | |
| display:flex; flex-direction:column; | |
| overflow:hidden; | |
| } | |
| .cam-detail.open { transform:translateY(0); } | |
| .cam-detail-hero { | |
| height:45vh; | |
| position:relative; | |
| overflow:hidden; | |
| } | |
| .cam-detail-hero-bg { | |
| position:absolute; inset:0; | |
| opacity:0.3; | |
| } | |
| .cam-detail-hero-content { | |
| position:absolute; inset:0; | |
| display:flex; flex-direction:column; | |
| align-items:center; justify-content:center; | |
| padding:20px; | |
| text-align:center; | |
| } | |
| .cam-detail-icon { | |
| width:80px; height:80px; | |
| border-radius:20px; | |
| display:flex; align-items:center; justify-content:center; | |
| font-size:28px; font-weight:900; | |
| font-family:'Playfair Display',serif; | |
| margin-bottom:16px; | |
| border:2px solid rgba(255,255,255,0.1); | |
| } | |
| .cam-detail-name { | |
| font-family:'Playfair Display',serif; | |
| font-size:28px; font-weight:900; | |
| margin-bottom:4px; | |
| } | |
| .cam-detail-sub { | |
| font-size:11px; color:var(--muted); | |
| text-transform:uppercase; letter-spacing:3px; | |
| } | |
| .cam-detail-body { | |
| flex:1; overflow-y:auto; | |
| padding:24px 20px; | |
| } | |
| .cam-detail-desc { | |
| font-size:14px; line-height:1.7; | |
| color:rgba(240,235,227,0.8); | |
| margin-bottom:24px; | |
| } | |
| .cam-detail-section-title { | |
| font-size:10px; text-transform:uppercase; | |
| letter-spacing:3px; color:var(--muted); | |
| margin-bottom:12px; | |
| } | |
| .color-chips { | |
| display:flex; gap:8px; flex-wrap:wrap; | |
| margin-bottom:24px; | |
| } | |
| .color-chip { | |
| width:32px; height:32px; | |
| border-radius:50%; | |
| border:2px solid rgba(255,255,255,0.1); | |
| cursor:pointer; | |
| transition:transform .2s; | |
| } | |
| .color-chip:hover { transform:scale(1.2); } | |
| .tip-card { | |
| background:var(--card); | |
| border-radius:12px; | |
| padding:16px; | |
| margin-bottom:12px; | |
| border:1px solid var(--border); | |
| } | |
| .tip-card-title { | |
| font-size:12px; font-weight:700; | |
| margin-bottom:6px; | |
| color:var(--accent); | |
| } | |
| .tip-card-text { | |
| font-size:12px; line-height:1.6; | |
| color:rgba(240,235,227,0.7); | |
| } | |
| .cam-detail-back { | |
| position:absolute; top:16px; left:16px; | |
| background:rgba(0,0,0,0.4); | |
| backdrop-filter:blur(8px); | |
| border:none; color:#fff; | |
| width:36px; height:36px; | |
| border-radius:50%; | |
| cursor:pointer; | |
| font-size:16px; | |
| z-index:10; | |
| display:flex; align-items:center; justify-content:center; | |
| } | |
| .cam-detail-fav { | |
| position:absolute; top:16px; right:16px; | |
| background:rgba(0,0,0,0.4); | |
| backdrop-filter:blur(8px); | |
| border:none; color:#fff; | |
| width:36px; height:36px; | |
| border-radius:50%; | |
| cursor:pointer; | |
| font-size:16px; | |
| z-index:10; | |
| display:flex; align-items:center; justify-content:center; | |
| } | |
| .cam-detail-fav.faved { color:var(--accent); } | |
| /* FLASH ANIMATION */ | |
| .flash-overlay { | |
| position:fixed; inset:0; | |
| background:#fff; | |
| z-index:9999; | |
| opacity:0; | |
| pointer-events:none; | |
| transition:opacity 0.05s; | |
| } | |
| .flash-overlay.flash { | |
| animation: flashAnim 0.4s ease-out; | |
| } | |
| @keyframes flashAnim { | |
| 0% { opacity:0.9; } | |
| 100% { opacity:0; } | |
| } | |
| /* TOAST */ | |
| .toast { | |
| position:fixed; top:60px; left:50%; | |
| transform:translateX(-50%) translateY(-20px); | |
| background:var(--glass); | |
| backdrop-filter:blur(12px); | |
| border:1px solid var(--border); | |
| border-radius:12px; | |
| padding:10px 20px; | |
| font-size:12px; color:var(--fg); | |
| z-index:10000; | |
| opacity:0; | |
| transition:all .3s; | |
| pointer-events:none; | |
| } | |
| .toast.show { | |
| opacity:1; | |
| transform:translateX(-50%) translateY(0); | |
| } | |
| /* IMPORT INPUT */ | |
| #importInput { display:none; } | |
| /* Responsive */ | |
| @media (min-width:768px) { | |
| .app { flex-direction:row; } | |
| .viewfinder { flex:1; } | |
| .bottom-controls { | |
| position:relative; | |
| background:var(--bg); | |
| width:320px; | |
| border-left:1px solid var(--border); | |
| } | |
| .camera-carousel { flex-wrap:wrap; } | |
| .shutter-row { padding:16px 0; } | |
| } | |
| /* Animated bg for cam chips */ | |
| @keyframes shimmer { | |
| 0% { background-position:-200% 0; } | |
| 100% { background-position:200% 0; } | |
| } | |
| .cam-chip-icon.shimmer { | |
| background: linear-gradient(90deg, var(--c1) 0%, var(--c2) 50%, var(--c1) 100%); | |
| background-size:200% 100%; | |
| animation: shimmer 3s ease infinite; | |
| } | |
| /* Mirror effect for frames */ | |
| .mirror-frame { | |
| position:absolute; inset:0; | |
| pointer-events:none; | |
| z-index:14; | |
| display:none; | |
| } | |
| .mirror-frame.active { | |
| display:block; | |
| } | |
| .mirror-surface { | |
| width:100%; height:100%; | |
| background: linear-gradient(135deg, | |
| rgba(255,255,255,0.03) 0%, | |
| rgba(255,255,255,0.08) 25%, | |
| rgba(255,255,255,0.02) 50%, | |
| rgba(255,255,255,0.06) 75%, | |
| rgba(255,255,255,0.03) 100% | |
| ); | |
| backdrop-filter:blur(0.5px); | |
| } | |
| /* Curtain / Lacquer effect */ | |
| .lacquer-overlay { | |
| position:absolute; inset:0; | |
| pointer-events:none; z-index:16; | |
| display:none; | |
| } | |
| .lacquer-overlay.active { display:block; } | |
| .lacquer-surface { | |
| width:100%; height:100%; | |
| background: linear-gradient(160deg, | |
| transparent 0%, | |
| rgba(255,255,255,0.04) 20%, | |
| rgba(255,255,255,0.1) 40%, | |
| rgba(255,255,255,0.02) 60%, | |
| rgba(255,255,255,0.07) 80%, | |
| transparent 100% | |
| ); | |
| animation: lacquerMove 8s ease-in-out infinite alternate; | |
| } | |
| @keyframes lacquerMove { | |
| 0% { background-position:0% 0%; } | |
| 100% { background-position:100% 100%; } | |
| } | |
| /* Photo counter badge */ | |
| .photo-counter { | |
| position:absolute; top:56px; left:16px; | |
| background:rgba(200,149,108,0.15); | |
| border:1px solid rgba(200,149,108,0.3); | |
| border-radius:8px; | |
| padding:2px 8px; | |
| font-size:10px; color:var(--accent); | |
| z-index:25; | |
| display:flex; align-items:center; gap:4px; | |
| } | |
| /* Aspect ratio guides */ | |
| .aspect-guide { | |
| position:absolute; | |
| border:1px dashed rgba(255,255,255,0.15); | |
| z-index:9; | |
| pointer-events:none; | |
| display:none; | |
| } | |
| .aspect-guide.active { display:block; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="app" id="app"> | |
| <!-- Flash overlay --> | |
| <div class="flash-overlay" id="flashOverlay"></div> | |
| <!-- Toast --> | |
| <div class="toast" id="toast"></div> | |
| <!-- Hidden file input --> | |
| <input type="file" id="importInput" accept="image/*"> | |
| <!-- HEADER --> | |
| <div class="header"> | |
| <div class="header-left"> | |
| <div> | |
| <div class="header-logo">Film Cam</div> | |
| <div class="header-sub">Vintage Analog</div> | |
| </div> | |
| </div> | |
| <div class="header-right"> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" rel="noopener" style="font-size:10px;letter-spacing:1px;">Built with anycoder</a> | |
| <button class="hdr-btn" onclick="openPanel('settings')" title="Einstellungen"><i class="fas fa-sliders-h"></i></button> | |
| <button class="hdr-btn" onclick="openPanel('gallery')" title="Galerie"><i class="fas fa-images"></i></button> | |
| </div> | |
| </div> | |
| <!-- VIEWFINDER --> | |
| <div class="viewfinder" id="viewfinder"> | |
| <div class="vf-canvas-wrap"> | |
| <canvas id="mainCanvas" width="720" height="960"></canvas> | |
| </div> | |
| <div class="vf-grain"></div> | |
| <div class="vf-vignette" id="vfVignette"></div> | |
| <div class="vf-lightleak vf-lightleak-warm" id="lightleakWarm"></div> | |
| <div class="vf-lightleak vf-lightleak-cool" id="lightleakCool"></div> | |
| <div class="vf-lightleak vf-lightleak-rainbow" id="lightleakRainbow"></div> | |
| <div class="vf-timestamp" id="vfTimestamp"></div> | |
| <div class="mirror-frame" id="mirrorFrame"><div class="mirror-surface"></div></div> | |
| <div class="lacquer-overlay" id="lacquerOverlay"><div class="lacquer-surface"></div></div> | |
| <div class="dx-indicator" id="dxIndicator"><i class="fas fa-layer-group"></i> Doppelbelichtung</div> | |
| <div class="photo-counter" id="photoCounter"><i class="fas fa-film"></i> <span id="photoCount">0</span></div> | |
| <div class="aspect-guide" id="aspectGuide"></div> | |
| </div> | |
| <!-- BOTTOM CONTROLS --> | |
| <div class="bottom-controls" id="bottomControls"> | |
| <!-- Mode tabs --> | |
| <div class="mode-tabs"> | |
| <button class="mode-tab active" data-mode="photo" onclick="switchMode('photo')">Foto</button> | |
| <button class="mode-tab" data-mode="video" onclick="switchMode('video')">Video</button> | |
| <button class="mode-tab" data-mode="import" onclick="triggerImport()">Import</button> | |
| </div> | |
| <!-- Camera carousel --> | |
| <div class="camera-carousel" id="cameraCarousel"></div> | |
| <!-- Shutter row --> | |
| <div class="shutter-row"> | |
| <button class="shutter-side-btn" onclick="openDXPanel()" title="Doppelbelichtung"><i class="fas fa-clone"></i></button> | |
| <button class="shutter-side-btn" onclick="toggleTimer()" title="Timer" id="timerBtn"><i class="fas fa-clock"></i></button> | |
| <button class="shutter-btn" id="shutterBtn" onclick="capturePhoto()"></button> | |
| <button class="shutter-side-btn" onclick="flipCamera()" title="Drehen"><i class="fas fa-sync-alt"></i></button> | |
| <button class="shutter-side-btn" onclick="openPanel('effects')" title="Effekte"><i class="fas fa-magic"></i></button> | |
| </div> | |
| </div> | |
| <!-- CAMERA DETAIL PAGE --> | |
| <div class="cam-detail" id="camDetail"> | |
| <button class="cam-detail-back" onclick="closeCamDetail()"><i class="fas fa-chevron-left"></i></button> | |
| <button class="cam-detail-fav" id="camFavBtn" onclick="toggleFav()"><i class="far fa-heart"></i></button> | |
| <div class="cam-detail-hero"> | |
| <div class="cam-detail-hero-bg" id="camDetailBg"></div> | |
| <div class="cam-detail-hero-content"> | |
| <div class="cam-detail-icon" id="camDetailIcon"></div> | |
| <div class="cam-detail-name" id="camDetailName"></div> | |
| <div class="cam-detail-sub" id="camDetailSub"></div> | |
| </div> | |
| </div> | |
| <div class="cam-detail-body"> | |
| <div class="cam-detail-desc" id="camDetailDesc"></div> | |
| <div class="cam-detail-section-title">Farbpalette</div> | |
| <div class="color-chips" id="camDetailColors"></div> | |
| <div class="cam-detail-section-title">Tipps für perfekte Aufnahmen</div> | |
| <div id="camDetailTips"></div> | |
| </div> | |
| </div> | |
| <!-- EFFECTS PANEL --> | |
| <div class="panel" id="effectsPanel"> | |
| <div class="panel-header"> | |
| <div class="panel-title">Effekte</div> | |
| <button class="panel-close" onclick="closePanel('effects')"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="panel-body"> | |
| <!-- Light effects --> | |
| <div class="effect-category"> | |
| <div class="effect-category-title">Lichteffekte</div> | |
| <div class="effect-grid" id="lightEffectGrid"></div> | |
| </div> | |
| <!-- Texture effects --> | |
| <div class="effect-category"> | |
| <div class="effect-category-title">Textureffekte</div> | |
| <div class="effect-grid" id="textureEffectGrid"></div> | |
| </div> | |
| <!-- Scratch / Noise --> | |
| <div class="effect-category"> | |
| <div class="effect-category-title">Kratzer & Rauschen</div> | |
| <div class="effect-grid" id="scratchEffectGrid"></div> | |
| </div> | |
| <!-- Creative --> | |
| <div class="effect-category"> | |
| <div class="effect-category-title">Kreativ</div> | |
| <div class="effect-grid" id="creativeEffectGrid"></div> | |
| </div> | |
| <!-- Frames --> | |
| <div class="effect-category"> | |
| <div class="effect-category-title">Rahmen</div> | |
| <div class="frame-grid" id="frameGrid"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- SETTINGS PANEL --> | |
| <div class="panel" id="settingsPanel"> | |
| <div class="panel-header"> | |
| <div class="panel-title">Einstellungen</div> | |
| <button class="panel-close" onclick="closePanel('settings')"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="panel-body"> | |
| <div class="setting-row"> | |
| <span class="setting-label">Belichtung</span> | |
| <div class="setting-control"> | |
| <input type="range" class="setting-slider" min="-100" max="100" value="0" id="exposureSlider" oninput="updateSetting('exposure',this.value)"> | |
| <span class="setting-val" id="exposureVal">0</span> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Brennweite</span> | |
| <div class="setting-control"> | |
| <input type="range" class="setting-slider" min="10" max="200" value="50" id="focalSlider" oninput="updateSetting('focal',this.value)"> | |
| <span class="setting-val" id="focalVal">50</span> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Weißabgleich</span> | |
| <div class="setting-control"> | |
| <input type="range" class="setting-slider" min="2500" max="9000" value="5500" id="wbSlider" oninput="updateSetting('wb',this.value)"> | |
| <span class="setting-val" id="wbVal">5500K</span> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Seitenverhältnis</span> | |
| <div class="setting-control"> | |
| <select id="aspectSelect" onchange="updateSetting('aspect',this.value)" style="background:var(--card);color:var(--fg);border:1px solid var(--border);border-radius:8px;padding:6px 10px;font-size:12px;"> | |
| <option value="4:3">4:3</option> | |
| <option value="1:1">1:1</option> | |
| <option value="16:9">16:9</option> | |
| <option value="3:2">3:2</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Blitz</span> | |
| <div class="setting-control"> | |
| <button class="setting-toggle" id="flashToggle" onclick="toggleSetting('flash')"></button> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Zeitstempel</span> | |
| <div class="setting-control"> | |
| <button class="setting-toggle" id="timestampToggle" onclick="toggleSetting('timestamp')"></button> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Vignette</span> | |
| <div class="setting-control"> | |
| <button class="setting-toggle on" id="vignetteToggle" onclick="toggleSetting('vignette')"></button> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Filmkörnung</span> | |
| <div class="setting-control"> | |
| <button class="setting-toggle on" id="grainToggle" onclick="toggleSetting('grain')"></button> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Spiegel-Effekt</span> | |
| <div class="setting-control"> | |
| <button class="setting-toggle" id="mirrorToggle" onclick="toggleSetting('mirror')"></button> | |
| </div> | |
| </div> | |
| <div class="setting-row"> | |
| <span class="setting-label">Lack/Vorhang-Effekt</span> | |
| <div class="setting-control"> | |
| <button class="setting-toggle" id="lacquerToggle" onclick="toggleSetting('lacquer')"></button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- GALLERY PANEL --> | |
| <div class="panel" id="galleryPanel"> | |
| <div class="panel-header"> | |
| <div class="panel-title">Galerie</div> | |
| <button class="panel-close" onclick="closePanel('gallery')"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="panel-body"> | |
| <div class="gallery-grid" id="galleryGrid"> | |
| <div style="grid-column:1/-1;text-align:center;padding:40px 0;color:var(--muted);font-size:13px;"> | |
| <i class="fas fa-camera-retro" style="font-size:32px;margin-bottom:12px;display:block;opacity:.3;"></i> | |
| Noch keine Fotos aufgenommen | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- DOUBLE EXPOSURE PANEL --> | |
| <div class="dx-panel" id="dxPanel"> | |
| <div class="dx-handle"></div> | |
| <div class="dx-header"> | |
| <div class="dx-title">Doppelbelichtung</div> | |
| <button style="background:none;border:none;color:var(--muted);cursor:pointer;" onclick="closeDXPanel()"><i class="fas fa-times"></i></button> | |
| </div> | |
| <div class="dx-body"> | |
| <!-- Blend mode --> | |
| <div style="font-size:10px;text-transform:uppercase;letter-spacing:2px;color:var(--muted);margin-bottom:8px;">Mischmodus</div> | |
| <div class="blend-modes" id="blendModes"></div> | |
| <!-- Opacity slider --> | |
| <div class="dx-slider-wrap"> | |
| <div class="dx-slider-label"> | |
| <span>Original</span> | |
| <span>Effekt</span> | |
| </div> | |
| <input type="range" class="dx-slider" min="0" max="100" value="50" id="dxOpacitySlider" oninput="updateDXOpacity(this.value)"> | |
| </div> | |
| <!-- Texture selection --> | |
| <div style="font-size:10px;text-transform:uppercase;letter-spacing:2px;color:var(--muted);margin:16px 0 8px;">Textur überlagern</div> | |
| <div class="texture-grid" id="textureGrid"></div> | |
| <!-- Second camera overlay --> | |
| <div style="font-size:10px;text-transform:uppercase;letter-spacing:2px;color:var(--muted);margin:16px 0 8px;">Zweite Kamera überlagern</div> | |
| <div class="dx-slider-wrap"> | |
| <div class="dx-slider-label"> | |
| <span>Kamera 1</span> | |
| <span>Kamera 2</span> | |
| </div> | |
| <input type="range" class=" |