From cd61dc9ac8041a50378050fce806991036bbb7de Mon Sep 17 00:00:00 2001 From: ertunc-ozbay Date: Wed, 21 Oct 2026 20:19:11 +0300 Subject: [PATCH] Simplify stylesheet and copy to clean Light/Dark layout without emojis --- README.md | 14 +- about.html | 28 +- assets/css/style.css | 1523 +++++++-------------- assets/js/main.js | 189 +-- blog/index.html | 28 +- blog/post-template.html | 33 +- blog/welcome-to-my-workshop-note.html | 24 +- contact.html | 48 +- index.html | 77 +- lab.html | 46 +- projects/index.html | 40 +- projects/midi-breadboard-instrument.html | 68 +- projects/multi-functional-controller.html | 64 +- projects/rc-autonomous-vehicle.html | 44 +- 14 files changed, 809 insertions(+), 1417 deletions(-) diff --git a/README.md b/README.md index 404dc4d..b9bc81f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Ertunç Özbay — Embedded Systems & Hardware Engineering Studio (`ertuncozbay.dev`) +# ertuncozbay.dev -This repository contains the static HTML5, CSS3, and vanilla JavaScript source code for **[https://ertuncozbay.dev](https://ertuncozbay.dev)**, self-hosted on a Debian 12 Google Cloud VM with **Caddy** (automatic Let's Encrypt TLS/HTTP3) and **Forgejo** (**[https://git.ertuncozbay.dev](https://git.ertuncozbay.dev)**). +Personal website and project notes for Ertunç Özbay (Electrical and Electronics Engineering student at Bülent Ecevit University). -## Architecture -- **Web Server:** Caddy (`/var/www/ertuncozbay.dev`) -- **Self-Hosted Git Server:** Forgejo (`https://git.ertuncozbay.dev/ertunc-ozbay`) -- **UI Themes:** 3-Mode Studio Theme Switcher (`🎨 Colorful` default, `🌈 Neon`, `📐 Blueprint`) -- **Contact:** `ertunc.ozbay@outlook.com` +Plain HTML, CSS, and vanilla JavaScript served by Caddy on Debian 12. + +- Website: https://ertuncozbay.dev +- Git repositories: https://git.ertuncozbay.dev/ertunc-ozbay +- Contact: ertunc.ozbay@outlook.com diff --git a/about.html b/about.html index ad4cd27..4b5c8a4 100644 --- a/about.html +++ b/about.html @@ -1,12 +1,12 @@ - + - About — Ertunç Özbay + About - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -50,7 +46,7 @@
- ⚡ ABOUT // IDENTITY & ENGINEERING APPROACH + ABOUT // IDENTITY & ENGINEERING APPROACH

About Me & This Engineering Studio

I am an Electrical & Electronics Engineering student at Bülent Ecevit University who builds hardware, writes low-level C and Rust software, and learns by going deeper than the first explanation. @@ -58,7 +54,7 @@

- +

Learning by Building and Investigating

My interests span both hardware and software. I do not want to limit myself to only one layer of a system—I want to understand how physical components, electronics, firmware, and higher-level software work together. @@ -79,7 +75,7 @@

- +

Why I Want to Understand Both Sides of a System

Core Principle @@ -100,7 +96,7 @@
- +

Areas I Am Building & Exploring

