Ob in der Arduino IDE oder VS Code oder sonstige Entwicklung Umgebungen, wo kann ich das angesteckte Board ansprechen. Ach wäre es nicht toll, wenn ich die USB Anschluss Nummer (COM-Port) beim verbinden, direkt sehen könnte?
Welche meiner installierten Anwendungsprogramme unter Windows 11 sollten mal Upgedatet werden?
Wie kann ich als Ausbilder, bildhafter ich im Netzwerkunterricht, die 7 Schichten im OSI erklären?
Du brauchst schnell mal eine Erweiterung für Windows oder interaktive Darstellung? Da haben wir was für sie! Tada…
Google Antigravity macht es sehr leicht möglich. (Tatsächlich!)

Antigravity ist eine KI-gestützte Entwicklungsplattform, die autonome Agenten einsetzt, um Softwareprojekte zu planen, zu programmieren, zu testen und zu dokumentieren. Sie wurde von Google DeepMind entwickelt als AI-native Entwicklungsumgebungs-App, die klassische Coding-Tools erweitert, indem sie KI-Agenten in den Mittelpunkt stellt. Anders als herkömmliche Assistenten, die nur Codezeilen ergänzen, kann Antigravity komplette Aufgabenpakete autonom bearbeiten – von der Planung über die Umsetzung bis hin zur Überprüfung im Browser.
Klingt nach wenig Aufwand und schnellem Ergebnis 🙂
Download der App: https://antigravity.google/

Hier 4 Anwendungsbeispiele die zeigt wie wenig das Projekt beschrieben werden muss und wie effektiv das Ergebnis war:
Beispiel 1 – Serielle Schnittstellen Anzeige
Anforderung:
Erstelle eine Lösung die im Task Manager die sobald ein Arduino oder esp32 angesteckt wird, den verwendeten COM Port anzeigt und wenn wieder abgeklemmt dann „kein COM Port wird verwendet“ angezeigt sein
Erzeugt wurden im Ordner C:\Users\prilchen\OneDrive\Dokumente\antigravity\ die Datei ComPortMonitor.ps1
Zum lesen anklicken
param(
[switch]$Hidden = $true
)
if ($Hidden) {
# Verstecke das Konsolenfenster
$code = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
}
"@
try {
Add-Type -TypeDefinition $code -ErrorAction SilentlyContinue
[Win32]::ShowWindow([Win32]::GetConsoleWindow(), 0) | Out-Null
} catch {}
}
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
# Erstelle das System-Tray-Icon
$icon = New-Object System.Windows.Forms.NotifyIcon
$icon.Icon = [System.Drawing.SystemIcons]::Information
$icon.Visible = $true
$icon.Text = "Initialisiere COM Port Monitor..."
# Kontextmenü (Rechtsklick) hinzufügen, um das Skript beenden zu können
$contextMenu = New-Object System.Windows.Forms.ContextMenu
$menuItemExit = New-Object System.Windows.Forms.MenuItem
$menuItemExit.Text = "Beenden"
$menuItemExit.add_Click({
$timer.Stop()
$icon.Visible = $false
[System.Windows.Forms.Application]::Exit()
})
$contextMenu.MenuItems.Add($menuItemExit)
$icon.ContextMenu = $contextMenu
# Timer für die Überprüfung der COM Ports (jede Sekunde)
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000
$script:currentPortNames = @()
$script:firstRun = $true
$timer.add_Tick({
# Hole aktuelle COM Ports (sehr schnell, keine hohe CPU Last)
$newPortNames = [System.IO.Ports.SerialPort]::GetPortNames() | Sort-Object
$changed = $false
if ($newPortNames.Count -ne $script:currentPortNames.Count) {
$changed = $true
} else {
for ($i=0; $i -lt $newPortNames.Count; $i++) {
if ($newPortNames[$i] -ne $script:currentPortNames[$i]) {
$changed = $true
break
}
}
}
if ($changed -or $script:firstRun) {
$script:currentPortNames = $newPortNames
if ($newPortNames.Count -gt 0) {
# Wenn Ports vorhanden sind, hole die freundlichen Namen über WMI (z.B. "Arduino Uno (COM3)")
$wmiPorts = Get-CimInstance Win32_PnPEntity | Where-Object { $_.Name -match "\((COM\d+)\)" }
$textParts = @()
foreach ($port in $newPortNames) {
$friendlyName = $port
if ($wmiPorts) {
foreach ($wmi in $wmiPorts) {
if ($wmi.Name -match "\($port\)") {
$friendlyName = $wmi.Name
break
}
}
}
$textParts += $friendlyName
}
$text = $textParts -join ", "
# NotifyIcon.Text ist auf 63 Zeichen limitiert
if ($text.Length -gt 63) {
$text = $text.Substring(0, 60) + "..."
}
$icon.Text = $text
# Wenn es sich geändert hat und es nicht der erste Start ist, zeige eine Benachrichtigung (Balloon Tip)
if (-not $script:firstRun) {
$icon.ShowBalloonTip(3000, "ESP32/Arduino verbunden", ($textParts -join "`n"), [System.Windows.Forms.ToolTipIcon]::Info)
}
} else {
$icon.Text = "kein COM Port wird verwendet"
if (-not $script:firstRun) {
$icon.ShowBalloonTip(3000, "Gerät getrennt", "kein COM Port wird verwendet", [System.Windows.Forms.ToolTipIcon]::Warning)
}
}
$script:firstRun = $false
}
})
$timer.Start()
# Starte die Windows Forms Anwendungsschleife, damit das Icon aktiv bleibt
[System.Windows.Forms.Application]::Run()
und damit ein jeder das sofort starten kann, diese StartMonitor.bat noch dazu:
@echo off
REM Startet den COM Port Monitor im Hintergrund
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0ComPortMonitor.ps1"
Ergebnis:

