Wednesday, May 28, 2025

The Art of Vibe Coding - Transformer Architecture Simulator

I asked Claude Sonnet 4 to create a Transformer Architecture Simulator - this may not be perfect, but it is nice. And it is Vibe Coding.


Here is the prompt I used:

Create a single web page that simulates the inference of a Transformer architecture. All activities need to be shown: tokenization, embeddings, all types of attention, residual connection, feed forward and normalization, masking and the provisioning of the LLMs completion. The user enters a text in a prompt text box. After pressing the <start> button the prompt is processed step by step. Show multiple layers, encoders and decoders. The actual processing step is always highlighted. If one step is completed, the simulator continues with the next step. Build an awesome UI with dynamic lighting and awesome animations. Goal of the simulator is to teach how Transformers architectures work in detail. In each step the mathematical formulas used in this step and the data structures are presented.



 <!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Transformer Architecture Simulator</title>

    <style>

        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

        }


        body {

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);

            color: #fff;

            height: 100vh;

            overflow: hidden;

        }


        .container {

            height: 100vh;

            display: flex;

            flex-direction: column;

            padding: 10px;

        }


        h1 {

            text-align: center;

            font-size: 1.8em;

            margin-bottom: 10px;

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            -webkit-background-clip: text;

            -webkit-text-fill-color: transparent;

            text-shadow: 0 0 30px rgba(0, 210, 255, 0.5);

        }


        .input-section {

            background: rgba(255, 255, 255, 0.1);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 10px;

            margin-bottom: 10px;

            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);

            border: 1px solid rgba(255, 255, 255, 0.2);

        }


        .input-group {

            display: flex;

            gap: 10px;

            margin-bottom: 10px;

        }


        #promptInput {

            flex: 1;

            padding: 8px;

            border: none;

            border-radius: 6px;

            background: rgba(255, 255, 255, 0.2);

            color: #fff;

            font-size: 14px;

        }


        #promptInput::placeholder {

            color: rgba(255, 255, 255, 0.6);

        }


        button {

            padding: 8px 20px;

            border: none;

            border-radius: 6px;

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            color: #fff;

            font-size: 14px;

            font-weight: bold;

            cursor: pointer;

            transition: all 0.3s ease;

            box-shadow: 0 2px 8px rgba(0, 210, 255, 0.4);

        }


        button:hover {

            transform: translateY(-1px);

            box-shadow: 0 4px 12px rgba(0, 210, 255, 0.6);

        }


        button:disabled {

            opacity: 0.5;

            cursor: not-allowed;

        }


        .main-content {

            flex: 1;

            display: grid;

            grid-template-columns: 1fr 2fr 1fr;

            gap: 10px;

            overflow: hidden;

        }


        .panel {

            background: rgba(255, 255, 255, 0.05);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 15px;

            border: 1px solid rgba(255, 255, 255, 0.1);

            transition: all 0.3s ease;

            overflow-y: auto;

            display: flex;

            flex-direction: column;

        }


        .panel.active {

            border-color: #00d2ff;

            box-shadow: 0 0 20px rgba(0, 210, 255, 0.5);

            animation: pulse 2s infinite;

        }


        @keyframes pulse {

            0% { box-shadow: 0 0 20px rgba(0, 210, 255, 0.5); }

            50% { box-shadow: 0 0 30px rgba(0, 210, 255, 0.8); }

            100% { box-shadow: 0 0 20px rgba(0, 210, 255, 0.5); }

        }


        .step-title {

            font-size: 1em;

            font-weight: bold;

            margin-bottom: 10px;

            color: #00d2ff;

        }


        .transformer-visual {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 10px;

            padding: 15px;

            overflow-y: auto;

            display: flex;

            flex-direction: column;

            gap: 10px;

        }


        .layer {

            background: rgba(255, 255, 255, 0.05);

            border: 2px solid rgba(255, 255, 255, 0.2);

            border-radius: 8px;

            padding: 10px;

            transition: all 0.3s ease;

            flex-shrink: 0;

        }


        .layer.active {

            border-color: #00d2ff;

            background: rgba(0, 210, 255, 0.1);

            transform: scale(1.02);

        }


        .component {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 6px;

            padding: 8px;

            margin: 5px 0;

            text-align: center;

            transition: all 0.3s ease;

            cursor: pointer;

            font-size: 0.9em;

        }


        .component.active {

            background: linear-gradient(45deg, rgba(0, 210, 255, 0.3), rgba(58, 123, 213, 0.3));

            transform: translateX(3px);

            box-shadow: 0 0 15px rgba(0, 210, 255, 0.5);

        }


        .math-formula {

            background: rgba(0, 0, 0, 0.5);

            border-radius: 6px;

            padding: 10px;

            margin: 8px 0;

            font-family: 'Courier New', monospace;

            font-size: 12px;

            overflow-x: auto;

        }


        .data-structure {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 6px;

            padding: 8px;

            margin: 8px 0;

            font-size: 0.85em;

        }


        .matrix {

            display: inline-block;

            border: 2px solid #00d2ff;

            border-radius: 4px;

            padding: 4px;

            margin: 3px;

            font-family: monospace;

            font-size: 11px;

            background: rgba(0, 210, 255, 0.1);

        }


        .token {

            display: inline-block;

            background: rgba(255, 255, 255, 0.2);

            border-radius: 4px;

            padding: 4px 8px;

            margin: 2px;

            font-family: monospace;

            transition: all 0.3s ease;

            font-size: 0.85em;

        }


        .token.highlighted {

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            transform: scale(1.1);

            box-shadow: 0 0 10px rgba(0, 210, 255, 0.8);

        }


        .progress-bar {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 6px;

            height: 6px;

            margin: 10px 0;

            overflow: hidden;

        }


        .progress-fill {

            height: 100%;

            background: linear-gradient(90deg, #00d2ff, #3a7bd5);

            border-radius: 6px;

            transition: width 0.5s ease;

            box-shadow: 0 0 8px rgba(0, 210, 255, 0.8);

        }


        .speed-control {

            display: flex;

            align-items: center;

            gap: 10px;

            background: rgba(255, 255, 255, 0.1);

            padding: 8px 15px;

            border-radius: 6px;

            font-size: 0.9em;

        }


        .attention-weights {

            display: grid;

            grid-template-columns: repeat(5, 1fr);

            gap: 2px;

            margin: 8px 0;

            max-width: 200px;

        }


        .weight-cell {

            aspect-ratio: 1;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 9px;

            border-radius: 3px;

            transition: all 0.3s ease;

            color: #fff;

            font-weight: bold;

        }


        .explanation {

            background: rgba(0, 0, 0, 0.5);

            border-left: 3px solid #00d2ff;

            padding: 10px;

            margin: 10px 0;

            border-radius: 0 6px 6px 0;

            font-size: 0.9em;

        }


        .layer-label {

            font-weight: bold;

            color: #00d2ff;

            margin-bottom: 8px;

            font-size: 0.95em;

        }


        .bottom-panel {

            background: rgba(255, 255, 255, 0.05);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 10px;

            margin-top: 10px;

            border: 1px solid rgba(255, 255, 255, 0.1);

            max-height: 200px;

            overflow-y: auto;

        }


        .info-grid {

            display: grid;

            grid-template-columns: 1fr 1fr 1fr;

            gap: 10px;

        }


        .info-section {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 6px;

            padding: 10px;

        }


        .info-section h3 {

            font-size: 0.9em;

            color: #00d2ff;

            margin-bottom: 5px;

        }


        /* Scrollbar styling */

        ::-webkit-scrollbar {

            width: 6px;

            height: 6px;

        }


        ::-webkit-scrollbar-track {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 3px;

        }


        ::-webkit-scrollbar-thumb {

            background: rgba(0, 210, 255, 0.5);

            border-radius: 3px;

        }


        ::-webkit-scrollbar-thumb:hover {

            background: rgba(0, 210, 255, 0.7);

        }

    </style>

</head>

<body>

    <div class="container">

        <h1>🤖 Transformer Architecture Simulator</h1>

        

        <div class="input-section">

            <div class="input-group">

                <input type="text" id="promptInput" placeholder="Enter your text prompt here..." value="The cat sat on the mat">

                <button id="startBtn" onclick="startSimulation()">▶ Start</button>

                <button id="pauseBtn" onclick="pauseSimulation()" disabled>⏸ Pause</button>

                <button id="resetBtn" onclick="resetSimulation()">🔄 Reset</button>

            </div>

            <div class="speed-control">

                <label>Speed:</label>

                <input type="range" id="speedSlider" min="1" max="10" value="5">

                <span id="speedValue">5</span>

            </div>

        </div>


        <div class="progress-bar">

            <div class="progress-fill" id="progressBar" style="width: 0%"></div>

        </div>


        <div class="main-content">

            <div class="panel" id="inputPanel">

                <div class="step-title">Input Processing</div>

                <div id="tokenizationStep" class="component">

                    <strong>1. Tokenization</strong>

                    <div id="tokens" class="data-structure"></div>

                </div>

                <div id="embeddingStep" class="component">

                    <strong>2. Embeddings</strong>

                    <div id="embeddings" class="data-structure"></div>

                </div>

                <div id="positionalStep" class="component">

                    <strong>3. Positional Encoding</strong>

                    <div id="positional" class="data-structure"></div>

                </div>

            </div>


            <div class="transformer-visual">

                <div class="layer-label">ENCODER STACK</div>

                <div class="layer" id="encoder1">

                    <strong>Encoder Layer 1</strong>

                    <div class="component" id="enc1-mha">Multi-Head Attention</div>

                    <div class="component" id="enc1-norm1">Add & Norm</div>

                    <div class="component" id="enc1-ff">Feed Forward</div>

                    <div class="component" id="enc1-norm2">Add & Norm</div>

                </div>

                <div class="layer" id="encoder2">

                    <strong>Encoder Layer 2</strong>

                    <div class="component" id="enc2-mha">Multi-Head Attention</div>

                    <div class="component" id="enc2-norm1">Add & Norm</div>

                    <div class="component" id="enc2-ff">Feed Forward</div>

                    <div class="component" id="enc2-norm2">Add & Norm</div>

                </div>


                <div class="layer-label" style="margin-top: 10px;">DECODER STACK</div>

                <div class="layer" id="decoder1">

                    <strong>Decoder Layer 1</strong>

                    <div class="component" id="dec1-mha1">Masked Multi-Head Attention</div>

                    <div class="component" id="dec1-norm1">Add & Norm</div>

                    <div class="component" id="dec1-mha2">Cross-Attention</div>

                    <div class="component" id="dec1-norm2">Add & Norm</div>

                    <div class="component" id="dec1-ff">Feed Forward</div>

                    <div class="component" id="dec1-norm3">Add & Norm</div>

                </div>

                <div class="layer" id="decoder2">

                    <strong>Decoder Layer 2</strong>

                    <div class="component" id="dec2-mha1">Masked Multi-Head Attention</div>

                    <div class="component" id="dec2-norm1">Add & Norm</div>

                    <div class="component" id="dec2-mha2">Cross-Attention</div>

                    <div class="component" id="dec2-norm2">Add & Norm</div>

                    <div class="component" id="dec2-ff">Feed Forward</div>

                    <div class="component" id="dec2-norm3">Add & Norm</div>

                </div>

            </div>


            <div class="panel" id="outputPanel">

                <div class="step-title">Output Generation</div>

                <div id="linearStep" class="component">

                    <strong>Linear Projection</strong>

                    <div id="linear" class="data-structure"></div>

                </div>

                <div id="softmaxStep" class="component">

                    <strong>Softmax</strong>

                    <div id="softmax" class="data-structure"></div>

                </div>

                <div id="outputStep" class="component">

                    <strong>Generated Output</strong>

                    <div id="output" class="data-structure"></div>

                </div>

            </div>

        </div>


        <div class="bottom-panel">

            <div class="info-grid">

                <div class="info-section">

                    <h3>Current Step</h3>

                    <div id="stepExplanation" class="explanation">

                        Click "Start" to begin the transformer inference visualization.

                    </div>

                </div>

                <div class="info-section">

                    <h3>Mathematical Formula</h3>

                    <div id="mathFormula" class="math-formula">

                        Formulas will appear here during simulation...

                    </div>

                </div>

                <div class="info-section">

                    <h3>Data Visualization</h3>

                    <div id="dataVisualization" class="data-structure">

                        Data structures and matrices will be visualized here...

                    </div>

                </div>

            </div>

        </div>

    </div>


    <script>

        let simulationRunning = false;

        let simulationPaused = false;

        let currentStep = 0;

        let animationSpeed = 5;

        let generatedTokens = [];


        const speedSlider = document.getElementById('speedSlider');

        speedSlider.addEventListener('input', (e) => {

            animationSpeed = parseInt(e.target.value);

            document.getElementById('speedValue').textContent = animationSpeed;

        });


        const steps = [

            {

                id: 'tokenization',

                element: 'tokenizationStep',

                title: 'Tokenization',

                explanation: 'Breaking down the input text into tokens (subwords or words) that the model can process.',

                formula: 'tokens = tokenizer.encode(text)',

                visualize: tokenizeText

            },

            {

                id: 'embedding',

                element: 'embeddingStep',

                title: 'Token Embeddings',

                explanation: 'Converting tokens into dense vector representations in high-dimensional space.',

                formula: 'E(x) = embedding_matrix[token_id] ∈ ℝ^d_model',

                visualize: showEmbeddings

            },

            {

                id: 'positional',

                element: 'positionalStep',

                title: 'Positional Encoding',

                explanation: 'Adding positional information to embeddings so the model knows token positions.',

                formula: 'PE(pos, 2i) = sin(pos/10000^(2i/d_model))\nPE(pos, 2i+1) = cos(pos/10000^(2i/d_model))',

                visualize: showPositionalEncoding

            },

            {

                id: 'enc1-mha',

                element: 'enc1-mha',

                layer: 'encoder1',

                title: 'Encoder Self-Attention',

                explanation: 'Computing attention weights between all tokens to capture relationships.',

                formula: 'Attention(Q,K,V) = softmax(QK^T/√d_k)V\nwhere Q=XW_Q, K=XW_K, V=XW_V',

                visualize: showSelfAttention

            },

            {

                id: 'enc1-norm1',

                element: 'enc1-norm1',

                layer: 'encoder1',

                title: 'Add & Normalize',

                explanation: 'Residual connection and layer normalization for stable training.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc1-ff',

                element: 'enc1-ff',

                layer: 'encoder1',

                title: 'Feed Forward Network',

                explanation: 'Two linear transformations with ReLU activation.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'enc1-norm2',

                element: 'enc1-norm2',

                layer: 'encoder1',

                title: 'Add & Normalize',

                explanation: 'Second residual connection and normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc2-mha',

                element: 'enc2-mha',

                layer: 'encoder2',

                title: 'Encoder Self-Attention (Layer 2)',

                explanation: 'Second layer captures higher-level patterns.',

                formula: 'Attention(Q,K,V) = softmax(QK^T/√d_k)V',

                visualize: showSelfAttention

            },

            {

                id: 'enc2-norm1',

                element: 'enc2-norm1',

                layer: 'encoder2',

                title: 'Add & Normalize',

                explanation: 'Residual and normalization in layer 2.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc2-ff',

                element: 'enc2-ff',

                layer: 'encoder2',

                title: 'Feed Forward (Layer 2)',

                explanation: 'Second layer feed-forward network.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'enc2-norm2',

                element: 'enc2-norm2',

                layer: 'encoder2',

                title: 'Add & Normalize',

                explanation: 'Final encoder layer 2 normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-mha1',

                element: 'dec1-mha1',

                layer: 'decoder1',

                title: 'Masked Self-Attention',

                explanation: 'Self-attention with causal mask to prevent looking at future tokens.',

                formula: 'MaskedAttention(Q,K,V) = softmax((QK^T + M)/√d_k)V',

                visualize: showMaskedAttention

            },

            {

                id: 'dec1-norm1',

                element: 'dec1-norm1',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'First decoder residual and normalization.',

                formula: 'LayerNorm(x + MaskedAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-mha2',

                element: 'dec1-mha2',

                layer: 'decoder1',

                title: 'Cross-Attention',

                explanation: 'Attending to encoder output to incorporate source information.',

                formula: 'CrossAttention(Q_dec, K_enc, V_enc)',

                visualize: showCrossAttention

            },

            {

                id: 'dec1-norm2',

                element: 'dec1-norm2',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'Cross-attention residual and normalization.',

                formula: 'LayerNorm(x + CrossAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-ff',

                element: 'dec1-ff',

                layer: 'decoder1',

                title: 'Feed Forward',

                explanation: 'Decoder feed-forward network.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'dec1-norm3',

                element: 'dec1-norm3',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'Final decoder layer 1 normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-mha1',

                element: 'dec2-mha1',

                layer: 'decoder2',

                title: 'Masked Self-Attention (Layer 2)',

                explanation: 'Second decoder layer masked attention.',

                formula: 'MaskedAttention(Q,K,V)',

                visualize: showMaskedAttention

            },

            {

                id: 'dec2-norm1',

                element: 'dec2-norm1',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Layer 2 first normalization.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-mha2',

                element: 'dec2-mha2',

                layer: 'decoder2',

                title: 'Cross-Attention (Layer 2)',

                explanation: 'Second layer cross-attention.',

                formula: 'CrossAttention(Q_dec, K_enc, V_enc)',

                visualize: showCrossAttention

            },

            {

                id: 'dec2-norm2',

                element: 'dec2-norm2',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Layer 2 cross-attention normalization.',

                formula: 'LayerNorm(x + CrossAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-ff',

                element: 'dec2-ff',

                layer: 'decoder2',

                title: 'Feed Forward (Layer 2)',

                explanation: 'Final decoder feed-forward.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'dec2-norm3',

                element: 'dec2-norm3',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Final decoder normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'linear',

                element: 'linearStep',

                title: 'Linear Projection',

                explanation: 'Projecting decoder output to vocabulary size for token prediction.',

                formula: 'logits = decoder_output @ W_vocab + b_vocab',

                visualize: showLinearProjection

            },

            {

                id: 'softmax',

                element: 'softmaxStep',

                title: 'Softmax',

                explanation: 'Converting logits to probability distribution over vocabulary.',

                formula: 'P(token_i) = exp(logit_i) / Σ_j exp(logit_j)',

                visualize: showSoftmax

            },

            {

                id: 'output',

                element: 'outputStep',

                title: 'Token Generation',

                explanation: 'Selecting the next token based on probability distribution.',

                formula: 'next_token = argmax(P) or sample(P)',

                visualize: showOutput

            }

        ];


        function startSimulation() {

            if (simulationRunning && !simulationPaused) return;

            

            simulationRunning = true;

            simulationPaused = false;

            document.getElementById('startBtn').disabled = true;

            document.getElementById('pauseBtn').disabled = false;

            

            if (currentStep === 0) {

                resetVisualization();

                generatedTokens = [];

            }

            

            runStep();

        }


        function pauseSimulation() {

            simulationPaused = true;

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

        }


        function resetSimulation() {

            simulationRunning = false;

            simulationPaused = false;

            currentStep = 0;

            generatedTokens = [];

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

            resetVisualization();

            updateProgress(0);

        }


        function resetVisualization() {

            document.querySelectorAll('.component, .layer, .panel').forEach(el => {

                el.classList.remove('active');

            });

            document.getElementById('tokens').innerHTML = '';

            document.getElementById('embeddings').innerHTML = '';

            document.getElementById('positional').innerHTML = '';

            document.getElementById('linear').innerHTML = '';

            document.getElementById('softmax').innerHTML = '';

            document.getElementById('output').innerHTML = '';

            document.getElementById('stepExplanation').innerHTML = 'Click "Start" to begin.';

            document.getElementById('mathFormula').innerHTML = 'Formulas will appear here...';

            document.getElementById('dataVisualization').innerHTML = '';

        }


        function runStep() {

            if (!simulationRunning || simulationPaused || currentStep >= steps.length) {

                if (currentStep >= steps.length) {

                    completeSimulation();

                }

                return;

            }


            const step = steps[currentStep];

            highlightStep(step);

            updateStepInfo(step);

            step.visualize();

            updateProgress((currentStep + 1) / steps.length * 100);


            currentStep++;

            setTimeout(runStep, 2000 / animationSpeed);

        }


        function highlightStep(step) {

            document.querySelectorAll('.component, .layer, .panel').forEach(el => {

                el.classList.remove('active');

            });


            const element = document.getElementById(step.element);

            if (element) {

                element.classList.add('active');

                // Scroll into view within the parent container

                const parent = element.closest('.panel, .transformer-visual');

                if (parent) {

                    const elementTop = element.offsetTop;

                    const elementHeight = element.offsetHeight;

                    const parentHeight = parent.clientHeight;

                    const scrollTop = parent.scrollTop;

                    

                    if (elementTop < scrollTop || elementTop + elementHeight > scrollTop + parentHeight) {

                        parent.scrollTop = elementTop - parentHeight / 2 + elementHeight / 2;

                    }

                }

            }


            if (step.layer) {

                document.getElementById(step.layer).classList.add('active');

            }


            // Highlight the appropriate panel

            if (step.id.includes('enc') || step.id.includes('dec')) {

                // Main transformer panel is always visible

            } else if (['tokenization', 'embedding', 'positional'].includes(step.id)) {

                document.getElementById('inputPanel').classList.add('active');

            } else if (['linear', 'softmax', 'output'].includes(step.id)) {

                document.getElementById('outputPanel').classList.add('active');

            }

        }


        function updateStepInfo(step) {

            document.getElementById('stepExplanation').innerHTML = `

                <strong>${step.title}</strong><br>

                ${step.explanation}

            `;

            document.getElementById('mathFormula').innerHTML = `<pre>${step.formula}</pre>`;

        }


        function updateProgress(percent) {

            document.getElementById('progressBar').style.width = percent + '%';

        }


        function tokenizeText() {

            const text = document.getElementById('promptInput').value;

            const tokens = text.split(' ').map(word => `[${word}]`);

            const tokensDiv = document.getElementById('tokens');

            tokensDiv.innerHTML = '';

            

            tokens.forEach((token, i) => {

                const tokenEl = document.createElement('span');

                tokenEl.className = 'token';

                tokenEl.textContent = token;

                tokensDiv.appendChild(tokenEl);

                

                setTimeout(() => {

                    tokenEl.classList.add('highlighted');

                    setTimeout(() => tokenEl.classList.remove('highlighted'), 500);

                }, i * 100);

            });


            document.getElementById('dataVisualization').innerHTML = `

                <div>Token IDs: [${tokens.map((_, i) => 1000 + i).join(', ')}]</div>

                <div>Vocabulary size: 50,000</div>

            `;

        }


        function showEmbeddings() {

            const embDiv = document.getElementById('embeddings');

            embDiv.innerHTML = '';

            

            const text = document.getElementById('promptInput').value;

            const tokens = text.split(' ');

            

            tokens.slice(0, 3).forEach((token, i) => {

                const matrix = document.createElement('div');

                matrix.className = 'matrix';

                matrix.innerHTML = `[${token}]<br>[${Array(4).fill(0).map(() => 

                    (Math.random() * 2 - 1).toFixed(2)).join(', ')}...]`;

                embDiv.appendChild(matrix);

            });


            document.getElementById('dataVisualization').innerHTML = `

                <div>Embedding dim: 512</div>

                <div>Matrix: [50000 × 512]</div>

            `;

        }


        function showPositionalEncoding() {

            const posDiv = document.getElementById('positional');

            posDiv.innerHTML = '<div>Adding sinusoidal encodings...</div>';

            

            const canvas = document.createElement('canvas');

            canvas.width = 180;

            canvas.height = 60;

            canvas.style.width = '100%';

            canvas.style.borderRadius = '6px';

            canvas.style.marginTop = '5px';

            

            const ctx = canvas.getContext('2d');

            ctx.fillStyle = '#00d2ff';

            

            for (let x = 0; x < canvas.width; x++) {

                const y = 30 + 20 * Math.sin(x * 0.05);

                ctx.fillRect(x, y, 2, 2);

            }

            

            posDiv.appendChild(canvas);


            document.getElementById('dataVisualization').innerHTML = `

                <div>PE added to embeddings</div>

                <div>E(x) + PE(pos)</div>

            `;

        }


        function showSelfAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Attention scores:</div>

                <div class="attention-weights">

                    ${Array(25).fill(0).map(() => 

                        `<div class="weight-cell" style="background: rgba(0, 210, 255, ${Math.random()})">

                            ${Math.random().toFixed(2)}

                        </div>`

                    ).join('')}

                </div>

                <div>8 heads in parallel</div>

            `;

        }


        function showMaskedAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Masked attention:</div>

                <div class="attention-weights">

                    ${Array(25).fill(0).map((_, i) => {

                        const row = Math.floor(i / 5);

                        const col = i % 5;

                        const masked = col > row;

                        return `<div class="weight-cell" style="background: ${masked ? '#333' : `rgba(0, 210, 255, ${Math.random()})`}">

                            ${masked ? '-∞' : Math.random().toFixed(2)}

                        </div>`;

                    }).join('')}

                </div>

            `;

        }


        function showCrossAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Cross-attention:</div>

                <div style="display: flex; align-items: center; gap: 10px; margin-top: 5px;">

                    <div class="matrix">Q_dec</div>

                    <div>×</div>

                    <div class="matrix">K_enc</div>

                    <div>=</div>

                    <div class="matrix">Scores</div>

                </div>

            `;

        }


        function showLayerNorm() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Normalizing output</div>

                <div>μ = 0.0, σ = 1.0</div>

                <div>Residual: x + sublayer(x)</div>

            `;

        }


        function showFeedForward() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>FFN layers:</div>

                <div style="display: flex; align-items: center; gap: 8px; margin-top: 5px;">

                    <div class="matrix">[512]</div>

                    <div>→</div>

                    <div class="matrix">[2048]</div>

                    <div>→</div>

                    <div class="matrix">[512]</div>

                </div>

            `;

        }


        function showLinearProjection() {

            const linearDiv = document.getElementById('linear');

            linearDiv.innerHTML = '<div class="matrix">Logits: [50000]</div>';

            

            document.getElementById('dataVisualization').innerHTML = `

                <div>Projecting to vocab</div>

                <div class="matrix">W: [512 × 50000]</div>

            `;

        }


        function showSoftmax() {

            const softmaxDiv = document.getElementById('softmax');

            const candidates = ['mat', 'floor', 'table', 'ground', 'chair'];

            const probs = candidates.map(() => Math.random());

            const sum = probs.reduce((a, b) => a + b, 0);

            const normalized = probs.map(p => (p / sum).toFixed(3));

            

            softmaxDiv.innerHTML = `

                <div>Top probabilities:</div>

                ${normalized.map((p, i) => 

                    `<div class="token">${candidates[i]}: ${p}</div>`

                ).join('')}

            `;


            document.getElementById('dataVisualization').innerHTML = `

                <div>Temperature = 1.0</div>

                <div>Probability distribution</div>

            `;

        }


        function showOutput() {

            const outputDiv = document.getElementById('output');

            const nextToken = 'mat';

            generatedTokens.push(nextToken);

            

            outputDiv.innerHTML = `

                <div class="token highlighted">Next token: "${nextToken}"</div>

                <div style="margin-top: 5px;">Generated: ${generatedTokens.join(' ')}</div>

            `;

            

            document.getElementById('dataVisualization').innerHTML = `

                <div>Token selected: "${nextToken}"</div>

                <div>Method: greedy decoding</div>

            `;

        }


        function completeSimulation() {

            document.getElementById('stepExplanation').innerHTML = `

                <strong>Simulation Complete!</strong><br>

                The transformer has processed the input and generated the next token.

                This process repeats for each token generation.

            `;

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

        }

    </script>

</body>

</html>


```I'll fix these issues and improve the layout for better visibility:


