tinytools: easily test your html apps

anthropic claude has the amazing artefact feature, which allows it to generate a web app and immediately display it next to the chat for you to interact with. it is phenomenal for prototyping or just iterating quickly on solving a specific problem. unfortunately, other llms like google gemini do not have this feature (afaik and ofc you can use alternative guis that do have it). instead, you have to save the html locally to interact with it in your browser, which is annoying

i therefore present the addition of HTML Paste Display to my tinytools collection. you can just paste some html and see the result live.

it has some clear limitations in comparison to claude: it is not inline and you have to switch to another tab to use it. moreover, it only supports plain html rather than the fancy react apps with shadcn components that claude supports. but very often, it is enough

case in point, in an earlier conversation, claude failed to produce a working implementation of just this tool granted, it might have been bc i was testing inside the more restricted artefact sandbox and i didn’t give it much of a chance to do better, but gemini’s approach worked very well. you can still use the test example that claude produced to try it out yourself:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Random Color Generator</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, sans-serif;
            margin: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            transition: background-color 0.5s ease;
            text-align: center;
            padding: 20px;
        }
        
        .container {
            background-color: rgba(255, 255, 255, 0.8);
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
            max-width: 500px;
            width: 100%;
        }
        
        h1 {
            margin-top: 0;
            color: #333;
        }
        
        .color-display {
            font-size: 24px;
            font-weight: bold;
            margin: 20px 0;
            padding: 10px;
            border-radius: 4px;
            background-color: rgba(255, 255, 255, 0.5);
        }
        
        button {
            background-color: #4CAF50;
            border: none;
            color: white;
            padding: 10px 20px;
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: 10px 5px;
            cursor: pointer;
            border-radius: 4px;
            transition: background-color 0.3s;
        }
        
        button:hover {
            background-color: #45a049;
        }
        
        .color-history {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 8px;
            margin-top: 20px;
        }
        
        .history-item {
            width: 40px;
            height: 40px;
            border-radius: 4px;
            cursor: pointer;
            border: 1px solid rgba(0, 0, 0, 0.1);
            transition: transform 0.2s;
        }
        
        .history-item:hover {
            transform: scale(1.1);
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>Random Color Generator</h1>
        <div class="color-display" id="colorCode">#FFFFFF</div>
        <button id="generateBtn">Generate Color</button>
        <button id="copyBtn">Copy Hex Code</button>
        <div>
            <p>Recent colors:</p>
            <div class="color-history" id="colorHistory"></div>
        </div>
    </div>

    <script>
        const body = document.body;
        const colorCode = document.getElementById('colorCode');
        const generateBtn = document.getElementById('generateBtn');
        const copyBtn = document.getElementById('copyBtn');
        const colorHistory = document.getElementById('colorHistory');
        
        // Max history items to display
        const MAX_HISTORY = 10;
        
        // Array to store color history
        let history = [];
        
        // Generate a random color
        function generateRandomColor() {
            const letters = '0123456789ABCDEF';
            let color = '#';
            
            for (let i = 0; i < 6; i++) {
                color += letters[Math.floor(Math.random() * 16)];
            }
            
            return color;
        }
        
        // Update the UI with a new color
        function updateColor(color) {
            body.style.backgroundColor = color;
            colorCode.textContent = color;
            
            // Add to history
            if (!history.includes(color)) {
                history.unshift(color);
                
                // Keep history at MAX_HISTORY items
                if (history.length > MAX_HISTORY) {
                    history.pop();
                }
                
                updateColorHistory();
            }
        }
        
        // Update the color history display
        function updateColorHistory() {
            colorHistory.innerHTML = '';
            
            history.forEach(color => {
                const historyItem = document.createElement('div');
                historyItem.className = 'history-item';
                historyItem.style.backgroundColor = color;
                historyItem.setAttribute('title', color);
                
                historyItem.addEventListener('click', () => {
                    updateColor(color);
                });
                
                colorHistory.appendChild(historyItem);
            });
        }
        
        // Generate button click event
        generateBtn.addEventListener('click', () => {
            const newColor = generateRandomColor();
            updateColor(newColor);
        });
        
        // Copy button click event
        copyBtn.addEventListener('click', () => {
            navigator.clipboard.writeText(colorCode.textContent)
                .then(() => {
                    // Temporarily change button text as feedback
                    const originalText = copyBtn.textContent;
                    copyBtn.textContent = 'Copied!';
                    
                    setTimeout(() => {
                        copyBtn.textContent = originalText;
                    }, 1500);
                })
                .catch(err => {
                    console.error('Could not copy text: ', err);
                });
        });
        
        // Initialize with a random color
        updateColor(generateRandomColor());
    </script>
</body>
</html>