pull down to refresh

I've been seeing a lot of hype around vibe coding (as popularized by Andrej Karpathy) on twitter but have never really tried it out before. I started screwing around with it on grok and very quickly got it to one-shot (admittedly very shitty) html/javascript versions of a bananagrams game and then a simple Atari Breakout game.
I asked it for a retro-gameboy style Tetris game, which it quickly delivered a skeleton version of. Then with a couple of more prompts was able to get it to add a scoreboard, level changes, a border, and then a next-piece preview, all within seconds.
TBH my feelings are mixed- half mind blown 🤯 but also half depressed and how quickly we are commoditizing intelligence and far out-pacing my meat-computer. I remember painstakingly programming a breakout game on my TI-89 in high school during math classes. I have not coded in a decade but the version of Tetris it made within seconds would have probably taken me a full day or weekend, and twice or more lines of code. How will the new generation ever learn the basics of programming with this power at your fingertips...
Curious what have you guys have "vibe coded" so far?
Yes45.5%
No45.5%
Show Me Results9.1%
22 votes \ poll ended
63 sats \ 0 replies \ @carter 12h
I look at it as turning off most of your programmer brain and just pasting the errors into chat until it fixes the problem. Sometimes i'll need to jump back or paste together chunks of different responses but I would never code anything for production this way. It makes very messy code and would be a pain to manage, anyway heres the example https://gist.github.com/neopunisher/a0ea9c46ef58624b0002729d948dd896
reply
I'm not sure what vibe coding means. If it just means AI assisted coding then yes I've done it. If it means something else, then I'm not sure.
reply
30 sats \ 1 reply \ @gmd OP 23 Mar
I think it's when you start a project and basically let AI do 90% of the heavy lifting and code via english prompting...
reply
I don't think anything I've done has been 90% for the whole project.
Mostly i've used AI to either A) help me understand someone else's code; or B) write up small snippets where it's pretty easy to define what the snippet needs to do.
reply
I still like to understand what the AI recommends, and I don't really trust it to write large sections of code. For example when using ethers.js, you have to remind it you're using a different version.
Overall it is useful for finding out quickly how an API works, and it makes coding faster in that respect. It's really pleasant to ask a question about an API and see a code snippet rather than looking through API docs. I still have the API docs open but it definitely saves time.
ChatGPT is also decent at telling you what parts of the code are, and whether something is necessary 'framework magic' (its term not mine) that shouldn't be fiddle with.
reply
The last couple of years AI really changed the nature of coding, and I love it. No more browsing manuals and googling debugging errors. This is the nature of progress and technological singularity we are living through. Exponential acceleration of productivity. Am I scared for myself? No, I'm old. For the young generation? Sure.
reply
HTML code to play my vibe-coded Tetris game (239 lines):
<!DOCTYPE html>
<html>
<head>
    <title>Tetris - Game Boy Style</title>
    <style>
        body {
            background-color: #9bbc0f; /* Game Boy screen greenish tint */
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            font-family: 'Courier New', Courier, monospace;
        }
        #gameContainer {
            background-color: #8bac0f; /* Slightly darker green */
            padding: 20px;
            border: 4px solid #0f380f; /* Dark border like Game Boy */
            border-radius: 10px;
            display: flex;
            align-items: flex-start;
        }
        #gameCanvas {
            background-color: #8bac0f;
            image-rendering: pixelated;
            border: 2px solid #306230; /* Visible border around playfield */
        }
        #previewCanvas {
            background-color: #8bac0f;
            image-rendering: pixelated;
            border: 2px solid #306230;
            width: 64px; /* 4 blocks wide */
            height: 64px; /* 4 blocks tall */
            margin-left: 20px;
        }
        #scoreboard {
            color: #0f380f;
            font-size: 16px;
            margin-left: 20px;
            text-align: left;
        }
    </style>