```html


<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Transformer Architecture Simulator</title>

    <style>

        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

        }


        body {

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);

            color: #fff;

            height: 100vh;

            overflow: hidden;

        }


        .container {

            height: 100vh;

            display: flex;

            flex-direction: column;

            padding: 10px;

        }


        h1 {

            text-align: center;

            font-size: 1.8em;

            margin-bottom: 10px;

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            -webkit-background-clip: text;

            -webkit-text-fill-color: transparent;

            text-shadow: 0 0 30px rgba(0, 210, 255, 0.5);

        }


        .input-section {

            background: rgba(255, 255, 255, 0.1);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 10px;

            margin-bottom: 10px;

            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);

            border: 1px solid rgba(255, 255, 255, 0.2);

        }


        .input-group {

            display: flex;

            gap: 10px;

            margin-bottom: 10px;

        }


        #promptInput {

            flex: 1;

            padding: 8px;

            border: none;

            border-radius: 6px;

            background: rgba(255, 255, 255, 0.2);

            color: #fff;

            font-size: 14px;

        }


        #promptInput::placeholder {

            color: rgba(255, 255, 255, 0.6);

        }


        button {

            padding: 8px 20px;

            border: none;

            border-radius: 6px;

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            color: #fff;

            font-size: 14px;

            font-weight: bold;

            cursor: pointer;

            transition: all 0.3s ease;

            box-shadow: 0 2px 8px rgba(0, 210, 255, 0.4);

        }


        button:hover {

            transform: translateY(-1px);

            box-shadow: 0 4px 12px rgba(0, 210, 255, 0.6);

        }


        button:disabled {

            opacity: 0.5;

            cursor: not-allowed;

        }


        .main-content {

            flex: 1;

            display: grid;

            grid-template-columns: 1fr 2fr 1fr;

            gap: 10px;

            overflow: hidden;

        }


        .panel {

            background: rgba(255, 255, 255, 0.05);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 15px;

            border: 1px solid rgba(255, 255, 255, 0.1);

            transition: all 0.3s ease;

            overflow-y: auto;

            display: flex;

            flex-direction: column;

        }


        .panel.active {

            border-color: #00d2ff;

            box-shadow: 0 0 20px rgba(0, 210, 255, 0.5);

            animation: pulse 2s infinite;

        }


        @keyframes pulse {

            0% { box-shadow: 0 0 20px rgba(0, 210, 255, 0.5); }

            50% { box-shadow: 0 0 30px rgba(0, 210, 255, 0.8); }

            100% { box-shadow: 0 0 20px rgba(0, 210, 255, 0.5); }

        }


        .step-title {

            font-size: 1em;

            font-weight: bold;

            margin-bottom: 10px;

            color: #00d2ff;

        }


        .transformer-visual {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 10px;

            padding: 15px;

            overflow-y: auto;

            display: flex;

            flex-direction: column;

            gap: 10px;

        }


        .layer {

            background: rgba(255, 255, 255, 0.05);

            border: 2px solid rgba(255, 255, 255, 0.2);

            border-radius: 8px;

            padding: 10px;

            transition: all 0.3s ease;

            flex-shrink: 0;

        }


        .layer.active {

            border-color: #00d2ff;

            background: rgba(0, 210, 255, 0.1);

            transform: scale(1.02);

        }


        .component {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 6px;

            padding: 8px;

            margin: 5px 0;

            text-align: center;

            transition: all 0.3s ease;

            cursor: pointer;

            font-size: 0.9em;

        }


        .component.active {

            background: linear-gradient(45deg, rgba(0, 210, 255, 0.3), rgba(58, 123, 213, 0.3));

            transform: translateX(3px);

            box-shadow: 0 0 15px rgba(0, 210, 255, 0.5);

        }


        .math-formula {

            background: rgba(0, 0, 0, 0.5);

            border-radius: 6px;

            padding: 10px;

            margin: 8px 0;

            font-family: 'Courier New', monospace;

            font-size: 12px;

            overflow-x: auto;

        }


        .data-structure {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 6px;

            padding: 8px;

            margin: 8px 0;

            font-size: 0.85em;

        }


        .matrix {

            display: inline-block;

            border: 2px solid #00d2ff;

            border-radius: 4px;

            padding: 4px;

            margin: 3px;

            font-family: monospace;

            font-size: 11px;

            background: rgba(0, 210, 255, 0.1);

        }


        .token {

            display: inline-block;

            background: rgba(255, 255, 255, 0.2);

            border-radius: 4px;

            padding: 4px 8px;

            margin: 2px;

            font-family: monospace;

            transition: all 0.3s ease;

            font-size: 0.85em;

        }


        .token.highlighted {

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            transform: scale(1.1);

            box-shadow: 0 0 10px rgba(0, 210, 255, 0.8);

        }


        .progress-bar {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 6px;

            height: 6px;

            margin: 10px 0;

            overflow: hidden;

        }


        .progress-fill {

            height: 100%;

            background: linear-gradient(90deg, #00d2ff, #3a7bd5);

            border-radius: 6px;

            transition: width 0.5s ease;

            box-shadow: 0 0 8px rgba(0, 210, 255, 0.8);

        }


        .speed-control {

            display: flex;

            align-items: center;

            gap: 10px;

            background: rgba(255, 255, 255, 0.1);

            padding: 8px 15px;

            border-radius: 6px;

            font-size: 0.9em;

        }


        .attention-weights {

            display: grid;

            grid-template-columns: repeat(5, 1fr);

            gap: 2px;

            margin: 8px 0;

            max-width: 200px;

        }


        .weight-cell {

            aspect-ratio: 1;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 9px;

            border-radius: 3px;

            transition: all 0.3s ease;

            color: #fff;

            font-weight: bold;

        }


        .explanation {

            background: rgba(0, 0, 0, 0.5);

            border-left: 3px solid #00d2ff;

            padding: 10px;

            margin: 10px 0;

            border-radius: 0 6px 6px 0;

            font-size: 0.9em;

        }


        .layer-label {

            font-weight: bold;

            color: #00d2ff;

            margin-bottom: 8px;

            font-size: 0.95em;

        }


        .bottom-panel {

            background: rgba(255, 255, 255, 0.05);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 10px;

            margin-top: 10px;

            border: 1px solid rgba(255, 255, 255, 0.1);

            max-height: 200px;

            overflow-y: auto;

        }


        .info-grid {

            display: grid;

            grid-template-columns: 1fr 1fr 1fr;

            gap: 10px;

        }


        .info-section {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 6px;

            padding: 10px;

        }


        .info-section h3 {

            font-size: 0.9em;

            color: #00d2ff;

            margin-bottom: 5px;

        }


        /* Scrollbar styling */

        ::-webkit-scrollbar {

            width: 6px;

            height: 6px;

        }


        ::-webkit-scrollbar-track {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 3px;

        }


        ::-webkit-scrollbar-thumb {

            background: rgba(0, 210, 255, 0.5);

            border-radius: 3px;

        }


        ::-webkit-scrollbar-thumb:hover {

            background: rgba(0, 210, 255, 0.7);

        }

    </style>

</head>

<body>

    <div class="container">

        <h1>🤖 Transformer Architecture Simulator</h1>

        

        <div class="input-section">

            <div class="input-group">

                <input type="text" id="promptInput" placeholder="Enter your text prompt here..." value="The cat sat on the mat">

                <button id="startBtn" onclick="startSimulation()">▶ Start</button>

                <button id="pauseBtn" onclick="pauseSimulation()" disabled>⏸ Pause</button>

                <button id="resetBtn" onclick="resetSimulation()">🔄 Reset</button>

            </div>

            <div class="speed-control">

                <label>Speed:</label>

                <input type="range" id="speedSlider" min="1" max="10" value="5">

                <span id="speedValue">5</span>

            </div>

        </div>


        <div class="progress-bar">

            <div class="progress-fill" id="progressBar" style="width: 0%"></div>

        </div>


        <div class="main-content">

            <div class="panel" id="inputPanel">

                <div class="step-title">Input Processing</div>

                <div id="tokenizationStep" class="component">

                    <strong>1. Tokenization</strong>

                    <div id="tokens" class="data-structure"></div>

                </div>

                <div id="embeddingStep" class="component">

                    <strong>2. Embeddings</strong>

                    <div id="embeddings" class="data-structure"></div>

                </div>

                <div id="positionalStep" class="component">

                    <strong>3. Positional Encoding</strong>

                    <div id="positional" class="data-structure"></div>

                </div>

            </div>


            <div class="transformer-visual">

                <div class="layer-label">ENCODER STACK</div>

                <div class="layer" id="encoder1">

                    <strong>Encoder Layer 1</strong>

                    <div class="component" id="enc1-mha">Multi-Head Attention</div>

                    <div class="component" id="enc1-norm1">Add & Norm</div>

                    <div class="component" id="enc1-ff">Feed Forward</div>

                    <div class="component" id="enc1-norm2">Add & Norm</div>

                </div>

                <div class="layer" id="encoder2">

                    <strong>Encoder Layer 2</strong>

                    <div class="component" id="enc2-mha">Multi-Head Attention</div>

                    <div class="component" id="enc2-norm1">Add & Norm</div>

                    <div class="component" id="enc2-ff">Feed Forward</div>

                    <div class="component" id="enc2-norm2">Add & Norm</div>

                </div>


                <div class="layer-label" style="margin-top: 10px;">DECODER STACK</div>

                <div class="layer" id="decoder1">

                    <strong>Decoder Layer 1</strong>

                    <div class="component" id="dec1-mha1">Masked Multi-Head Attention</div>

                    <div class="component" id="dec1-norm1">Add & Norm</div>

                    <div class="component" id="dec1-mha2">Cross-Attention</div>

                    <div class="component" id="dec1-norm2">Add & Norm</div>

                    <div class="component" id="dec1-ff">Feed Forward</div>

                    <div class="component" id="dec1-norm3">Add & Norm</div>

                </div>

                <div class="layer" id="decoder2">

                    <strong>Decoder Layer 2</strong>

                    <div class="component" id="dec2-mha1">Masked Multi-Head Attention</div>

                    <div class="component" id="dec2-norm1">Add & Norm</div>

                    <div class="component" id="dec2-mha2">Cross-Attention</div>

                    <div class="component" id="dec2-norm2">Add & Norm</div>

                    <div class="component" id="dec2-ff">Feed Forward</div>

                    <div class="component" id="dec2-norm3">Add & Norm</div>

                </div>

            </div>


            <div class="panel" id="outputPanel">

                <div class="step-title">Output Generation</div>

                <div id="linearStep" class="component">

                    <strong>Linear Projection</strong>

                    <div id="linear" class="data-structure"></div>

                </div>

                <div id="softmaxStep" class="component">

                    <strong>Softmax</strong>

                    <div id="softmax" class="data-structure"></div>

                </div>

                <div id="outputStep" class="component">

                    <strong>Generated Output</strong>

                    <div id="output" class="data-structure"></div>

                </div>

            </div>

        </div>


        <div class="bottom-panel">

            <div class="info-grid">

                <div class="info-section">

                    <h3>Current Step</h3>

                    <div id="stepExplanation" class="explanation">

                        Click "Start" to begin the transformer inference visualization.

                    </div>

                </div>

                <div class="info-section">

                    <h3>Mathematical Formula</h3>

                    <div id="mathFormula" class="math-formula">

                        Formulas will appear here during simulation...

                    </div>

                </div>

                <div class="info-section">

                    <h3>Data Visualization</h3>

                    <div id="dataVisualization" class="data-structure">

                        Data structures and matrices will be visualized here...

                    </div>

                </div>

            </div>

        </div>

    </div>


    <script>

        let simulationRunning = false;

        let simulationPaused = false;

        let currentStep = 0;

        let animationSpeed = 5;

        let generatedTokens = [];


        const speedSlider = document.getElementById('speedSlider');

        speedSlider.addEventListener('input', (e) => {

            animationSpeed = parseInt(e.target.value);

            document.getElementById('speedValue').textContent = animationSpeed;

        });


        const steps = [

            {

                id: 'tokenization',

                element: 'tokenizationStep',

                title: 'Tokenization',

                explanation: 'Breaking down the input text into tokens (subwords or words) that the model can process.',

                formula: 'tokens = tokenizer.encode(text)',

                visualize: tokenizeText

            },

            {

                id: 'embedding',

                element: 'embeddingStep',

                title: 'Token Embeddings',

                explanation: 'Converting tokens into dense vector representations in high-dimensional space.',

                formula: 'E(x) = embedding_matrix[token_id] ∈ ℝ^d_model',

                visualize: showEmbeddings

            },

            {

                id: 'positional',

                element: 'positionalStep',

                title: 'Positional Encoding',

                explanation: 'Adding positional information to embeddings so the model knows token positions.',

                formula: 'PE(pos, 2i) = sin(pos/10000^(2i/d_model))\nPE(pos, 2i+1) = cos(pos/10000^(2i/d_model))',

                visualize: showPositionalEncoding

            },

            {

                id: 'enc1-mha',

                element: 'enc1-mha',

                layer: 'encoder1',

                title: 'Encoder Self-Attention',

                explanation: 'Computing attention weights between all tokens to capture relationships.',

                formula: 'Attention(Q,K,V) = softmax(QK^T/√d_k)V\nwhere Q=XW_Q, K=XW_K, V=XW_V',

                visualize: showSelfAttention

            },

            {

                id: 'enc1-norm1',

                element: 'enc1-norm1',

                layer: 'encoder1',

                title: 'Add & Normalize',

                explanation: 'Residual connection and layer normalization for stable training.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc1-ff',

                element: 'enc1-ff',

                layer: 'encoder1',

                title: 'Feed Forward Network',

                explanation: 'Two linear transformations with ReLU activation.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'enc1-norm2',

                element: 'enc1-norm2',

                layer: 'encoder1',

                title: 'Add & Normalize',

                explanation: 'Second residual connection and normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc2-mha',

                element: 'enc2-mha',

                layer: 'encoder2',

                title: 'Encoder Self-Attention (Layer 2)',

                explanation: 'Second layer captures higher-level patterns.',

                formula: 'Attention(Q,K,V) = softmax(QK^T/√d_k)V',

                visualize: showSelfAttention

            },

            {

                id: 'enc2-norm1',

                element: 'enc2-norm1',

                layer: 'encoder2',

                title: 'Add & Normalize',

                explanation: 'Residual and normalization in layer 2.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc2-ff',

                element: 'enc2-ff',

                layer: 'encoder2',

                title: 'Feed Forward (Layer 2)',

                explanation: 'Second layer feed-forward network.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'enc2-norm2',

                element: 'enc2-norm2',

                layer: 'encoder2',

                title: 'Add & Normalize',

                explanation: 'Final encoder layer 2 normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-mha1',

                element: 'dec1-mha1',

                layer: 'decoder1',

                title: 'Masked Self-Attention',

                explanation: 'Self-attention with causal mask to prevent looking at future tokens.',

                formula: 'MaskedAttention(Q,K,V) = softmax((QK^T + M)/√d_k)V',

                visualize: showMaskedAttention

            },

            {

                id: 'dec1-norm1',

                element: 'dec1-norm1',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'First decoder residual and normalization.',

                formula: 'LayerNorm(x + MaskedAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-mha2',

                element: 'dec1-mha2',

                layer: 'decoder1',

                title: 'Cross-Attention',

                explanation: 'Attending to encoder output to incorporate source information.',

                formula: 'CrossAttention(Q_dec, K_enc, V_enc)',

                visualize: showCrossAttention

            },

            {

                id: 'dec1-norm2',

                element: 'dec1-norm2',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'Cross-attention residual and normalization.',

                formula: 'LayerNorm(x + CrossAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-ff',

                element: 'dec1-ff',

                layer: 'decoder1',

                title: 'Feed Forward',

                explanation: 'Decoder feed-forward network.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'dec1-norm3',

                element: 'dec1-norm3',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'Final decoder layer 1 normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-mha1',

                element: 'dec2-mha1',

                layer: 'decoder2',

                title: 'Masked Self-Attention (Layer 2)',

                explanation: 'Second decoder layer masked attention.',

                formula: 'MaskedAttention(Q,K,V)',

                visualize: showMaskedAttention

            },

            {

                id: 'dec2-norm1',

                element: 'dec2-norm1',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Layer 2 first normalization.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-mha2',

                element: 'dec2-mha2',

                layer: 'decoder2',

                title: 'Cross-Attention (Layer 2)',

                explanation: 'Second layer cross-attention.',

                formula: 'CrossAttention(Q_dec, K_enc, V_enc)',

                visualize: showCrossAttention

            },

            {

                id: 'dec2-norm2',

                element: 'dec2-norm2',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Layer 2 cross-attention normalization.',

                formula: 'LayerNorm(x + CrossAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-ff',

                element: 'dec2-ff',

                layer: 'decoder2',

                title: 'Feed Forward (Layer 2)',

                explanation: 'Final decoder feed-forward.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'dec2-norm3',

                element: 'dec2-norm3',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Final decoder normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'linear',

                element: 'linearStep',

                title: 'Linear Projection',

                explanation: 'Projecting decoder output to vocabulary size for token prediction.',

                formula: 'logits = decoder_output @ W_vocab + b_vocab',

                visualize: showLinearProjection

            },

            {

                id: 'softmax',

                element: 'softmaxStep',

                title: 'Softmax',

                explanation: 'Converting logits to probability distribution over vocabulary.',

                formula: 'P(token_i) = exp(logit_i) / Σ_j exp(logit_j)',

                visualize: showSoftmax

            },

            {

                id: 'output',

                element: 'outputStep',

                title: 'Token Generation',

                explanation: 'Selecting the next token based on probability distribution.',

                formula: 'next_token = argmax(P) or sample(P)',

                visualize: showOutput

            }

        ];


        function startSimulation() {

            if (simulationRunning && !simulationPaused) return;

            

            simulationRunning = true;

            simulationPaused = false;

            document.getElementById('startBtn').disabled = true;

            document.getElementById('pauseBtn').disabled = false;

            

            if (currentStep === 0) {

                resetVisualization();

                generatedTokens = [];

            }

            

            runStep();

        }


        function pauseSimulation() {

            simulationPaused = true;

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

        }


        function resetSimulation() {

            simulationRunning = false;

            simulationPaused = false;

            currentStep = 0;

            generatedTokens = [];

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

            resetVisualization();

            updateProgress(0);

        }


        function resetVisualization() {

            document.querySelectorAll('.component, .layer, .panel').forEach(el => {

                el.classList.remove('active');

            });

            document.getElementById('tokens').innerHTML = '';

            document.getElementById('embeddings').innerHTML = '';

            document.getElementById('positional').innerHTML = '';

            document.getElementById('linear').innerHTML = '';

            document.getElementById('softmax').innerHTML = '';

            document.getElementById('output').innerHTML = '';

            document.getElementById('stepExplanation').innerHTML = 'Click "Start" to begin.';

            document.getElementById('mathFormula').innerHTML = 'Formulas will appear here...';

            document.getElementById('dataVisualization').innerHTML = '';

        }


        function runStep() {

            if (!simulationRunning || simulationPaused || currentStep >= steps.length) {

                if (currentStep >= steps.length) {

                    completeSimulation();

                }

                return;

            }


            const step = steps[currentStep];

            highlightStep(step);

            updateStepInfo(step);

            step.visualize();

            updateProgress((currentStep + 1) / steps.length * 100);


            currentStep++;

            setTimeout(runStep, 2000 / animationSpeed);

        }


        function highlightStep(step) {

            document.querySelectorAll('.component, .layer, .panel').forEach(el => {

                el.classList.remove('active');

            });


            const element = document.getElementById(step.element);

            if (element) {

                element.classList.add('active');

                // Scroll into view within the parent container

                const parent = element.closest('.panel, .transformer-visual');

                if (parent) {

                    const elementTop = element.offsetTop;

                    const elementHeight = element.offsetHeight;

                    const parentHeight = parent.clientHeight;

                    const scrollTop = parent.scrollTop;

                    

                    if (elementTop < scrollTop || elementTop + elementHeight > scrollTop + parentHeight) {

                        parent.scrollTop = elementTop - parentHeight / 2 + elementHeight / 2;

                    }

                }

            }


            if (step.layer) {

                document.getElementById(step.layer).classList.add('active');

            }


            // Highlight the appropriate panel

            if (step.id.includes('enc') || step.id.includes('dec')) {

                // Main transformer panel is always visible

            } else if (['tokenization', 'embedding', 'positional'].includes(step.id)) {

                document.getElementById('inputPanel').classList.add('active');

            } else if (['linear', 'softmax', 'output'].includes(step.id)) {

                document.getElementById('outputPanel').classList.add('active');

            }

        }


        function updateStepInfo(step) {

            document.getElementById('stepExplanation').innerHTML = `

                <strong>${step.title}</strong><br>

                ${step.explanation}

            `;

            document.getElementById('mathFormula').innerHTML = `<pre>${step.formula}</pre>`;

        }


        function updateProgress(percent) {

            document.getElementById('progressBar').style.width = percent + '%';

        }


        function tokenizeText() {

            const text = document.getElementById('promptInput').value;

            const tokens = text.split(' ').map(word => `[${word}]`);

            const tokensDiv = document.getElementById('tokens');

            tokensDiv.innerHTML = '';

            

            tokens.forEach((token, i) => {

                const tokenEl = document.createElement('span');

                tokenEl.className = 'token';

                tokenEl.textContent = token;

                tokensDiv.appendChild(tokenEl);

                

                setTimeout(() => {

                    tokenEl.classList.add('highlighted');

                    setTimeout(() => tokenEl.classList.remove('highlighted'), 500);

                }, i * 100);

            });


            document.getElementById('dataVisualization').innerHTML = `

                <div>Token IDs: [${tokens.map((_, i) => 1000 + i).join(', ')}]</div>

                <div>Vocabulary size: 50,000</div>

            `;

        }


        function showEmbeddings() {

            const embDiv = document.getElementById('embeddings');

            embDiv.innerHTML = '';

            

            const text = document.getElementById('promptInput').value;

            const tokens = text.split(' ');

            

            tokens.slice(0, 3).forEach((token, i) => {

                const matrix = document.createElement('div');

                matrix.className = 'matrix';

                matrix.innerHTML = `[${token}]<br>[${Array(4).fill(0).map(() => 

                    (Math.random() * 2 - 1).toFixed(2)).join(', ')}...]`;

                embDiv.appendChild(matrix);

            });


            document.getElementById('dataVisualization').innerHTML = `

                <div>Embedding dim: 512</div>

                <div>Matrix: [50000 × 512]</div>

            `;

        }


        function showPositionalEncoding() {

            const posDiv = document.getElementById('positional');

            posDiv.innerHTML = '<div>Adding sinusoidal encodings...</div>';

            

            const canvas = document.createElement('canvas');

            canvas.width = 180;

            canvas.height = 60;

            canvas.style.width = '100%';

            canvas.style.borderRadius = '6px';

            canvas.style.marginTop = '5px';

            

            const ctx = canvas.getContext('2d');

            ctx.fillStyle = '#00d2ff';

            

            for (let x = 0; x < canvas.width; x++) {

                const y = 30 + 20 * Math.sin(x * 0.05);

                ctx.fillRect(x, y, 2, 2);

            }

            

            posDiv.appendChild(canvas);


            document.getElementById('dataVisualization').innerHTML = `

                <div>PE added to embeddings</div>

                <div>E(x) + PE(pos)</div>

            `;

        }


        function showSelfAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Attention scores:</div>

                <div class="attention-weights">

                    ${Array(25).fill(0).map(() => 

                        `<div class="weight-cell" style="background: rgba(0, 210, 255, ${Math.random()})">

                            ${Math.random().toFixed(2)}

                        </div>`

                    ).join('')}

                </div>

                <div>8 heads in parallel</div>

            `;

        }


        function showMaskedAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Masked attention:</div>

                <div class="attention-weights">

                    ${Array(25).fill(0).map((_, i) => {

                        const row = Math.floor(i / 5);

                        const col = i % 5;

                        const masked = col > row;

                        return `<div class="weight-cell" style="background: ${masked ? '#333' : `rgba(0, 210, 255, ${Math.random()})`}">

                            ${masked ? '-∞' : Math.random().toFixed(2)}

                        </div>`;

                    }).join('')}

                </div>

            `;

        }


        function showCrossAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Cross-attention:</div>

                <div style="display: flex; align-items: center; gap: 10px; margin-top: 5px;">

                    <div class="matrix">Q_dec</div>

                    <div>×</div>

                    <div class="matrix">K_enc</div>

                    <div>=</div>

                    <div class="matrix">Scores</div>

                </div>

            `;

        }


        function showLayerNorm() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Normalizing output</div>

                <div>μ = 0.0, σ = 1.0</div>

                <div>Residual: x + sublayer(x)</div>

            `;

        }


        function showFeedForward() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>FFN layers:</div>

                <div style="display: flex; align-items: center; gap: 8px; margin-top: 5px;">

                    <div class="matrix">[512]</div>

                    <div>→</div>

                    <div class="matrix">[2048]</div>

                    <div>→</div>

                    <div class="matrix">[512]</div>

                </div>

            `;

        }


        function showLinearProjection() {

            const linearDiv = document.getElementById('linear');

            linearDiv.innerHTML = '<div class="matrix">Logits: [50000]</div>';

            

            document.getElementById('dataVisualization').innerHTML = `

                <div>Projecting to vocab</div>

                <div class="matrix">W: [512 × 50000]</div>

            `;

        }


        function showSoftmax() {

            const softmaxDiv = document.getElementById('softmax');

            const candidates = ['mat', 'floor', 'table', 'ground', 'chair'];

            const probs = candidates.map(() => Math.random());

            const sum = probs.reduce((a, b) => a + b, 0);

            const normalized = probs.map(p => (p / sum).toFixed(3));

            

            softmaxDiv.innerHTML = `

                <div>Top probabilities:</div>

                ${normalized.map((p, i) => 

                    `<div class="token">${candidates[i]}: ${p}</div>`

                ).join('')}

            `;


            document.getElementById('dataVisualization').innerHTML = `

                <div>Temperature = 1.0</div>

                <div>Probability distribution</div>

            `;

        }


        function showOutput() {

            const outputDiv = document.getElementById('output');

            const nextToken = 'mat';

            generatedTokens.push(nextToken);

            

            outputDiv.innerHTML = `

                <div class="token highlighted">Next token: "${nextToken}"</div>

                <div style="margin-top: 5px;">Generated: ${generatedTokens.join(' ')}</div>

            `;

            

            document.getElementById('dataVisualization').innerHTML = `

                <div>Token selected: "${nextToken}"</div>

                <div>Method: greedy decoding</div>

            `;

        }


        function completeSimulation() {

            document.getElementById('stepExplanation').innerHTML = `

                <strong>Simulation Complete!</strong><br>

                The transformer has processed the input and generated the next token.

                This process repeats for each token generation.

            `;

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

        }

    </script>