In Windows unten rechts, bei der Uhr taucht immer wenn ein Microcontroller angeschlossen wird, nun die gewünschte Info auf 🙂
2tes Beispiel – Update Checker
Anforderung:
Erstelle eine Win11 App die beim Start prüft, welche der installierten Programme upgegraded werden können.
Antwort:
Ich habe einen Implementierungsplan für die Windows 11 App erstellt. Bitte sieh dir den Plan an (implementation_plan.md) und teile mir mit, ob du mit dem Technologie-Stack (C# WPF mit nativem Win11 Design) einverstanden bist und beantworte kurz die offenen Fragen.
Auszug:
Bist du mit C# und WPF (Windows Presentation Foundation) in Kombination mit der Bibliothek WPF-UI (für das native Windows 11 Fluent Design mit Mica-Effekt) einverstanden?
Die App wird im Hintergrund den Windows Package Manager (winget) nutzen, um die Updates abzufragen. Ist das in Ordnung?
Hast du .NET 8 SDK auf deinem System installiert? (Falls nicht, müssen wir es installieren oder eine andere Technologie wie Python oder eine Web-App mit Tauri wählen).Sobald du das Go gibst, fange ich mit der Erstellung der App an!
Erzeugte ps1-Datei (Zum Anzeigen anklicken)
import customtkinter as ctk
import subprocess
import threading
import sys
# Configure appearance
ctk.set_appearance_mode("System") # Follow Windows 11 system theme (Dark/Light)
ctk.set_default_color_theme("blue") # Windows 11 style blue accent
class App(ctk.CTk):
def __init__(self):
super().__init__()
self.title("Windows 11 Upgrade Checker")
self.geometry("850x550")
self.minsize(800, 500)
# Grid layout
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
# Header
self.header_frame = ctk.CTkFrame(self, fg_color="transparent")
self.header_frame.grid(row=0, column=0, padx=20, pady=(20, 10), sticky="ew")
self.title_label = ctk.CTkLabel(self.header_frame, text="Verfügbare Updates", font=ctk.CTkFont(family="Segoe UI Variable Display", size=24, weight="bold"))
self.title_label.pack(side="left")
self.refresh_btn = ctk.CTkButton(self.header_frame, text="Aktualisieren", width=120, command=self.load_updates_async)
self.refresh_btn.pack(side="right")
# Loading indicator
self.loading_label = ctk.CTkLabel(self, text="Suche nach Updates (winget wird ausgeführt)...", font=ctk.CTkFont(family="Segoe UI Variable", size=16))
self.loading_label.grid(row=1, column=0, padx=20, pady=20)
# Main scrollable frame for list
self.scroll_frame = ctk.CTkScrollableFrame(self)
# We don't grid it initially, wait until loading is done
self.update_list = []
# Start initial load
self.load_updates_async()
def load_updates_async(self):
self.scroll_frame.grid_forget()
self.loading_label.grid(row=1, column=0, padx=20, pady=20)
self.refresh_btn.configure(state="disabled")
# Clear existing
for widget in self.scroll_frame.winfo_children():
widget.destroy()
thread = threading.Thread(target=self.fetch_winget_updates)
thread.start()
def fetch_winget_updates(self):
try:
# winget upgrade returns non-zero if no updates are found or if there's a warning, so we don't check returncode strictly
startupinfo = None
if sys.platform == "win32":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
result = subprocess.run(
["winget", "upgrade"],
capture_output=True,
text=True,
encoding='utf-8',
errors='ignore',
startupinfo=startupinfo
)
output = result.stdout
apps = self.parse_winget_output(output)
# Update UI on main thread
self.after(0, self.display_updates, apps)
except Exception as e:
self.after(0, self.display_error, str(e))
def parse_winget_output(self, output):
lines = output.split('\n')
header_line = None
header_idx = -1
for i, line in enumerate(lines):
if line.startswith('Name') and 'ID' in line and 'Version' in line:
header_line = line
header_idx = i
break
if not header_line:
return [] # No updates or parsing failed
id_idx = header_line.find('ID')
version_idx = header_line.find('Version')
avail_idx = header_line.find('Verfügbar')
if avail_idx == -1: avail_idx = header_line.find('Available')
source_idx = header_line.find('Quelle')
if source_idx == -1: source_idx = header_line.find('Source')
apps = []
for line in lines[header_idx + 2:]:
if not line.strip() or line.startswith('-'): continue
# Stop parsing if we hit summary lines
if any(keyword in line for keyword in ['Aktualisierung', 'Paket', 'packages', 'updates', 'Mindestens']):
continue
name = line[:id_idx].strip()
app_id = line[id_idx:version_idx].strip()
version = line[version_idx:avail_idx].strip()
if source_idx != -1:
available = line[avail_idx:source_idx].strip()
else:
available = line[avail_idx:].strip()
# Filter out strange symbols sometimes found at the end of names
name = name.rstrip('…')
if name and app_id:
apps.append({
'name': name,
'id': app_id,
'version': version,
'available': available
})
return apps
def display_updates(self, apps):
self.loading_label.grid_forget()
self.scroll_frame.grid(row=1, column=0, padx=20, pady=(0, 20), sticky="nsew")
self.refresh_btn.configure(state="normal")
if not apps:
no_updates = ctk.CTkLabel(self.scroll_frame, text="Dein System ist auf dem neuesten Stand! 🎉", font=ctk.CTkFont(size=16))
no_updates.pack(pady=40)
return
# Headers for the list
header_frm = ctk.CTkFrame(self.scroll_frame, fg_color="transparent")
header_frm.pack(fill="x", padx=10, pady=5)
ctk.CTkLabel(header_frm, text="Name", font=ctk.CTkFont(weight="bold"), width=250, anchor="w").pack(side="left")
ctk.CTkLabel(header_frm, text="Installiert", font=ctk.CTkFont(weight="bold"), width=100, anchor="w").pack(side="left", padx=10)
ctk.CTkLabel(header_frm, text="Verfügbar", font=ctk.CTkFont(weight="bold"), width=100, anchor="w").pack(side="left", padx=10)
for app in apps:
item_frm = ctk.CTkFrame(self.scroll_frame)
item_frm.pack(fill="x", padx=5, pady=5)
# App Name
name_lbl = ctk.CTkLabel(item_frm, text=app['name'], width=250, anchor="w")
name_lbl.pack(side="left", padx=10, pady=10)
# Current Version
cur_lbl = ctk.CTkLabel(item_frm, text=app['version'], width=100, anchor="w", text_color="gray")
cur_lbl.pack(side="left", padx=10, pady=10)
# Available Version
new_lbl = ctk.CTkLabel(item_frm, text=app['available'], width=100, anchor="w", text_color="#2da44e")
new_lbl.pack(side="left", padx=10, pady=10)
# Update Button
update_btn = ctk.CTkButton(
item_frm,
text="Update",
width=80,
command=lambda a_id=app['id']: self.run_update(a_id)
)
update_btn.pack(side="right", padx=15, pady=10)
def display_error(self, err_msg):
self.loading_label.grid_forget()
self.scroll_frame.grid(row=1, column=0, padx=20, pady=(0, 20), sticky="nsew")
self.refresh_btn.configure(state="normal")
err_lbl = ctk.CTkLabel(self.scroll_frame, text=f"Fehler beim Abrufen der Updates:\n{err_msg}", text_color="red")
err_lbl.pack(pady=40)
def run_update(self, app_id):
# Starts a new cmd window to show the winget upgrade process to the user
command = f'winget upgrade --id {app_id} --accept-source-agreements'
subprocess.Popen(f'start cmd /c "{command} & pause"', shell=True)
if __name__ == "__main__":
app = App()
app.mainloop()
Es wird Python unter Windows benötigt. Wer das noch installieren muss, hier die Anleitung:
ESP32 Firmware sichern und wiederherstellen mit ESPTool
Erzeugte Batch:
@echo off
cd /d "%~dp0"
start "" ".\venv\Scripts\pythonw.exe" "main.py"
Ergebnis:

Beim Klick auf einer Update Aufforderung einer Anwendung, geht eine separate Eingabeaufforderung auf. Ein Winget Befehl führt das update dann zuverlässig aus!
3tes Beispiel:
Anforderung:
Ich brauche für die Ausbildung eine grafische Darstellung beim versenden einer email. Die schritt für schritt das verschicken in den 7 OSI Schichten zeigt. Also smtp, utf8 oder kodierung, schicht id, tcp, ip-adressen, mac-adressen und binäre werte
Erzeugt diesen HTML-Code: (anklicken zum lesen)
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OSI-Modell: E-Mail Versand</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=Fira+Code:wght@400;600&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #0f172a;
--text-color: #f8fafc;
--accent-color: #3b82f6;
--accent-hover: #2563eb;
--glass-bg: rgba(255, 255, 255, 0.05);
--glass-border: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 100%);
color: var(--text-color);
min-height: 100vh;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
header {
text-align: center;
padding: 2rem;
background: var(--glass-bg);
border-bottom: 1px solid var(--glass-border);
backdrop-filter: blur(10px);
}
header h1 {
font-weight: 700;
font-size: 2.5rem;
background: linear-gradient(to right, #60a5fa, #c084fc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 0.5rem;
}
.container {
display: flex;
flex: 1;
padding: 2rem;
gap: 2rem;
max-width: 1400px;
margin: 0 auto;
width: 100%;
}
.sidebar {
flex: 0 0 300px;
display: flex;
flex-direction: column;
gap: 1rem;
}
.layer-btn {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
color: var(--text-color);
padding: 1rem;
border-radius: 12px;
cursor: pointer;
text-align: left;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.layer-btn.active {
background: rgba(59, 130, 246, 0.2);
border-color: var(--accent-color);
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3);
transform: translateX(10px);
}
.layer-btn:hover:not(.active) {
background: rgba(255, 255, 255, 0.1);
}
.layer-number {
font-weight: 700;
color: #94a3b8;
font-size: 0.875rem;
margin-bottom: 0.25rem;
}
.active .layer-number {
color: #60a5fa;
}
.layer-name {
font-weight: 600;
font-size: 1.125rem;
}
.main-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 2rem;
}
.info-panel {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(10px);
min-height: 250px;
}
.info-panel h2 {
margin-bottom: 1rem;
color: #c084fc;
}
.info-panel p {
line-height: 1.6;
color: #cbd5e1;
font-size: 1.1rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-top: 1.5rem;
}
.detail-item {
background: rgba(0, 0, 0, 0.2);
padding: 1rem;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.05);
}
.detail-label {
font-size: 0.8rem;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.5rem;
}
.detail-value {
font-family: 'Fira Code', monospace;
font-size: 1rem;
color: #34d399;
word-break: break-all;
}
.packet-visualization {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 2rem;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
overflow-x: auto;
backdrop-filter: blur(10px);
min-height: 180px;
}
.packet-container {
display: flex;
flex-direction: row;
align-items: stretch;
gap: 0.5rem;
}
.packet-chunk {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.5rem;
border-radius: 8px;
font-family: 'Fira Code', monospace;
font-size: 1.1rem;
font-weight: 700;
color: #fff;
opacity: 0;
transform: translateY(-20px);
animation: dropIn 0.3s forwards ease-out;
min-width: 120px;
text-align: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
border: 1px solid rgba(255, 255, 255, 0.2);
}
@keyframes dropIn {
to {
opacity: 1;
transform: translateY(0);
}
}
.controls {
display: flex;
justify-content: space-between;
margin-top: auto;
}
button.nav-btn {
background: var(--accent-color);
color: white;
border: none;
padding: 1rem 2.5rem;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
button.nav-btn:hover:not(:disabled) {
background: var(--accent-hover);
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
button.nav-btn:disabled {
background: #475569;
cursor: not-allowed;
opacity: 0.5;
box-shadow: none;
transform: none;
}
/* Layer specific colors */
.color-7 { background: linear-gradient(135deg, #ec4899, #be185d); }
.color-6 { background: linear-gradient(135deg, #d946ef, #a21caf); }
.color-5 { background: linear-gradient(135deg, #8b5cf6, #6d28d9); }
.color-4 { background: linear-gradient(135deg, #6366f1, #4338ca); }
.color-3 { background: linear-gradient(135deg, #3b82f6, #1d4ed8); }
.color-2 { background: linear-gradient(135deg, #0ea5e9, #0369a1); }
.color-1 { background: linear-gradient(135deg, #14b8a6, #0f766e); }
.binary-stream {
font-family: 'Fira Code', monospace;
font-size: 1.2rem;
color: #34d399;
letter-spacing: 3px;
word-break: break-all;
line-height: 1.8;
max-height: 150px;
overflow: hidden;
position: relative;
text-align: center;
}
.pulse-text {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { opacity: 0.6; }
50% { opacity: 1; text-shadow: 0 0 10px #34d399; }
100% { opacity: 0.6; }
}
</style>
</head>
<body>
<header>
<h1>OSI-Modell: E-Mail Versand</h1>
<p>Schritt-für-Schritt Darstellung der Netzwerkschichten (Top-Down)</p>
</header>
<div class="container">
<div class="sidebar" id="sidebar">
<!-- Dynamically populated -->
</div>
<div class="main-content">
<div class="info-panel" id="infoPanel">
<!-- Dynamically populated -->
</div>
<div class="packet-visualization">
<div class="packet-container" id="packetContainer">
<!-- Dynamically populated -->
</div>
</div>
<div class="controls">
<button class="nav-btn" id="prevBtn" onclick="prevLayer()">Zurück</button>
<button class="nav-btn" id="nextBtn" onclick="nextLayer()">Weiter (Nächste Schicht)</button>
</div>
</div>
</div>
<script>
const layers = [
{
number: 7,
name: "Anwendungsschicht (Application)",
title: "Schicht 7: E-Mail wird verfasst",
desc: "Der Benutzer schreibt eine E-Mail im E-Mail-Client. Das Simple Mail Transfer Protocol (SMTP) wird verwendet, um die Nachricht zu formatieren und für den Versand vorzubereiten.",
details: {
"Protokoll": "SMTP",
"Aktion": "MAIL FROM, RCPT TO, DATA",
"Nutzdaten": "\"Hallo, wie geht's?\""
},
packetLabel: "DATA",
packetColor: "color-7"
},
{
number: 6,
name: "Darstellungsschicht (Presentation)",
title: "Schicht 6: Formatierung & Kodierung",
desc: "Die Nachricht wird in ein einheitliches Format übersetzt. Der Text wird z.B. in UTF-8 kodiert. Hier könnte auch Verschlüsselung (TLS) oder Komprimierung stattfinden.",
details: {
"Kodierung": "UTF-8",
"MIME-Type": "text/plain",
"Konvertiert": "48 61 6c 6c 6f..."
},
packetLabel: "UTF8",
packetColor: "color-6"
},
{
number: 5,
name: "Sitzungsschicht (Session)",
title: "Schicht 5: Sitzungsverwaltung",
desc: "Die Verbindung (Sitzung) zwischen Sender und Empfänger-Server wird logisch aufgebaut und aufrechterhalten. Eine eindeutige Schicht-ID (Session-ID) wird zugewiesen.",
details: {
"Schicht-ID (Session)": "0x8A9B7C2F",
"Status": "Established",
"Kontrolle": "Dialog Control"
},
packetLabel: "SESS",
packetColor: "color-5"
},
{
number: 4,
name: "Transportschicht (Transport)",
title: "Schicht 4: TCP Segmentierung",
desc: "Die Daten werden zuverlässig übertragen. Ein TCP-Header wird hinzugefügt. Da es sich um SMTP handelt, ist der Ziel-Port 25 (oder 587/465).",
details: {
"Protokoll": "TCP",
"Source-Port": "54321 (Dynamisch)",
"Dest-Port": "25 (SMTP)",
"Sequenz-Nr": "1001"
},
packetLabel: "TCP",
packetColor: "color-4"
},
{
number: 3,
name: "Vermittlungsschicht (Network)",
title: "Schicht 3: IP Adressierung (Pakete)",
desc: "Das TCP-Segment wird in ein IP-Paket gepackt. Hier werden die logischen IP-Adressen von Sender und Empfänger hinzugefügt, damit das Paket geroutet werden kann.",
details: {
"Protokoll": "IPv4 / IPv6",
"Source-IP": "192.168.1.10",
"Dest-IP": "203.0.113.50",
"TTL": "64"
},
packetLabel: "IP",
packetColor: "color-3"
},
{
number: 2,
name: "Sicherungsschicht (Data Link)",
title: "Schicht 2: MAC Adressierung (Frames)",
desc: "Das IP-Paket wird in einen Ethernet-Frame gepackt. Die physikalischen MAC-Adressen der Netzwerkkarten (Sender und nächster Router) werden als Header hinzugefügt, plus ein Trailer zur Fehlerprüfung.",
details: {
"Protokoll": "Ethernet II",
"Source-MAC": "AA:BB:CC:DD:EE:FF",
"Dest-MAC": "11:22:33:44:55:66",
"FCS (Trailer)": "0x3A4B5C6D"
},
packetLabel: "MAC",
packetColor: "color-2"
},
{
number: 1,
name: "Bitübertragungsschicht (Physical)",
title: "Schicht 1: Binäre Übertragung",
desc: "Der gesamte Frame wird in eine Folge von Nullen und Einsen (Bits) umgewandelt und als elektrisches Signal, Lichtsignal oder Funkwelle über das physikalische Medium gesendet.",
details: {
"Medium": "Kupfer (CAT6) / WLAN",
"Signal": "Elektrische Impulse",
"Binäre Werte": "01001000 01100101 01101100..."
},
packetLabel: "BITS",
packetColor: "color-1"
}
];
let currentStep = 0;
function init() {
renderSidebar();
updateView();
}
function renderSidebar() {
const sidebar = document.getElementById('sidebar');
sidebar.innerHTML = '';
layers.forEach((layer, index) => {
const btn = document.createElement('div');
btn.className = `layer-btn ${index === currentStep ? 'active' : ''}`;
btn.onclick = () => {
currentStep = index;
updateView();
};
btn.innerHTML = `
<div class="layer-number">Schicht ${layer.number}</div>
<div class="layer-name">${layer.name}</div>
`;
sidebar.appendChild(btn);
});
}
function updateView() {
// Update sidebar active state
document.querySelectorAll('.layer-btn').forEach((btn, idx) => {
btn.className = `layer-btn ${idx === currentStep ? 'active' : ''}`;
});
const layer = layers[currentStep];
// Update info panel
let detailsHtml = '';
for (const [key, value] of Object.entries(layer.details)) {
detailsHtml += `
<div class="detail-item">
<div class="detail-label">${key}</div>
<div class="detail-value">${value}</div>
</div>
`;
}
const infoPanel = document.getElementById('infoPanel');
infoPanel.innerHTML = `
<h2>${layer.title}</h2>
<p>${layer.desc}</p>
<div class="detail-grid">
${detailsHtml}
</div>
`;
// Update packet visualization
const packetContainer = document.getElementById('packetContainer');
if (layer.number === 1) {
// Physical layer - show binary stream
packetContainer.innerHTML = `
<div class="binary-stream pulse-text">
01001000 01100101 01101100 01101100<br>
01101111 00100000 01010111 01101111<br>
01110010 01101100 01100100 00100001<br>
<br>... SIGNAL WIRD ÜBERTRAGEN ...
</div>
`;
} else {
// Show stacked headers
packetContainer.innerHTML = '';
// Construct the packet from currentStep down to 0
// This appends Headers to the left of the Data (as expected)
for (let i = currentStep; i >= 0; i--) {
const l = layers[i];
const chunk = document.createElement('div');
chunk.className = `packet-chunk ${l.packetColor}`;
// Simple animation delay for the newest layer added
if (i === currentStep && currentStep > 0) {
chunk.style.animation = 'dropIn 0.4s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275)';
} else {
chunk.style.opacity = '1';
chunk.style.transform = 'translateY(0)';
chunk.style.animation = 'none';
}
chunk.innerHTML = `
<div style="font-size: 0.75rem; margin-bottom: 8px; opacity: 0.8;">Schicht ${l.number}</div>
<div>${l.packetLabel}</div>
`;
packetContainer.appendChild(chunk);
}
// Add Trailer if Data Link Layer (Schicht 2)
if (layer.number === 2) {
const trailer = document.createElement('div');
trailer.className = `packet-chunk color-2`;
trailer.style.animation = 'dropIn 0.4s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275)';
trailer.innerHTML = `
<div style="font-size: 0.75rem; margin-bottom: 8px; opacity: 0.8;">Trailer</div>
<div>FCS</div>
`;
packetContainer.appendChild(trailer);
}
}
// Update buttons
document.getElementById('prevBtn').disabled = currentStep === 0;
document.getElementById('nextBtn').disabled = currentStep === layers.length - 1;
if (currentStep === layers.length - 1) {
document.getElementById('nextBtn').innerText = "Versand abgeschlossen";
} else {
document.getElementById('nextBtn').innerText = "Weiter (Nächste Schicht)";
}
}
function nextLayer() {
if (currentStep < layers.length - 1) {
currentStep++;
updateView();
}
}
function prevLayer() {
if (currentStep > 0) {
currentStep--;
updateView();
}
}
// Initialize
init();
</script>
</body>
</html>
Ergebnis:

Beispiel 4:
bitte auch als weiters Beispiel, das abrufen der webseite „https://prilchen.de“ in den 7 osi schichten zeigt
Erzeugt diesen HTML-Code: (anklicken zum lesen)
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OSI-Modell: Webseite abrufen</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=Fira+Code:wght@400;600&display=swap" rel="stylesheet">
<style>
:root {
--bg-color: #0f172a;
--text-color: #f8fafc;
--accent-color: #3b82f6;
--accent-hover: #2563eb;
--glass-bg: rgba(255, 255, 255, 0.05);
--glass-border: rgba(255, 255, 255, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 100%);
color: var(--text-color);
min-height: 100vh;
display: flex;
flex-direction: column;
overflow-x: hidden;
}
header {
text-align: center;
padding: 2rem;
background: var(--glass-bg);
border-bottom: 1px solid var(--glass-border);
backdrop-filter: blur(10px);
}
header h1 {
font-weight: 700;
font-size: 2.5rem;
background: linear-gradient(to right, #60a5fa, #34d399);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 0.5rem;
}
.container {
display: flex;
flex: 1;
padding: 2rem;
gap: 2rem;
max-width: 1400px;
margin: 0 auto;
width: 100%;
}
.sidebar {
flex: 0 0 300px;
display: flex;
flex-direction: column;
gap: 1rem;
}
.layer-btn {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
color: var(--text-color);
padding: 1rem;
border-radius: 12px;
cursor: pointer;
text-align: left;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.layer-btn.active {
background: rgba(59, 130, 246, 0.2);
border-color: var(--accent-color);
box-shadow: 0 0 20px rgba(59, 130, 246, 0.3);
transform: translateX(10px);
}
.layer-btn:hover:not(.active) {
background: rgba(255, 255, 255, 0.1);
}
.layer-number {
font-weight: 700;
color: #94a3b8;
font-size: 0.875rem;
margin-bottom: 0.25rem;
}
.active .layer-number {
color: #60a5fa;
}
.layer-name {
font-weight: 600;
font-size: 1.125rem;
}
.main-content {
flex: 1;
display: flex;
flex-direction: column;
gap: 2rem;
}
.info-panel {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(10px);
min-height: 250px;
}
.info-panel h2 {
margin-bottom: 1rem;
color: #34d399;
}
.info-panel p {
line-height: 1.6;
color: #cbd5e1;
font-size: 1.1rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-top: 1.5rem;
}
.detail-item {
background: rgba(0, 0, 0, 0.2);
padding: 1rem;
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.05);
}
.detail-label {
font-size: 0.8rem;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.5rem;
}
.detail-value {
font-family: 'Fira Code', monospace;
font-size: 1rem;
color: #34d399;
word-break: break-all;
}
.packet-visualization {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 2rem;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
overflow-x: auto;
backdrop-filter: blur(10px);
min-height: 180px;
}
.packet-container {
display: flex;
flex-direction: row;
align-items: stretch;
gap: 0.5rem;
}
.packet-chunk {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1.5rem;
border-radius: 8px;
font-family: 'Fira Code', monospace;
font-size: 1.1rem;
font-weight: 700;
color: #fff;
opacity: 0;
transform: translateY(-20px);
animation: dropIn 0.3s forwards ease-out;
min-width: 120px;
text-align: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.4);
border: 1px solid rgba(255, 255, 255, 0.2);
}
@keyframes dropIn {
to {
opacity: 1;
transform: translateY(0);
}
}
.controls {
display: flex;
justify-content: space-between;
margin-top: auto;
}
button.nav-btn {
background: var(--accent-color);
color: white;
border: none;
padding: 1rem 2.5rem;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
}
button.nav-btn:hover:not(:disabled) {
background: var(--accent-hover);
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
button.nav-btn:disabled {
background: #475569;
cursor: not-allowed;
opacity: 0.5;
box-shadow: none;
transform: none;
}
/* Layer specific colors */
.color-7 { background: linear-gradient(135deg, #ec4899, #be185d); }
.color-6 { background: linear-gradient(135deg, #d946ef, #a21caf); }
.color-5 { background: linear-gradient(135deg, #8b5cf6, #6d28d9); }
.color-4 { background: linear-gradient(135deg, #6366f1, #4338ca); }
.color-3 { background: linear-gradient(135deg, #3b82f6, #1d4ed8); }
.color-2 { background: linear-gradient(135deg, #0ea5e9, #0369a1); }
.color-1 { background: linear-gradient(135deg, #14b8a6, #0f766e); }
.binary-stream {
font-family: 'Fira Code', monospace;
font-size: 1.2rem;
color: #34d399;
letter-spacing: 3px;
word-break: break-all;
line-height: 1.8;
max-height: 150px;
overflow: hidden;
position: relative;
text-align: center;
}
.pulse-text {
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0% { opacity: 0.6; }
50% { opacity: 1; text-shadow: 0 0 10px #34d399; }
100% { opacity: 0.6; }
}
</style>
</head>
<body>
<header>
<h1>OSI-Modell: Abruf von https://prilchen.de</h1>
<p>Schritt-für-Schritt Darstellung des Webseiten-Aufrufs (Top-Down)</p>
</header>
<div class="container">
<div class="sidebar" id="sidebar">
<!-- Dynamically populated -->
</div>
<div class="main-content">
<div class="info-panel" id="infoPanel">
<!-- Dynamically populated -->
</div>
<div class="packet-visualization">
<div class="packet-container" id="packetContainer">
<!-- Dynamically populated -->
</div>
</div>
<div class="controls">
<button class="nav-btn" id="prevBtn" onclick="prevLayer()">Zurück</button>
<button class="nav-btn" id="nextBtn" onclick="nextLayer()">Weiter (Nächste Schicht)</button>
</div>
</div>
</div>
<script>
const layers = [
{
number: 7,
name: "Anwendungsschicht (Application)",
title: "Schicht 7: HTTP GET Request",
desc: "Der Webbrowser möchte die Webseite 'https://prilchen.de' abrufen. Das Protokoll HTTP (meist Version 1.1, 2 oder 3) formuliert eine Anfrage an den Webserver.",
details: {
"Protokoll": "HTTP",
"Aktion": "GET / HTTP/1.1",
"Host": "prilchen.de"
},
packetLabel: "HTTP",
packetColor: "color-7"
},
{
number: 6,
name: "Darstellungsschicht (Presentation)",
title: "Schicht 6: TLS Verschlüsselung",
desc: "Da die Webseite über HTTPS (sicher) aufgerufen wird, müssen die Daten verschlüsselt werden (TLS). Der HTTP-Klartext wird in unverständlichen Ciphertext umgewandelt.",
details: {
"Verschlüsselung": "TLS 1.3 (AES-256)",
"Format": "Ciphertext",
"Status": "Encrypted Payload"
},
packetLabel: "TLS",
packetColor: "color-6"
},
{
number: 5,
name: "Sitzungsschicht (Session)",
title: "Schicht 5: TLS-Sitzungsverwaltung",
desc: "Die sichere Sitzung mit dem Server von prilchen.de wird etabliert und aufrechterhalten. Eine TLS Session-ID wird generiert, um spätere Verbindungen zu beschleunigen (Session Resumption).",
details: {
"Schicht-ID (Session)": "0xF9A2B4C1",
"Status": "TLS Handshake OK",
"Keep-Alive": "Aktiv"
},
packetLabel: "SESS",
packetColor: "color-5"
},
{
number: 4,
name: "Transportschicht (Transport)",
title: "Schicht 4: TCP Segmentierung",
desc: "Der verschlüsselte Datenstrom wird in Segmente unterteilt. Ein TCP-Header wird angehängt. Der Ziel-Port für sicheren Web-Traffic (HTTPS) ist immer Port 443.",
details: {
"Protokoll": "TCP",
"Source-Port": "60123 (Dynamisch)",
"Dest-Port": "443 (HTTPS)",
"Sequenz-Nr": "54321"
},
packetLabel: "TCP",
packetColor: "color-4"
},
{
number: 3,
name: "Vermittlungsschicht (Network)",
title: "Schicht 3: IP Adressierung",
desc: "Das TCP-Segment wird in ein IP-Paket verpackt. Der Browser hat zuvor über DNS die IP-Adresse von prilchen.de ermittelt und trägt diese als Ziel-IP ein.",
details: {
"Protokoll": "IPv4 / IPv6",
"Source-IP": "192.168.1.10 (Lokal)",
"Dest-IP": "85.13.149.33 (prilchen.de)",
"TTL": "128"
},
packetLabel: "IP",
packetColor: "color-3"
},
{
number: 2,
name: "Sicherungsschicht (Data Link)",
title: "Schicht 2: MAC Adressierung",
desc: "Das IP-Paket wird in einen Frame (z.B. Ethernet oder WLAN) verpackt. Die MAC-Adresse deines lokalen Routers (Standardgateway) wird als Ziel-MAC eingetragen, damit das Paket dein Heimnetzwerk verlassen kann.",
details: {
"Protokoll": "Ethernet II / WLAN",
"Source-MAC": "AA:BB:CC:DD:EE:FF",
"Dest-MAC": "99:88:77:66:55:44 (Router)",
"FCS (Trailer)": "0x4C5D6E7F"
},
packetLabel: "MAC",
packetColor: "color-2"
},
{
number: 1,
name: "Bitübertragungsschicht (Physical)",
title: "Schicht 1: Binäre Übertragung",
desc: "Der gesamte Frame wird in eine Folge von Nullen und Einsen (Bits) umgewandelt und als physikalisches Signal (z.B. Funkwellen im WLAN oder elektrische Impulse im Netzwerkkabel) zum Router gesendet.",
details: {
"Medium": "WLAN (Radio) / Kupfer",
"Signal": "Modulierte Welle",
"Binäre Werte": "10101010 11001100 00110011..."
},
packetLabel: "BITS",
packetColor: "color-1"
}
];
let currentStep = 0;
function init() {
renderSidebar();
updateView();
}
function renderSidebar() {
const sidebar = document.getElementById('sidebar');
sidebar.innerHTML = '';
layers.forEach((layer, index) => {
const btn = document.createElement('div');
btn.className = `layer-btn ${index === currentStep ? 'active' : ''}`;
btn.onclick = () => {
currentStep = index;
updateView();
};
btn.innerHTML = `
<div class="layer-number">Schicht ${layer.number}</div>
<div class="layer-name">${layer.name}</div>
`;
sidebar.appendChild(btn);
});
}
function updateView() {
// Update sidebar active state
document.querySelectorAll('.layer-btn').forEach((btn, idx) => {
btn.className = `layer-btn ${idx === currentStep ? 'active' : ''}`;
});
const layer = layers[currentStep];
// Update info panel
let detailsHtml = '';
for (const [key, value] of Object.entries(layer.details)) {
detailsHtml += `
<div class="detail-item">
<div class="detail-label">${key}</div>
<div class="detail-value">${value}</div>
</div>
`;
}
const infoPanel = document.getElementById('infoPanel');
infoPanel.innerHTML = `
<h2>${layer.title}</h2>
<p>${layer.desc}</p>
<div class="detail-grid">
${detailsHtml}
</div>
`;
// Update packet visualization
const packetContainer = document.getElementById('packetContainer');
if (layer.number === 1) {
// Physical layer - show binary stream
packetContainer.innerHTML = `
<div class="binary-stream pulse-text">
10101010 11001100 00110011 11110000<br>
00001111 10101010 01010101 11001100<br>
11111111 00000000 10101010 10101010<br>
<br>... SIGNAL WIRD ÜBERTRAGEN ...
</div>
`;
} else {
// Show stacked headers
packetContainer.innerHTML = '';
// Construct the packet from currentStep down to 0
for (let i = currentStep; i >= 0; i--) {
const l = layers[i];
const chunk = document.createElement('div');
chunk.className = `packet-chunk ${l.packetColor}`;
// Simple animation delay for the newest layer added
if (i === currentStep && currentStep > 0) {
chunk.style.animation = 'dropIn 0.4s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275)';
} else {
chunk.style.opacity = '1';
chunk.style.transform = 'translateY(0)';
chunk.style.animation = 'none';
}
chunk.innerHTML = `
<div style="font-size: 0.75rem; margin-bottom: 8px; opacity: 0.8;">Schicht ${l.number}</div>
<div>${l.packetLabel}</div>
`;
packetContainer.appendChild(chunk);
}
// Add Trailer if Data Link Layer (Schicht 2)
if (layer.number === 2) {
const trailer = document.createElement('div');
trailer.className = `packet-chunk color-2`;
trailer.style.animation = 'dropIn 0.4s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275)';
trailer.innerHTML = `
<div style="font-size: 0.75rem; margin-bottom: 8px; opacity: 0.8;">Trailer</div>
<div>FCS</div>
`;
packetContainer.appendChild(trailer);
}
}
// Update buttons
document.getElementById('prevBtn').disabled = currentStep === 0;
document.getElementById('nextBtn').disabled = currentStep === layers.length - 1;
if (currentStep === layers.length - 1) {
document.getElementById('nextBtn').innerText = "Abruf gestartet";
} else {
document.getElementById('nextBtn').innerText = "Weiter (Nächste Schicht)";
}
}
function nextLayer() {
if (currentStep < layers.length - 1) {
currentStep++;
updateView();
}
}
function prevLayer() {
if (currentStep > 0) {
currentStep--;
updateView();
}
}
// Initialize
init();
</script>
</body>
</html>
Ergebnis:

Jede einzelne Schichten wird nun näher beschrieben. Super anwendbar für Ausbildung und interessierte!
Fazit:
Die Seite zeigt, wie Antigravity schnell funktionale Windows‑Tools und technische Visualisierungen erzeugt – von COM‑Port‑Monitoring über Update‑Checker bis hin zu OSI‑Schicht‑Darstellungen. Wenig aufwand und überzeugendes Ergebnis.
Für mich ein echter Mehrwert.
