Easy ein Windows Tool wie „ComPortAnzeiger“ mit Antigravity erstellen

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.

Youtube Video:

, ,
Datenschutz-Übersicht

Diese Website verwendet Cookies, damit wir dir die bestmögliche Benutzerkomfort bieten können. Cookie-Informationen werden in deinem Browser gespeichert und führen Funktionen aus, wie das Wiedererkennen von dir, wenn du auf unsere Website zurückkehrst und hilft uns zu verstehen, welche Abschnitte der Website für dich am interessantesten und nützlichsten sind.