</body>

</html>


```I'll fix those issues and create an improved version with better layout and visibility:


```html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Transformer Architecture Simulator</title>

    <style>

        * {

            margin: 0;

            padding: 0;

            box-sizing: border-box;

        }


        body {

            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

            background: linear-gradient(135deg, #0f0c29, #302b63, #24243e);

            color: #fff;

            height: 100vh;

            overflow: hidden;

        }


        .container {

            height: 100vh;

            display: flex;

            flex-direction: column;

            padding: 10px;

        }


        h1 {

            text-align: center;

            font-size: 1.8em;

            margin-bottom: 10px;

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            -webkit-background-clip: text;

            -webkit-text-fill-color: transparent;

            text-shadow: 0 0 30px rgba(0, 210, 255, 0.5);

        }


        .input-section {

            background: rgba(255, 255, 255, 0.1);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 10px;

            margin-bottom: 10px;

            box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);

            border: 1px solid rgba(255, 255, 255, 0.2);

        }


        .input-group {

            display: flex;

            gap: 10px;

            margin-bottom: 10px;

        }


        #promptInput {

            flex: 1;

            padding: 8px;

            border: none;

            border-radius: 6px;

            background: rgba(255, 255, 255, 0.2);

            color: #fff;

            font-size: 14px;

        }


        #promptInput::placeholder {

            color: rgba(255, 255, 255, 0.6);

        }


        button {

            padding: 8px 20px;

            border: none;

            border-radius: 6px;

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            color: #fff;

            font-size: 14px;

            font-weight: bold;

            cursor: pointer;

            transition: all 0.3s ease;

            box-shadow: 0 2px 8px rgba(0, 210, 255, 0.4);

        }


        button:hover {

            transform: translateY(-1px);

            box-shadow: 0 4px 12px rgba(0, 210, 255, 0.6);

        }


        button:disabled {

            opacity: 0.5;

            cursor: not-allowed;

        }


        .main-content {

            flex: 1;

            display: flex;

            gap: 10px;

            overflow: hidden;

        }


        .left-panel {

            width: 300px;

            display: flex;

            flex-direction: column;

            gap: 10px;

        }


        .center-panel {

            flex: 1;

            display: flex;

            flex-direction: column;

        }


        .right-panel {

            width: 350px;

            overflow-y: auto;

        }


        .panel {

            background: rgba(255, 255, 255, 0.05);

            backdrop-filter: blur(10px);

            border-radius: 10px;

            padding: 15px;

            border: 1px solid rgba(255, 255, 255, 0.1);

            transition: all 0.3s ease;

        }


        .panel.active {

            border-color: #00d2ff;

            box-shadow: 0 0 20px rgba(0, 210, 255, 0.5);

            animation: pulse 2s infinite;

        }


        @keyframes pulse {

            0% { box-shadow: 0 0 20px rgba(0, 210, 255, 0.5); }

            50% { box-shadow: 0 0 30px rgba(0, 210, 255, 0.8); }

            100% { box-shadow: 0 0 20px rgba(0, 210, 255, 0.5); }

        }


        .step-title {

            font-size: 1em;

            font-weight: bold;

            margin-bottom: 10px;

            color: #00d2ff;

        }


        .transformer-visual {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 10px;

            padding: 15px;

            flex: 1;

            overflow-y: auto;

            display: flex;

            flex-direction: column;

            gap: 10px;

        }


        .layer {

            background: rgba(255, 255, 255, 0.05);

            border: 2px solid rgba(255, 255, 255, 0.2);

            border-radius: 8px;

            padding: 10px;

            transition: all 0.3s ease;

        }


        .layer.active {

            border-color: #00d2ff;

            background: rgba(0, 210, 255, 0.1);

            transform: scale(1.02);

        }


        .layer-title {

            font-weight: bold;

            font-size: 0.9em;

            margin-bottom: 8px;

            color: #fff;

        }


        .component {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 6px;

            padding: 8px;

            margin: 5px 0;

            text-align: center;

            transition: all 0.3s ease;

            cursor: pointer;

            font-size: 0.85em;

        }


        .component.active {

            background: linear-gradient(45deg, rgba(0, 210, 255, 0.3), rgba(58, 123, 213, 0.3));

            transform: translateX(3px);

            box-shadow: 0 0 15px rgba(0, 210, 255, 0.5);

        }


        .math-formula {

            background: rgba(0, 0, 0, 0.5);

            border-radius: 6px;

            padding: 10px;

            margin: 8px 0;

            font-family: 'Courier New', monospace;

            font-size: 12px;

            overflow-x: auto;

        }


        .data-structure {

            background: rgba(0, 0, 0, 0.3);

            border-radius: 6px;

            padding: 8px;

            margin: 8px 0;

            font-size: 0.85em;

        }


        .matrix {

            display: inline-block;

            border: 2px solid #00d2ff;

            border-radius: 4px;

            padding: 4px;

            margin: 3px;

            font-family: monospace;

            font-size: 11px;

            background: rgba(0, 210, 255, 0.1);

        }


        .token {

            display: inline-block;

            background: rgba(255, 255, 255, 0.2);

            border-radius: 4px;

            padding: 4px 8px;

            margin: 2px;

            font-family: monospace;

            font-size: 0.85em;

            transition: all 0.3s ease;

        }


        .token.highlighted {

            background: linear-gradient(45deg, #00d2ff, #3a7bd5);

            transform: scale(1.1);

            box-shadow: 0 0 10px rgba(0, 210, 255, 0.8);

        }


        .progress-bar {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 6px;

            height: 6px;

            margin: 10px 0;

            overflow: hidden;

        }


        .progress-fill {

            height: 100%;

            background: linear-gradient(90deg, #00d2ff, #3a7bd5);

            border-radius: 6px;

            transition: width 0.5s ease;

            box-shadow: 0 0 8px rgba(0, 210, 255, 0.8);

        }


        .speed-control {

            display: flex;

            align-items: center;

            gap: 10px;

            font-size: 0.85em;

        }


        .attention-weights {

            display: grid;

            grid-template-columns: repeat(5, 1fr);

            gap: 2px;

            margin: 8px 0;

            max-width: 200px;

        }


        .weight-cell {

            aspect-ratio: 1;

            display: flex;

            align-items: center;

            justify-content: center;

            font-size: 9px;

            border-radius: 3px;

            transition: all 0.3s ease;

            color: #fff;

            font-weight: bold;

        }


        .explanation {

            background: rgba(0, 0, 0, 0.5);

            border-left: 3px solid #00d2ff;

            padding: 10px;

            margin: 10px 0;

            border-radius: 0 6px 6px 0;

            font-size: 0.85em;

        }


        .layer-label {

            font-weight: bold;

            color: #00d2ff;

            margin: 5px 0;

            font-size: 0.95em;

            text-align: center;

            background: rgba(0, 210, 255, 0.1);

            padding: 5px;

            border-radius: 6px;

        }


        .input-output-container {

            display: flex;

            flex-direction: column;

            gap: 10px;

            height: 100%;

        }


        .input-panel {

            flex: 1;

        }


        .output-panel {

            flex: 1;

        }


        /* Scrollbar styling */

        ::-webkit-scrollbar {

            width: 8px;

            height: 8px;

        }


        ::-webkit-scrollbar-track {

            background: rgba(255, 255, 255, 0.1);

            border-radius: 4px;

        }


        ::-webkit-scrollbar-thumb {

            background: rgba(0, 210, 255, 0.5);

            border-radius: 4px;

        }


        ::-webkit-scrollbar-thumb:hover {

            background: rgba(0, 210, 255, 0.7);

        }

    </style>

</head>

<body>

    <div class="container">

        <h1>🤖 Transformer Architecture Simulator</h1>

        

        <div class="input-section">

            <div class="input-group">

                <input type="text" id="promptInput" placeholder="Enter your text prompt here..." value="The cat sat on the mat">

                <button id="startBtn" onclick="startSimulation()">▶ Start</button>

                <button id="pauseBtn" onclick="pauseSimulation()" disabled>⏸ Pause</button>

                <button id="resetBtn" onclick="resetSimulation()">🔄 Reset</button>

                <div class="speed-control">

                    <label>Speed:</label>

                    <input type="range" id="speedSlider" min="1" max="10" value="5" style="width: 80px;">

                    <span id="speedValue">5</span>

                </div>

            </div>

            <div class="progress-bar">

                <div class="progress-fill" id="progressBar" style="width: 0%"></div>

            </div>

        </div>


        <div class="main-content">

            <div class="left-panel">

                <div class="input-output-container">

                    <div class="panel input-panel" id="inputPanel">

                        <div class="step-title">Input Processing</div>

                        <div id="tokenizationStep" class="component">

                            <strong>1. Tokenization</strong>

                            <div id="tokens" class="data-structure"></div>

                        </div>

                        <div id="embeddingStep" class="component">

                            <strong>2. Embeddings</strong>

                            <div id="embeddings" class="data-structure"></div>

                        </div>

                        <div id="positionalStep" class="component">

                            <strong>3. Positional Encoding</strong>

                            <div id="positional" class="data-structure"></div>

                        </div>

                    </div>


                    <div class="panel output-panel" id="outputPanel">

                        <div class="step-title">Output Generation</div>

                        <div id="linearStep" class="component">

                            <strong>Linear Projection</strong>

                            <div id="linear" class="data-structure"></div>

                        </div>

                        <div id="softmaxStep" class="component">

                            <strong>Softmax</strong>

                            <div id="softmax" class="data-structure"></div>

                        </div>

                        <div id="outputStep" class="component">

                            <strong>Generated Output</strong>

                            <div id="output" class="data-structure"></div>

                        </div>

                    </div>

                </div>

            </div>


            <div class="center-panel">

                <div class="transformer-visual">

                    <div class="layer-label">ENCODER STACK</div>

                    

                    <div class="layer" id="encoder1">

                        <div class="layer-title">Encoder Layer 1</div>

                        <div class="component" id="enc1-mha">Multi-Head Attention</div>

                        <div class="component" id="enc1-norm1">Add & Norm</div>

                        <div class="component" id="enc1-ff">Feed Forward</div>

                        <div class="component" id="enc1-norm2">Add & Norm</div>

                    </div>

                    

                    <div class="layer" id="encoder2">

                        <div class="layer-title">Encoder Layer 2</div>

                        <div class="component" id="enc2-mha">Multi-Head Attention</div>

                        <div class="component" id="enc2-norm1">Add & Norm</div>

                        <div class="component" id="enc2-ff">Feed Forward</div>

                        <div class="component" id="enc2-norm2">Add & Norm</div>

                    </div>


                    <div class="layer-label">DECODER STACK</div>

                    

                    <div class="layer" id="decoder1">

                        <div class="layer-title">Decoder Layer 1</div>

                        <div class="component" id="dec1-mha1">Masked Multi-Head Attention</div>

                        <div class="component" id="dec1-norm1">Add & Norm</div>

                        <div class="component" id="dec1-mha2">Cross-Attention</div>

                        <div class="component" id="dec1-norm2">Add & Norm</div>

                        <div class="component" id="dec1-ff">Feed Forward</div>

                        <div class="component" id="dec1-norm3">Add & Norm</div>

                    </div>

                    

                    <div class="layer" id="decoder2">

                        <div class="layer-title">Decoder Layer 2</div>

                        <div class="component" id="dec2-mha1">Masked Multi-Head Attention</div>

                        <div class="component" id="dec2-norm1">Add & Norm</div>

                        <div class="component" id="dec2-mha2">Cross-Attention</div>

                        <div class="component" id="dec2-norm2">Add & Norm</div>

                        <div class="component" id="dec2-ff">Feed Forward</div>

                        <div class="component" id="dec2-norm3">Add & Norm</div>

                    </div>

                </div>

            </div>


            <div class="right-panel">

                <div class="panel">

                    <div class="step-title">Current Step Details</div>

                    <div id="stepExplanation" class="explanation">

                        Click "Start" to begin the transformer inference visualization.

                    </div>

                    <div class="step-title">Mathematical Formula</div>

                    <div id="mathFormula" class="math-formula">

                        Formulas will appear here during simulation...

                    </div>

                    <div class="step-title">Data Visualization</div>

                    <div id="dataVisualization" class="data-structure">

                        Data structures and matrices will be visualized here...

                    </div>

                </div>

            </div>

        </div>

    </div>


    <script>

        let simulationRunning = false;

        let simulationPaused = false;

        let currentStep = 0;

        let animationSpeed = 5;

        let generatedTokens = [];


        const speedSlider = document.getElementById('speedSlider');

        speedSlider.addEventListener('input', (e) => {

            animationSpeed = parseInt(e.target.value);

            document.getElementById('speedValue').textContent = animationSpeed;

        });


        const steps = [

            {

                id: 'tokenization',

                element: 'tokenizationStep',

                title: 'Tokenization',

                explanation: 'Breaking down the input text into tokens (subwords or words) that the model can process.',

                formula: 'tokens = tokenizer.encode(text)',

                visualize: tokenizeText

            },

            {

                id: 'embedding',

                element: 'embeddingStep',

                title: 'Token Embeddings',

                explanation: 'Converting tokens into dense vector representations in high-dimensional space.',

                formula: 'E(x) = embedding_matrix[token_id] ∈ ℝ^d_model',

                visualize: showEmbeddings

            },

            {

                id: 'positional',

                element: 'positionalStep',

                title: 'Positional Encoding',

                explanation: 'Adding positional information to embeddings so the model knows token positions.',

                formula: 'PE(pos, 2i) = sin(pos/10000^(2i/d_model))\nPE(pos, 2i+1) = cos(pos/10000^(2i/d_model))',

                visualize: showPositionalEncoding

            },

            {

                id: 'enc1-mha',

                element: 'enc1-mha',

                layer: 'encoder1',

                title: 'Encoder Self-Attention',

                explanation: 'Computing attention weights between all tokens to capture relationships.',

                formula: 'Attention(Q,K,V) = softmax(QK^T/√d_k)V\nwhere Q=XW_Q, K=XW_K, V=XW_V',

                visualize: showSelfAttention

            },

            {

                id: 'enc1-norm1',

                element: 'enc1-norm1',

                layer: 'encoder1',

                title: 'Add & Normalize',

                explanation: 'Adding residual connection and normalizing for stable training.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc1-ff',

                element: 'enc1-ff',

                layer: 'encoder1',

                title: 'Feed Forward Network',

                explanation: 'Two linear transformations with ReLU activation.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'enc1-norm2',

                element: 'enc1-norm2',

                layer: 'encoder1',

                title: 'Add & Normalize',

                explanation: 'Second residual connection and normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc2-mha',

                element: 'enc2-mha',

                layer: 'encoder2',

                title: 'Encoder Self-Attention (Layer 2)',

                explanation: 'Second layer captures higher-level patterns.',

                formula: 'Attention(Q,K,V) = softmax(QK^T/√d_k)V',

                visualize: showSelfAttention

            },

            {

                id: 'enc2-norm1',

                element: 'enc2-norm1',

                layer: 'encoder2',

                title: 'Add & Normalize',

                explanation: 'Residual and normalization in second encoder.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'enc2-ff',

                element: 'enc2-ff',

                layer: 'encoder2',

                title: 'Feed Forward (Layer 2)',

                explanation: 'Second layer feed-forward transformation.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'enc2-norm2',

                element: 'enc2-norm2',

                layer: 'encoder2',

                title: 'Add & Normalize',

                explanation: 'Final encoder normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-mha1',

                element: 'dec1-mha1',

                layer: 'decoder1',

                title: 'Masked Self-Attention',

                explanation: 'Self-attention with causal mask to prevent looking ahead.',

                formula: 'MaskedAttention(Q,K,V) = softmax((QK^T + M)/√d_k)V',

                visualize: showMaskedAttention

            },

            {

                id: 'dec1-norm1',

                element: 'dec1-norm1',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'First decoder residual and normalization.',

                formula: 'LayerNorm(x + MaskedAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-mha2',

                element: 'dec1-mha2',

                layer: 'decoder1',

                title: 'Cross-Attention',

                explanation: 'Attending to encoder output.',

                formula: 'CrossAttention(Q_dec, K_enc, V_enc)',

                visualize: showCrossAttention

            },

            {

                id: 'dec1-norm2',

                element: 'dec1-norm2',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'Residual after cross-attention.',

                formula: 'LayerNorm(x + CrossAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec1-ff',

                element: 'dec1-ff',

                layer: 'decoder1',

                title: 'Feed Forward',

                explanation: 'Decoder feed-forward network.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'dec1-norm3',

                element: 'dec1-norm3',

                layer: 'decoder1',

                title: 'Add & Normalize',

                explanation: 'Final normalization in first decoder.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-mha1',

                element: 'dec2-mha1',

                layer: 'decoder2',

                title: 'Masked Self-Attention (Layer 2)',

                explanation: 'Second decoder masked attention.',

                formula: 'MaskedAttention(Q,K,V)',

                visualize: showMaskedAttention

            },

            {

                id: 'dec2-norm1',

                element: 'dec2-norm1',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Layer 2 decoder normalization.',

                formula: 'LayerNorm(x + Sublayer(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-mha2',

                element: 'dec2-mha2',

                layer: 'decoder2',

                title: 'Cross-Attention (Layer 2)',

                explanation: 'Second layer cross-attention.',

                formula: 'CrossAttention(Q_dec, K_enc, V_enc)',

                visualize: showCrossAttention

            },

            {

                id: 'dec2-norm2',

                element: 'dec2-norm2',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Post cross-attention normalization.',

                formula: 'LayerNorm(x + CrossAttention(x))',

                visualize: showLayerNorm

            },

            {

                id: 'dec2-ff',

                element: 'dec2-ff',

                layer: 'decoder2',

                title: 'Feed Forward (Layer 2)',

                explanation: 'Final decoder feed-forward.',

                formula: 'FFN(x) = max(0, xW_1 + b_1)W_2 + b_2',

                visualize: showFeedForward

            },

            {

                id: 'dec2-norm3',

                element: 'dec2-norm3',

                layer: 'decoder2',

                title: 'Add & Normalize',

                explanation: 'Final decoder normalization.',

                formula: 'LayerNorm(x + FFN(x))',

                visualize: showLayerNorm

            },

            {

                id: 'linear',

                element: 'linearStep',

                title: 'Linear Projection',

                explanation: 'Projecting to vocabulary size.',

                formula: 'logits = decoder_output @ W_vocab + b_vocab',

                visualize: showLinearProjection

            },

            {

                id: 'softmax',

                element: 'softmaxStep',

                title: 'Softmax',

                explanation: 'Converting to probabilities.',

                formula: 'P(token_i) = exp(logit_i) / Σ_j exp(logit_j)',

                visualize: showSoftmax

            },

            {

                id: 'output',

                element: 'outputStep',

                title: 'Token Generation',

                explanation: 'Selecting the next token.',

                formula: 'next_token = argmax(P) or sample(P)',

                visualize: showOutput

            }

        ];


        function startSimulation() {

            if (simulationRunning && !simulationPaused) return;

            

            simulationRunning = true;

            simulationPaused = false;

            document.getElementById('startBtn').disabled = true;

            document.getElementById('pauseBtn').disabled = false;

            

            if (currentStep === 0) {

                resetVisualization();

                generatedTokens = [];

            }

            

            runStep();

        }


        function pauseSimulation() {

            simulationPaused = true;

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

        }


        function resetSimulation() {

            simulationRunning = false;

            simulationPaused = false;

            currentStep = 0;

            generatedTokens = [];

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

            resetVisualization();

            updateProgress(0);

        }


        function resetVisualization() {

            document.querySelectorAll('.component, .layer, .panel').forEach(el => {

                el.classList.remove('active');

            });

            document.getElementById('tokens').innerHTML = '';

            document.getElementById('embeddings').innerHTML = '';

            document.getElementById('positional').innerHTML = '';

            document.getElementById('linear').innerHTML = '';

            document.getElementById('softmax').innerHTML = '';

            document.getElementById('output').innerHTML = '';

            document.getElementById('stepExplanation').textContent = 'Click "Start" to begin.';

            document.getElementById('mathFormula').textContent = 'Formulas will appear here...';

            document.getElementById('dataVisualization').innerHTML = '';

        }


        function runStep() {

            if (!simulationRunning || simulationPaused || currentStep >= steps.length) {

                if (currentStep >= steps.length) {

                    completeSimulation();

                }

                return;

            }


            const step = steps[currentStep];

            highlightStep(step);

            updateStepInfo(step);

            step.visualize();

            updateProgress((currentStep + 1) / steps.length * 100);


            currentStep++;

            setTimeout(runStep, 2000 / animationSpeed);

        }


        function highlightStep(step) {

            document.querySelectorAll('.component, .layer, .panel').forEach(el => {

                el.classList.remove('active');

            });


            const element = document.getElementById(step.element);

            if (element) {

                element.classList.add('active');

            }


            if (step.layer) {

                document.getElementById(step.layer).classList.add('active');

            }


            if (['tokenization', 'embedding', 'positional'].includes(step.id)) {

                document.getElementById('inputPanel').classList.add('active');

            } else if (['linear', 'softmax', 'output'].includes(step.id)) {

                document.getElementById('outputPanel').classList.add('active');

            }

        }


        function updateStepInfo(step) {

            document.getElementById('stepExplanation').innerHTML = `

                <strong>${step.title}</strong><br>

                ${step.explanation}

            `;

            document.getElementById('mathFormula').innerHTML = `<pre>${step.formula}</pre>`;

        }


        function updateProgress(percent) {

            document.getElementById('progressBar').style.width = percent + '%';

        }


        function tokenizeText() {

            const text = document.getElementById('promptInput').value;

            const tokens = text.split(' ').map(word => `[${word}]`);

            const tokensDiv = document.getElementById('tokens');

            tokensDiv.innerHTML = '';

            

            tokens.forEach((token, i) => {

                const tokenEl = document.createElement('span');

                tokenEl.className = 'token';

                tokenEl.textContent = token;

                tokensDiv.appendChild(tokenEl);

                

                setTimeout(() => {

                    tokenEl.classList.add('highlighted');

                    setTimeout(() => tokenEl.classList.remove('highlighted'), 500);

                }, i * 100);

            });


            document.getElementById('dataVisualization').innerHTML = `

                <div>Token IDs: [${tokens.map((_, i) => 1000 + i).join(', ')}]</div>

                <div>Vocabulary size: 50,000</div>

            `;

        }


        function showEmbeddings() {

            const embDiv = document.getElementById('embeddings');

            embDiv.innerHTML = '';

            

            const text = document.getElementById('promptInput').value;

            const tokens = text.split(' ');

            

            tokens.slice(0, 3).forEach((token, i) => {

                const matrix = document.createElement('div');

                matrix.className = 'matrix';

                matrix.innerHTML = `[${token}]<br>[${Array(4).fill(0).map(() => 

                    (Math.random() * 2 - 1).toFixed(2)).join(', ')}...]`;

                embDiv.appendChild(matrix);

            });


            document.getElementById('dataVisualization').innerHTML = `

                <div>Embedding dimension: 512</div>

                <div>Each token → 512-dimensional vector</div>

                <div class="matrix" style="margin-top: 10px;">

                    Embedding Matrix: [50000 × 512]

                </div>

            `;

        }


        function showPositionalEncoding() {

            const posDiv = document.getElementById('positional');

            posDiv.innerHTML = '<div>Adding sinusoidal encodings...</div>';

            

            const canvas = document.createElement('canvas');

            canvas.width = 200;

            canvas.height = 60;

            canvas.style.width = '100%';

            canvas.style.borderRadius = '6px';

            canvas.style.marginTop = '8px';

            

            const ctx = canvas.getContext('2d');

            ctx.fillStyle = '#00d2ff';

            

            for (let x = 0; x < canvas.width; x++) {

                const y = 30 + 20 * Math.sin(x * 0.05);

                ctx.fillRect(x, y, 2, 2);

            }

            

            posDiv.appendChild(canvas);


            document.getElementById('dataVisualization').innerHTML = `

                <div>Position encoding added to embeddings</div>

                <div>Final input: E(x) + PE(pos)</div>

            `;

        }


        function showSelfAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div style="margin-bottom: 8px;">Computing attention scores...</div>

                <div class="attention-weights">

                    ${Array(25).fill(0).map(() => 

                        `<div class="weight-cell" style="background: rgba(0, 210, 255, ${Math.random()})">

                            ${Math.random().toFixed(2)}

                        </div>`

                    ).join('')}

                </div>

                <div style="margin-top: 8px;">8 attention heads in parallel</div>

            `;

        }


        function showMaskedAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div style="margin-bottom: 8px;">Masked attention (causal)</div>

                <div class="attention-weights">

                    ${Array(25).fill(0).map((_, i) => {

                        const row = Math.floor(i / 5);

                        const col = i % 5;

                        const masked = col > row;

                        return `<div class="weight-cell" style="background: ${masked ? '#333' : `rgba(0, 210, 255, ${Math.random()})`}">

                            ${masked ? '-∞' : Math.random().toFixed(2)}

                        </div>`;

                    }).join('')}

                </div>

            `;

        }


        function showCrossAttention() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Decoder attending to encoder</div>

                <div style="display: flex; align-items: center; gap: 10px; margin-top: 8px;">

                    <div class="matrix">Query</div>

                    <div>×</div>

                    <div class="matrix">Keys</div>

                    <div>=</div>

                    <div class="matrix">Scores</div>

                </div>

            `;

        }


        function showLayerNorm() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Normalizing layer output</div>

                <div style="margin-top: 8px;">μ = 0.0, σ = 1.0</div>

                <div>Residual: output = norm(x + sublayer(x))</div>

            `;

        }


        function showFeedForward() {

            const dataViz = document.getElementById('dataVisualization');

            dataViz.innerHTML = `

                <div>Feed-forward network</div>

                <div style="display: flex; align-items: center; gap: 8px; margin-top: 8px;">

                    <div class="matrix">Input<br>[512]</div>

                    <div>→</div>

                    <div class="matrix">Hidden<br>[2048]</div>

                    <div>→</div>

                    <div class="matrix">Output<br>[512]</div>

                </div>

                <div style="margin-top: 8px;">ReLU activation</div>

            `;

        }


        function showLinearProjection() {

            const linearDiv = document.getElementById('linear');

            linearDiv.innerHTML = '<div class="matrix">Logits: [50000]</div>';

            

            document.getElementById('dataVisualization').innerHTML = `

                <div>Projecting to vocabulary</div>

                <div class="matrix" style="margin-top: 8px;">

                    W_vocab: [512 × 50000]

                </div>

            `;

        }


        function showSoftmax() {

            const softmaxDiv = document.getElementById('softmax');

            const candidates = ['mat', 'floor', 'table', 'chair', 'rug'];

            const probs = candidates.map(() => Math.random());

            const sum = probs.reduce((a, b) => a + b, 0);

            const normalized = probs.map(p => (p / sum).toFixed(3));

            

            softmaxDiv.innerHTML = `

                <div>Top probabilities:</div>

                ${normalized.map((p, i) => 

                    `<div class="token">${candidates[i]}: ${p}</div>`

                ).join('')}

            `;


            document.getElementById('dataVisualization').innerHTML = `

                <div>Temperature = 1.0</div>

                <div>Converting logits to probabilities</div>

            `;

        }


        function showOutput() {

            const outputDiv = document.getElementById('output');

            const nextToken = 'mat';

            generatedTokens.push(nextToken);

            

            outputDiv.innerHTML = `

                <div class="token highlighted">Next token: "${nextToken}"</div>

                <div style="margin-top: 8px;">Generated sequence: ${generatedTokens.join(' ')}</div>

            `;

            

            document.getElementById('dataVisualization').innerHTML = `

                <div>Token selected based on probability</div>

                <div>Methods: greedy, beam search, sampling</div>

            `;

        }


        function completeSimulation() {

            document.getElementById('stepExplanation').innerHTML = `

                <strong>Simulation Complete!</strong><br>

                The transformer has processed the input through all layers and generated the next token.

                This process repeats for each token generation.

            `;

            document.getElementById('startBtn').disabled = false;

            document.getElementById('pauseBtn').disabled = true;

        }

    </script>

</body>

</html>

No comments: