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 nun 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.
implementation_plan.md:
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
# Setzt das Erscheinungsbild der GUI:
# - "System": folgt dem Windows‑11‑Design (Dark/Light Mode)
# - "blue": Windows‑typischer Akzentfarbton
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")
class App(ctk.CTk):
def __init__(self):
super().__init__()
# Grundlegende Fensterkonfiguration
self.title("Windows 11 Upgrade Checker")
self.geometry("850x550")
self.minsize(800, 500)
# Grid‑Layout für dynamische Größenanpassung
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
# -------------------------
# HEADER-BEREICH
# -------------------------
self.header_frame = ctk.CTkFrame(self, fg_color="transparent")
self.header_frame.grid(row=0, column=0, padx=20, pady=(20, 10), sticky="ew")
# Titel
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")
# Aktualisieren‑Button → lädt Updates neu
self.refresh_btn = ctk.CTkButton(
self.header_frame,
text="Aktualisieren",
width=120,
command=self.load_updates_async
)
self.refresh_btn.pack(side="right")
# -------------------------
# LADEN-ANZEIGE
# -------------------------
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)
# Scrollbarer Bereich für die Update-Liste
self.scroll_frame = ctk.CTkScrollableFrame(self)
# Liste der gefundenen Updates
self.update_list = []
# Beim Start sofort Updates laden
self.load_updates_async()
# ---------------------------------------------------------
# Asynchrones Laden der Updates (damit GUI nicht blockiert)
# ---------------------------------------------------------
def load_updates_async(self):
# Scrollbereich verstecken, Ladeanzeige zeigen
self.scroll_frame.grid_forget()
self.loading_label.grid(row=1, column=0, padx=20, pady=20)
self.refresh_btn.configure(state="disabled")
# Alte Einträge entfernen
for widget in self.scroll_frame.winfo_children():
widget.destroy()
# winget-Aufruf in separatem Thread starten
thread = threading.Thread(target=self.fetch_winget_updates)
thread.start()
# ---------------------------------------------------------
# winget upgrade ausführen und Ausgabe parsen
# ---------------------------------------------------------
def fetch_winget_updates(self):
try:
# Unter Windows: verhindert das Öffnen eines extra Konsolenfensters
startupinfo = None
if sys.platform == "win32":
startupinfo = subprocess.STARTUPINFO()
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
# winget upgrade ausführen
result = subprocess.run(
["winget", "upgrade"],
capture_output=True,
text=True,
encoding='utf-8',
errors='ignore',
startupinfo=startupinfo
)
output = result.stdout
# Ausgabe parsen
apps = self.parse_winget_output(output)
# UI‑Update im Hauptthread
self.after(0, self.display_updates, apps)
except Exception as e:
self.after(0, self.display_error, str(e))
# ---------------------------------------------------------
# winget‑Textausgabe in strukturierte App‑Objekte umwandeln
# ---------------------------------------------------------
def parse_winget_output(self, output):
lines = output.split('\n')
header_line = None
header_idx = -1
# Header suchen (Name | ID | Version | Verfügbar | Quelle)
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
# Keine Updates gefunden oder Format unbekannt
if not header_line:
return []
# Spaltenpositionen bestimmen
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 = []
# Ab Zeile nach dem Header parsen
for line in lines[header_idx + 2:]:
if not line.strip() or line.startswith('-'):
continue
# Zusammenfassungszeilen überspringen
if any(keyword in line for keyword in ['Aktualisierung', 'Paket', 'packages', 'updates', 'Mindestens']):
continue
# Spalten extrahieren
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()
# Unicode‑Ellipsen entfernen
name = name.rstrip('…')
if name and app_id:
apps.append({
'name': name,
'id': app_id,
'version': version,
'available': available
})
return apps
# ---------------------------------------------------------
# Updates in der GUI anzeigen
# ---------------------------------------------------------
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")
# Keine Updates gefunden
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
# Tabellenkopf
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)
# Jede App als Zeile anzeigen
for app in apps:
item_frm = ctk.CTkFrame(self.scroll_frame)
item_frm.pack(fill="x", padx=5, pady=5)
# Name
name_lbl = ctk.CTkLabel(item_frm, text=app['name'], width=250, anchor="w")
name_lbl.pack(side="left", padx=10, pady=10)
# Installierte 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)
# Verfügbare 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 → öffnet CMD‑Fenster
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)
# ---------------------------------------------------------
# Fehleranzeige
# ---------------------------------------------------------
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)
# ---------------------------------------------------------
# Update ausführen → neues CMD‑Fenster mit winget upgrade
# ---------------------------------------------------------
def run_update(self, app_id):
command = f'winget upgrade --id {app_id} --accept-source-agreements'
subprocess.Popen(f'start cmd /c "{command} & pause"', shell=True)
# Start der Anwendung
if __name__ == "__main__":
app = App()
app.mainloop()
Main.py erstellen und das Script hinein kopieren.
Es wird Python unter Windows benötigt.
Wer das noch installieren muss, hier die Anleitung:
ESP32 Firmware sichern und wiederherstellen mit ESPTool
Erzeugte Batch zum einfachen starten, Start.bat erzeugen und dies hier hinein kopieren:
@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!
Alternativ geht es auch, um schnell mal alles zu aktualisieren, in der Eingabeausforderung mit Befehl: winget update –all 😉
Beispiel 3:
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.
