From ac7a3a6e66e26769bbec201d585cb89ededb7fcf Mon Sep 17 00:00:00 2001
From: ertunc-ozbay
Date: Sun, 18 Oct 2026 03:38:48 +0300
Subject: [PATCH] feat: make Colorful Studio default UI, add visible 3-mode
theme switcher bar, use ertunc.ozbay@outlook.com, and add CLI commands, code
blocks & direct downloads
---
about.html | 44 +-
assets/css/style.css | 676 +++++++++++++---------
assets/js/main.js | 89 +--
blog/index.html | 44 +-
blog/post-template.html | 135 ++---
blog/welcome-to-my-workshop-note.html | 72 +--
contact.html | 86 +--
index.html | 154 +++--
lab.html | 63 +-
projects/index.html | 139 +++--
projects/midi-breadboard-instrument.html | 179 ++++--
projects/multi-functional-controller.html | 138 ++++-
projects/pointblank-linux.html | 147 +++--
projects/rc-autonomous-vehicle.html | 100 ++--
14 files changed, 1279 insertions(+), 787 deletions(-)
diff --git a/about.html b/about.html
index 36e1722..235f5b5 100644
--- a/about.html
+++ b/about.html
@@ -1,12 +1,12 @@
-
+
About — Ertunç Özbay
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -145,7 +153,7 @@
-
+
diff --git a/assets/css/style.css b/assets/css/style.css
index ce46f7c..7cc3836 100644
--- a/assets/css/style.css
+++ b/assets/css/style.css
@@ -1,99 +1,153 @@
/* ==========================================================================
- Ertunç Özbay — Personal Workshop, Project Lab & Technical Notebook
- Vibrant Luminous Engineering Studio + Daylight Theme Support
- Plain CSS • Accessible • Responsive • Reduced-Motion Ready
+ 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
========================================================================== */
-:root {
- /* Luminous Indigo-Slate Canvas (Brighter, Richer, Colorful) */
- --bg-primary: #111827;
- --bg-secondary: #182235;
- --bg-card: #1e293b;
- --bg-card-hover: #243248;
- --bg-code: #0f172a;
- --bg-header: rgba(17, 24, 39, 0.88);
-
- /* Crisp Borders & Hairlines */
- --border-subtle: #334155;
- --border-strong: #475569;
- --border-accent: #f59e0b;
-
- /* High-Contrast Typography */
- --text-primary: #f8fafc;
- --text-secondary: #cbd5e1;
- --text-muted: #94a3b8;
-
- /* Multi-Color Engineering Accents */
- --accent-amber: #f59e0b;
- --accent-amber-soft: rgba(245, 158, 11, 0.16);
- --accent-teal: #06b6d4;
- --accent-teal-soft: rgba(6, 182, 212, 0.16);
- --accent-emerald: #10b981;
- --accent-emerald-soft: rgba(16, 185, 129, 0.16);
- --accent-magenta: #ec4899;
- --accent-magenta-soft: rgba(236, 72, 153, 0.16);
- --accent-violet: #8b5cf6;
- --accent-violet-soft: rgba(139, 92, 246, 0.16);
- --accent-coral: #f43f5e;
- --accent-coral-soft: rgba(244, 63, 94, 0.16);
- --accent-blue: #38bdf8;
- --accent-youtube: #ff0033;
-
- /* Gradients */
- --grad-hero: linear-gradient(135deg, rgba(30, 41, 59, 0.96) 0%, rgba(24, 34, 53, 0.96) 55%, rgba(36, 28, 62, 0.92) 100%);
- --grad-brand: linear-gradient(135deg, #f59e0b 0%, #ec4899 55%, #06b6d4 100%);
- --grad-amber: linear-gradient(90deg, #f59e0b, #f97316);
- --grad-synth: linear-gradient(90deg, #ec4899, #8b5cf6, #06b6d4);
- --grad-emerald: linear-gradient(90deg, #10b981, #06b6d4);
- --grad-coral: linear-gradient(90deg, #f43f5e, #fb923c);
-
- /* Typography & Rhythm */
- --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: 1100px;
- --max-reading-width: 74ch;
- --radius-sm: 8px;
- --radius-md: 14px;
- --radius-lg: 18px;
- --shadow-panel: 0 12px 32px rgba(2, 6, 23, 0.42);
- --shadow-card: 0 8px 24px rgba(2, 6, 23, 0.28);
-}
-
-/* Optional Sunlit Studio Light Mode */
-[data-theme="light"] {
- --bg-primary: #f8fafc;
- --bg-secondary: #f1f5f9;
+: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: #f8fafc;
+ --bg-card-hover: #f8faff;
--bg-code: #0f172a;
- --bg-header: rgba(255, 255, 255, 0.90);
+ --bg-header: rgba(255, 255, 255, 0.92);
- --border-subtle: #e2e8f0;
- --border-strong: #cbd5e1;
- --border-accent: #d97706;
+ /* 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: #64748b;
+ --text-muted: #5b6b82;
- --accent-amber: #d97706;
- --accent-amber-soft: rgba(217, 119, 6, 0.12);
- --accent-teal: #0891b2;
- --accent-teal-soft: rgba(8, 145, 178, 0.12);
+ /* 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: #7c3aed;
- --accent-violet-soft: rgba(124, 58, 237, 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: #0284c7;
+ --accent-blue: #2563eb;
- --grad-hero: linear-gradient(135deg, #ffffff 0%, #f0f9ff 50%, #fdf4ff 100%);
- --shadow-panel: 0 12px 32px rgba(15, 23, 42, 0.08);
- --shadow-card: 0 6px 20px rgba(15, 23, 42, 0.06);
+ /* 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;
+}
+
+/* 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);
+}
+
+/* 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 */
@@ -115,17 +169,18 @@ body {
font-family: var(--font-sans);
line-height: 1.68;
background-color: var(--bg-primary);
- background-image:
- radial-gradient(circle at 12% 10%, rgba(6, 182, 212, 0.14), transparent 34%),
- radial-gradient(circle at 88% 14%, rgba(236, 72, 153, 0.13), transparent 34%),
- radial-gradient(circle at 50% 85%, rgba(245, 158, 11, 0.10), transparent 40%),
- radial-gradient(rgba(148, 163, 184, 0.08) 1px, transparent 1px);
- background-size: 100% 100%, 100% 100%, 100% 100%, 28px 28px;
+ 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;
+}
+
+[data-theme="blueprint"] body {
+ background-size: 24px 24px, 24px 24px;
}
/* Accessibility: Skip Link */
@@ -134,8 +189,8 @@ body {
top: -100px;
left: 1rem;
z-index: 1000;
- background: var(--grad-amber);
- color: #0f172a;
+ background: var(--grad-brand);
+ color: #ffffff;
padding: 0.65rem 1.1rem;
font-weight: 700;
border-radius: var(--radius-sm);
@@ -145,11 +200,11 @@ body {
.skip-link:focus {
top: 1rem;
- outline: 3px solid #ffffff;
+ outline: 3px solid var(--accent-teal);
outline-offset: 2px;
}
-/* Accessibility: Visible Keyboard Focus States */
+/* Focus States */
a:focus-visible,
button:focus-visible,
input:focus-visible,
@@ -177,7 +232,7 @@ h1 {
}
.gradient-title {
- background: linear-gradient(90deg, var(--text-primary) 0%, #38bdf8 48%, #f59e0b 100%);
+ background: var(--grad-title);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
@@ -213,42 +268,105 @@ li {
strong {
color: var(--text-primary);
- font-weight: 650;
+ font-weight: 700;
}
code, pre {
font-family: var(--font-mono);
- font-size: 0.9em;
+ font-size: 0.89em;
}
code {
- background-color: rgba(15, 23, 42, 0.75);
- color: #38bdf8;
- padding: 0.16rem 0.45rem;
+ background-color: var(--accent-teal-soft);
+ color: var(--accent-teal);
+ padding: 0.15rem 0.45rem;
border-radius: 5px;
- border: 1px solid var(--border-subtle);
-}
-
-[data-theme="light"] code {
- background-color: #f1f5f9;
- color: #0369a1;
+ border: 1px solid rgba(2, 132, 199, 0.22);
+ font-weight: 600;
}
pre {
background-color: var(--bg-code);
color: #f8fafc;
- padding: 1.1rem 1.25rem;
- border-radius: var(--radius-sm);
+ padding: 1.15rem 1.25rem;
+ border-radius: 0 0 var(--radius-sm) var(--radius-sm);
border: 1px solid var(--border-subtle);
overflow-x: auto;
line-height: 1.55;
+ margin: 0;
}
pre code {
background: none;
border: none;
padding: 0;
- color: inherit;
+ color: #e2e8f0;
+ font-weight: 400;
+}
+
+/* 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 {
@@ -259,7 +377,7 @@ a {
}
a:hover {
- color: var(--accent-amber);
+ color: var(--accent-magenta);
}
img {
@@ -282,10 +400,10 @@ img {
main {
flex: 1;
- padding: 2.5rem 0 4.5rem;
+ padding: 2.35rem 0 4.5rem;
}
-/* Header & Navigation */
+/* Header, Navigation & Always-Visible Theme Switcher */
.site-header {
background-color: var(--bg-header);
border-bottom: 1px solid var(--border-subtle);
@@ -293,22 +411,26 @@ main {
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: 3px;
+ height: 4px;
width: 100%;
- background: linear-gradient(90deg, #06b6d4 0%, #8b5cf6 35%, #ec4899 68%, #f59e0b 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.4rem;
- gap: 1rem;
+ min-height: 4.5rem;
+ gap: 0.85rem;
+ flex-wrap: wrap;
+ padding-top: 0.4rem;
+ padding-bottom: 0.4rem;
}
.site-brand {
@@ -329,30 +451,75 @@ main {
display: inline-flex;
align-items: center;
justify-content: center;
- width: 2.25rem;
- height: 2.25rem;
+ width: 2.35rem;
+ height: 2.35rem;
background: var(--grad-brand);
border-radius: var(--radius-sm);
font-family: var(--font-mono);
- font-size: 0.88rem;
+ font-size: 0.9rem;
font-weight: 800;
color: #ffffff;
- box-shadow: 0 4px 12px rgba(236, 72, 153, 0.3);
+ box-shadow: 0 4px 12px rgba(221, 36, 118, 0.35);
}
.brand-subtitle {
display: block;
font-family: var(--font-mono);
font-size: 0.72rem;
- font-weight: 500;
- color: var(--accent-teal);
+ font-weight: 600;
+ color: var(--accent-magenta);
}
-/* Mobile Navigation Button & Theme Button */
-.nav-toggle,
-.theme-toggle {
+/* Header Controls Wrapper (Nav + Prominent Theme Switcher) */
+.header-controls {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ 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);
@@ -361,26 +528,14 @@ main {
padding: 0.45rem 0.75rem;
font-family: var(--font-mono);
font-size: 0.8rem;
- font-weight: 600;
+ font-weight: 700;
cursor: pointer;
- transition: all 0.15s ease;
-}
-
-.nav-toggle {
- display: none;
-}
-
-.nav-toggle:hover,
-.theme-toggle:hover {
- border-color: var(--accent-teal);
- color: var(--accent-teal);
- transform: translateY(-1px);
}
.nav-list {
display: flex;
align-items: center;
- gap: 0.35rem;
+ gap: 0.3rem;
list-style: none;
margin: 0;
padding: 0;
@@ -392,11 +547,11 @@ main {
.nav-link {
display: inline-block;
- padding: 0.45rem 0.85rem;
+ padding: 0.42rem 0.8rem;
color: var(--text-secondary);
text-decoration: none;
- font-size: 0.95rem;
- font-weight: 600;
+ font-size: 0.94rem;
+ font-weight: 650;
border-radius: var(--radius-sm);
border: 1px solid transparent;
transition: all 0.15s ease;
@@ -404,18 +559,21 @@ main {
.nav-link:hover {
color: var(--text-primary);
- background-color: var(--bg-card);
+ background-color: var(--bg-secondary);
border-color: var(--border-subtle);
}
.nav-link[aria-current="page"] {
- color: #ffffff;
- background: linear-gradient(135deg, rgba(6, 182, 212, 0.28), rgba(139, 92, 246, 0.28));
- border-color: rgba(6, 182, 212, 0.55);
+ color: var(--accent-violet);
+ background-color: var(--accent-violet-soft);
+ border-color: rgba(109, 40, 217, 0.35);
+ font-weight: 750;
}
-[data-theme="light"] .nav-link[aria-current="page"] {
- color: #0f172a;
+[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 */
@@ -423,7 +581,7 @@ main {
position: relative;
background: var(--grad-hero);
border: 1px solid var(--border-strong);
- border-left: 5px solid var(--accent-teal);
+ border-left: 6px solid var(--accent-magenta);
border-radius: var(--radius-lg);
padding: clamp(1.65rem, 3.8vw, 2.75rem);
margin-bottom: 2.75rem;
@@ -431,53 +589,33 @@ main {
overflow: hidden;
}
-.workshop-hero::after {
- content: "";
- position: absolute;
- top: -60px;
- right: -60px;
- width: 240px;
- height: 240px;
- background: radial-gradient(circle, rgba(6, 182, 212, 0.18) 0%, rgba(236, 72, 153, 0.10) 50%, transparent 70%);
- pointer-events: none;
-}
-
.workshop-eyebrow {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-family: var(--font-mono);
- font-size: 0.8rem;
- font-weight: 700;
- color: var(--accent-teal);
- background-color: var(--accent-teal-soft);
- border: 1px solid rgba(6, 182, 212, 0.45);
- padding: 0.28rem 0.75rem;
+ 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);
}
.hero-lead {
font-size: clamp(1.12rem, 2.1vw, 1.32rem);
color: var(--text-primary);
- max-width: 66ch;
+ max-width: 68ch;
margin-bottom: 1rem;
- font-weight: 500;
-}
-
-.hero-supporting-line {
- font-family: var(--font-mono);
- font-size: 0.92rem;
- color: var(--accent-amber);
- margin-top: 1.1rem;
- margin-bottom: 1.5rem;
font-weight: 600;
}
/* Stats / Quick Highlights Bar */
.stats-strip {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ grid-template-columns: repeat(auto-fit, minmax(185px, 1fr));
gap: 0.9rem;
margin-top: 1.65rem;
padding-top: 1.35rem;
@@ -485,20 +623,22 @@ main {
}
.stat-pill {
- background-color: rgba(15, 23, 42, 0.45);
+ 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.75rem 1rem;
+ padding: 0.8rem 1rem;
+ box-shadow: var(--shadow-card);
}
-[data-theme="light"] .stat-pill {
- background-color: rgba(255, 255, 255, 0.8);
-}
+.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 {
display: block;
font-family: var(--font-mono);
- font-size: 1.15rem;
+ font-size: 1.12rem;
font-weight: 800;
color: var(--accent-teal);
}
@@ -510,6 +650,7 @@ main {
.stat-label {
font-size: 0.82rem;
color: var(--text-muted);
+ font-weight: 500;
}
/* Buttons */
@@ -526,7 +667,7 @@ main {
justify-content: center;
gap: 0.45rem;
padding: 0.62rem 1.15rem;
- font-size: 0.94rem;
+ font-size: 0.92rem;
font-weight: 700;
border-radius: var(--radius-sm);
text-decoration: none;
@@ -536,26 +677,38 @@ main {
}
.btn-primary {
- background: linear-gradient(135deg, #f59e0b 0%, #f97316 100%);
- color: #0f172a;
- box-shadow: 0 4px 14px rgba(245, 158, 11, 0.3);
+ 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, #fbbf24 0%, #fb923c 100%);
- color: #0f172a;
+ background: linear-gradient(135deg, #4338ca 0%, #be185d 100%);
+ color: #ffffff;
transform: translateY(-1px);
- box-shadow: 0 6px 20px rgba(245, 158, 11, 0.45);
+ box-shadow: 0 6px 20px rgba(219, 39, 119, 0.4);
}
.btn-cyan {
- background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%);
+ background: linear-gradient(135deg, #0284c7 0%, #2563eb 100%);
color: #ffffff;
- box-shadow: 0 4px 14px rgba(6, 182, 212, 0.3);
+ box-shadow: 0 4px 14px rgba(2, 132, 199, 0.28);
}
.btn-cyan:hover {
- background: linear-gradient(135deg, #22d3ee 0%, #60a5fa 100%);
+ 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);
}
@@ -567,19 +720,19 @@ main {
}
.btn-youtube:hover {
- background: linear-gradient(135deg, #ff1a47 0%, #f43f5e 100%);
+ background: linear-gradient(135deg, #d9002b 0%, #be123c 100%);
color: #ffffff;
transform: translateY(-1px);
}
.btn-secondary {
- background-color: var(--bg-secondary);
+ background-color: var(--bg-card);
color: var(--text-primary);
border-color: var(--border-strong);
}
.btn-secondary:hover {
- background-color: var(--bg-card-hover);
+ background-color: var(--bg-secondary);
border-color: var(--accent-teal);
color: var(--accent-teal);
transform: translateY(-1px);
@@ -596,7 +749,7 @@ main {
align-items: baseline;
justify-content: space-between;
gap: 0.75rem;
- border-bottom: 1px solid var(--border-subtle);
+ border-bottom: 2px solid var(--border-subtle);
padding-bottom: 0.65rem;
margin-bottom: 1.45rem;
}
@@ -604,10 +757,10 @@ main {
.section-label {
font-family: var(--font-mono);
font-size: 0.78rem;
- font-weight: 700;
+ font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.08em;
- color: var(--accent-teal);
+ color: var(--accent-magenta);
display: block;
margin-bottom: 0.25rem;
}
@@ -620,7 +773,7 @@ main {
.card-grid-2 {
display: grid;
- grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
+ grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
gap: 1.35rem;
}
@@ -629,7 +782,7 @@ main {
position: relative;
background-color: var(--bg-card);
border: 1px solid var(--border-subtle);
- border-top: 3px solid var(--accent-teal);
+ border-top: 5px solid var(--accent-teal);
border-radius: var(--radius-md);
padding: 1.5rem;
display: flex;
@@ -640,16 +793,15 @@ main {
}
.card:hover {
- border-color: var(--border-strong);
transform: translateY(-3px);
box-shadow: var(--shadow-panel);
}
-.card.card-amber { border-top-color: var(--accent-amber); }
-.card.card-synth { border-top-color: var(--accent-magenta); }
-.card.card-emerald { border-top-color: var(--accent-emerald); }
-.card.card-coral { border-top-color: var(--accent-coral); }
-.card.card-violet { border-top-color: var(--accent-violet); }
+.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;
@@ -661,7 +813,7 @@ main {
}
.card h3 a:hover {
- color: var(--accent-teal);
+ color: var(--accent-magenta);
text-decoration: underline;
}
@@ -672,7 +824,7 @@ main {
gap: 0.5rem;
margin-bottom: 0.8rem;
font-family: var(--font-mono);
- font-size: 0.78rem;
+ font-size: 0.76rem;
color: var(--text-muted);
}
@@ -683,8 +835,8 @@ main {
gap: 0.35rem;
font-family: var(--font-mono);
font-size: 0.74rem;
- font-weight: 700;
- padding: 0.22rem 0.6rem;
+ font-weight: 800;
+ padding: 0.22rem 0.65rem;
border-radius: 999px;
border: 1px solid transparent;
}
@@ -692,31 +844,31 @@ main {
.badge-progress {
background-color: var(--accent-amber-soft);
color: var(--accent-amber);
- border-color: rgba(245, 158, 11, 0.45);
+ border-color: rgba(234, 88, 12, 0.35);
}
.badge-experimental {
background-color: var(--accent-magenta-soft);
color: var(--accent-magenta);
- border-color: rgba(236, 72, 153, 0.45);
+ border-color: rgba(219, 39, 119, 0.35);
}
.badge-active {
background-color: var(--accent-emerald-soft);
color: var(--accent-emerald);
- border-color: rgba(16, 185, 129, 0.45);
+ border-color: rgba(5, 150, 105, 0.35);
}
.badge-coral {
background-color: var(--accent-coral-soft);
color: var(--accent-coral);
- border-color: rgba(244, 63, 94, 0.45);
+ border-color: rgba(225, 29, 72, 0.35);
}
.badge-draft {
background-color: var(--accent-teal-soft);
color: var(--accent-teal);
- border-color: rgba(6, 182, 212, 0.45);
+ border-color: rgba(2, 132, 199, 0.35);
}
.tag-list {
@@ -736,7 +888,7 @@ main {
display: inline-block;
font-family: var(--font-mono);
font-size: 0.75rem;
- font-weight: 600;
+ font-weight: 700;
color: var(--text-secondary);
background-color: var(--bg-secondary);
border: 1px solid var(--border-subtle);
@@ -744,18 +896,18 @@ main {
border-radius: 6px;
}
-.tag.tag-c { color: #38bdf8; border-color: rgba(56, 189, 248, 0.35); background: rgba(56, 189, 248, 0.1); }
-.tag.tag-esp { color: #f59e0b; border-color: rgba(245, 158, 11, 0.35); background: rgba(245, 158, 11, 0.1); }
-.tag.tag-rust { color: #fb7185; border-color: rgba(251, 113, 133, 0.35); background: rgba(251, 113, 133, 0.1); }
-.tag.tag-python { color: #a78bfa; border-color: rgba(167, 139, 250, 0.35); background: rgba(167, 139, 250, 0.1); }
-.tag.tag-hw { color: #34d399; border-color: rgba(52, 211, 153, 0.35); background: rgba(52, 211, 153, 0.1); }
-.tag.tag-synth { color: #f472b6; border-color: rgba(244, 114, 182, 0.35); background: rgba(244, 114, 182, 0.1); }
+.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: 3px solid var(--accent-violet);
+ border-left: 4px solid var(--accent-violet);
border-radius: var(--radius-sm);
padding: 0.9rem 1.05rem;
margin: 0.85rem 0 1.1rem;
@@ -773,7 +925,7 @@ main {
.card-actions {
display: flex;
flex-wrap: wrap;
- gap: 0.65rem;
+ gap: 0.6rem;
padding-top: 0.95rem;
border-top: 1px solid var(--border-subtle);
}
@@ -787,11 +939,12 @@ main {
.poc-video-card {
position: relative;
- background: linear-gradient(135deg, rgba(15, 23, 42, 0.95) 0%, rgba(30, 27, 75, 0.92) 50%, rgba(49, 16, 47, 0.9) 100%);
- border: 1px solid rgba(244, 63, 94, 0.45);
+ 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: 0 14px 36px rgba(244, 63, 94, 0.14);
+ box-shadow: var(--shadow-panel);
overflow: hidden;
}
@@ -800,10 +953,9 @@ main {
aspect-ratio: 16 / 9;
width: 100%;
background:
- radial-gradient(circle at 50% 50%, rgba(255, 0, 51, 0.18), transparent 60%),
- repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.02) 0px, rgba(255, 255, 255, 0.02) 1px, transparent 1px, transparent 24px),
- linear-gradient(180deg, #090d16 0%, #111827 100%);
- border: 1px solid rgba(255, 255, 255, 0.14);
+ 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);
display: flex;
flex-direction: column;
@@ -822,14 +974,14 @@ main {
display: inline-flex;
align-items: center;
justify-content: center;
- box-shadow: 0 0 0 8px rgba(255, 0, 51, 0.18), 0 10px 28px rgba(255, 0, 51, 0.45);
+ 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.25), 0 14px 32px rgba(255, 0, 51, 0.6);
+ box-shadow: 0 0 0 12px rgba(255, 0, 51, 0.3), 0 14px 32px rgba(255, 0, 51, 0.65);
}
.poc-play-triangle {
@@ -850,10 +1002,10 @@ main {
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.06em;
- color: #fda4af;
- background: rgba(244, 63, 94, 0.2);
- border: 1px solid rgba(244, 63, 94, 0.45);
- padding: 0.25rem 0.7rem;
+ 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;
}
@@ -866,8 +1018,8 @@ main {
}
.poc-video-desc {
- color: #cbd5e1;
- max-width: 56ch;
+ color: #e2e8f0;
+ max-width: 58ch;
font-size: 0.94rem;
margin-bottom: 0;
}
@@ -876,7 +1028,7 @@ main {
.callout-box {
background-color: var(--bg-secondary);
border: 1px solid var(--border-strong);
- border-left: 4px solid var(--accent-teal);
+ border-left: 5px solid var(--accent-teal);
border-radius: var(--radius-md);
padding: 1.4rem 1.55rem;
margin: 1.5rem 0;
@@ -893,7 +1045,7 @@ main {
.callout-title {
font-family: var(--font-mono);
font-size: 0.85rem;
- font-weight: 700;
+ font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--accent-teal);
@@ -911,11 +1063,12 @@ main {
/* Figure & Schematic Frames + Zoomable Images */
.schematic-frame {
- background-color: var(--bg-secondary);
- border: 1px solid var(--border-subtle);
+ 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);
}
.schematic-caption {
@@ -939,7 +1092,7 @@ main {
.lightbox-backdrop {
position: fixed;
inset: 0;
- background: rgba(2, 6, 23, 0.92);
+ background: rgba(15, 23, 42, 0.92);
backdrop-filter: blur(8px);
z-index: 2000;
display: flex;
@@ -974,12 +1127,13 @@ main {
position: absolute;
top: 1.25rem;
right: 1.5rem;
- background: var(--bg-card);
+ background: #ff0033;
color: #ffffff;
- border: 1px solid var(--border-strong);
+ border: none;
border-radius: var(--radius-sm);
- padding: 0.45rem 0.9rem;
+ padding: 0.5rem 0.95rem;
font-family: var(--font-mono);
+ font-weight: 700;
cursor: pointer;
}
@@ -988,6 +1142,7 @@ main {
margin-bottom: 1.25rem;
font-family: var(--font-mono);
font-size: 0.85rem;
+ font-weight: 700;
}
.breadcrumb a {
@@ -996,7 +1151,7 @@ main {
}
.breadcrumb a:hover {
- color: var(--accent-amber);
+ color: var(--accent-magenta);
text-decoration: underline;
}
@@ -1009,14 +1164,14 @@ main {
}
.filter-btn {
- background-color: var(--bg-secondary);
+ background-color: var(--bg-card);
color: var(--text-secondary);
- border: 1px solid var(--border-subtle);
+ 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: 600;
+ font-weight: 700;
cursor: pointer;
}
@@ -1026,10 +1181,9 @@ main {
}
.filter-btn[aria-pressed="true"] {
- background-color: var(--accent-teal-soft);
- color: var(--accent-teal);
- border-color: var(--accent-teal);
- font-weight: 700;
+ background: var(--grad-brand);
+ color: #ffffff;
+ border-color: transparent;
}
/* Spec / Component Table */
@@ -1038,10 +1192,11 @@ main {
border-collapse: collapse;
margin: 1rem 0 1.5rem;
font-size: 0.95rem;
- background-color: var(--bg-secondary);
- border: 1px solid var(--border-subtle);
+ 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,
@@ -1052,10 +1207,11 @@ main {
}
.spec-table th {
- background-color: var(--bg-card);
- color: var(--accent-teal);
+ 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;
}
@@ -1067,7 +1223,7 @@ main {
/* Footer */
.site-footer {
background-color: var(--bg-secondary);
- border-top: 1px solid var(--border-subtle);
+ border-top: 2px solid var(--border-subtle);
padding: 2.25rem 0;
margin-top: auto;
font-size: 0.92rem;
@@ -1095,7 +1251,7 @@ main {
}
/* Responsive Mobile Navigation */
-@media (max-width: 780px) {
+@media (max-width: 840px) {
.nav-toggle {
display: inline-flex;
}
@@ -1111,12 +1267,6 @@ main {
border-top: 1px solid var(--border-subtle);
}
- .header-inner {
- flex-wrap: wrap;
- padding-top: 0.6rem;
- padding-bottom: 0.6rem;
- }
-
.nav-list {
flex-direction: column;
align-items: stretch;
diff --git a/assets/js/main.js b/assets/js/main.js
index ccf7027..59bf886 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,56 +1,53 @@
/* ==========================================================================
Ertunç Özbay — Workshop & Portfolio Script (Plain JS, No Dependencies)
Handles:
- 1. Accessible mobile navigation menu toggle (with Escape key support)
- 2. Luminous Aurora / Daylight Studio theme switcher (persisted in localStorage)
+ 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 email button on Contact page
+ 4. One-click copy buttons for Email addresses and Code/Command blocks
5. Image lightbox for hardware prototype photos and schematics
========================================================================== */
(function () {
"use strict";
- // 1. Theme Switcher (Vibrant Aurora Default + Daylight Studio Mode)
+ // 1. Multi-Theme Switcher (Colorful Default, Cyber Neon, Blueprint Lab)
var rootEl = document.documentElement;
- var savedTheme = null;
+ var validThemes = ["colorful", "neon", "blueprint"];
+ var savedTheme = "colorful";
+
try {
- savedTheme = localStorage.getItem("eo-theme");
+ var stored = localStorage.getItem("eo-studio-theme");
+ if (stored && validThemes.indexOf(stored) !== -1) {
+ savedTheme = stored;
+ }
} catch (e) {}
- if (savedTheme === "light" || savedTheme === "dark") {
- rootEl.setAttribute("data-theme", savedTheme);
- }
-
- var navList = document.querySelector(".nav-list");
- if (navList && !document.querySelector("[data-theme-toggle]")) {
- var li = document.createElement("li");
- var btn = document.createElement("button");
- btn.type = "button";
- btn.className = "theme-toggle";
- btn.setAttribute("data-theme-toggle", "");
- btn.setAttribute("aria-label", "Toggle color theme");
-
- function updateThemeBtnLabel() {
- var isLight = rootEl.getAttribute("data-theme") === "light";
- btn.textContent = isLight ? "🌙 Aurora" : "☀️ Daylight";
+ function applyTheme(themeName) {
+ if (validThemes.indexOf(themeName) === -1) {
+ themeName = "colorful";
}
- updateThemeBtnLabel();
+ rootEl.setAttribute("data-theme", themeName);
+ try {
+ localStorage.setItem("eo-studio-theme", themeName);
+ } catch (e) {}
- btn.addEventListener("click", function () {
- var isLight = rootEl.getAttribute("data-theme") === "light";
- var nextTheme = isLight ? "dark" : "light";
- rootEl.setAttribute("data-theme", nextTheme);
- try {
- localStorage.setItem("eo-theme", nextTheme);
- } catch (e) {}
- updateThemeBtnLabel();
+ 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");
});
-
- li.appendChild(btn);
- navList.appendChild(li);
}
+ applyTheme(savedTheme);
+
+ document.addEventListener("click", function (event) {
+ var themeBtn = event.target.closest("[data-set-theme]");
+ if (themeBtn) {
+ applyTheme(themeBtn.getAttribute("data-set-theme"));
+ }
+ });
+
// 2. Mobile Navigation Toggle
var navToggle = document.querySelector("[data-nav-toggle]");
var siteNav = document.querySelector("[data-site-nav]");
@@ -114,8 +111,8 @@
}
// 4. Copy Email to Clipboard Buttons
- var copyButtons = document.querySelectorAll("[data-copy-email]");
- copyButtons.forEach(function (btn) {
+ var copyEmailButtons = document.querySelectorAll("[data-copy-email]");
+ copyEmailButtons.forEach(function (btn) {
btn.addEventListener("click", function () {
var email = btn.getAttribute("data-copy-email");
if (!email || !navigator.clipboard) return;
@@ -129,7 +126,25 @@
});
});
- // 5. Image Lightbox for Hardware Photos & Schematics
+ // 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;
+ }, 2000);
+ });
+ });
+ });
+
+ // 6. Image Lightbox for Hardware Photos & Schematics
var zoomImages = document.querySelectorAll(".zoomable-img");
if (zoomImages.length > 0) {
var backdrop = document.createElement("div");
diff --git a/blog/index.html b/blog/index.html
index 52b3fcd..ba8122a 100644
--- a/blog/index.html
+++ b/blog/index.html
@@ -1,12 +1,12 @@
-
+
Blog & Build Notes — Ertunç Özbay
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -121,7 +129,7 @@
-
+
diff --git a/blog/post-template.html b/blog/post-template.html
index a1321fb..b032774 100644
--- a/blog/post-template.html
+++ b/blog/post-template.html
@@ -1,12 +1,12 @@
-
+
- [Template] Project Build Log & Technical Note Template — Blog — Ertunç Özbay
-
+ [Template] Project Build Log & Technical Note — Blog — Ertunç Özbay
+
-
+
Skip to main content
@@ -17,25 +17,33 @@
EÖ
Ertunç Özbay
- workshop // notebook // lab
+ embedded // hardware // open-source
-
- ☰
- Menu
-
+
@@ -45,91 +53,47 @@
← Back to Blog
-
-
- Template • Draft Example
- YYYY-MM-DD (Template)
+ Template • Draft
+ YYYY-MM-DD
• Category: Build Log / Technical Note
- • Reading time: X min read
- [Template] Article Title: What I Tested and Learned on the Bench
+ [Template] Project Build Log & Technical Note Title
- Summary: This page is a clearly labeled static HTML template for future blog posts. Copy this file whenever you want to publish a new build log, C programming note, or circuit experiment.
+ Copy this file to create a new static build log entry with hardware notes, copyable code windows, and lessons learned.
-
- template
- draft
- embedded-learning
- c-programming
-
-
-
Template Notice
-
- This entry is a reusable Template / Draft kept in the repository so creating new posts requires only copying a single HTML file—no CMS, database, or build script needed.
-
-
-
-
- 1. Goal of the Experiment or Build Step
-
- Write a short paragraph explaining what you set out to build, test, or investigate. Keep it personal and honest—just like explaining the setup to a friend or engineering teammate.
-
-
-
-
- 2. Hardware & Software Setup
-
- List only the confirmed hardware components, tools, or code files you actually used during this session.
-
- /* Example C code snippet or terminal note */
-// Document register settings, MIDI array structures, or test logic here.
-
-
-
- 3. What Worked and What Failed
-
- Documenting what failed is just as valuable as documenting what worked. Note any wiring mistakes, timing bugs, or AI-generated code assumptions that needed manual debugging.
-
-
-
-
- 4. Next Step & Related Projects
-
- Link this post back to the relevant project detail page so visitors can follow the full story:
-
-
+
+ 1. Goal & Hardware Setup
+ Describe the circuit, microcontroller, or software module under test.
+
+
+
// Example code block in post template
+void app_main(void) {
+ printf("Hello from ESP-IDF!\n");
+}
+
-
-
+
diff --git a/blog/welcome-to-my-workshop-note.html b/blog/welcome-to-my-workshop-note.html
index 7c79599..2fe2e99 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
-
+
Skip to main content
@@ -17,25 +17,33 @@
EÖ
Ertunç Özbay
- workshop // notebook // lab
+ embedded // hardware // open-source
-
- ☰
- Menu
-
+
@@ -48,20 +56,19 @@
- Example • Starter Note
+ Starter Note
October 14, 2026
• Category: Personal Learning Reflections
• Reading time: 3 min read
- Why I Built This Personal Workshop & Learning Notebook
+ Why I Built This Personal Workshop & Learning Notebook
A short starter note on why I want my website to feel like an open engineering workbench rather than a polished corporate résumé.
- workshop
- hardware-software
- open-source
- learning-in-public
+ workshop
+ hardware-software
+ open-source
@@ -78,19 +85,17 @@
Hardware, Software, and Responsibility
- Whether I am working on my MIDI Breadboard Instrument , my Multi-Functional RC Controller , or my RC and Autonomous Vehicle project, my goal is to understand how the physical circuit and the code interact.
-
-
- Just like understanding a car’s steering, brakes, and dynamics makes you a more responsible driver, understanding both hardware and software helps me ask better questions, evaluate AI output critically, spot mistakes, and take responsibility for what I build.
+ Whether I am working on my MIDI Breadboard Instrument , my Multi-Functional RC Controller , my Point Blank Linux Launcher , or my RC and Autonomous Vehicle project, my goal is to understand how the physical circuit and the code interact.
Related Projects
@@ -45,12 +53,13 @@
✉️ DIRECT CONTACT // OPEN 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 Gmail, LinkedIn, or GitHub.
+ 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 GitHub.
@@ -58,29 +67,26 @@
-
+
- Primary Inbox • Gmail
- Fastest Response
+ Primary Email
+ Direct Inbox
-
+
- My primary personal and engineering Gmail inbox. Ideal for project discussions, schematic/code questions, internship or collaboration inquiries, and fellow student builders.
-
-
- Secondary / Git Email (Outlook): ertunc.ozbay@outlook.com
+ My official engineering and open-source email inbox. Ideal for project discussions, schematic/firmware questions, internship or collaboration inquiries, and fellow student builders.
@@ -111,7 +117,7 @@
@@ -139,7 +147,9 @@
@@ -152,7 +162,9 @@
@@ -188,7 +200,7 @@
-
+
diff --git a/index.html b/index.html
index 1ecf054..779e5c6 100644
--- a/index.html
+++ b/index.html
@@ -1,12 +1,12 @@
-
+
Ertunç Özbay — Embedded Systems, Hardware Lab & Open-Source Projects
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -48,12 +56,12 @@
I design embedded hardware, write bare-metal C & FreeRTOS firmware, and build open-source systems from the transistor level up to Linux desktop tooling.
- Welcome to my engineering studio and notebook. Here I document my real hardware prototypes—from an ESP32-S3 2.4 GHz Multi-Functional RC Console and a Dual-Core ESP32 16-Track MIDI Synthesizer to a 4WD Autonomous Vehicle and a Standalone Linux Game Launcher written in Rust .
+ 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 .
@@ -70,8 +78,8 @@
Custom Python RLE MIDI-to-C Compiler
- Open Source
- Schematics, Firmware & Build Logs
+ Direct Downloads
+ Pre-Built Binaries, Firmware & Schematics
@@ -79,10 +87,10 @@
@@ -101,12 +109,13 @@
ESP32-S3-N16R8
ESP-IDF C99
nRF24L01+ 2.4GHz
- KiCad Schematic
+ KiCad Schematic
@@ -129,12 +138,37 @@
+
+
+
+ v1.0.0 Binary Released
+ Rust • Linux Systems & Wine
+
+
+
+ An all-in-one standalone Linux desktop launcher written in Rust that runs Point Blank (Zepetto / TAM) on Linux with 100% unmodified official CheatBlocker anti-cheat, automated Wine prefix provisioning, and DirectX 9 / DirectX 11 support.
+
+
+ Rust
+ Wine / DirectX 11
+ Linux x86_64 Binary
+
+
+
+
+
+
+
-
-
-
-
- v1.0.0 Released
- Rust • Linux Systems & Wine
-
-
-
- An all-in-one standalone Linux desktop launcher written in Rust that runs Point Blank (Zepetto / TAM) on Linux with 100% unmodified official CheatBlocker anti-cheat, automated Wine prefix provisioning, and DirectX 9 / DirectX 11 support.
-
-
- Rust
- Wine / DirectX 11
- Linux Desktop
-
-
-
-
+
+
+
+
+
+
+
# 1. ESP32-S3 Multi-Functional Controller (ESP-IDF v5.2.2)
+git clone https://github.com/ertunc-ozbay/multi-functional-controller.git
+cd multi-functional-controller/firmware && source ~/esp/esp-idf/export.sh && idf.py build
+
+# 2. ESP32 16-Track MIDI Breadboard Synthesizer & Python RLE Compiler
+git clone https://github.com/ertunc-ozbay/midi-breadboard-instrument.git
+cd midi-breadboard-instrument && python3 scripts/midi_to_c.py scripts/midillis/Alla_Turca/Alla_Turca.mid
+
+# 3. Point Blank Linux Standalone Launcher (Download Pre-Compiled x86_64 Release)
+curl -L -O https://github.com/ertunc-ozbay/pointblank-linux/releases/latest/download/pointblank-linux-v1.0.0-linux-x86_64.tar.gz
+tar -xzf pointblank-linux-v1.0.0-linux-x86_64.tar.gz && cd pointblank-linux-v1.0.0-linux-x86_64 && ./pointblank-linux
@@ -217,7 +259,7 @@
Direct Contact
Collaborate & Connect
- Reach out directly via Gmail (ertuncozbayh@gmail.com), Outlook, LinkedIn, or GitHub to discuss embedded systems, electronics, or open-source builds.
+ Reach out directly via email at ertunc.ozbay@outlook.com, LinkedIn, or GitHub to discuss embedded systems, electronics, or open-source builds.
View Contact & Email Details →
@@ -231,7 +273,7 @@
-
+
diff --git a/lab.html b/lab.html
index afc17ee..f3039a6 100644
--- a/lab.html
+++ b/lab.html
@@ -1,15 +1,15 @@
-
+
Lab & Experiment Notebook — Ertunç Özbay
-
+
- Skip to main content
+ Skip to main content
@@ -69,6 +77,10 @@
While building the 16-Track MIDI Breadboard Instrument , raw MIDI delta-slices caused the LEDs and 1.3" SPI OLED to strobe violently. Writing a custom Run-Length Encoding (RLE) compressor in Python (midi_to_c.py) and transposing bass-heavy tracks like Seven Nation Army +2 octaves solved both flash exhaustion and piezo acoustic roll-off.
+
@@ -82,6 +94,10 @@
On the
Multi-Functional RC Controller , the ESP32-S3-N16R8 reserves
GPIO 35–37 for internal Octal PSRAM/Flash. We remapped the shared SPI2 bus (
MOSI: 11, MISO: 13, SCK: 12) with dedicated hardware CS lines for the nRF24L01+ (
CSN: 10), MicroSD (
CS: 39), and ST7789 IPS TFT (
CS: 40).
+
@@ -106,6 +122,10 @@
In pointblank-linux , we engineered a standalone Rust launcher that automatically provisions a 16-byte TLS-aligned ntdll.dll runtime and vcrun2022 / d3dx11_43 components so Point Blank runs at 200 FPS in DirectX 11 on Linux with unmodified official CheatBlocker anti-cheat.
+
@@ -116,9 +136,12 @@
RLE MIDI-to-C Struct Compiler (midi_to_c.py)
- Converts multi-channel `.mid` files into compact C99 SequenceStep struct arrays (`{frequency, duration, kick_drum, hi_hat}`), automatically routing MIDI Channel 10 and low bass notes (`< MIDI 50`) to hardware percussion buzzers.
+ Converts multi-channel `.mid` files into compact C99 SequenceStep struct arrays ({frequency, duration, kick_drum, hi_hat}), automatically routing MIDI Channel 10 and low bass notes (< MIDI 50) to hardware percussion buzzers.
+
@@ -148,7 +171,7 @@
-
+
diff --git a/projects/index.html b/projects/index.html
index 6fe2c3f..34726a1 100644
--- a/projects/index.html
+++ b/projects/index.html
@@ -1,12 +1,12 @@
-
+
- Projects — Ertunç Özbay
-
+ Projects, Code & Downloads — Ertunç Özbay
+
-
+
Skip to main content
@@ -21,31 +21,39 @@
-
- ☰
- Menu
-
+
- ⚡ PROJECT SHOWCASE // VERIFIED BUILDS & REPOSITORIES
+ ⚡ PROJECT SHOWCASE // CODE, COMMANDS, DOWNLOADS & POC VIDEOS
Engineering Projects & Open-Source Builds
- Every project documented here is backed by real hardware on my bench or shipped open-source code on my GitHub—complete with verified pinouts, schematics, build photos, and dedicated slots for upcoming YouTube Proof-of-Concept (PoC) demonstration videos .
+ 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 .
@@ -67,7 +75,7 @@
- A custom 2.4 GHz wireless remote controller and multi-purpose embedded console built around the ESP32-S3-N16R8 and nRF24L01+ PA+LNA transceiver. Currently built as an early Rev 0.1 perfboard carrier and transitioning into a DT-100 (190×137×59 mm) desktop console with dual K-Silver Hall-effect gimbals and a 1.3" ST7789 IPS TFT display.
+ A custom 2.4 GHz wireless remote controller and multi-purpose embedded console built around the ESP32-S3-N16R8 and nRF24L01+ PA+LNA transceiver. Includes C99 ESP-IDF firmware, KiCad 9.0 schematics, Rev 0.1 perfboard photos, and Phase 2 DT-100 console BOM.
-
Includes on page: 3 early prototype build photos, full KiCad SVG schematic, verified ESP32-S3 GPIO pinout, Phase 2 DT-100 BOM, and 🎬 YouTube PoC Video Placeholder .
+
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 .
@@ -112,51 +121,23 @@
-
Includes on page: 3 high-res breadboard photos, 16-track playlist table, ESP32 pinout, RLE compression architecture, and 🎬 YouTube PoC Video Placeholder .
+
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 .
-
-
-
-
- In Progress
- Project 03 • Robotics & Control
-
-
-
- An ongoing 4WD robotic vehicle platform exploring manual 2.4 GHz RF remote control (paired with the Multi-Functional Controller) alongside autonomous obstacle avoidance, motor driver electronics, and real-time control logic.
-
-
-
- 4WD Vehicle Platform
- 2.4 GHz RF Receiver Link
- Autonomous Control Logic
- Power & Motor Electronics
-
-
-
-
Includes on page: System scope, manual-to-autonomous control transition notes, and 🎬 YouTube PoC Video Placeholder .
-
-
-
-
-
-
-
+
- v1.0.0 Shipped
- Project 04 • Rust & Linux Systems
+ v1.0.0 Shipped Binary
+ Project 03 • Rust & Linux Systems
@@ -171,13 +152,43 @@
-
Includes on page: Architecture overview, Wine prefix automation breakdown, release links, and 🎬 YouTube PoC Video Placeholder .
+
Included on page: Direct pre-compiled `x86_64` release `.tar.gz` download, copyable distro dependency commands (Arch/Ubuntu/Fedora), Rust source build commands, and 🎬 YouTube PoC Video slot .
+
+
+
+
+
+
+ In Progress
+ Project 04 • Robotics & Control
+
+
+
+ An ongoing 4WD robotic vehicle platform exploring manual 2.4 GHz RF remote control (paired with the Multi-Functional Controller) alongside autonomous obstacle avoidance, motor driver electronics, and real-time control logic.
+
+
+
+ 4WD Vehicle Platform
+ 2.4 GHz RF Receiver Link
+ Autonomous Control Logic
+ Power & Motor Electronics
+
+
+
+
Included on page: C99 2.4 GHz telemetry receiver packet & differential motor drive code structure, companion controller link, and 🎬 YouTube PoC Video slot .
+
+
+
+
@@ -189,7 +200,7 @@
-
+
diff --git a/projects/midi-breadboard-instrument.html b/projects/midi-breadboard-instrument.html
index f732f0b..a2384cb 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
-
+
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -59,9 +67,10 @@
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.
@@ -70,7 +79,6 @@
🎬 Proof of Concept // YouTube Video Showcase
YouTube Proof-of-Concept Demonstration
-
-
- 02 // Engineering Challenges Solved
- From a Squeaking Buzzer to a Dual-Core Synthesizer
-
- Pushing a bare-metal breadboard setup to play recognizable, energetic multi-track music required solving several real embedded systems challenges:
+
+
+ 02 // Terminal Commands, Python RLE Compiler & C99 Firmware
+ 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:
-
- The Strobe-Light Bug & RLE Compression (midi_to_c.py): Raw MIDI files often slice sustained notes into microscopic fragments, causing the LEDs and OLED UI to strobe at 30+ Hz while wasting flash memory. We built a custom Python Run-Length Encoding (RLE) compressor using mido that merges contiguous identical pitch/drum states into solid SequenceStep blocks and routes bass/percussion channels to dedicated drum triggers.
- Acoustic Hardware Limits (+2 Octave Transposition): Passive piezo buzzers physically struggle to resonate at low bass frequencies. Tracks with deep basslines like Seven Nation Army were transposed up two full octaves so the piezo disc resonates clearly while the active buzzers carry the rhythmic punch.
- Dual-Core FreeRTOS Lockless IPC: Core 0 runs oled_visualizer_task (30 FPS SPI DMA framebuffer engine) and button_task (debounced input polling), while Core 1 exclusively runs buzzer_sequence_task for microsecond-accurate LEDC PWM pitch generation and hardware PCNT rotary encoder scaling.
-
+
+
+
+
# 1. Clone the repository
+git clone https://github.com/ertunc-ozbay/midi-breadboard-instrument.git
+cd midi-breadboard-instrument
+
+# 2. (Optional) Convert a custom .mid file into an RLE-compressed C struct array
+pip install mido
+python3 scripts/midi_to_c.py scripts/midillis/Alla_Turca/Alla_Turca.mid > my_track.h
+
+# 3. Build and flash the 16-track firmware to ESP32
+source ~/esp/esp-idf/export.sh
+idf.py build
+idf.py -p /dev/ttyUSB0 flash monitor
+
+
+ Python RLE MIDI-to-C Compiler (scripts/midi_to_c.py)
+
+ To prevent fragmented MIDI delta-times from strobing the LEDs/OLED at 30+ Hz and exhausting flash memory, midi_to_c.py merges contiguous identical states via Run-Length Encoding and routes Channel 10 + bass notes (`< MIDI 50`) to hardware percussion buzzers:
+
+
+
+
+
#!/usr/bin/env python3
+import sys, mido
+
+def convert_midi_to_c(midi_filename):
+ mid = mido.MidiFile(midi_filename)
+ safe_name = midi_filename.split('/')[-1].replace('.mid', '').replace('-', '_')
+ print(f"const SequenceStep midi_{safe_name}[] = {{")
+
+ active_melody_notes = set()
+ time_accum = 0.0
+ trigger_kick = trigger_hat = False
+ rle_freq, rle_dur, rle_kick, rle_hat = -1, 0, False, False
+
+ for msg in mid:
+ time_accum += msg.time
+ if msg.type in ['note_on', 'note_off'] and time_accum > 0.01:
+ duration_ms = int(time_accum * 1000)
+ freq = int(440.0 * (2.0 ** ((max(active_melody_notes) - 69) / 12.0))) if active_melody_notes else 0
+
+ # RLE Engine: coalesce contiguous identical frequency & drum states
+ if freq == rle_freq and trigger_kick == rle_kick and trigger_hat == rle_hat:
+ rle_dur += duration_ms
+ else:
+ if rle_dur > 0:
+ print(f" {{{rle_freq}, {rle_dur}, {str(rle_kick).lower()}, {str(rle_hat).lower()}}},")
+ rle_freq, rle_dur, rle_kick, rle_hat = freq, duration_ms, trigger_kick, trigger_hat
+
+ time_accum, trigger_kick, trigger_hat = 0.0, False, False
+
+
+ Dual-Core FreeRTOS Music & Visualizer Architecture (main/mmcontroller.c)
+
+
+
typedef struct {
+ uint16_t frequency; // Melody pitch in Hz (driven by 13-bit LEDC PWM on GPIO 25)
+ uint16_t duration; // Step duration in ms (scaled live by PCNT rotary speed)
+ bool kick_drum; // Triggers Active Buzzer 1 (GPIO 26) + Kick LED (GPIO 21)
+ bool hi_hat; // Triggers Active Buzzer 2 (GPIO 27) + Hat LED (GPIO 22)
+} SequenceStep;
+
+void app_main(void) {
+ printf("Desk Rave: 16-Track Symphony Edition Initializing...\n");
+ init_hardware();
+
+ // Core 0: 30 FPS SPI OLED Framebuffer Visualizer & 50ms Button Polling
+ xTaskCreatePinnedToCore(oled_visualizer_task, "oled_task", 4096, NULL, 4, NULL, 0);
+ xTaskCreatePinnedToCore(button_task, "btn_task", 4096, NULL, 5, NULL, 0);
+
+ // Core 1: Dedicated Real-Time Audio Synthesizer & PCNT Rotary Scaling
+ xTaskCreatePinnedToCore(buzzer_sequence_task, "music_task", 4096, NULL, 5, NULL, 1);
+}
+
@@ -188,9 +286,6 @@
04 // Flash Memory Playlist
The 16-Track Symphony
-
- All 16 tracks are stored in ESP32 flash memory as SequenceStep arrays featuring frequency, duration, kick_drum, and hi_hat triggers:
-
Careless Whisper (Extended Club Edit)
Take On Me (EDM Build-up Edition)
@@ -210,20 +305,6 @@
Mega Man 2 (Dr. Wily Stage)
-
-
- 05 // Workshop Notes & Next Steps
- Current State & Roadmap
-
-
Current State & Next Steps
-
- The firmware is rock-solid on the breadboard: the rotary encoder dynamically scales volume and tempo via lockless IPC variables, all 16 tracks play from flash memory, and the 1.3" SPI OLED renders real-time frequency bars and drum hits at 30 FPS.
-
-
- Next Step: Migrating the dual-breadboard circuit onto a soldered perfboard or custom KiCad PCB.
-
-
-
@@ -232,7 +313,7 @@
-
+
diff --git a/projects/multi-functional-controller.html b/projects/multi-functional-controller.html
index 94482c5..d75f2a2 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
-
+
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -59,9 +67,10 @@
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.
@@ -70,7 +79,6 @@
🎬 Proof of Concept // YouTube Video Showcase
YouTube Proof-of-Concept Demonstration
-
@@ -87,9 +95,9 @@
01 // Early Prototype Build (Rev 0.1 Perfboard Carrier)
- Very Early Prototype Hardware Gallery
+ Very Early Prototype Hardware Gallery (Click to Zoom)
- Note: The photos below show the very early Phase 1 (Rev 0.1) perfboard carrier build (click any image to zoom). 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.
+ 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.
@@ -113,25 +121,93 @@
+
+
+ 02 // Terminal Commands & ESP-IDF C99 Firmware
+ 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:
+
+
+
+
+
# 1. Clone the Multi-Functional Controller repository
+git clone https://github.com/ertunc-ozbay/multi-functional-controller.git
+cd multi-functional-controller/firmware
+
+# 2. Export the ESP-IDF v5.2.2 toolchain environment
+source ~/esp/esp-idf/export.sh
+
+# 3. Verify target is set to esp32s3 and compile the firmware
+idf.py set-target esp32s3
+idf.py build
+
+# 4. Flash over USB-JTAG/UART and open real-time serial telemetry monitor
+idf.py -p /dev/ttyACM0 flash monitor
+
+
+ Master Node Pinout & Telemetry Firmware Snippet (firmware/main/mmcontroller.c)
+
+ Below is the hardware pinout and hardware `PCNT` quadrature rotary encoder / ADC1 setup from firmware/main/mmcontroller.c :
+
+
+
+
+
// --- 1. ADC1 ANALOG INPUTS (K-Silver Hall-Effect Joysticks & MAX4466 Mic) ---
+#define PIN_JOY_LX GPIO_NUM_4 // ADC1_CH3
+#define PIN_JOY_LY GPIO_NUM_5 // ADC1_CH4
+#define PIN_JOY_RX GPIO_NUM_6 // ADC1_CH5
+#define PIN_JOY_RY GPIO_NUM_7 // ADC1_CH6
+#define PIN_MIC_OUT GPIO_NUM_1 // ADC1_CH0 (MAX4466 Audio Preamp)
+
+// --- 2. SHARED SPI2 BUS (nRF24L01+ PA+LNA, ST7789 1.3" IPS TFT & MicroSD) ---
+#define PIN_SPI_MOSI GPIO_NUM_11
+#define PIN_SPI_SCK GPIO_NUM_12
+#define PIN_SPI_MISO GPIO_NUM_13
+
+#define PIN_NRF_CE GPIO_NUM_9
+#define PIN_NRF_CSN GPIO_NUM_10
+#define PIN_SD_CS GPIO_NUM_39
+#define PIN_TFT_CS GPIO_NUM_40
+#define PIN_TFT_DC GPIO_NUM_41
+#define PIN_TFT_RST GPIO_NUM_42
+
+// --- 3. HARDWARE PCNT ROTARY ENCODER & 2N2222A BJT DRIVER ---
+#define PIN_ENC_CLK GPIO_NUM_15
+#define PIN_ENC_DT GPIO_NUM_16
+#define PIN_ENC_SW GPIO_NUM_17
+#define PIN_BJT_BASE GPIO_NUM_21 // Drives 2N2222A base via 1 kOhm resistor
+
+
+
- 02 // Hardware Schematic Capture
+ 03 // Hardware Schematic Capture
Early KiCad 9.0 Schematic (mfc-1.svg)
- Early prototype KiCad schematic (mfc-1.kicad_sch) — click to zoom full-screen.
+ Early prototype KiCad schematic (mfc-1.kicad_sch) — click to zoom full-screen or download the raw KiCad 9.0 file .
- 03 // Verified ESP32-S3-N16R8 Pinout & Bus Architecture
+ 04 // Verified ESP32-S3-N16R8 Pinout & Bus Architecture
Master Node GPIO Allocation
-
- Because the ESP32-S3-N16R8 reserves GPIO 35–37 internally for its 8 MB Octal PSRAM and 16 MB SPI Flash, all peripherals are mapped across safe ADC1, SPI2, and PCNT pins:
-
@@ -187,7 +263,7 @@
- 04 // Build Roadmap & Phase 2 Console BOM
+ 05 // Build Roadmap & Phase 2 Console BOM
From Rev 0.1 Carrier to the DT-100 Desktop Console
Phase 2 Hardware Upgrade (Direnc.net Procurement List)
@@ -212,7 +288,7 @@
-
+
diff --git a/projects/pointblank-linux.html b/projects/pointblank-linux.html
index a738295..f120491 100644
--- a/projects/pointblank-linux.html
+++ b/projects/pointblank-linux.html
@@ -1,12 +1,12 @@
-
+
Point Blank on Linux (Standalone Rust Launcher) — Projects — Ertunç Özbay
-
+
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -48,8 +56,8 @@
- Status: v1.0.0 Released
- Project 04 // Rust • Linux Systems • Wine & DirectX 9/11
+ Status: v1.0.0 Pre-Compiled Binary Released
+ Project 03 // Rust • Linux Systems • Wine & DirectX 9/11
Point Blank on Linux — Standalone Community Launcher
@@ -59,8 +67,9 @@
Built on Arch Linux without requiring Heroic, Lutris, or external wrappers—featuring automated Wine prefix & Winetricks provisioning, 16-byte TLS-aligned runtime support for DirectX 11, multi-region authentication, and native 1920×1080 borderless fullscreen at 200 FPS.
@@ -70,7 +79,6 @@
🎬 Proof of Concept // YouTube Video Showcase
YouTube Proof-of-Concept Demonstration
-
-
- 01 // Systems Engineering Overview
- Solving Low-Level Windows-on-Linux Compatibility
-
- Running legacy 32-bit/64-bit online Windows games with kernel/user-mode anti-cheat modules like CheatBlocker on Linux often fails due to unaligned Thread Local Storage (TLS) allocations in `ntdll.dll`, missing Visual C++ MFC redistributables, and broken WebView2 login flows.
+
+
+ 01 // Direct Download & Linux Terminal Commands
+ Quick Download & Launch Commands
+
+ You do not need to compile from source—download and run the pre-compiled `x86_64` Linux release archive directly from the terminal:
+
+
+
+
# 1. Download & extract the official pre-compiled Linux x86_64 release archive
+curl -L -O https://github.com/ertunc-ozbay/pointblank-linux/releases/latest/download/pointblank-linux-v1.0.0-linux-x86_64.tar.gz
+tar -xzf pointblank-linux-v1.0.0-linux-x86_64.tar.gz
+cd pointblank-linux-v1.0.0-linux-x86_64
+
+# 2. Make executable and launch (or install desktop menu shortcut)
+chmod +x pointblank-linux install-desktop.sh
+./install-desktop.sh
+./pointblank-linux
+
+
+ 1. Install System Dependencies (Arch / Ubuntu / Fedora)
+
+
+
# Arch Linux / CachyOS / Manjaro / EndeavourOS (with [multilib] enabled)
+sudo pacman -Syu --needed wine wine-mono wine-gecko winetricks mingw-w64-gcc \
+ lib32-vulkan-icd-loader vulkan-icd-loader cabextract curl unzip
+
+# Ubuntu / Debian / Linux Mint / Pop!_OS
+sudo dpkg --add-architecture i386 && sudo apt update
+sudo apt install -y wine wine32 wine64 winetricks gcc-mingw-w64-i686 \
+ mesa-vulkan-drivers mesa-vulkan-drivers:i386 cabextract curl unzip
+
+# Fedora / Nobara
+sudo dnf install -y wine winetricks mingw32-gcc vulkan-loader vulkan-loader.i686 \
+ cabextract curl unzip
+
+
+ 2. Build from Source with Cargo (Rust)
+
+
+
git clone https://github.com/ertunc-ozbay/pointblank-linux.git
+cd pointblank-linux
+cargo build --release
+./target/release/pointblank-linux
+
+
+
+
+ 02 // Systems Engineering Overview
+ Solving Low-Level Windows-on-Linux Compatibility
- 16-Byte TLS-Aligned Runtime for DirectX 11: Automatically provisions a 16-byte TLS-aligned `ntdll.dll` Wine runtime so both DirectX 9 (`DXVersion = 9`) and DirectX 11 (`DXVersion = 11`) render cleanly without crashes.
- One-Click Isolated Prefix Provisioning: Configures `~/.local/share/pointblank-linux/prefix` with `vcrun2022` (`mfc140.dll`, `msvcp140.dll`, `vcruntime140.dll`), `d3dx9_31..43`, `d3dcompiler_43`, `d3dx11_43`, and Edge WebView2 (`109.0.1518.78`).
- In-Game `F11` Borderless Fullscreen Helper: Compiles a lightweight MinGW-w64 helper utility for instant 1920×1080 borderless fullscreen switching at 200 FPS.
+ 16-Byte TLS-Aligned Runtime for DirectX 11: Automatically provisions a 16-byte TLS-aligned ntdll.dll Wine runtime so both DirectX 9 (DXVersion = 9) and DirectX 11 (DXVersion = 11) render cleanly without crashes.
+ One-Click Isolated Prefix Provisioning: Configures ~/.local/share/pointblank-linux/prefix with vcrun2022 (mfc140.dll, msvcp140.dll, vcruntime140.dll), d3dx9_31..43, d3dcompiler_43, d3dx11_43, and Edge WebView2 (109.0.1518.78).
+ In-Game F11 Borderless Fullscreen Helper: Compiles a lightweight MinGW-w64 helper utility for instant 1920×1080 borderless fullscreen switching at 200 FPS.
- 02 // Technical Specifications
+ 03 // Technical Specifications
Confirmed Capabilities & Supported Distros
@@ -110,22 +181,22 @@
Primary Language
- Rust (Standalone Linux `x86_64` executable)
+ Rust (Standalone Linux x86_64 executable)
Anti-Cheat Compatibility
- 100% Unmodified Official CheatBlocker (`CB.exe` + `CB.cbm`)
+ 100% Unmodified Official CheatBlocker (CB.exe + CB.cbm)
Render Pipelines
DirectX 9 & DirectX 11 (1920×1080 Borderless Fullscreen @ 200 FPS)
- Supported Linux Distributions
- Arch Linux / CachyOS / Manjaro, Ubuntu / Debian / Mint / Pop!_OS, Fedora / Nobara
+ Direct Binary Download
+ pointblank-linux-v1.0.0-linux-x86_64.tar.gz
- Source & Binary Releases
+ Source Repository
github.com/ertunc-ozbay/pointblank-linux
@@ -139,7 +210,7 @@
-
+
diff --git a/projects/rc-autonomous-vehicle.html b/projects/rc-autonomous-vehicle.html
index 6398ea0..d757608 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
-
+
-
+
Skip to main content
@@ -21,21 +21,29 @@
-
- ☰
- Menu
-
+
@@ -49,7 +57,7 @@
Status: In Progress
- Project 03 // 4WD Robotics, Control Logic & 2.4 GHz Telemetry
+ Project 04 // 4WD Robotics, Control Logic & 2.4 GHz Telemetry
RC and Autonomous 4WD Vehicle
@@ -57,7 +65,7 @@
@@ -67,7 +75,6 @@
🎬 Proof of Concept // YouTube Video Showcase
YouTube Proof-of-Concept Demonstration
-
@@ -92,8 +99,40 @@
+
+
+ 02 // 2.4 GHz Wireless Protocol Structure
+ 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:
+
+
+
+
+
#include <stdint.h>
+#include <assert.h>
+
+typedef struct __attribute__((packed)) {
+ uint8_t magic; // 0xA5 frame sync byte
+ uint8_t seq; // Rolling packet sequence number
+ int16_t throttle_pwm; // -1000 to +1000 normalized longitudinal drive
+ int16_t steering_pwm; // -1000 to +1000 differential yaw command
+ uint8_t mode_flags; // Bit 0: Autonomous Mode, Bit 1: Emergency Stop
+ uint8_t crc8; // Checksum for packet integrity
+} RcControlPacket_t;
+
+_Static_assert(sizeof(RcControlPacket_t) == 8, "RcControlPacket_t must be 8 bytes");
+
+
+
- 02 // Confirmed Information
+ 03 // Confirmed Information
Current Documentation Status
-
-
- 03 // Workshop Notes
- What I Am Currently Learning & Next Steps
-
-
What I Am Currently Learning
-
- Understanding how power supply decoupling, motor driver PWM control, and wireless telemetry packets interact when transitioning smoothly between manual remote control and autonomous vehicle behavior.
-
-
Next Step
-
- Publishing the dedicated vehicle repository, chassis photos, and the YouTube Proof-of-Concept drive video once bench and floor testing are complete.
-
-
-
@@ -145,7 +169,7 @@
-
+