</head>
<body>
    <div id="gameContainer">
        <canvas id="gameCanvas" width="160" height="320"></canvas>
        <div>
            <canvas id="previewCanvas" width="64" height="64"></canvas>
            <div id="scoreboard">
                Score: 0<br>
                Lines: 0<br>
                Level: 1
            </div>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const previewCanvas = document.getElementById('previewCanvas');
        const previewCtx = previewCanvas.getContext('2d');
        const scoreboard = document.getElementById('scoreboard');

        // Game constants
        const BLOCK_SIZE = 16;
        const COLS = 10;
        const ROWS = 20;
        const canvasWidth = COLS * BLOCK_SIZE;
        const canvasHeight = ROWS * BLOCK_SIZE;
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;

        const TETROMINOES = [
            [[1,1,1,1]], // I
            [[1,1],[1,1]], // O
            [[0,1,0],[1,1,1]], // T
            [[0,1,1],[1,1,0]], // S
            [[1,1,0],[0,1,1]], // Z
            [[1,0,0],[1,1,1]], // J
            [[0,0,1],[1,1,1]]  // L
        ];
        const COLORS = ['#0f380f']; // Dark green for blocks

        let board = Array(ROWS).fill().map(() => Array(COLS).fill(0));
        let score = 0;
        let linesCleared = 0;
        let level = 1;
        let currentPiece, currentX, currentY;
        let nextPiece;
        let gameOver = false;

        // Piece spawning
        function spawnPiece() {
            if (!nextPiece) {
                nextPiece = TETROMINOES[Math.floor(Math.random() * TETROMINOES.length)];
            }
            currentPiece = nextPiece;
            nextPiece = TETROMINOES[Math.floor(Math.random() * TETROMINOES.length)];
            currentX = Math.floor(COLS / 2) - Math.floor(currentPiece[0].length / 2);
            currentY = 0;
            if (!canMove(0, 0)) {
                gameOver = true;
                alert(`Game Over! Score: ${score}, Lines: ${linesCleared}, Level: ${level}`);
                document.location.reload();
            }
            drawPreview();
        }

        // Drawing
        function drawBlock(x, y, context = ctx) {
            context.fillStyle = COLORS[0];
            context.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE - 1, BLOCK_SIZE - 1);
            context.strokeStyle = '#306230'; // Lighter green for outline
            context.strokeRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE - 1, BLOCK_SIZE - 1);
        }

        function drawBoard() {
            ctx.clearRect(0, 0, canvasWidth, canvasHeight);
            for (let r = 0; r < ROWS; r++) {
                for (let c = 0; c < COLS; c++) {
                    if (board[r][c]) drawBlock(c, r);
                }
            }
            for (let r = 0; r < currentPiece.length; r++) {
                for (let c = 0; c < currentPiece[r].length; c++) {
                    if (currentPiece[r][c]) drawBlock(currentX + c, currentY + r);
                }
            }
        }

        function drawPreview() {
            previewCtx.clearRect(0, 0, previewCanvas.width, previewCanvas.height);
            const offsetX = (4 - nextPiece[0].length) / 2; // Center horizontally
            const offsetY = (4 - nextPiece.length) / 2; // Center vertically
            for (let r = 0; r < nextPiece.length; r++) {
                for (let c = 0; c < nextPiece[r].length; c++) {
                    if (nextPiece[r][c]) drawBlock(c + offsetX, r + offsetY, previewCtx);
                }
            }
        }

        // Movement and collision
        function canMove(dx, dy, newPiece = currentPiece) {
            for (let r = 0; r < newPiece.length; r++) {
                for (let c = 0; c < newPiece[r].length; c++) {
                    if (!newPiece[r][c]) continue;
                    const newX = currentX + c + dx;
                    const newY = currentY + r + dy;
                    if (newX < 0 || newX >= COLS || newY >= ROWS) return false;
                    if (newY >= 0 && board[newY][newX]) return false;
                }
            }
            return true;
        }

        function mergePiece() {
            for (let r = 0; r < currentPiece.length; r++) {
                for (let c = 0; c < currentPiece[r].length; c++) {
                    if (currentPiece[r][c]) {
                        board[currentY + r][currentX + c] = 1;
                    }
                }
            }
        }

        function clearLines() {
            let linesThisTime = 0;
            for (let r = ROWS - 1; r >= 0; r--) {
                if (board[r].every(cell => cell)) {
                    board.splice(r, 1);
                    board.unshift(Array(COLS).fill(0));
                    linesThisTime++;
                    r++; // Check the same row again after shifting
                }
            }
            if (linesThisTime > 0) {
                linesCleared += linesThisTime;
                score += [0, 40, 100, 300, 1200][linesThisTime] * level; // Level multiplier
                level = Math.floor(linesCleared / 10) + 1; // Level up every 10 lines
                updateScoreboard();
            }
        }

        function updateScoreboard() {
            scoreboard.innerHTML = `Score: ${score}<br>Lines: ${linesCleared}<br>Level: ${level}`;
        }

        // Rotation
        function rotatePiece() {
            const rotated = currentPiece[0].map((_, i) => 
                currentPiece.map(row => row[i]).reverse()
            );
            if (canMove(0, 0, rotated)) currentPiece = rotated;
        }

        // Game loop
        let dropCounter = 0;
        function getDropInterval() {
            const baseSpeed = 800; // Starting speed in ms (Level 1)
            return baseSpeed / (1 + (level - 1) * 0.2); // 20% faster per level
        }

        function update() {
            if (gameOver) return;
            dropCounter += 16.67; // ~60 FPS
            const dropInterval = getDropInterval();
            if (dropCounter >= dropInterval) {
                if (canMove(0, 1)) {
                    currentY++;
                } else {
                    mergePiece();
                    clearLines();
                    spawnPiece();
                }
                dropCounter = 0;
            }
            drawBoard();
            requestAnimationFrame(update);
        }

        // Controls
        document.addEventListener('keydown', e => {
            if (gameOver) return;
            switch (e.key) {
                case 'ArrowLeft': if (canMove(-1, 0)) currentX--; break;
                case 'ArrowRight': if (canMove(1, 0)) currentX++; break;
                case 'ArrowDown': if (canMove(0, 1)) currentY++; break;
                case 'ArrowUp': rotatePiece(); break;
            }
            drawBoard();
        });

        // Start game
        spawnPiece(); // Initial spawn sets both current and next
        updateScoreboard();
        update();
    </script>
</body>
</html>
reply