IKP Builder – Desktop
Offline-Version des Karteikarten-Builders. Trage hier die passende Release-Datei ein.
001<?php002/**003 * Pixel3DLab – complete illustrative page source.004 * This file is displayed as background decoration; it is not executed.005 */006declare(strict_types=1);007session_start();008 009$page = filter_input(INPUT_GET, 'page') ?? 'home';010$theme = $_SESSION['theme'] ?? 'light';011 012$tools = [013 [014 'title' => 'Preisrechner',015 'description' => 'Material und Druckzeit kalkulieren.',016 'href' => '?page=calculator',017 'category' => 'browser',018 ],019 [020 'title' => 'Temp Tower Generator',021 'description' => 'Temperaturprofile vergleichen.',022 'href' => '?page=temp_tower',023 'category' => '3d-print',024 ],025 [026 'title' => 'STL Repair',027 'description' => 'Modelle für den nächsten Druck vorbereiten.',028 'href' => '?page=stl_repair',029 'category' => 'model',030 ],031 [032 'title' => 'Maps & Texturen',033 'description' => 'Texturen für kreative Projekte erzeugen.',034 'href' => '?page=normal_map',035 'category' => 'graphics',036 ],037 [038 'title' => 'Seamless Generator',039 'description' => 'Nahtlose Oberflächen erstellen.',040 'href' => '?page=seamless_texture',041 'category' => 'texture',042 ],043];044 045$downloads = [046 ['title' => 'IKP Builder Desktop', 'version' => '1.0.0', 'file' => 'downloads/ikp-builder.zip'],047 ['title' => 'Folder Structure Builder', 'version' => '5.4.1', 'file' => 'downloads/folder-builder.zip'],048];049 050function escapeOutput(string $value): string051{052 return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');053}054 055$toolCount = count($tools);056$downloadCount = count($downloads);057?>058<!DOCTYPE html>059<html lang="de" data-theme="<?= escapeOutput((string) $theme) ?>">060<head>061 <meta charset="UTF-8">062 <meta name="viewport" content="width=device-width, initial-scale=1">063 <meta name="description" content="Nützliche Tools, eigene Programme und Downloads von Pixel3DLab.">064 <meta name="theme-color" content="#0b1626">065 <title>Pixel3DLab – Tools & Downloads</title>066 <style>067 :root {068 --page: #f5f8fc;069 --surface: rgba(255, 255, 255, .52);070 --text: #243348;071 --muted: #64748b;072 --accent: #3ea0ff;073 --cyan: #55e1ff;074 --line: rgba(100, 116, 139, .22);075 }076 [data-theme="dark"] {077 --page: #0b1220;078 --surface: rgba(12, 24, 40, .50);079 --text: #e7edf6;080 --muted: #9aaac0;081 --line: rgba(148, 163, 184, .20);082 }083 * { box-sizing: border-box; }084 html { scroll-behavior: smooth; scroll-padding-top: 90px; }085 body {086 min-width: 320px;087 margin: 0;088 color: var(--text);089 background: var(--page);090 font: 16px/1.65 system-ui, sans-serif;091 }092 a { color: inherit; }093 button { font: inherit; cursor: pointer; }094 .site-header {095 position: sticky;096 top: 0;097 z-index: 50;098 display: flex;099 align-items: center;100 justify-content: space-between;101 min-height: 76px;102 padding: 12px 5vw;103 border-bottom: 1px solid var(--line);104 background: var(--surface);105 backdrop-filter: blur(22px) saturate(140%);106 }107 .brand { font-weight: 850; letter-spacing: -.05em; text-decoration: none; }108 .site-nav { display: flex; align-items: center; gap: 10px; }109 .site-nav a { padding: 8px 12px; border-radius: 9px; text-decoration: none; }110 .site-nav a:hover { color: var(--accent); background: rgba(62, 160, 255, .08); }111 .site-shell { position: relative; isolation: isolate; overflow: clip; }112 .container { width: min(1180px, calc(100% - 40px)); margin-inline: auto; }113 .section { position: relative; padding: clamp(60px, 8vw, 108px) 0; }114 .eyebrow { color: var(--accent); font: 700 11px/1.4 ui-monospace, Consolas, monospace; letter-spacing: .14em; text-transform: uppercase; }115 h1, h2, h3 { line-height: 1.05; letter-spacing: -.04em; }116 h1 { font-size: clamp(42px, 7vw, 82px); }117 h2 { font-size: clamp(30px, 4.5vw, 54px); }118 p { color: var(--muted); }119 .glass-card {120 border: 1px solid var(--line);121 border-radius: 16px;122 background: var(--surface);123 backdrop-filter: blur(16px) saturate(135%);124 box-shadow: 0 18px 46px rgba(15, 23, 42, .07);125 }126 .hero { min-height: 690px; display: grid; align-items: center; padding: 100px 0; }127 .hero-inner { max-width: 780px; }128 .hero-lead { max-width: 650px; font-size: clamp(16px, 1.8vw, 19px); }129 .button-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }130 .button { display: inline-flex; align-items: center; gap: 9px; padding: 12px 16px; border-radius: 10px; text-decoration: none; font-weight: 750; }131 .button-primary { color: #061522; background: var(--cyan); }132 .button-secondary { border: 1px solid var(--line); background: var(--surface); }133 .tool-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 15px; }134 .tool-card { display: flex; flex-direction: column; min-height: 235px; padding: 22px; text-decoration: none; }135 .tool-card h3 { margin-top: 32px; font-size: 19px; }136 .tool-card p { flex: 1; font-size: 13px; }137 .download-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }138 .download-card { display: flex; justify-content: space-between; gap: 20px; padding: 22px; }139 .site-footer { padding: 68px 0 24px; border-top: 1px solid var(--line); }140 @media (max-width: 760px) {141 .site-nav { gap: 5px; }142 .site-nav a { padding: 7px; font-size: 12px; }143 .tool-grid, .download-grid { grid-template-columns: 1fr; }144 .section { padding: 58px 0; }145 }146 </style>147</head>148<body>149 <div class="site-shell">150 <header class="site-header">151 <a class="brand" href="?page=home">Pixel3DLab</a>152 <nav class="site-nav" aria-label="Hauptnavigation">153 <a href="?page=home">Startseite</a>154 <a href="?page=forum">Forum</a>155 <a href="#tools">Tools</a>156 <a href="?page=login">Login</a>157 </nav>158 <button type="button" data-theme-toggle aria-pressed="false">Theme wechseln</button>159 </header>160 <main id="main-content">161 <section class="hero section">162 <div class="container hero-inner">163 <p class="eyebrow">Digital Workshop / Pixel3DLab</p>164 <h1>Nützliche Tools.<br>Eigene Ideen.</h1>165 <p class="hero-lead">Praktische Programme und kleine Helfer für kreative und technische Aufgaben.</p>166 <div class="button-row">167 <a class="button button-primary" href="#tools">Werkzeuge entdecken</a>168 <a class="button button-secondary" href="#downloads">Downloads ansehen</a>169 </div>170 </div>171 </section>172 <section class="section" id="intro">173 <div class="container intro-grid">174 <p class="eyebrow">01 / Die Idee</p>175 <article class="glass-card intro-card">176 <h2>Weniger Umwege. Mehr Möglichkeiten.</h2>177 <p>Tools sollen eine Aufgabe vereinfachen und sich selbstverständlich bedienen lassen.</p>178 <p>Jedes Projekt beginnt mit einem Problem, einer Idee oder einem kleinen Experiment.</p>179 </article>180 </div>181 </section>182 <section class="section" id="tools">183 <div class="container">184 <p class="eyebrow">02 / Toolbox</p>185 <h2>Was brauchst du heute?</h2>186 <div class="tool-grid">187 <?php foreach ($tools as $tool): ?>188 <a class="glass-card tool-card" href="<?= escapeOutput($tool['href']) ?>">189 <span class="tool-kind"><?= escapeOutput($tool['category']) ?></span>190 <h3><?= escapeOutput($tool['title']) ?></h3>191 <p><?= escapeOutput($tool['description']) ?></p>192 </a>193 <?php endforeach; ?>194 </div>195 </div>196 </section>197 <section class="section" id="downloads">198 <div class="container">199 <p class="eyebrow">03 / Downloads</p>200 <h2>Tools für deinen Rechner.</h2>201 <div class="download-grid">202 <?php foreach ($downloads as $download): ?>203 <article class="glass-card download-card">204 <div>205 <h3><?= escapeOutput($download['title']) ?></h3>206 <p>Version <?= escapeOutput($download['version']) ?></p>207 </div>208 <a href="<?= escapeOutput($download['file']) ?>" download>Download</a>209 </article>210 <?php endforeach; ?>211 </div>212 </div>213 </section>214 <section class="section" id="community">215 <div class="container glass-card community-card">216 <p class="eyebrow">04 / Community</p>217 <h2>Ideen werden besser, wenn man sie teilt.</h2>218 <p>Im Forum finden Fragen, Feedback und neue Projektideen ihren Platz.</p>219 <a href="?page=forum">Zum Forum</a>220 </div>221 </section>222 </main>223 <footer class="site-footer">224 <div class="container footer-grid">225 <a class="brand" href="?page=home">Pixel3DLab</a>226 <p>Eine Werkstatt für digitale Ideen.</p>227 <a href="#impressum">Impressum</a>228 </div>229 </footer>230 </div>231 <script>232 (() => {233 const root = document.documentElement;234 const themeToggle = document.querySelector('[data-theme-toggle]');235 const storedTheme = localStorage.getItem('theme');236 if (storedTheme === 'dark' || storedTheme === 'light') {237 root.dataset.theme = storedTheme;238 }239 themeToggle?.addEventListener('click', () => {240 const next = root.dataset.theme === 'dark' ? 'light' : 'dark';241 root.dataset.theme = next;242 localStorage.setItem('theme', next);243 });244 const toolCards = document.querySelectorAll('.tool-card');245 toolCards.forEach((card, index) => {246 card.style.setProperty('--card-index', String(index));247 });248 })();249 </script>250</body>251</html>
001/* Pixel3DLab – complete layout stylesheet */002:root {003 --page-bg: #f4f7fb;004 --surface: rgba(255, 255, 255, .54);005 --surface-strong: rgba(255, 255, 255, .72);006 --text: #243348;007 --muted: #64748b;008 --line: rgba(100, 116, 139, .22);009 --accent: #3ea0ff;010 --accent-soft: rgba(62, 160, 255, .10);011 --cyan: #55e1ff;012 --violet: #8586ff;013 --radius: 16px;014 --content-width: 1180px;015 --shadow: 0 18px 48px rgba(15, 23, 42, .08);016}017 018[data-theme="dark"] {019 --page-bg: #0b1220;020 --surface: rgba(12, 24, 40, .50);021 --surface-strong: rgba(12, 24, 40, .70);022 --text: #e7edf6;023 --muted: #9aaac0;024 --line: rgba(148, 163, 184, .20);025 --shadow: 0 24px 60px rgba(0, 0, 0, .24);026}027 028* { box-sizing: border-box; }029html { scroll-behavior: smooth; scroll-padding-top: 92px; }030body {031 min-width: 320px;032 margin: 0;033 color: var(--text);034 background: var(--page-bg);035 font: 16px/1.65 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;036}037img { display: block; max-width: 100%; }038a { color: inherit; }039button, input, select, textarea { font: inherit; }040button, a { -webkit-tap-highlight-color: transparent; }041:focus-visible { outline: 3px solid #ffeb3b; outline-offset: 3px; }042 043.site-header {044 position: sticky;045 top: 0;046 z-index: 1000;047 display: flex;048 align-items: center;049 justify-content: space-between;050 min-height: 76px;051 padding: 12px clamp(18px, 4vw, 54px);052 border-bottom: 1px solid var(--line);053 background: var(--surface);054 backdrop-filter: blur(22px) saturate(140%);055 -webkit-backdrop-filter: blur(22px) saturate(140%);056}057.site-brand { font-weight: 850; letter-spacing: -.05em; text-decoration: none; }058.site-nav { display: flex; align-items: center; gap: 8px; }059.site-nav a { padding: 8px 12px; border-radius: 9px; text-decoration: none; font-size: 13px; font-weight: 700; }060.site-nav a:hover { background: var(--accent-soft); color: var(--accent); }061 062.page-shell { position: relative; isolation: isolate; overflow: clip; }063.page-content { position: relative; z-index: 2; }064.page-section { position: relative; padding: clamp(60px, 8vw, 108px) 0; }065.container { width: min(var(--content-width), calc(100% - 40px)); margin-inline: auto; }066.section-label { margin: 0 0 16px; color: var(--accent); font: 700 11px/1.4 ui-monospace, Consolas, monospace; letter-spacing: .14em; text-transform: uppercase; }067h1, h2, h3 { line-height: 1.06; letter-spacing: -.04em; }068h1 { font-size: clamp(42px, 7vw, 82px); }069h2 { font-size: clamp(30px, 4.4vw, 52px); }070p { color: var(--muted); }071 072.glass-card {073 border: 1px solid var(--line);074 border-radius: var(--radius);075 background: var(--surface);076 backdrop-filter: blur(16px) saturate(135%);077 -webkit-backdrop-filter: blur(16px) saturate(135%);078 box-shadow: var(--shadow);079}080.hero { min-height: 690px; display: grid; align-items: center; padding: 100px 0; }081.hero-layout { display: grid; grid-template-columns: 1.1fr .9fr; align-items: center; gap: clamp(28px, 5vw, 70px); }082.hero-copy { max-width: 720px; }083.hero-lead { max-width: 650px; font-size: clamp(16px, 1.8vw, 19px); }084.button-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }085.button { display: inline-flex; align-items: center; gap: 9px; padding: 12px 16px; border-radius: 10px; text-decoration: none; font-weight: 750; }086.button-primary { color: #061522; background: var(--cyan); }087.button-secondary { color: var(--text); background: var(--surface); border: 1px solid var(--line); }088 089.intro-section { background: transparent; }090.intro-grid { display: grid; grid-template-columns: .5fr 1.5fr; gap: 38px; }091.intro-panel { padding: clamp(24px, 4vw, 44px); }092.feature-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 26px; }093.feature { display: flex; gap: 12px; padding: 16px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; }094.feature-icon { flex: 0 0 36px; width: 36px; height: 36px; border-radius: 10px; background: var(--accent-soft); }095 096.tools-section { border-block: 1px solid var(--line); background: rgba(62, 160, 255, .025); }097.section-heading { display: flex; justify-content: space-between; align-items: end; gap: 30px; margin-bottom: 32px; }098.section-heading p { max-width: 420px; margin-bottom: 4px; }099.tool-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 15px; }100.tool-card { display: flex; flex-direction: column; min-height: 240px; padding: 22px; text-decoration: none; transition: border-color .2s ease, transform .2s ease, background .2s ease; }101.tool-card:hover { transform: translateY(-3px); border-color: rgba(62, 160, 255, .42); background: var(--surface-strong); }102.tool-card h3 { margin-top: 32px; font-size: 19px; }103.tool-card p { flex: 1; font-size: 13px; }104.tool-card .tool-link { color: var(--accent); font-size: 12px; font-weight: 750; }105 106.download-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }107.download-card { display: flex; flex-direction: column; min-height: 240px; padding: 22px; }108.download-card p { flex: 1; font-size: 13px; }109.download-action { display: inline-flex; align-items: center; gap: 8px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 9px; text-decoration: none; }110.download-action[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }111 112.community-panel { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; align-items: center; gap: 22px; padding: clamp(24px, 4vw, 44px); }113.community-panel p { max-width: 650px; }114.site-footer { padding: 64px 0 24px; border-top: 1px solid var(--line); }115.footer-main { display: grid; grid-template-columns: 1.5fr repeat(3, 1fr); gap: 28px; }116.footer-column { display: grid; align-content: start; gap: 9px; }117.footer-column a { color: var(--muted); text-decoration: none; font-size: 13px; }118.footer-column a:hover { color: var(--accent); }119.footer-bottom { display: flex; justify-content: space-between; gap: 20px; margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--line); font-size: 11px; }120 121@media (max-width: 900px) {122 .hero-layout { grid-template-columns: 1fr; }123 .intro-grid { grid-template-columns: 1fr; gap: 20px; }124 .tool-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }125 .footer-main { grid-template-columns: repeat(2, minmax(0, 1fr)); }126}127@media (max-width: 620px) {128 .site-nav a { padding: 8px; font-size: 12px; }129 .tool-grid, .download-grid, .feature-grid { grid-template-columns: 1fr; }130 .section-heading { display: block; }131 .section-heading p { margin-top: 16px; }132 .community-panel { grid-template-columns: 1fr; }133 .footer-main { grid-template-columns: 1fr 1fr; }134 .footer-bottom { display: grid; }135}136@media (prefers-reduced-motion: reduce) {137 html { scroll-behavior: auto; }138 *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }139}140 141/* Accessible states and small interface details */142.site-nav a[aria-current="location"] {143 color: var(--accent);144 background: var(--accent-soft);145}146.skip-link {147 position: fixed;148 top: 8px;149 left: 8px;150 z-index: 10000;151 padding: 10px 14px;152 color: #111827;153 background: #ffeb3b;154 border-radius: 8px;155 font-weight: 800;156 transform: translateY(-150%);157}158.skip-link:focus { transform: translateY(0); }159.scroll-progress {160 position: fixed;161 top: 0;162 left: 0;163 z-index: 1500;164 width: 100%;165 height: 2px;166 background: transparent;167 transform: scaleX(0);168 transform-origin: left center;169}170.scroll-progress::before {171 content: "";172 position: absolute;173 inset: 0;174 background: linear-gradient(90deg, var(--accent), var(--cyan), var(--violet));175}176.notice {177 display: flex;178 align-items: flex-start;179 gap: 12px;180 padding: 16px;181 border: 1px solid var(--line);182 border-radius: 12px;183 background: var(--surface);184}185.notice strong { display: block; margin-bottom: 3px; }186.notice p { margin: 0; font-size: 13px; }187.form-control {188 width: 100%;189 min-height: 44px;190 padding: 10px 12px;191 border: 1px solid var(--line);192 border-radius: 9px;193 background: var(--surface-strong);194 color: var(--text);195}196.form-control:focus { border-color: var(--accent); outline: 2px solid rgba(62,160,255,.14); }197.badge {198 display: inline-flex;199 align-items: center;200 gap: 6px;201 padding: 5px 8px;202 border: 1px solid var(--line);203 border-radius: 999px;204 color: var(--muted);205 font: 10px/1 ui-monospace, Consolas, monospace;206}207.badge-dot { width: 6px; height: 6px; border-radius: 50%; background: #58d7a6; }208.icon-button {209 display: inline-grid;210 place-items: center;211 width: 40px;212 height: 40px;213 border: 1px solid var(--line);214 border-radius: 10px;215 background: var(--surface);216 color: var(--text);217}218.icon-button:hover { background: var(--surface-strong); }219.card-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; color: var(--muted); font-size: 11px; }220.card-divider { height: 1px; border: 0; background: var(--line); margin: 20px 0; }221.empty-state { padding: 32px; border: 1px dashed var(--line); border-radius: 14px; text-align: center; }222.empty-state p { max-width: 540px; margin-inline: auto; }223.pagination { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 28px; }224.pagination a { min-width: 38px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 8px; text-align: center; text-decoration: none; }225.pagination a[aria-current="page"] { color: #061522; border-color: var(--cyan); background: var(--cyan); }226 227@media (hover: hover) and (pointer: fine) {228 .glass-card { transition: border-color .22s ease, background .22s ease, box-shadow .22s ease; }229 .glass-card:hover { border-color: rgba(62,160,255,.34); }230}231@media (max-width: 480px) {232 .site-header { padding-inline: 12px; }233 .brand { font-size: 15px; }234 .hero { padding-block: 72px; }235 .hero h1 { font-size: clamp(38px, 12vw, 54px); }236 .tool-card, .download-card { padding: 18px; }237 .footer-main { gap: 20px 12px; }238}239@media print {240 .site-header, .scroll-progress, .button-row { display: none !important; }241 body { color: #111; background: #fff; }242 .glass-card { box-shadow: none; backdrop-filter: none; background: #fff; }243 .page-section { padding-block: 24px; }244}245 246 247 248/* Tool search, validation and small notice components */249.tool-search { display: grid; grid-template-columns: 1fr auto; gap: 10px; margin: 0 0 24px; }250.tool-search input { width: 100%; min-height: 44px; padding: 10px 13px; border: 1px solid var(--line); border-radius: 10px; color: var(--text); background: var(--surface); }251.tool-search input:focus-visible { outline: 3px solid rgba(62, 160, 255, .42); outline-offset: 2px; }252.tool-card[hidden] { display: none !important; }253.has-validation-error :invalid { border-color: #e45b68; box-shadow: 0 0 0 3px rgba(228, 91, 104, .12); }254.field-help { display: block; margin-top: 5px; color: var(--muted); font-size: 12px; }255.field-error { display: none; margin-top: 6px; color: #e45b68; font-size: 12px; }256.has-validation-error :invalid + .field-error { display: block; }257.site-notice { position: fixed; right: 22px; bottom: 22px; z-index: 12000; max-width: min(420px, calc(100vw - 44px)); padding: 13px 16px; border: 1px solid var(--line); border-radius: 11px; color: var(--text); background: var(--surface-strong); box-shadow: var(--shadow); backdrop-filter: blur(18px); opacity: 0; transform: translateY(8px); pointer-events: none; transition: opacity .2s ease, transform .2s ease; }258.site-notice.is-visible { opacity: 1; transform: none; }259.site-notice[data-type="success"] { border-color: rgba(88, 215, 166, .45); }260.site-notice[data-type="error"] { border-color: rgba(228, 91, 104, .5); }261.copy-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 38px; padding: 8px 11px; border: 1px solid var(--line); border-radius: 8px; color: var(--text); background: var(--surface); cursor: pointer; }262.copy-button:hover { border-color: rgba(62, 160, 255, .45); background: var(--surface-strong); }263.copy-button:active { transform: translateY(1px); }264.tool-card[aria-current="true"] { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(62, 160, 255, .12); }265.tool-card .tool-kind { align-self: flex-start; padding: 4px 7px; border: 1px solid var(--line); border-radius: 6px; color: var(--muted); font: 10px ui-monospace, Consolas, monospace; text-transform: uppercase; }266.tool-card .tool-arrow { width: 18px; height: 18px; margin-top: 16px; color: var(--accent); }267.tool-card:focus-visible, .download-action:focus-visible { outline: 3px solid #ffeb3b; outline-offset: 4px; }268 269/* Optional high-contrast theme for system accessibility settings */270@media (prefers-contrast: more) {271 :root { --line: rgba(30, 41, 59, .45); }272 [data-theme="dark"] { --line: rgba(226, 232, 240, .48); }273 a { text-decoration-thickness: .09em; }274 .glass-card { box-shadow: none; }275}276 277/* Landscape tablets use a tighter content grid */278@media (min-width: 621px) and (max-width: 1024px) {279 .container { width: min(var(--content-width), calc(100% - 56px)); }280 .hero-layout { gap: 28px; }281 .tool-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }282 .feature-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }283 .community-panel { grid-template-columns: 48px minmax(0, 1fr); }284 .community-panel > a { grid-column: 2; justify-self: start; }285}286 287/* Narrow devices keep controls comfortably tappable */288@media (max-width: 420px) {289 .container { width: calc(100% - 28px); }290 .button-row { align-items: stretch; flex-direction: column; }291 .button-row .button { justify-content: center; }292 .feature-grid { grid-template-columns: 1fr; }293 .tool-card, .download-card { padding: 17px; }294 .footer-main { grid-template-columns: 1fr; }295 .site-notice { right: 12px; bottom: 12px; max-width: calc(100vw - 24px); }296}297 298/* Motion and contrast preferences are always more important than decoration */299@media (prefers-reduced-motion: reduce) {300 html { scroll-behavior: auto !important; }301 *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }302}
001/* Pixel3DLab – progressive page interaction */002(() => {003 'use strict';004 005 const root = document.documentElement;006 const page = document.querySelector('.site-shell');007 const themeButton = document.querySelector('[data-theme-toggle]');008 const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');009 010 const readStoredTheme = () => {011 try {012 const value = localStorage.getItem('theme');013 return value === 'dark' || value === 'light' ? value : 'light';014 } catch (error) {015 return 'light';016 }017 };018 019 const writeStoredTheme = (value) => {020 try {021 localStorage.setItem('theme', value);022 } catch (error) {023 // The current session still receives the selected theme.024 }025 };026 027 const setTheme = (value) => {028 root.dataset.theme = value;029 if (themeButton) {030 themeButton.setAttribute('aria-pressed', String(value === 'dark'));031 themeButton.setAttribute('aria-label', value === 'dark'032 ? 'Helles Design aktivieren'033 : 'Dunkles Design aktivieren');034 }035 writeStoredTheme(value);036 };037 038 setTheme(readStoredTheme());039 040 if (themeButton) {041 themeButton.addEventListener('click', () => {042 setTheme(root.dataset.theme === 'dark' ? 'light' : 'dark');043 });044 }045 046 const motionDisabled = () => reduceMotion.matches ||047 document.body.classList.contains('a11y-no-animations');048 049 const revealItems = document.querySelectorAll('[data-reveal]');050 if (motionDisabled() || !('IntersectionObserver' in window)) {051 revealItems.forEach((item) => item.classList.add('is-visible'));052 } else {053 const observer = new IntersectionObserver((entries, instance) => {054 entries.forEach((entry) => {055 if (!entry.isIntersecting) return;056 entry.target.classList.add('is-visible');057 instance.unobserve(entry.target);058 });059 }, { threshold: 0.12, rootMargin: '0px 0px -4% 0px' });060 revealItems.forEach((item) => observer.observe(item));061 }062 063 const toggle = document.querySelector('[data-menu-toggle]');064 const menu = document.querySelector('[data-mobile-menu]');065 if (toggle && menu) {066 toggle.addEventListener('click', () => {067 const open = toggle.getAttribute('aria-expanded') === 'true';068 toggle.setAttribute('aria-expanded', String(!open));069 menu.hidden = open;070 });071 menu.querySelectorAll('a').forEach((link) => {072 link.addEventListener('click', () => {073 menu.hidden = true;074 toggle.setAttribute('aria-expanded', 'false');075 });076 });077 }078 079 // Keep the source example readable when a visitor disables motion.080 if (page && motionDisabled()) {081 page.classList.add('motion-disabled');082 }083 084 const progressBar = document.querySelector('[data-scroll-progress]');085 let scrollScheduled = false;086 087 const updateScrollProgress = () => {088 if (!progressBar) return;089 const documentHeight = document.documentElement.scrollHeight - window.innerHeight;090 const progress = documentHeight > 0 ? window.scrollY / documentHeight : 0;091 progressBar.style.transform = `scaleX(${Math.max(0, Math.min(1, progress))})`;092 };093 094 window.addEventListener('scroll', () => {095 if (scrollScheduled) return;096 scrollScheduled = true;097 window.requestAnimationFrame(() => {098 updateScrollProgress();099 scrollScheduled = false;100 });101 }, { passive: true });102 window.addEventListener('resize', updateScrollProgress, { passive: true });103 updateScrollProgress();104 105 const navigationLinks = Array.from(document.querySelectorAll('.site-nav a[href^="#"]'));106 const observedSections = navigationLinks107 .map((link) => document.querySelector(link.getAttribute('href')))108 .filter(Boolean);109 110 if ('IntersectionObserver' in window && observedSections.length > 0) {111 const sectionObserver = new IntersectionObserver((entries) => {112 entries.forEach((entry) => {113 const activeLink = navigationLinks.find((link) =>114 link.getAttribute('href') === `#${entry.target.id}`115 );116 if (!activeLink) return;117 if (entry.isIntersecting) {118 navigationLinks.forEach((link) => link.removeAttribute('aria-current'));119 activeLink.setAttribute('aria-current', 'location');120 }121 });122 }, { rootMargin: '-30% 0px -55% 0px', threshold: 0 });123 observedSections.forEach((section) => sectionObserver.observe(section));124 }125 126 document.querySelectorAll('[data-current-year]').forEach((node) => {127 node.textContent = String(new Date().getFullYear());128 });129 130 document.addEventListener('visibilitychange', () => {131 if (document.hidden) return;132 updateScrollProgress();133 });134 135 136 // Small, defensive storage wrapper keeps the interface usable when storage is blocked.137 const storage = {138 get(key, fallback = null) {139 try {140 const value = localStorage.getItem(key);141 return value === null ? fallback : value;142 } catch (error) {143 return fallback;144 }145 },146 set(key, value) {147 try {148 localStorage.setItem(key, String(value));149 return true;150 } catch (error) {151 return false;152 }153 },154 remove(key) {155 try { localStorage.removeItem(key); } catch (error) { /* storage optional */ }156 }157 };158 159 // Set up keyboard-safe expandable navigation.160 const navToggle = document.querySelector('[data-menu-toggle]');161 const navPanel = document.querySelector('[data-mobile-menu]');162 if (navToggle && navPanel) {163 const setMenuState = (open) => {164 navToggle.setAttribute('aria-expanded', String(open));165 navPanel.hidden = !open;166 };167 navToggle.addEventListener('click', () => {168 setMenuState(navToggle.getAttribute('aria-expanded') !== 'true');169 });170 navPanel.querySelectorAll('a').forEach((link) => {171 link.addEventListener('click', () => setMenuState(false));172 });173 document.addEventListener('keydown', (event) => {174 if (event.key === 'Escape') setMenuState(false);175 });176 }177 178 // Copy buttons use the Clipboard API when available and a selected fallback otherwise.179 document.querySelectorAll('[data-copy-target]').forEach((button) => {180 button.addEventListener('click', async () => {181 const selector = button.getAttribute('data-copy-target');182 const target = selector ? document.querySelector(selector) : null;183 if (!target) return;184 const value = 'value' in target ? target.value : target.textContent;185 try {186 await navigator.clipboard.writeText(value);187 button.setAttribute('data-copy-state', 'success');188 } catch (error) {189 const range = document.createRange();190 range.selectNodeContents(target);191 const selection = window.getSelection();192 selection?.removeAllRanges();193 selection?.addRange(range);194 button.setAttribute('data-copy-state', 'manual');195 }196 });197 });198 199 // A small search field filters tool cards without changing their order.200 const searchInput = document.querySelector('[data-tool-search]');201 const searchableCards = Array.from(document.querySelectorAll('[data-tool-card]'));202 if (searchInput && searchableCards.length) {203 searchInput.addEventListener('input', () => {204 const query = searchInput.value.trim().toLocaleLowerCase('de');205 searchableCards.forEach((card) => {206 const content = card.textContent.toLocaleLowerCase('de');207 card.hidden = query !== '' && !content.includes(query);208 });209 });210 }211 212 // Form validation adds a helpful state but leaves server-side validation authoritative.213 document.querySelectorAll('form[data-validate]').forEach((form) => {214 form.addEventListener('submit', (event) => {215 if (!form.checkValidity()) {216 event.preventDefault();217 form.classList.add('has-validation-error');218 form.querySelector(':invalid')?.focus();219 } else {220 form.classList.remove('has-validation-error');221 }222 });223 });224 225 // Mark external links and open them safely in a separate tab if requested.226 document.querySelectorAll('a[data-external="true"]').forEach((link) => {227 link.setAttribute('rel', 'noopener noreferrer');228 if (link.target === '_blank') link.setAttribute('aria-label', `${link.textContent.trim()} (öffnet in neuem Tab)`);229 });230 231 // A compact notification helper can be reused by save and copy actions.232 let noticeTimer = 0;233 function showNotice(message, type = 'info') {234 let notice = document.querySelector('[data-site-notice]');235 if (!notice) {236 notice = document.createElement('div');237 notice.dataset.siteNotice = 'true';238 notice.className = 'site-notice';239 notice.setAttribute('role', 'status');240 notice.setAttribute('aria-live', 'polite');241 document.body.appendChild(notice);242 }243 notice.dataset.type = type;244 notice.textContent = message;245 notice.classList.add('is-visible');246 window.clearTimeout(noticeTimer);247 noticeTimer = window.setTimeout(() => notice.classList.remove('is-visible'), 3600);248 }249 250 // Attach reusable feedback to controls that declare a status message.251 document.querySelectorAll('[data-notice-message]').forEach((button) => {252 button.addEventListener('click', () => {253 const message = button.getAttribute('data-notice-message');254 if (message) showNotice(message, button.dataset.noticeType || 'info');255 });256 });257 258 // Respect reduced-motion preferences in any script-driven scroll action.259 document.querySelectorAll('a[href^="#"]').forEach((link) => {260 link.addEventListener('click', (event) => {261 const id = link.getAttribute('href').slice(1);262 const target = id ? document.getElementById(id) : null;263 if (!target) return;264 event.preventDefault();265 target.scrollIntoView({266 behavior: motionDisabled() ? 'auto' : 'smooth',267 block: 'start'268 });269 if (id) history.replaceState(null, '', `#${id}`);270 });271 });272 273 // The current year is rendered client-side to avoid stale footer copy.274 document.querySelectorAll('[data-current-year]').forEach((node) => {275 node.textContent = String(new Date().getFullYear());276 });277 278})();
Ich entwickle kleine Helfer, Web-Tools und Programme, die Arbeit erleichtern – von praktischen 3D-Druck-Werkzeugen bis zu eigenen Anwendungen zum Ausprobieren und Herunterladen.
<?php// Aus einer Idee wird ein Tool.$tools = [ 'entwickeln', 'testen', 'teilen'];echo 'Viel Spaß beim Ausprobieren!';?>Pixel3DLab ist meine digitale Werkstatt für praktische Tools, kleine Programme und eigene Projekte. Hier findest du Anwendungen, die direkt im Browser laufen, größere Projekte und Downloads, sobald sie bereitstehen.
Starte ein Werkzeug direkt oder springe zu einer der externen Web-Apps. Die Sammlung wird nach und nach erweitert.
Hier bekommen Desktop-Anwendungen, portable Helfer und weitere Dateien ihren Platz. Verfügbare Dateien werden direkt über die Download-Karten angeboten.
Offline-Version des Karteikarten-Builders. Trage hier die passende Release-Datei ein.
Hilfsprogramm zum Erstellen und Exportieren von Ordnerstrukturen.
Bitte lade nur Dateien herunter, die du erwartest. Versions- und Systemhinweise können bei den jeweiligen Einträgen ergänzt werden.
Im Forum ist Platz für Austausch, Fragen, Rückmeldungen und neue Ideen rund um Pixel3DLab.
Die Auswahl wird auf diesem Gerät gespeichert.
Angaben gemäß § 5 DDG
Mario Smiatalski
c/o IP-Management #8124
Ludwig-Erhard-Straße 18
20459 Hamburg
Kontakt
E-Mail: smiatalski@pixel3dlab.com
Telefon: 01785394654
Bitte prüfe vor Veröffentlichung, ob diese Angaben noch aktuell und vollständig sind.