@@ -153,7 +149,7 @@ - + diff --git a/assets/css/style.css b/assets/css/style.css index 7cc3836..c89b124 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -1,156 +1,54 @@ /* ========================================================================== - Ertunç Özbay — Engineering Studio, Hardware Lab & Open-Source Hub - Multi-Theme System: - 1. 🎨 Colorful Studio (DEFAULT — Bright, Vibrant, Multi-Color Engineering UI) - 2. 🌈 Cyber Neon (Rich Indigo/Violet Synthwave Night Theme) - 3. 📐 Blueprint Lab (Crisp Technical Paper & Cobalt Schematic Theme) - Plain CSS • Accessible • Responsive • Copyable Code & Command Blocks + Ertunç Özbay — Personal Engineering Website + Clean, restrained, readable stylesheet (Light & Dark modes) ========================================================================== */ :root, -[data-theme="colorful"] { - /* 1. DEFAULT: Vibrant Colorful Studio (Bright, Energetic, Non-Dark!) */ - --bg-primary: #f3f6fc; - --bg-secondary: #eaf0fa; - --bg-card: #ffffff; - --bg-card-hover: #f8faff; - --bg-code: #0f172a; - --bg-header: rgba(255, 255, 255, 0.92); - - /* Crisp Structural Borders */ - --border-subtle: #d8e2f0; - --border-strong: #b8c7de; - --border-accent: #6366f1; - - /* High-Contrast Typography on Bright Canvas */ - --text-primary: #0f172a; - --text-secondary: #334155; - --text-muted: #5b6b82; - - /* Vivid Multi-Color Accents */ - --accent-amber: #ea580c; - --accent-amber-soft: rgba(234, 88, 12, 0.12); - --accent-teal: #0284c7; - --accent-teal-soft: rgba(2, 132, 199, 0.12); - --accent-emerald: #059669; - --accent-emerald-soft: rgba(5, 150, 105, 0.12); - --accent-magenta: #db2777; - --accent-magenta-soft: rgba(219, 39, 119, 0.12); - --accent-violet: #6d28d9; - --accent-violet-soft: rgba(109, 40, 217, 0.12); - --accent-coral: #e11d48; - --accent-coral-soft: rgba(225, 29, 72, 0.12); - --accent-blue: #2563eb; - - /* Colorful Studio Gradients */ - --grad-hero: linear-gradient(135deg, #ffffff 0%, #eef2ff 45%, #fdf2f8 78%, #fff7ed 100%); - --grad-brand: linear-gradient(135deg, #ff512f 0%, #dd2476 50%, #4f46e5 100%); - --grad-title: linear-gradient(90deg, #0f172a 0%, #4f46e5 38%, #db2777 72%, #ea580c 100%); - --body-bg-image: - radial-gradient(circle at 8% 12%, rgba(56, 189, 248, 0.22), transparent 36%), - radial-gradient(circle at 92% 10%, rgba(244, 114, 182, 0.22), transparent 36%), - radial-gradient(circle at 85% 85%, rgba(251, 146, 60, 0.18), transparent 38%), - radial-gradient(circle at 15% 88%, rgba(52, 211, 153, 0.18), transparent 38%), - radial-gradient(rgba(99, 102, 241, 0.10) 1px, transparent 1px); - - --shadow-panel: 0 14px 36px rgba(30, 41, 59, 0.09); - --shadow-card: 0 8px 24px rgba(30, 41, 59, 0.07); - - /* Typography & Layout Tokens */ - --font-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; - --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace; - --max-width: 1140px; - --max-reading-width: 75ch; - --radius-sm: 8px; - --radius-md: 14px; - --radius-lg: 20px; +[data-theme="light"] { + --bg: #f7f7f5; + --bg-surface: #ffffff; + --bg-muted: #efefec; + --bg-code: #f1f1ee; + --text: #1c1c1c; + --text-secondary: #4a4a48; + --text-muted: #6e6e6a; + --border: #dcdcd6; + --accent: #1d4ed8; + --accent-hover: #1e40af; + --accent-subtle: #eff6ff; + --status-done-bg: #ecfdf5; + --status-done-text: #065f46; + --status-done-border: #a7f3d0; + --status-wip-bg: #fffbeb; + --status-wip-text: #92400e; + --status-wip-border: #fde68a; + --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + --font-mono: "JetBrains Mono", "Fira Code", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; + --max-width: 960px; + --reading-width: 720px; + --radius: 6px; } -/* 2. 🌈 Cyber Neon Theme (Rich Violet-Indigo Synthwave — Never Flat Gray!) */ -[data-theme="neon"] { - --bg-primary: #131129; - --bg-secondary: #1b1738; - --bg-card: #221d46; - --bg-card-hover: #2b2458; - --bg-code: #0b091b; - --bg-header: rgba(19, 17, 41, 0.90); - - --border-subtle: #38306b; - --border-strong: #524699; - --border-accent: #f472b6; - - --text-primary: #f8fafc; - --text-secondary: #dcd7fe; - --text-muted: #a59de6; - - --accent-amber: #fbbf24; - --accent-amber-soft: rgba(251, 191, 36, 0.18); - --accent-teal: #22d3ee; - --accent-teal-soft: rgba(34, 211, 238, 0.18); - --accent-emerald: #34d399; - --accent-emerald-soft: rgba(52, 211, 153, 0.18); - --accent-magenta: #f472b6; - --accent-magenta-soft: rgba(244, 114, 182, 0.18); - --accent-violet: #c084fc; - --accent-violet-soft: rgba(192, 132, 252, 0.18); - --accent-coral: #fb7185; - --accent-coral-soft: rgba(251, 113, 133, 0.18); - --accent-blue: #60a5fa; - - --grad-hero: linear-gradient(135deg, rgba(40, 31, 84, 0.96) 0%, rgba(59, 25, 84, 0.94) 55%, rgba(22, 46, 79, 0.94) 100%); - --grad-title: linear-gradient(90deg, #ffffff 0%, #22d3ee 35%, #f472b6 70%, #fbbf24 100%); - --body-bg-image: - radial-gradient(circle at 12% 12%, rgba(236, 72, 153, 0.24), transparent 36%), - radial-gradient(circle at 88% 15%, rgba(6, 182, 212, 0.22), transparent 36%), - radial-gradient(circle at 50% 85%, rgba(139, 92, 246, 0.22), transparent 42%), - radial-gradient(rgba(192, 132, 252, 0.12) 1px, transparent 1px); - - --shadow-panel: 0 16px 40px rgba(5, 3, 20, 0.55); - --shadow-card: 0 10px 28px rgba(5, 3, 20, 0.42); +[data-theme="dark"] { + --bg: #141517; + --bg-surface: #1c1d21; + --bg-muted: #25262b; + --bg-code: #18191c; + --text: #e5e7eb; + --text-secondary: #b0b5bd; + --text-muted: #848a94; + --border: #2e3036; + --accent: #60a5fa; + --accent-hover: #93c5fd; + --accent-subtle: rgba(96, 165, 250, 0.12); + --status-done-bg: rgba(16, 185, 129, 0.12); + --status-done-text: #6ee7b7; + --status-done-border: rgba(16, 185, 129, 0.3); + --status-wip-bg: rgba(245, 158, 11, 0.12); + --status-wip-text: #fcd34d; + --status-wip-border: rgba(245, 158, 11, 0.3); } -/* 3. 📐 Blueprint Lab Theme (Warm Technical Paper & Cobalt Schematic) */ -[data-theme="blueprint"] { - --bg-primary: #fdfbf7; - --bg-secondary: #f3efe6; - --bg-card: #ffffff; - --bg-card-hover: #f7f4ec; - --bg-code: #172554; - --bg-header: rgba(253, 251, 247, 0.94); - - --border-subtle: #d6d0c2; - --border-strong: #aca391; - --border-accent: #1d4ed8; - - --text-primary: #172554; - --text-secondary: #334155; - --text-muted: #64748b; - - --accent-amber: #d97706; - --accent-amber-soft: rgba(217, 119, 6, 0.14); - --accent-teal: #1d4ed8; - --accent-teal-soft: rgba(29, 78, 216, 0.12); - --accent-emerald: #047857; - --accent-emerald-soft: rgba(4, 120, 87, 0.12); - --accent-magenta: #be185d; - --accent-magenta-soft: rgba(190, 24, 93, 0.12); - --accent-violet: #4338ca; - --accent-violet-soft: rgba(67, 56, 202, 0.12); - --accent-coral: #b91c1c; - --accent-coral-soft: rgba(185, 28, 28, 0.12); - --accent-blue: #1d4ed8; - - --grad-hero: linear-gradient(135deg, #ffffff 0%, #eff6ff 55%, #fef3c7 100%); - --grad-title: linear-gradient(90deg, #172554 0%, #1d4ed8 50%, #d97706 100%); - --body-bg-image: - linear-gradient(rgba(29, 78, 216, 0.05) 1px, transparent 1px), - linear-gradient(90deg, rgba(29, 78, 216, 0.05) 1px, transparent 1px); - - --shadow-panel: 0 10px 28px rgba(23, 37, 84, 0.08); - --shadow-card: 0 6px 18px rgba(23, 37, 84, 0.06); -} - -/* Base Reset */ *, *::before, *::after { @@ -158,726 +56,389 @@ } html { - font-size: 100%; + font-size: 16px; scroll-behavior: smooth; - background-color: var(--bg-primary); - color: var(--text-primary); } body { margin: 0; font-family: var(--font-sans); - line-height: 1.68; - background-color: var(--bg-primary); - background-image: var(--body-bg-image); - background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%, 26px 26px; - background-attachment: fixed; - color: var(--text-primary); - min-height: 100vh; - display: flex; - flex-direction: column; - transition: background-color 0.2s ease, color 0.2s ease; + background-color: var(--bg); + color: var(--text); + line-height: 1.65; + -webkit-font-smoothing: antialiased; } -[data-theme="blueprint"] body { - background-size: 24px 24px, 24px 24px; -} - -/* Accessibility: Skip Link */ +/* Accessibility */ .skip-link { position: absolute; top: -100px; left: 1rem; + background: var(--accent); + color: #fff; + padding: 0.5rem 0.85rem; + border-radius: var(--radius); z-index: 1000; - background: var(--grad-brand); - color: #ffffff; - padding: 0.65rem 1.1rem; - font-weight: 700; - border-radius: var(--radius-sm); text-decoration: none; - box-shadow: var(--shadow-panel); } .skip-link:focus { - top: 1rem; - outline: 3px solid var(--accent-teal); - outline-offset: 2px; + top: 0.75rem; } -/* Focus States */ -a:focus-visible, -button:focus-visible, -input:focus-visible, -select:focus-visible, -textarea:focus-visible, -summary:focus-visible, -[tabindex]:focus-visible { - outline: 2px solid var(--accent-teal); - outline-offset: 3px; - border-radius: 4px; +/* Layout */ +.container { + width: 100%; + max-width: var(--max-width); + margin: 0 auto; + padding: 0 1.25rem; } -/* Typography Hierarchy */ +.reading-width { + max-width: var(--reading-width); +} + +/* Typography */ h1, h2, h3, h4 { - color: var(--text-primary); - line-height: 1.24; + color: var(--text); + font-weight: 600; + line-height: 1.3; margin-top: 0; - font-weight: 800; - letter-spacing: -0.02em; + letter-spacing: -0.015em; } h1 { - font-size: clamp(1.95rem, 3.6vw, 2.75rem); - margin-bottom: 1rem; -} - -.gradient-title { - background: var(--grad-title); - -webkit-background-clip: text; - background-clip: text; - color: transparent; - display: inline-block; + font-size: 2rem; + margin-bottom: 0.75rem; } h2 { - font-size: clamp(1.38rem, 2.5vw, 1.85rem); - margin-bottom: 0.85rem; + font-size: 1.35rem; + margin-bottom: 0.75rem; } h3 { - font-size: 1.22rem; - margin-bottom: 0.55rem; + font-size: 1.1rem; + margin-bottom: 0.4rem; } p { margin-top: 0; - margin-bottom: 1.15rem; + margin-bottom: 1rem; color: var(--text-secondary); } ul, ol { - margin-top: 0; - margin-bottom: 1.15rem; - padding-left: 1.35rem; color: var(--text-secondary); + padding-left: 1.25rem; + margin-top: 0; + margin-bottom: 1rem; } li { - margin-bottom: 0.45rem; + margin-bottom: 0.35rem; } -strong { - color: var(--text-primary); - font-weight: 700; +a { + color: var(--accent); + text-decoration: none; } -code, pre { - font-family: var(--font-mono); - font-size: 0.89em; +a:hover { + color: var(--accent-hover); + text-decoration: underline; } code { - background-color: var(--accent-teal-soft); - color: var(--accent-teal); - padding: 0.15rem 0.45rem; - border-radius: 5px; - border: 1px solid rgba(2, 132, 199, 0.22); - font-weight: 600; + font-family: var(--font-mono); + font-size: 0.875em; + background: var(--bg-code); + border: 1px solid var(--border); + padding: 0.12rem 0.35rem; + border-radius: 4px; + color: var(--text); } pre { - background-color: var(--bg-code); - color: #f8fafc; - padding: 1.15rem 1.25rem; - border-radius: 0 0 var(--radius-sm) var(--radius-sm); - border: 1px solid var(--border-subtle); - overflow-x: auto; + font-family: var(--font-mono); + font-size: 0.85rem; line-height: 1.55; - margin: 0; + background: var(--bg-code); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1rem; + overflow-x: auto; + margin: 0 0 1.25rem 0; } pre code { background: none; border: none; padding: 0; - color: #e2e8f0; - font-weight: 400; + font-size: inherit; } -/* Interactive Code & Terminal Window Component */ -.code-window { - margin: 1.15rem 0 1.65rem; - border-radius: var(--radius-sm); - overflow: hidden; - box-shadow: var(--shadow-card); - border: 1px solid var(--border-strong); -} - -.code-window-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem; - background: linear-gradient(90deg, #1e293b 0%, #0f172a 100%); - color: #f8fafc; - padding: 0.55rem 1rem; - font-family: var(--font-mono); - font-size: 0.78rem; - border-bottom: 1px solid rgba(255, 255, 255, 0.12); -} - -.code-window-title { - display: inline-flex; - align-items: center; - gap: 0.5rem; - font-weight: 700; - color: #38bdf8; -} - -.code-dots { - display: inline-flex; - gap: 0.35rem; -} - -.code-dot { - width: 10px; - height: 10px; - border-radius: 50%; - display: inline-block; -} - -.code-dot.red { background: #fb7185; } -.code-dot.amber { background: #fbbf24; } -.code-dot.green { background: #34d399; } - -.copy-code-btn { - background: rgba(255, 255, 255, 0.1); - color: #f8fafc; - border: 1px solid rgba(255, 255, 255, 0.22); - border-radius: 6px; - padding: 0.25rem 0.65rem; - font-family: var(--font-mono); - font-size: 0.74rem; - font-weight: 700; - cursor: pointer; - transition: all 0.15s ease; -} - -.copy-code-btn:hover { - background: #38bdf8; - color: #0f172a; - border-color: #38bdf8; -} - -a { - color: var(--accent-teal); - text-decoration: underline; - text-underline-offset: 0.22em; - transition: color 0.15s ease; -} - -a:hover { - color: var(--accent-magenta); -} - -img { - max-width: 100%; - height: auto; - display: block; -} - -/* Layout Containers */ -.container { - width: 100%; - max-width: var(--max-width); - margin: 0 auto; - padding: 0 1.35rem; -} - -.reading-width { - max-width: var(--max-reading-width); -} - -main { - flex: 1; - padding: 2.35rem 0 4.5rem; -} - -/* Header, Navigation & Always-Visible Theme Switcher */ +/* Header & Navigation */ .site-header { - background-color: var(--bg-header); - border-bottom: 1px solid var(--border-subtle); + background: var(--bg-surface); + border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 100; - backdrop-filter: blur(14px); - box-shadow: 0 4px 16px rgba(15, 23, 42, 0.05); -} - -.site-header::before { - content: ""; - display: block; - height: 4px; - width: 100%; - background: linear-gradient(90deg, #06b6d4 0%, #6366f1 28%, #ec4899 58%, #f59e0b 82%, #10b981 100%); } .header-inner { display: flex; align-items: center; justify-content: space-between; - min-height: 4.5rem; - gap: 0.85rem; + min-height: 3.75rem; + gap: 1rem; flex-wrap: wrap; - padding-top: 0.4rem; - padding-bottom: 0.4rem; + padding-top: 0.5rem; + padding-bottom: 0.5rem; } .site-brand { - display: inline-flex; - align-items: center; - gap: 0.75rem; + display: flex; + flex-direction: column; text-decoration: none; - color: var(--text-primary); - font-weight: 800; - font-size: 1.08rem; + color: var(--text); } .site-brand:hover { - color: var(--accent-teal); + text-decoration: none; } -.brand-mark { - display: inline-flex; - align-items: center; - justify-content: center; - width: 2.35rem; - height: 2.35rem; - background: var(--grad-brand); - border-radius: var(--radius-sm); - font-family: var(--font-mono); - font-size: 0.9rem; - font-weight: 800; - color: #ffffff; - box-shadow: 0 4px 12px rgba(221, 36, 118, 0.35); +.brand-name { + font-weight: 700; + font-size: 1.05rem; + color: var(--text); } -.brand-subtitle { - display: block; - font-family: var(--font-mono); - font-size: 0.72rem; - font-weight: 600; - color: var(--accent-magenta); +.brand-role { + font-size: 0.78rem; + color: var(--text-muted); } -/* Header Controls Wrapper (Nav + Prominent Theme Switcher) */ -.header-controls { +.site-nav { display: flex; align-items: center; - gap: 0.75rem; + gap: 1rem; flex-wrap: wrap; } -/* Prominent Multi-Theme Switcher Pill Bar */ -.theme-switcher { - display: inline-flex; - align-items: center; - gap: 0.25rem; - background-color: var(--bg-secondary); - border: 1px solid var(--border-strong); - padding: 0.22rem; - border-radius: 999px; - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06); -} - -.theme-btn { - display: inline-flex; - align-items: center; - gap: 0.3rem; - border: none; - background: transparent; - color: var(--text-secondary); - font-family: var(--font-mono); - font-size: 0.75rem; - font-weight: 700; - padding: 0.32rem 0.68rem; - border-radius: 999px; - cursor: pointer; - transition: all 0.15s ease; -} - -.theme-btn:hover { - color: var(--text-primary); -} - -.theme-btn[aria-pressed="true"] { - background: var(--grad-brand); - color: #ffffff; - box-shadow: 0 2px 8px rgba(221, 36, 118, 0.35); -} - -/* Mobile Navigation Button */ -.nav-toggle { - display: none; - align-items: center; - gap: 0.4rem; - background-color: var(--bg-card); - color: var(--text-primary); - border: 1px solid var(--border-strong); - border-radius: var(--radius-sm); - padding: 0.45rem 0.75rem; - font-family: var(--font-mono); - font-size: 0.8rem; - font-weight: 700; - cursor: pointer; -} - -.nav-list { +.nav-links { + list-style: none; display: flex; align-items: center; - gap: 0.3rem; - list-style: none; + gap: 0.25rem; margin: 0; padding: 0; } -.nav-list li { +.nav-links li { margin: 0; } -.nav-link { +.nav-links a { display: inline-block; - padding: 0.42rem 0.8rem; + padding: 0.35rem 0.65rem; + border-radius: var(--radius); color: var(--text-secondary); + font-size: 0.92rem; + font-weight: 500; text-decoration: none; - font-size: 0.94rem; - font-weight: 650; - border-radius: var(--radius-sm); - border: 1px solid transparent; - transition: all 0.15s ease; } -.nav-link:hover { - color: var(--text-primary); - background-color: var(--bg-secondary); - border-color: var(--border-subtle); +.nav-links a:hover, +.nav-links a[aria-current="page"] { + color: var(--text); + background: var(--bg-muted); } -.nav-link[aria-current="page"] { - color: var(--accent-violet); - background-color: var(--accent-violet-soft); - border-color: rgba(109, 40, 217, 0.35); - font-weight: 750; -} - -[data-theme="neon"] .nav-link[aria-current="page"] { - color: #ffffff; - background: linear-gradient(135deg, rgba(6, 182, 212, 0.32), rgba(236, 72, 153, 0.32)); - border-color: rgba(34, 211, 238, 0.6); -} - -/* Workshop Hero / Intro Panel */ -.workshop-hero { - position: relative; - background: var(--grad-hero); - border: 1px solid var(--border-strong); - border-left: 6px solid var(--accent-magenta); - border-radius: var(--radius-lg); - padding: clamp(1.65rem, 3.8vw, 2.75rem); - margin-bottom: 2.75rem; - box-shadow: var(--shadow-panel); - overflow: hidden; -} - -.workshop-eyebrow { +/* Theme Switcher */ +.theme-switcher { display: inline-flex; - align-items: center; - gap: 0.5rem; - font-family: var(--font-mono); - font-size: 0.78rem; - font-weight: 800; - color: #ffffff; - background: linear-gradient(90deg, #4f46e5 0%, #db2777 100%); - padding: 0.3rem 0.85rem; - border-radius: 999px; - margin-bottom: 1rem; - box-shadow: 0 4px 12px rgba(79, 70, 229, 0.25); + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; + background: var(--bg); } -.hero-lead { - font-size: clamp(1.12rem, 2.1vw, 1.32rem); - color: var(--text-primary); - max-width: 68ch; - margin-bottom: 1rem; +.theme-btn { + border: none; + background: transparent; + color: var(--text-muted); + font-family: var(--font-sans); + font-size: 0.8rem; + padding: 0.3rem 0.6rem; + cursor: pointer; +} + +.theme-btn:hover { + color: var(--text); +} + +.theme-btn.active { + background: var(--bg-surface); + color: var(--text); font-weight: 600; } -/* Stats / Quick Highlights Bar */ -.stats-strip { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(185px, 1fr)); - gap: 0.9rem; - margin-top: 1.65rem; - padding-top: 1.35rem; - border-top: 1px solid var(--border-subtle); +/* Main Content & Sections */ +main { + padding: 2.5rem 0 4rem; } -.stat-pill { - background-color: var(--bg-card); - border: 1px solid var(--border-subtle); - border-left: 4px solid var(--accent-teal); - border-radius: var(--radius-sm); - padding: 0.8rem 1rem; - box-shadow: var(--shadow-card); +.hero, +.page-header { + padding-bottom: 2rem; + margin-bottom: 2rem; + border-bottom: 1px solid var(--border); } -.stat-pill:nth-child(2) { border-left-color: var(--accent-amber); } -.stat-pill:nth-child(3) { border-left-color: var(--accent-magenta); } -.stat-pill:nth-child(4) { border-left-color: var(--accent-emerald); } - -.stat-value { +.hero-eyebrow, +.section-label { display: block; font-family: var(--font-mono); - font-size: 1.12rem; - font-weight: 800; - color: var(--accent-teal); -} - -.stat-pill:nth-child(2) .stat-value { color: var(--accent-amber); } -.stat-pill:nth-child(3) .stat-value { color: var(--accent-magenta); } -.stat-pill:nth-child(4) .stat-value { color: var(--accent-emerald); } - -.stat-label { - font-size: 0.82rem; + font-size: 0.78rem; color: var(--text-muted); - font-weight: 500; + margin-bottom: 0.35rem; } -/* Buttons */ -.button-row { +.hero-lead { + font-size: 1.05rem; + max-width: 68ch; + color: var(--text-secondary); +} + +.hero-actions, +.button-row, +.card-actions { display: flex; flex-wrap: wrap; - gap: 0.75rem; - margin-top: 1.25rem; + gap: 0.6rem; + margin-top: 1rem; } -.btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.45rem; - padding: 0.62rem 1.15rem; - font-size: 0.92rem; - font-weight: 700; - border-radius: var(--radius-sm); - text-decoration: none; - cursor: pointer; - border: 1px solid transparent; - transition: all 0.18s ease; -} - -.btn-primary { - background: linear-gradient(135deg, #4f46e5 0%, #db2777 100%); - color: #ffffff; - box-shadow: 0 4px 14px rgba(219, 39, 119, 0.28); -} - -.btn-primary:hover { - background: linear-gradient(135deg, #4338ca 0%, #be185d 100%); - color: #ffffff; - transform: translateY(-1px); - box-shadow: 0 6px 20px rgba(219, 39, 119, 0.4); -} - -.btn-cyan { - background: linear-gradient(135deg, #0284c7 0%, #2563eb 100%); - color: #ffffff; - box-shadow: 0 4px 14px rgba(2, 132, 199, 0.28); -} - -.btn-cyan:hover { - background: linear-gradient(135deg, #0369a1 0%, #1d4ed8 100%); - color: #ffffff; - transform: translateY(-1px); -} - -.btn-emerald { - background: linear-gradient(135deg, #059669 0%, #0d9488 100%); - color: #ffffff; - box-shadow: 0 4px 14px rgba(5, 150, 105, 0.28); -} - -.btn-emerald:hover { - background: linear-gradient(135deg, #047857 0%, #0f766e 100%); - color: #ffffff; - transform: translateY(-1px); -} - -.btn-youtube { - background: linear-gradient(135deg, #ff0033 0%, #e11d48 100%); - color: #ffffff; - box-shadow: 0 4px 14px rgba(255, 0, 51, 0.28); -} - -.btn-youtube:hover { - background: linear-gradient(135deg, #d9002b 0%, #be123c 100%); - color: #ffffff; - transform: translateY(-1px); -} - -.btn-secondary { - background-color: var(--bg-card); - color: var(--text-primary); - border-color: var(--border-strong); -} - -.btn-secondary:hover { - background-color: var(--bg-secondary); - border-color: var(--accent-teal); - color: var(--accent-teal); - transform: translateY(-1px); -} - -/* Section Headers & Grid Layouts */ .section-block { - margin-bottom: 3.25rem; + margin-bottom: 2.75rem; } .section-header { display: flex; - flex-wrap: wrap; align-items: baseline; justify-content: space-between; - gap: 0.75rem; - border-bottom: 2px solid var(--border-subtle); - padding-bottom: 0.65rem; - margin-bottom: 1.45rem; + gap: 1rem; + flex-wrap: wrap; + margin-bottom: 1.25rem; } -.section-label { - font-family: var(--font-mono); - font-size: 0.78rem; - font-weight: 800; - text-transform: uppercase; - letter-spacing: 0.08em; - color: var(--accent-magenta); - display: block; - margin-bottom: 0.25rem; +/* Buttons */ +.btn { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-family: var(--font-sans); + font-size: 0.88rem; + font-weight: 500; + padding: 0.45rem 0.85rem; + border-radius: var(--radius); + border: 1px solid var(--border); + background: var(--bg-surface); + color: var(--text); + cursor: pointer; + text-decoration: none; + transition: background-color 0.15s ease, border-color 0.15s ease; } -.card-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 1.35rem; +.btn:hover { + background: var(--bg-muted); + color: var(--text); + text-decoration: none; } +.btn-primary { + background: var(--accent); + border-color: var(--accent); + color: #ffffff; +} + +.btn-primary:hover { + background: var(--accent-hover); + border-color: var(--accent-hover); + color: #ffffff; +} + +/* Cards & Grids */ +.card-grid, .card-grid-2 { display: grid; - grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); - gap: 1.35rem; + grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); + gap: 1.25rem; } -/* Colorful Engineering Cards */ .card { - position: relative; - background-color: var(--bg-card); - border: 1px solid var(--border-subtle); - border-top: 5px solid var(--accent-teal); - border-radius: var(--radius-md); - padding: 1.5rem; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.35rem; display: flex; flex-direction: column; justify-content: space-between; - box-shadow: var(--shadow-card); - transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease; -} - -.card:hover { - transform: translateY(-3px); - box-shadow: var(--shadow-panel); -} - -.card.card-amber { border-top-color: #f97316; } -.card.card-synth { border-top-color: #ec4899; } -.card.card-emerald { border-top-color: #10b981; } -.card.card-coral { border-top-color: #f43f5e; } -.card.card-violet { border-top-color: #6366f1; } - -.card-top { - margin-bottom: 1rem; } .card h3 a { - color: var(--text-primary); + color: var(--text); text-decoration: none; } .card h3 a:hover { - color: var(--accent-magenta); + color: var(--accent); text-decoration: underline; } .card-meta { display: flex; + align-items: center; + gap: 0.6rem; flex-wrap: wrap; - align-items: center; - gap: 0.5rem; - margin-bottom: 0.8rem; - font-family: var(--font-mono); - font-size: 0.76rem; + font-size: 0.8rem; color: var(--text-muted); + margin-bottom: 0.5rem; } -/* Badges & Colorful Tech Tags */ +/* Badges & Tags */ .badge { - display: inline-flex; - align-items: center; - gap: 0.35rem; + display: inline-block; font-family: var(--font-mono); - font-size: 0.74rem; - font-weight: 800; - padding: 0.22rem 0.65rem; - border-radius: 999px; - border: 1px solid transparent; + font-size: 0.72rem; + padding: 0.15rem 0.5rem; + border-radius: 4px; + border: 1px solid var(--border); + background: var(--bg-muted); + color: var(--text-secondary); } -.badge-progress { - background-color: var(--accent-amber-soft); - color: var(--accent-amber); - border-color: rgba(234, 88, 12, 0.35); -} - -.badge-experimental { - background-color: var(--accent-magenta-soft); - color: var(--accent-magenta); - border-color: rgba(219, 39, 119, 0.35); +.badge-completed { + background: var(--status-done-bg); + color: var(--status-done-text); + border-color: var(--status-done-border); } .badge-active { - background-color: var(--accent-emerald-soft); - color: var(--accent-emerald); - border-color: rgba(5, 150, 105, 0.35); -} - -.badge-coral { - background-color: var(--accent-coral-soft); - color: var(--accent-coral); - border-color: rgba(225, 29, 72, 0.35); -} - -.badge-draft { - background-color: var(--accent-teal-soft); - color: var(--accent-teal); - border-color: rgba(2, 132, 199, 0.35); + background: var(--status-wip-bg); + color: var(--status-wip-text); + border-color: var(--status-wip-border); } .tag-list { + list-style: none; display: flex; flex-wrap: wrap; - gap: 0.45rem; - list-style: none; + gap: 0.4rem; padding: 0; - margin: 0.75rem 0 1rem; + margin: 0.75rem 0; } .tag-list li { @@ -888,212 +449,174 @@ main { display: inline-block; font-family: var(--font-mono); font-size: 0.75rem; - font-weight: 700; + padding: 0.15rem 0.5rem; + border-radius: 4px; + background: var(--bg-muted); color: var(--text-secondary); - background-color: var(--bg-secondary); - border: 1px solid var(--border-subtle); - padding: 0.2rem 0.6rem; - border-radius: 6px; + border: 1px solid var(--border); } -.tag.tag-c { color: var(--accent-teal); border-color: rgba(2, 132, 199, 0.35); background: var(--accent-teal-soft); } -.tag.tag-esp { color: var(--accent-amber); border-color: rgba(234, 88, 12, 0.35); background: var(--accent-amber-soft); } -.tag.tag-rust { color: var(--accent-coral); border-color: rgba(225, 29, 72, 0.35); background: var(--accent-coral-soft); } -.tag.tag-python { color: var(--accent-violet); border-color: rgba(109, 40, 217, 0.35); background: var(--accent-violet-soft); } -.tag.tag-hw { color: var(--accent-emerald); border-color: rgba(5, 150, 105, 0.35); background: var(--accent-emerald-soft); } -.tag.tag-synth { color: var(--accent-magenta); border-color: rgba(219, 39, 119, 0.35); background: var(--accent-magenta-soft); } - -/* Project Card Learning / Next Step Callouts */ -.project-notes { - background-color: var(--bg-secondary); - border: 1px solid var(--border-subtle); - border-left: 4px solid var(--accent-violet); - border-radius: var(--radius-sm); - padding: 0.9rem 1.05rem; - margin: 0.85rem 0 1.1rem; - font-size: 0.92rem; -} - -.project-notes p { - margin-bottom: 0.45rem; -} - -.project-notes p:last-child { - margin-bottom: 0; -} - -.card-actions { - display: flex; - flex-wrap: wrap; - gap: 0.6rem; - padding-top: 0.95rem; - border-top: 1px solid var(--border-subtle); -} - -/* ========================================================================== - YouTube Proof-of-Concept (PoC) Video Placeholder Component - ========================================================================== */ -.poc-video-section { - margin: 2rem 0 2.75rem; -} - -.poc-video-card { - position: relative; - background: var(--bg-card); - border: 2px solid rgba(225, 29, 72, 0.35); - border-top: 6px solid #ff0033; - border-radius: var(--radius-lg); - padding: clamp(1.35rem, 3vw, 2.2rem); - box-shadow: var(--shadow-panel); +/* Code Window */ +.code-window { + border: 1px solid var(--border); + border-radius: var(--radius); + background: var(--bg-code); + margin-bottom: 1.25rem; overflow: hidden; } -.poc-video-screen { - position: relative; - aspect-ratio: 16 / 9; - width: 100%; - background: - radial-gradient(circle at 50% 50%, rgba(255, 0, 51, 0.22), transparent 60%), - linear-gradient(135deg, #1e1b4b 0%, #31102f 55%, #0f172a 100%); - border: 1px solid rgba(255, 255, 255, 0.18); - border-radius: var(--radius-md); +.code-window-header { display: flex; - flex-direction: column; align-items: center; - justify-content: center; - text-align: center; - padding: 1.5rem; - color: #f8fafc; -} - -.poc-play-badge { - width: 74px; - height: 52px; - background: linear-gradient(135deg, #ff0033 0%, #e11d48 100%); - border-radius: 14px; - display: inline-flex; - align-items: center; - justify-content: center; - box-shadow: 0 0 0 8px rgba(255, 0, 51, 0.22), 0 10px 28px rgba(255, 0, 51, 0.5); - margin-bottom: 1rem; - transition: transform 0.2s ease, box-shadow 0.2s ease; -} - -.poc-video-screen:hover .poc-play-badge { - transform: scale(1.07); - box-shadow: 0 0 0 12px rgba(255, 0, 51, 0.3), 0 14px 32px rgba(255, 0, 51, 0.65); -} - -.poc-play-triangle { - width: 0; - height: 0; - border-top: 10px solid transparent; - border-bottom: 10px solid transparent; - border-left: 18px solid #ffffff; - margin-left: 4px; -} - -.poc-status-pill { - display: inline-flex; - align-items: center; - gap: 0.4rem; + justify-content: space-between; + padding: 0.45rem 0.85rem; + background: var(--bg-muted); + border-bottom: 1px solid var(--border); font-family: var(--font-mono); - font-size: 0.76rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.06em; - color: #ffe4e6; - background: rgba(244, 63, 94, 0.28); - border: 1px solid rgba(251, 113, 133, 0.55); - padding: 0.25rem 0.75rem; - border-radius: 999px; - margin-bottom: 0.6rem; + font-size: 0.78rem; + color: var(--text-secondary); } -.poc-video-title { - font-size: clamp(1.15rem, 2.2vw, 1.45rem); - font-weight: 800; - color: #ffffff; - margin-bottom: 0.4rem; +.code-dots { + display: none; } -.poc-video-desc { - color: #e2e8f0; - max-width: 58ch; - font-size: 0.94rem; - margin-bottom: 0; +.copy-code-btn { + font-family: var(--font-sans); + font-size: 0.75rem; + padding: 0.2rem 0.55rem; + border: 1px solid var(--border); + border-radius: 4px; + background: var(--bg-surface); + color: var(--text-secondary); + cursor: pointer; } -/* Callout / Philosophy Panels */ -.callout-box { - background-color: var(--bg-secondary); - border: 1px solid var(--border-strong); - border-left: 5px solid var(--accent-teal); - border-radius: var(--radius-md); - padding: 1.4rem 1.55rem; - margin: 1.5rem 0; +.copy-code-btn:hover { + color: var(--text); + background: var(--bg); } -.callout-box.amber { - border-left-color: var(--accent-amber); +.code-window pre { + border: none; + border-radius: 0; + margin: 0; } -.callout-box.magenta { - border-left-color: var(--accent-magenta); +/* Callout & Notes */ +.callout-box, +.project-notes { + background: var(--bg-surface); + border: 1px solid var(--border); + border-left: 3px solid var(--accent); + border-radius: var(--radius); + padding: 0.9rem 1.1rem; + margin: 1rem 0; } .callout-title { - font-family: var(--font-mono); - font-size: 0.85rem; - font-weight: 800; - text-transform: uppercase; - letter-spacing: 0.05em; - color: var(--accent-teal); - margin-bottom: 0.5rem; display: block; + font-weight: 600; + font-size: 0.9rem; + color: var(--text); + margin-bottom: 0.35rem; } -.callout-box.amber .callout-title { - color: var(--accent-amber); +/* Tables */ +.table-wrapper { + overflow-x: auto; + margin-bottom: 1.25rem; } -.callout-box.magenta .callout-title { - color: var(--accent-magenta); +table, +.spec-table { + width: 100%; + border-collapse: collapse; + font-size: 0.9rem; + background: var(--bg-surface); + border: 1px solid var(--border); } -/* Figure & Schematic Frames + Zoomable Images */ -.schematic-frame { - background-color: var(--bg-card); - border: 1px solid var(--border-strong); - border-radius: var(--radius-md); - padding: 1.1rem; - margin: 1.6rem 0; - box-shadow: var(--shadow-card); +th, td { + text-align: left; + padding: 0.65rem 0.85rem; + border-bottom: 1px solid var(--border); } -.schematic-caption { - font-family: var(--font-mono); - font-size: 0.82rem; - color: var(--text-muted); - margin-top: 0.75rem; +th { + background: var(--bg-muted); + color: var(--text); + font-weight: 600; +} + +td { + color: var(--text-secondary); +} + +/* Video Container & Placeholder */ +.video-showcase { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 1.25rem; + margin-bottom: 1.5rem; +} + +.video-placeholder { + border: 1px dashed var(--border); + border-radius: var(--radius); + background: var(--bg); + padding: 2rem 1.25rem; text-align: center; } -.zoomable-img { +.video-play-icon { + display: none; +} + +/* Images & Gallery */ +.gallery-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.gallery-item { + margin: 0; + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; +} + +.gallery-item img { + display: block; + width: 100%; + height: 220px; + object-fit: cover; cursor: zoom-in; - transition: transform 0.2s ease; } -.zoomable-img:hover { - transform: scale(1.015); +.gallery-item figcaption { + padding: 0.65rem 0.85rem; + font-size: 0.82rem; + color: var(--text-muted); + border-top: 1px solid var(--border); } -/* Lightbox Overlay */ +/* Breadcrumbs */ +.breadcrumb { + font-size: 0.85rem; + color: var(--text-muted); + margin-bottom: 0.75rem; +} + +/* Lightbox */ .lightbox-backdrop { position: fixed; inset: 0; - background: rgba(15, 23, 42, 0.92); - backdrop-filter: blur(8px); + background: rgba(0, 0, 0, 0.85); z-index: 2000; display: flex; flex-direction: column; @@ -1109,139 +632,49 @@ main { .lightbox-Backdrop-img { max-width: 92vw; max-height: 82vh; - border-radius: var(--radius-md); - border: 1px solid var(--border-strong); - box-shadow: 0 20px 50px rgba(0, 0, 0, 0.65); - background: #ffffff; + border-radius: 4px; } .lightbox-caption { - margin-top: 0.85rem; - font-family: var(--font-mono); + color: #e5e7eb; font-size: 0.9rem; - color: #f8fafc; + margin-top: 0.75rem; text-align: center; } .lightbox-close { position: absolute; - top: 1.25rem; - right: 1.5rem; - background: #ff0033; - color: #ffffff; - border: none; - border-radius: var(--radius-sm); - padding: 0.5rem 0.95rem; - font-family: var(--font-mono); - font-weight: 700; + top: 1rem; + right: 1.25rem; + background: #27272a; + color: #fff; + border: 1px solid #3f3f46; + padding: 0.4rem 0.75rem; + border-radius: 4px; cursor: pointer; } -/* Breadcrumb / Back Navigation */ -.breadcrumb { - margin-bottom: 1.25rem; - font-family: var(--font-mono); - font-size: 0.85rem; - font-weight: 700; -} - -.breadcrumb a { - color: var(--accent-teal); - text-decoration: none; -} - -.breadcrumb a:hover { - color: var(--accent-magenta); - text-decoration: underline; -} - -/* Filter Toolbar for Blog */ -.filter-bar { - display: flex; - flex-wrap: wrap; - gap: 0.5rem; - margin-bottom: 1.5rem; -} - -.filter-btn { - background-color: var(--bg-card); - color: var(--text-secondary); - border: 1px solid var(--border-strong); - padding: 0.45rem 0.9rem; - border-radius: var(--radius-sm); - font-family: var(--font-mono); - font-size: 0.82rem; - font-weight: 700; - cursor: pointer; -} - -.filter-btn:hover { - border-color: var(--accent-teal); - color: var(--text-primary); -} - -.filter-btn[aria-pressed="true"] { - background: var(--grad-brand); - color: #ffffff; - border-color: transparent; -} - -/* Spec / Component Table */ -.spec-table { - width: 100%; - border-collapse: collapse; - margin: 1rem 0 1.5rem; - font-size: 0.95rem; - background-color: var(--bg-card); - border: 1px solid var(--border-strong); - border-radius: var(--radius-sm); - overflow: hidden; - box-shadow: var(--shadow-card); -} - -.spec-table th, -.spec-table td { - text-align: left; - padding: 0.8rem 1rem; - border-bottom: 1px solid var(--border-subtle); -} - -.spec-table th { - background-color: var(--bg-secondary); - color: var(--accent-violet); - font-family: var(--font-mono); - font-size: 0.8rem; - font-weight: 800; - text-transform: uppercase; - letter-spacing: 0.05em; -} - -.spec-table td { - color: var(--text-secondary); -} - /* Footer */ .site-footer { - background-color: var(--bg-secondary); - border-top: 2px solid var(--border-subtle); - padding: 2.25rem 0; - margin-top: auto; - font-size: 0.92rem; + border-top: 1px solid var(--border); + background: var(--bg-surface); + padding: 1.5rem 0; + font-size: 0.88rem; + color: var(--text-muted); } .footer-inner { display: flex; - flex-wrap: wrap; - justify-content: space-between; align-items: center; + justify-content: space-between; + flex-wrap: wrap; gap: 1rem; } .footer-links { - display: flex; - flex-wrap: wrap; - gap: 1.1rem; list-style: none; + display: flex; + gap: 1rem; margin: 0; padding: 0; } @@ -1250,43 +683,137 @@ main { margin: 0; } -/* Responsive Mobile Navigation */ -@media (max-width: 840px) { - .nav-toggle { - display: inline-flex; - } - - .site-nav { - width: 100%; - display: none; - } - - .site-nav.is-open { - display: block; - padding: 0.75rem 0 1rem; - border-top: 1px solid var(--border-subtle); - } - - .nav-list { - flex-direction: column; - align-items: stretch; - gap: 0.25rem; - } - - .nav-link { - display: block; - padding: 0.65rem 0.85rem; - } +/* Additional Layout & Component Classes */ +.site-brand { + flex-direction: row; + align-items: center; + gap: 0.65rem; + font-weight: 600; } -/* Accessibility: Reduced Motion */ -@media (prefers-reduced-motion: reduce) { - *, - *::before, - *::after { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - scroll-behavior: auto !important; - } +.brand-mark { + display: inline-flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + border-radius: 4px; + background: var(--bg-muted); + border: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 0.82rem; + font-weight: 600; + color: var(--text); +} + +.brand-subtitle { + display: block; + font-size: 0.75rem; + font-weight: 400; + color: var(--text-muted); +} + +.header-controls { + display: flex; + align-items: center; + gap: 0.85rem; + flex-wrap: wrap; +} + +.nav-toggle { + display: none; +} + +.nav-list { + list-style: none; + display: flex; + align-items: center; + gap: 0.2rem; + margin: 0; + padding: 0; +} + +.nav-list li { + margin: 0; +} + +.nav-link { + display: inline-block; + padding: 0.35rem 0.65rem; + border-radius: var(--radius); + color: var(--text-secondary); + font-size: 0.9rem; + font-weight: 500; + text-decoration: none; +} + +.nav-link:hover, +.nav-link[aria-current="page"] { + color: var(--text); + background: var(--bg-muted); + text-decoration: none; +} + +.workshop-hero { + padding-bottom: 2rem; + margin-bottom: 2.25rem; + border-bottom: 1px solid var(--border); +} + +.workshop-eyebrow { + display: block; + font-family: var(--font-mono); + font-size: 0.78rem; + color: var(--text-muted); + margin-bottom: 0.4rem; +} + +.stats-strip, +.meta-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); + gap: 0.85rem; + margin-top: 1.5rem; +} + +.stat-pill, +.meta-item { + background: var(--bg-surface); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 0.85rem 1rem; +} + +.stat-value, +.meta-value { + display: block; + font-weight: 600; + font-size: 0.95rem; + color: var(--text); +} + +.stat-label, +.meta-label { + display: block; + font-size: 0.78rem; + color: var(--text-muted); + margin-top: 0.15rem; +} + +.video-frame-wrapper { + position: relative; + padding-bottom: 56.25%; + height: 0; + overflow: hidden; + border-radius: var(--radius); + border: 1px solid var(--border); +} + +.video-frame-wrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; } diff --git a/assets/js/main.js b/assets/js/main.js index 5ad9e81..0bf2519 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,157 +1,80 @@ -/* ========================================================================== - Ertunç Özbay — Workshop & Portfolio Script (Plain JS, No Dependencies) - Handles: - 1. Prominent Multi-Theme Switcher (🎨 Colorful Studio [Default] | 🌈 Neon | 📐 Blueprint) - 2. Accessible mobile navigation menu toggle (with Escape key support) - 3. Static blog category filtering on the Blog page - 4. One-click copy buttons for Email addresses and Code/Command blocks - 5. Image lightbox for hardware prototype photos and schematics - ========================================================================== */ - +/** + * Ertunç Özbay — Personal Engineering Website + * Theme toggle (Light / Dark), copy helpers, and image zoom + */ (function () { "use strict"; - // 1. Multi-Theme Switcher (Colorful Default, Cyber Neon, Blueprint Lab) - var rootEl = document.documentElement; - var validThemes = ["colorful", "neon", "blueprint"]; - var savedTheme = "colorful"; + var STORAGE_KEY = "ertunc_site_theme"; + var root = document.documentElement; - try { - var stored = localStorage.getItem("eo-studio-theme"); - if (stored && validThemes.indexOf(stored) !== -1) { - savedTheme = stored; - } - } catch (e) {} - - function applyTheme(themeName) { - if (validThemes.indexOf(themeName) === -1) { - themeName = "colorful"; - } - rootEl.setAttribute("data-theme", themeName); + function applyTheme(theme) { + var mode = theme === "dark" ? "dark" : "light"; + root.setAttribute("data-theme", mode); try { - localStorage.setItem("eo-studio-theme", themeName); + localStorage.setItem(STORAGE_KEY, mode); } catch (e) {} - var buttons = document.querySelectorAll("[data-set-theme]"); - buttons.forEach(function (btn) { - var isTarget = btn.getAttribute("data-set-theme") === themeName; - btn.setAttribute("aria-pressed", isTarget ? "true" : "false"); + document.querySelectorAll(".theme-btn[data-set-theme]").forEach(function (btn) { + var isMatch = btn.getAttribute("data-set-theme") === mode; + btn.classList.toggle("active", isMatch); + btn.setAttribute("aria-pressed", isMatch ? "true" : "false"); }); } - applyTheme(savedTheme); + var saved = null; + try { + saved = localStorage.getItem(STORAGE_KEY); + } catch (e) {} + applyTheme(saved === "dark" ? "dark" : "light"); - document.addEventListener("click", function (event) { - var themeBtn = event.target.closest("[data-set-theme]"); - if (themeBtn) { - applyTheme(themeBtn.getAttribute("data-set-theme")); - } + document.querySelectorAll(".theme-btn[data-set-theme]").forEach(function (btn) { + btn.addEventListener("click", function () { + applyTheme(btn.getAttribute("data-set-theme")); + }); }); - // 2. Mobile Navigation Toggle - var navToggle = document.querySelector("[data-nav-toggle]"); - var siteNav = document.querySelector("[data-site-nav]"); - - if (navToggle && siteNav) { - navToggle.addEventListener("click", function () { - var isExpanded = navToggle.getAttribute("aria-expanded") === "true"; - var nextState = !isExpanded; - navToggle.setAttribute("aria-expanded", String(nextState)); - siteNav.classList.toggle("is-open", nextState); - var labelSpan = navToggle.querySelector("[data-nav-label]"); - if (labelSpan) { - labelSpan.textContent = nextState ? "Close" : "Menu"; - } - }); - - document.addEventListener("keydown", function (event) { - if (event.key === "Escape" && siteNav.classList.contains("is-open")) { - navToggle.setAttribute("aria-expanded", "false"); - siteNav.classList.remove("is-open"); - var labelSpan = navToggle.querySelector("[data-nav-label]"); - if (labelSpan) { - labelSpan.textContent = "Menu"; - } - navToggle.focus(); - } - }); - } - - // 3. Blog Category Filter - var filterButtons = document.querySelectorAll("[data-blog-filter]"); - var blogCards = document.querySelectorAll("[data-blog-category]"); - var filterStatus = document.getElementById("blog-filter-status"); - - if (filterButtons.length > 0 && blogCards.length > 0) { - filterButtons.forEach(function (button) { - button.addEventListener("click", function () { - var selectedCategory = button.getAttribute("data-blog-filter"); - - filterButtons.forEach(function (btn) { - btn.setAttribute("aria-pressed", btn === button ? "true" : "false"); - }); - - var visibleCount = 0; - blogCards.forEach(function (card) { - var categories = (card.getAttribute("data-blog-category") || "").split(","); - var match = selectedCategory === "all" || categories.indexOf(selectedCategory) !== -1; - card.hidden = !match; - if (match) { - visibleCount += 1; - } - }); - - if (filterStatus) { - filterStatus.textContent = - "Showing " + visibleCount + (visibleCount === 1 ? " entry" : " entries") + - (selectedCategory === "all" ? "." : " in selected category."); - } - }); - }); - } - - // 4. Copy Email to Clipboard Buttons - var copyEmailButtons = document.querySelectorAll("[data-copy-email]"); - copyEmailButtons.forEach(function (btn) { + // Copy Email Button + var copyEmailBtns = document.querySelectorAll("[data-copy-email]"); + copyEmailBtns.forEach(function (btn) { btn.addEventListener("click", function () { - var email = btn.getAttribute("data-copy-email"); - if (!email || !navigator.clipboard) return; - var originalText = btn.textContent; + var email = btn.getAttribute("data-copy-email") || "ertunc.ozbay@outlook.com"; + if (!navigator.clipboard) return; navigator.clipboard.writeText(email).then(function () { - btn.textContent = "✓ Copied: " + email; + var orig = btn.textContent; + btn.textContent = "Copied: " + email; setTimeout(function () { - btn.textContent = originalText; - }, 2200); - }); - }); - }); - - // 5. Copy Code / Terminal Commands Buttons - var copyCodeButtons = document.querySelectorAll("[data-copy-code]"); - copyCodeButtons.forEach(function (btn) { - btn.addEventListener("click", function () { - var windowEl = btn.closest(".code-window"); - if (!windowEl || !navigator.clipboard) return; - var preEl = windowEl.querySelector("pre"); - if (!preEl) return; - var originalText = btn.textContent; - navigator.clipboard.writeText(preEl.innerText).then(function () { - btn.textContent = "✓ Copied!"; - setTimeout(function () { - btn.textContent = originalText; + btn.textContent = orig; }, 2000); }); }); }); - // 6. Image Lightbox for Hardware Photos & Schematics + // Copy Code Block Button + document.querySelectorAll("[data-copy-code]").forEach(function (btn) { + btn.addEventListener("click", function () { + var wrapper = btn.closest(".code-window"); + if (!wrapper) return; + var codeEl = wrapper.querySelector("pre code"); + if (!codeEl || !navigator.clipboard) return; + navigator.clipboard.writeText(codeEl.textContent).then(function () { + var orig = btn.textContent; + btn.textContent = "Copied"; + setTimeout(function () { + btn.textContent = orig; + }, 1800); + }); + }); + }); + + // Image Lightbox var zoomImages = document.querySelectorAll(".zoomable-img"); if (zoomImages.length > 0) { var backdrop = document.createElement("div"); backdrop.className = "lightbox-backdrop"; backdrop.hidden = true; backdrop.innerHTML = - '' + + '' + '' + ''; document.body.appendChild(backdrop); @@ -182,16 +105,4 @@ if (e.key === "Escape" && !backdrop.hidden) closeLightbox(); }); } - - // 7. Upgrade self-hosted Git links when accessed via ertuncozbay.dev domain - if (window.location.hostname.indexOf("ertuncozbay.dev") !== -1) { - document.querySelectorAll('a[href*="34.57.151.250:3000"]').forEach(function (a) { - a.href = a.href.replace("http://34.57.151.250:3000", "https://git.ertuncozbay.dev"); - }); - document.querySelectorAll(".code-window pre code").forEach(function (codeEl) { - codeEl.textContent = codeEl.textContent - .replace(/http:\/\/34\.57\.151\.250:3000/g, "https://git.ertuncozbay.dev") - .replace(/http:\/\/34\.57\.151\.250/g, "https://ertuncozbay.dev"); - }); - } })(); diff --git a/blog/index.html b/blog/index.html index d30f69a..1f03854 100644 --- a/blog/index.html +++ b/blog/index.html @@ -1,12 +1,12 @@ - + - Blog & Build Notes — Ertunç Özbay + Blog & Build Notes - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -50,7 +46,7 @@
- 📓 TECHNICAL NOTEBOOK // STATIC BLOG + TECHNICAL NOTEBOOK // STATIC BLOG

Blog & Build Notes

Where I document hardware build logs, ESP-IDF firmware architecture, circuit debugging stories, and honest reflections on what worked and what failed. @@ -82,7 +78,7 @@

Starter Note - • 3 min read + · 3 min read

Why I Built This Personal Workshop & Learning Notebook

@@ -103,9 +99,9 @@

- Template • Draft + Template · Draft - • 2 min read + · 2 min read

[Template] Project Build Log & Technical Note Template

@@ -129,7 +125,7 @@

- + diff --git a/blog/post-template.html b/blog/post-template.html index b3c65dc..5691c68 100644 --- a/blog/post-template.html +++ b/blog/post-template.html @@ -1,12 +1,12 @@ - + - [Template] Project Build Log & Technical Note — Blog — Ertunç Özbay + [Template] Project Build Log & Technical Note - Blog - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -56,13 +52,12 @@
- Template • Draft + Template · Draft - • Category: Build Log / Technical Note + · Category: Build Log / Technical Note

[Template] Project Build Log & Technical Note Title

-

- Copy this file to create a new static build log entry with hardware notes, copyable code windows, and lessons learned. +

Copy this file to create a new static build log entry with hardware notes, copyable code windows, and lessons learned.

@@ -72,10 +67,10 @@
- - c99 — Example Firmware Snippet + + c99 - Example Firmware Snippet - +
// Example code block in post template
 void app_main(void) {
@@ -93,7 +88,7 @@ void app_main(void) {
   
 
-  
+  
 
 
diff --git a/blog/welcome-to-my-workshop-note.html b/blog/welcome-to-my-workshop-note.html
index 08950cd..441e812 100644
--- a/blog/welcome-to-my-workshop-note.html
+++ b/blog/welcome-to-my-workshop-note.html
@@ -1,12 +1,12 @@
 
-
+
 
   
   
-  Why I Built This Personal Workshop & Learning Notebook — Blog — Ertunç Özbay
+  Why I Built This Personal Workshop & Learning Notebook - Blog - Ertunç Özbay
   
   
-  
+  
 
 
   
@@ -17,19 +17,15 @@
         
         
           Ertunç Özbay
-          embedded // hardware // open-source
+          Electrical & Electronics Engineering
         
       
 
       
-
- - - -
+
@@ -58,8 +54,8 @@
Starter Note - • Category: Personal Learning Reflections - • Reading time: 3 min read + · Category: Personal Learning Reflections + · Reading time: 3 min read

Why I Built This Personal Workshop & Learning Notebook

@@ -108,7 +104,7 @@

- + diff --git a/contact.html b/contact.html index b03329f..824259d 100644 --- a/contact.html +++ b/contact.html @@ -1,12 +1,12 @@ - + - Contact & Collaboration — Ertunç Özbay + Contact & Collaboration - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -50,23 +46,23 @@
- ✉️ DIRECT CONTACT // OPEN COLLABORATION + DIRECT CONTACT // OPEN COLLABORATION

Contact & Collaboration

Whether you want to talk about ESP32 embedded firmware, circuit design, Linux systems programming, or open-source hardware collaboration, feel free to reach out directly via email, LinkedIn, or my self-hosted Git server.

- +
@@ -86,7 +82,7 @@
Send Email - +
@@ -117,7 +113,7 @@
- +

Active Self-Hosted Git Repositories

@@ -125,7 +121,7 @@
- +

ertunc-ozbay/multi-functional-controller

ESP32-S3-N16R8 Multi-Functional Controller (MFC) featuring 2.4 GHz nRF24L01+ RF telemetry, K-Silver Hall-effect gimbals, hardware PCNT rotary decoder, and shared SPI2 display UI. @@ -133,14 +129,14 @@

- +

ertunc-ozbay/midi-breadboard-instrument

Dual-core ESP32 16-track MIDI breadboard synthesizer, drum sequencer, 30 FPS SPI OLED visualizer, and Python RLE MIDI-to-C compiler (ESP-IDF v5.2.2). @@ -148,14 +144,14 @@

- +

ertunc-ozbay/ertuncozbay.dev

Source repository for this static workshop website and engineering notebook hosted at ertuncozbay.dev. @@ -169,7 +165,7 @@

- +

Topics I Always Enjoy Discussing

  • Embedded Systems & Electronics: ESP32 / ESP32-S3, ESP-IDF, FreeRTOS, SPI/I2C/PWM/PCNT peripherals, schematic capture, and breadboard-to-perfboard builds.
  • @@ -185,7 +181,7 @@ - + diff --git a/index.html b/index.html index 3b86207..098eb3d 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,12 @@ - + - Ertunç Özbay — Embedded Systems, Hardware Lab & Open-Source Projects + Ertunç Özbay - Embedded Systems, Hardware Lab & Open-Source Projects - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
    -
    - - - -
    +
    @@ -50,36 +46,36 @@
    - ⚡ ELECTRICAL & ELECTRONICS ENGINEERING // OPEN WORKBENCH -

    Hi, I’m Ertunç Özbay.

    + Electrical & Electronics Engineering +

    Ertunç Özbay

    - I design embedded hardware, write bare-metal C & FreeRTOS firmware, and build open-source systems from the transistor level up to Linux desktop tooling. + Electrical and Electronics Engineering student at Bülent Ecevit University working on ESP32 embedded firmware, circuit design, and hardware prototypes.

    - Welcome to my engineering studio and notebook. Here you can inspect my real hardware prototypes, copy build/flash commands, browse source code, and download releases—from my ESP32-S3 2.4 GHz Multi-Functional RC Console and Dual-Core ESP32 16-Track MIDI Synthesizer to my 4WD Autonomous Vehicle and Standalone Linux Game Launcher written in Rust. + This site documents my hardware builds, schematics, and C/Python source code, including my ESP32-S3 2.4 GHz Multi-Functional RC Controller, ESP32 16-Track MIDI Breadboard Instrument, and 4WD RC / Autonomous Vehicle.

    -
    +
    - 4 Active Builds - ESP32-S3, ESP32, 4WD RC & Linux/Rust + 3 Hardware Projects + ESP32-S3, ESP32 & 4WD Robotics
    ESP-IDF v5.2.2 - ISO C99, Dual-Core FreeRTOS & KiCad + ISO C99, FreeRTOS & KiCad
    - 16-Track Synth - Custom Python RLE MIDI-to-C Compiler + MIDI Sequencer + Python RLE MIDI-to-C Tooling
    - Direct Downloads - Pre-Built Binaries, Firmware & Schematics + Source & Schematics + Self-Hosted on git.ertuncozbay.dev
    @@ -87,7 +83,7 @@
    - +

    Projects, Commands & Downloads

    View all project code, commands & PoC videos → @@ -99,7 +95,7 @@
    Hardware Rev 0.1 → Phase 2 Console - ESP32-S3 • 2.4 GHz RF + ESP32-S3 · 2.4 GHz RF

    Multi-Functional RC Controller (MFC)

    @@ -114,7 +110,7 @@

@@ -124,9 +120,9 @@
Active Prototype - Dual-Core ESP32 • Audio & UI + Dual-Core ESP32 · Audio & UI
-

MIDI Breadboard Instrument (Desk Rave 16-Track Symphony)

+

MIDI Breadboard Instrument (MIDI Sequencer 16-Track Symphony)

A standalone dual-core ESP32 MIDI synthesizer, drum sequencer, and 30 FPS SPI OLED visualizer with a custom Python RLE MIDI-to-C compiler (midi_to_c.py), hardware PCNT rotary encoder, passive melody piezo, and dual active drum buzzers.

@@ -139,7 +135,7 @@
@@ -149,7 +145,7 @@
In Development - Robotics • Control Logic + Robotics · Control Logic

RC and Autonomous 4WD Vehicle

@@ -172,7 +168,7 @@

- +

Clone & Build My Embedded Hardware Projects

@@ -180,10 +176,10 @@
- - bash — Clone & Build ESP-IDF Firmware (Arch Linux / ESP-IDF v5.2.2) + + bash - Clone & Build ESP-IDF Firmware (Arch Linux / ESP-IDF v5.2.2) - +
# 1. ESP32-S3 Multi-Functional Controller (ESP-IDF v5.2.2 + KiCad Schematic)
 git clone https://git.ertuncozbay.dev/ertunc-ozbay/multi-functional-controller.git
@@ -198,7 +194,7 @@ cd midi-breadboard-instrument && python3 scripts/midi_to_c.py scripts/mi
       
- +

How I Approach Engineering

@@ -219,8 +215,7 @@ cd midi-breadboard-instrument && python3 scripts/midi_to_c.py scripts/mi

The Open Workbench

-

- Explore my active breadboard tests, RLE MIDI-to-C compression algorithms, hardware protection fixes, and reverse-engineering study notes. +

Explore my active breadboard tests, RLE MIDI-to-C compression algorithms, hardware protection fixes, and reverse-engineering study notes.

Open the Lab Notebook → @@ -245,7 +240,7 @@ cd midi-breadboard-instrument && python3 scripts/midi_to_c.py scripts/mi
- + diff --git a/lab.html b/lab.html index 079de06..784f047 100644 --- a/lab.html +++ b/lab.html @@ -1,12 +1,12 @@ - + - Lab & Experiment Notebook — Ertunç Özbay + Lab & Experiment Notebook - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -50,7 +46,7 @@
- 🔬 WORKSHOP BENCH // LAB NOTEBOOK + WORKSHOP BENCH // LAB NOTEBOOK

Lab & Experiment Notebook

Welcome to my open workbench. This page tracks my real engineering experiments, hardware debugging breakthroughs, Python/Rust tooling scripts, and reverse-engineering study notes. @@ -61,7 +57,7 @@

- +

Recent Hardware & Firmware Experiments

@@ -70,7 +66,7 @@
Solved on Breadboard - ESP32 Dual-Core • Python RLE + ESP32 Dual-Core · Python RLE

Defeating the 30 Hz MIDI "Strobe-Light" Bug & Piezo Bass Roll-Off

@@ -78,8 +74,8 @@

@@ -88,7 +84,7 @@
Hardware Rev 0.1 → Phase 2 - ESP32-S3-N16R8 • SPI2 Bus + ESP32-S3-N16R8 · SPI2 Bus

ESP32-S3 Octal PSRAM Pin Collisions & Shared SPI2 Arbitration

@@ -96,8 +92,8 @@

@@ -108,7 +104,7 @@
- +

Custom Compilers & Linux Runtime Tools

@@ -116,7 +112,7 @@
- KiCad • Hardware Design + KiCad · Hardware Design Schematic & PCB Capture

KiCad Schematic Capture for ESP32-S3 Hardware (mfc-1.kicad_sch)

@@ -125,7 +121,7 @@

@@ -133,7 +129,7 @@
- Python 3 • mido + Python 3 · mido Embedded Audio Tooling

RLE MIDI-to-C Struct Compiler (midi_to_c.py)

@@ -152,7 +148,7 @@
- +

Reverse-Engineering & Low-Level Study Log

@@ -173,7 +169,7 @@ - + diff --git a/projects/index.html b/projects/index.html index 8aaca5a..cc818c6 100644 --- a/projects/index.html +++ b/projects/index.html @@ -1,12 +1,12 @@ - + - Projects, Code & Downloads — Ertunç Özbay + Projects, Code & Downloads - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -50,7 +46,7 @@
- ⚡ PROJECT SHOWCASE // CODE, COMMANDS, DOWNLOADS & POC VIDEOS + PROJECT SHOWCASE // CODE, COMMANDS, DOWNLOADS & POC VIDEOS

Engineering Projects & Open-Source Builds

Every project documented here includes verified hardware pinouts, build photos, copyable terminal commands, source code snippets, direct download links, and a dedicated YouTube Proof-of-Concept (PoC) video showcase. @@ -71,7 +67,7 @@

Rev 0.1 Built → Phase 2 Console - Project 01 • Embedded Hardware + Project 01 · Embedded Hardware

Multi-Functional RC Controller (MFC)

@@ -88,13 +84,13 @@

-

Included on page: Copyable `idf.py` build/flash commands, C99 firmware source code, downloadable KiCad `.kicad_sch` schematic & `.zip` archive, 3 prototype photos, and 🎬 YouTube PoC Video slot.

+

Included on page:Copyable `idf.py` build/flash commands, C99 firmware source code, downloadable KiCad `.kicad_sch` schematic & `.zip` archive, 3 prototype photos, and YouTube PoC Video slot.

@@ -104,9 +100,9 @@
Active Breadboard Synth - Project 02 • Audio & Dual-Core RTOS + Project 02 · Audio & Dual-Core RTOS
-

MIDI Breadboard Instrument — Desk Rave 16-Track Symphony

+

MIDI Breadboard Instrument - MIDI Sequencer 16-Track Symphony

A standalone dual-core ESP32 MIDI synthesizer, drum sequencer, and 30 FPS SPI OLED visualizer programmed in ESP-IDF v5.2.2, paired with a custom Python Run-Length Encoding (RLE) MIDI-to-C compiler (midi_to_c.py) driving a passive melody buzzer, two active drum buzzers, LEDs, and a hardware PCNT rotary encoder.

@@ -121,13 +117,13 @@
-

Included on page: Full `midi_to_c.py` Python script & C99 Dual-Core FreeRTOS audio engine code, copyable CLI commands, downloadable `.py` & `.zip` links, 3 breadboard photos, and 🎬 YouTube PoC Video slot.

+

Included on page: Full `midi_to_c.py` Python script & C99 Dual-Core FreeRTOS audio engine code, copyable CLI commands, downloadable `.py` & `.zip` links, 3 breadboard photos, and YouTube PoC Video slot.

@@ -137,7 +133,7 @@
In Progress - Project 03 • Robotics & Control + Project 03 · Robotics & Control

RC and Autonomous 4WD Vehicle

@@ -152,7 +148,7 @@

-

Included on page: C99 2.4 GHz telemetry receiver packet & differential motor drive code structure, companion controller link, and 🎬 YouTube PoC Video slot.

+

Included on page: C99 2.4 GHz telemetry receiver packet & differential motor drive code structure, companion controller link, and YouTube PoC Video slot.

@@ -169,7 +165,7 @@ - + diff --git a/projects/midi-breadboard-instrument.html b/projects/midi-breadboard-instrument.html index 96705ba..86ddfdd 100644 --- a/projects/midi-breadboard-instrument.html +++ b/projects/midi-breadboard-instrument.html @@ -1,12 +1,12 @@ - + - MIDI Breadboard Instrument (Desk Rave & 16-Track Symphony) — Projects — Ertunç Özbay + MIDI Breadboard Instrument (MIDI Sequencer & 16-Track Symphony) - Projects - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -57,9 +53,9 @@
Status: Active Breadboard Prototype - Project 02 // ESP32 Dual-Core • ESP-IDF C99 • FreeRTOS • Python RLE + Project ESP32 Dual-Core · ESP-IDF C99 · FreeRTOS · Python RLE
-

MIDI Breadboard Instrument — Desk Rave & 16-Track Symphony

+

MIDI Breadboard Instrument - MIDI Sequencer & 16-Track Symphony

A standalone, dual-core ESP32 MIDI synthesizer, drum sequencer, and 30 FPS SPI OLED visualizer written in ESP-IDF v5.2.2 (C99 / FreeRTOS), powered by a custom Run-Length Encoding (RLE) Python MIDI-to-C compiler.

@@ -67,25 +63,25 @@ What started as making a passive piezo buzzer squeak evolved into a full 16-track embedded music box with live kick/hi-hat drum transients, hardware PCNT quadrature rotary controls for real-time tempo and volume scaling, and dual-core FreeRTOS task isolation.

- +

YouTube Proof-of-Concept Demonstration

- 🎥 YouTube PoC Video — Recording / Coming Soon -
Desk Rave 16-Track ESP32 MIDI Synthesizer — Live Audio & 30 FPS OLED Demo
+ YouTube PoC Video - Recording / Coming Soon +
MIDI Sequencer 16-Track ESP32 MIDI Synthesizer - Live Audio & 30 FPS OLED Demo

Upcoming YouTube video showcasing live playback across the 16-track flash playlist (Careless Whisper, Rondo Alla Turca, Seven Nation Army +2 octave transpose), real-time rotary speed/volume tweaking, and synchronized kick/hi-hat buzzers + LEDs.

@@ -101,7 +97,7 @@
- +
@@ -127,7 +123,7 @@
- +

Build, Flash & MIDI Conversion Commands

Clone the repository, convert any `.mid` file into an RLE-compressed C struct array using `scripts/midi_to_c.py`, and flash the 16-track firmware to an ESP32: @@ -136,10 +132,10 @@

- - bash — Convert MIDI to C & Flash ESP32 Firmware (ESP-IDF v5.2.2) + + bash - Convert MIDI to C & Flash ESP32 Firmware (ESP-IDF v5.2.2) - +
# 1. Clone the repository
 git clone https://git.ertuncozbay.dev/ertunc-ozbay/midi-breadboard-instrument.git
@@ -163,10 +159,10 @@ idf.py -p /dev/ttyUSB0 flash monitor
- - python3 — scripts/midi_to_c.py (RLE Compression & Drum Routing Engine) + + python3 - scripts/midi_to_c.py (RLE Compression & Drum Routing Engine) - +
#!/usr/bin/env python3
 import sys, mido
@@ -202,10 +198,10 @@ def convert_midi_to_c(midi_filename):
           
- - c99 — main/mmcontroller.c (SequenceStep Struct & Dual-Core Task Pinning) + + c99 - main/mmcontroller.c (SequenceStep Struct & Dual-Core Task Pinning) - +
typedef struct {
     uint16_t frequency; // Melody pitch in Hz (driven by 13-bit LEDC PWM on GPIO 25)
@@ -215,7 +211,7 @@ def convert_midi_to_c(midi_filename):
 } SequenceStep;
 
 void app_main(void) {
-    printf("Desk Rave: 16-Track Symphony Edition Initializing...\n");
+    printf("MIDI Sequencer: 16-Track Symphony Edition Initializing...\n");
     init_hardware();
 
     // Core 0: 30 FPS SPI OLED Framebuffer Visualizer & 50ms Button Polling
@@ -229,7 +225,7 @@ void app_main(void) {
         
- +

ESP32 Pinout & Architecture Specifications

@@ -285,7 +281,7 @@ void app_main(void) {
- +

The 16-Track Symphony

  1. Careless Whisper (Extended Club Edit)
  2. @@ -314,7 +310,7 @@ void app_main(void) { - + diff --git a/projects/multi-functional-controller.html b/projects/multi-functional-controller.html index afd26a4..85f1aad 100644 --- a/projects/multi-functional-controller.html +++ b/projects/multi-functional-controller.html @@ -1,12 +1,12 @@ - + - Multi-Functional RC Controller (MFC) — Projects — Ertunç Özbay + Multi-Functional RC Controller (MFC) - Projects - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
    -
    - - - -
    +
    @@ -57,7 +53,7 @@
    Status: Rev 0.1 Carrier Built → Phase 2 Console Expansion - Project 01 // ESP32-S3-N16R8 • 2.4 GHz RF • ESP-IDF C99 + Project ESP32-S3-N16R8 · 2.4 GHz RF · ESP-IDF C99

    Multi-Functional RC Controller (MFC)

    @@ -67,25 +63,25 @@ Designed to serve as a universal handheld and desktop transmitter for external robotic platforms (such as my 4WD RC & Autonomous Vehicle) while integrating dual K-Silver Hall-effect joysticks, a 1.3" ST7789 IPS TFT display, MicroSD storage, and MAX4466 audio capture.

    - +

    YouTube Proof-of-Concept Demonstration

    - 🎥 YouTube PoC Video — Recording / Coming Soon -
    ESP32-S3 Multi-Functional Controller — Hardware & 2.4 GHz RF Telemetry Demo
    + YouTube PoC Video - Recording / Coming Soon +
    ESP32-S3 Multi-Functional Controller - Hardware & 2.4 GHz RF Telemetry Demo

    Upcoming YouTube demonstration covering the Rev 0.1 perfboard carrier power-on test, 2.4 GHz nRF24L01+ packet transmission, Hall-effect gimbal ADC sampling, and ST7789 IPS TFT UI rendering.

    @@ -95,7 +91,7 @@
    - +

    Note: The photos below show the very early Phase 1 (Rev 0.1) perfboard carrier build. Currently populated: female/male pin header sockets, 100 µF electrolytic bulk decoupling capacitor, ESP32-S3-N16R8 module, nRF24L01+ 2.4 GHz radio header, and 3.3V/5V/GND power distribution rails. These photos will be updated as the Phase 2 DT-100 desktop console modules are installed. @@ -124,7 +120,7 @@

    - +

    Clone, Build & Flash Commands (ESP-IDF v5.2.2)

    To build and flash the ESP32-S3 master firmware on Arch Linux (or any Linux system with ESP-IDF v5.2.2 installed), run the following commands: @@ -133,10 +129,10 @@

    - - bash — Clone, Configure Target (esp32s3), Build & Flash + + bash - Clone, Configure Target (esp32s3), Build & Flash - +
    # 1. Clone the Multi-Functional Controller repository
     git clone https://git.ertuncozbay.dev/ertunc-ozbay/multi-functional-controller.git
    @@ -161,10 +157,10 @@ idf.py -p /dev/ttyACM0 flash monitor
    - - c99 — firmware/main/mmcontroller.c (ESP32-S3-N16R8 Hardware Definitions) + + c99 - firmware/main/mmcontroller.c (ESP32-S3-N16R8 Hardware Definitions) - +
    // --- 1. ADC1 ANALOG INPUTS (K-Silver Hall-Effect Joysticks & MAX4466 Mic) ---
     #define PIN_JOY_LX      GPIO_NUM_4   // ADC1_CH3
    @@ -195,19 +191,19 @@ idf.py -p /dev/ttyACM0 flash monitor
    - +

    Early KiCad 9.0 Schematic (mfc-1.svg)

    KiCad schematic diagram of the ESP32-S3 Multi-Functional Controller
    - Early prototype KiCad schematic (mfc-1.kicad_sch) — click to zoom full-screen or download the raw KiCad 9.0 file. + Early prototype KiCad schematic (mfc-1.kicad_sch) - click to zoom full-screen or download the raw KiCad 9.0 file.
    - +

    Master Node GPIO Allocation

@@ -221,7 +217,7 @@ idf.py -p /dev/ttyACM0 flash monitor - + @@ -264,7 +260,7 @@ idf.py -p /dev/ttyACM0 flash monitor
- +

From Rev 0.1 Carrier to the DT-100 Desktop Console

Phase 2 Hardware Upgrade (Direnc.net Procurement List) @@ -289,7 +285,7 @@ idf.py -p /dev/ttyACM0 flash monitor - + diff --git a/projects/rc-autonomous-vehicle.html b/projects/rc-autonomous-vehicle.html index 08a7df6..c5ad886 100644 --- a/projects/rc-autonomous-vehicle.html +++ b/projects/rc-autonomous-vehicle.html @@ -1,12 +1,12 @@ - + - RC and Autonomous 4WD Vehicle — Projects — Ertunç Özbay + RC and Autonomous 4WD Vehicle - Projects - Ertunç Özbay - + @@ -17,19 +17,15 @@ Ertunç Özbay - embedded // hardware // open-source + Electrical & Electronics Engineering
-
- - - -
+
@@ -57,15 +53,15 @@
Status: In Progress - Project 04 // 4WD Robotics, Control Logic & 2.4 GHz Telemetry + Project 4WD Robotics, Control Logic & 2.4 GHz Telemetry

RC and Autonomous 4WD Vehicle

A standalone 4WD robotic vehicle project exploring manual 2.4 GHz wireless control (paired with my Multi-Functional RC Controller) and autonomous obstacle-avoidance behavior.

@@ -73,14 +69,14 @@
- +

YouTube Proof-of-Concept Demonstration

- 🎥 YouTube PoC Video — Recording / Coming Soon -
4WD RC & Autonomous Vehicle — Wireless Drive & Control Loop Test
+ YouTube PoC Video - Recording / Coming Soon +
4WD RC & Autonomous Vehicle - Wireless Drive & Control Loop Test

Upcoming YouTube demonstration covering 2.4 GHz remote drive response from the Multi-Functional Controller, motor driver PWM tuning, and autonomous mode switching.

@@ -89,7 +85,7 @@
- +

Why I Am Building This

A physical vehicle sits right at the intersection of the subjects I care about most: power electronics, closed-loop control logic, and real-time embedded decision-making. If a firmware routine makes a bad timing assumption or power transients aren't filtered properly, you see it immediately in how the vehicle behaves on the floor. @@ -101,7 +97,7 @@

- +

Packed C99 Telemetry & Drive Structs

To guarantee deterministic serialization over the 32-byte nRF24L01+ payload buffer between the controller and the vehicle, the link layer uses packed fixed-width C99 structs: @@ -110,10 +106,10 @@

- - c99 — Packed 2.4 GHz Control & Telemetry Packet Definition + + c99 - Packed 2.4 GHz Control & Telemetry Packet Definition - +
#include <stdint.h>
 #include <assert.h>
@@ -132,7 +128,7 @@ _Static_assert(sizeof(RcControlPacket_t) == 8, "RcControlPacket_t must be 8 byte
         
- +

Current Documentation Status

Dual Hall-Effect Joysticks (4 Axes) GPIO 4, 5, 6, 712-bit SAR ADC1 (LX, LY, RX, RY) — avoids ADC2 Wi-Fi/RF conflicts12-bit SAR ADC1 (LX, LY, RX, RY) - avoids ADC2 Wi-Fi/RF conflicts
MAX4466 Electret Mic Preamp
@@ -169,7 +165,7 @@ _Static_assert(sizeof(RcControlPacket_t) == 8, "RcControlPacket_t must be 8 byte
- +