here's html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Adventure Farming Game</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #87CEEB;
        }
        canvas {
            display: block;
            margin: 0 auto;
            background-color: #F0F8FF;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <script src="game.js"></script>
</body>
</html>


here's js
// Setup the canvas
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");

// Tile size and world dimensions
const TILE_SIZE = 32;
let worldWidth, worldHeight;

// Set canvas size to fill the entire window
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// Calculate world dimensions (larger than the screen)
worldWidth = Math.floor(canvas.width / TILE_SIZE) * 2; // The world will be twice the width of the screen
worldHeight = Math.floor(canvas.height / TILE_SIZE) * 2; // The world will be twice the height of the screen

// Define the player object
const player = {
    x: Math.floor(worldWidth / 2) * TILE_SIZE,  // Start in the center of the world
    y: Math.floor(worldHeight / 2) * TILE_SIZE,
    width: TILE_SIZE,
    height: TILE_SIZE,
    speed: 4,
};

// World grid (generated procedurally)
const world = [];

// Initialize world with random grass, dirt, and water tiles
function generateWorld() {
    // First, create all grass and dirt tiles
    for (let y = 0; y < worldHeight; y++) {
        world[y] = [];
        for (let x = 0; x < worldWidth; x++) {
            const rand = Math.random();
            let type = 'grass';
            if (rand < 0.8) {
                type = 'grass';  // 80% chance for grass
            } else {
                type = 'dirt';   // 20% chance for dirt
            }
            world[y][x] = {
                type: type,
                tilled: false,
                crop: null,
            };
        }
    }

    // Now, let's add water pools randomly but smaller and less frequent
    let numberOfWaterPools = Math.floor(worldWidth * worldHeight / 200);  // Less frequent water pools
    for (let i = 0; i < numberOfWaterPools; i++) {
        let poolWidth = Math.floor(Math.random() * 4) + 2;  // Water pool width between 2 and 5 tiles
        let poolHeight = Math.floor(Math.random() * 4) + 2;  // Water pool height between 2 and 5 tiles
        let startX = Math.floor(Math.random() * (worldWidth - poolWidth));
        let startY = Math.floor(Math.random() * (worldHeight - poolHeight));

        // Fill the region with water
        for (let y = startY; y < startY + poolHeight; y++) {
            for (let x = startX; x < startX + poolWidth; x++) {
                world[y][x] = {
                    type: 'water',
                    tilled: false,
                    crop: null,
                };
            }
        }
    }
}

// Define crops and their growth stages
const crops = {
    'wheat': {
        name: 'Wheat',
        growthStages: 5,
        textures: [
            drawWheatStage1,
            drawWheatStage2,
            drawWheatStage3,
            drawWheatStage4,
            drawWheatStage5,
        ],
        harvestable: true,
    },
    // Add more crops if needed
};

// Define the player's inventory and selected hotbar index
const inventory = [
    { item: 'hoe', quantity: 1 },
    { item: 'wheat_seeds', quantity: 10 },
    { item: 'harvester', quantity: 1 },
    null,
    null,
    null,
    null,
    null,
    null,
];

let selectedHotbarIndex = 0; // Index of the currently selected item

// Set up movement controls
let keys = {
    w: false,
    a: false,
    s: false,
    d: false,
};

window.addEventListener('keydown', (e) => {
    if (e.key === 'w') keys.w = true;
    if (e.key === 'a') keys.a = true;
    if (e.key === 's') keys.s = true;
    if (e.key === 'd') keys.d = true;

    // Hotbar selection via number keys
    if (e.key >= '1' && e.key <= '9') {
        selectedHotbarIndex = parseInt(e.key) - 1;
    }
});

window.addEventListener('keyup', (e) => {
    if (e.key === 'w') keys.w = false;
    if (e.key === 'a') keys.a = false;
    if (e.key === 's') keys.s = false;
    if (e.key === 'd') keys.d = false;
});

// Add event listener for mouse clicks (tilling, planting, harvesting)
canvas.addEventListener('click', (e) => {
    // Get mouse position relative to the canvas
    const rect = canvas.getBoundingClientRect();
    const mouseX = e.clientX - rect.left + cameraOffset.x;
    const mouseY = e.clientY - rect.top + cameraOffset.y;

    const tileX = Math.floor(mouseX / TILE_SIZE);
    const tileY = Math.floor(mouseY / TILE_SIZE);

    if (tileX >= 0 && tileX < worldWidth && tileY >= 0 && tileY < worldHeight) {
        const tile = world[tileY][tileX];

        // Get the selected item from hotbar
        const selectedItem = inventory[selectedHotbarIndex];

        if (selectedItem) {
            // Tilling action
            if (selectedItem.item === 'hoe') {
                tillTile(tileX, tileY);
            }
            // Planting action
            else if (selectedItem.item === 'wheat_seeds') {
                plantCrop(tileX, tileY, 'wheat');
            }
            // Harvesting action
            else if (selectedItem.item === 'harvester') {
                harvestCrop(tileX, tileY);
            }
        }
    }
});

// Move the player
function movePlayer() {
    let newX = player.x;
    let newY = player.y;

    // Calculate the direction of movement based on the key pressed
    if (keys.w) newY -= player.speed;
    if (keys.s) newY += player.speed;
    if (keys.a) newX -= player.speed;
    if (keys.d) newX += player.speed;

    // Check the tile in the direction of movement to see if it's water
    const targetTileX = Math.floor(newX / TILE_SIZE);
    const targetTileY = Math.floor(newY / TILE_SIZE);

    // Function to check if a tile is water
    const isWater = (x, y) => world[y] && world[y][x] && world[y][x].type === 'water';

    // Check if the tile the player is trying to move into is water
    if (isWater(targetTileX, targetTileY)) {
        // Prevent movement if the player is trying to move into water
        return;
    }

    // Allow movement if it's not water
    player.x = newX;
    player.y = newY;
}

// Draw the world (tiles)
function drawWorld() {
    for (let y = 0; y < worldHeight; y++) {
        for (let x = 0; x < worldWidth; x++) {
            const tile = world[y][x];
            const posX = x * TILE_SIZE - cameraOffset.x;
            const posY = y * TILE_SIZE - cameraOffset.y;

            // Draw base tile
            if (tile.type === 'grass') {
                drawGrass(posX, posY);
            } else if (tile.type === 'dirt') {
                if (tile.tilled) {
                    drawTilledDirt(posX, posY);
                } else {
                    drawDirt(posX, posY);
                }
            } else if (tile.type === 'water') {
                drawWater(posX, posY);
            }

            // Draw crop if present
            if (tile.crop) {
                const crop = crops[tile.crop.type];
                const drawFunction = crop.textures[tile.crop.growthStage];
                drawFunction(posX, posY);
            }
        }
    }
}

// Drawing functions for Tiles and Crops
function drawGrass(x, y) {
    ctx.fillStyle = "#8bff66"; // light green color for grass
    ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE); // Fill the tile with color
    // Draw grass texture (small lines for detail)
    ctx.fillStyle = "#4f9d3f"; // darker green for grass texture
    ctx.fillRect(x + 5, y + 5, 5, 10);
    ctx.fillRect(x + 10, y + 8, 5, 10);
    ctx.fillRect(x + 15, y + 6, 5, 10);
    ctx.fillRect(x + 20, y + 5, 5, 10);
}

function drawDirt(x, y) {
    ctx.fillStyle = "#d0b77b"; // light brown color for dirt
    ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE); // Fill the tile with color
    // Add some texture for dirt
    ctx.fillStyle = "#8b6c2f"; // darker brown for texture
    ctx.fillRect(x + 8, y + 8, 5, 5);
    ctx.fillRect(x + 15, y + 12, 6, 6);
}

function drawTilledDirt(x, y) {
    ctx.fillStyle = "#a67c52"; // Color for tilled dirt
    ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE);
    // Add texture lines
    ctx.strokeStyle = "#8b6c2f";
    ctx.lineWidth = 1;
    for (let i = 0; i < TILE_SIZE; i += 4) {
        ctx.beginPath();
        ctx.moveTo(x + i, y);
        ctx.lineTo(x + i, y + TILE_SIZE);
        ctx.stroke();
    }
}

function drawWater(x, y) {
    ctx.fillStyle = "#1f8dff"; // blue for water
    ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE); // Fill the tile with color
    // Draw some waves for texture (light blue)
    ctx.fillStyle = "#63b9ff"; 
    ctx.beginPath();
    ctx.arc(x + 8, y + 12, 4, 0, Math.PI * 2, false);
    ctx.fill();
    ctx.beginPath();
    ctx.arc(x + 24, y + 20, 4, 0, Math.PI * 2, false);
    ctx.fill();
}

// Drawing functions for crops (Wheat)
function drawWheatStage1(x, y) {
    ctx.fillStyle = "#9b7653"; // Seed color
    ctx.fillRect(x + TILE_SIZE / 2 - 2, y + TILE_SIZE - 5, 4, 5); // Simple representation
}

function drawWheatStage2(x, y) {
    ctx.fillStyle = "#c2b280"; // Young wheat color
    ctx.fillRect(x + TILE_SIZE / 2 - 3, y + TILE_SIZE - 10, 6, 10);
}

function drawWheatStage3(x, y) {
    ctx.fillStyle = "#e0c070";
    ctx.fillRect(x + TILE_SIZE / 2 - 4, y + TILE_SIZE - 15, 8, 15);
}

function drawWheatStage4(x, y) {
    ctx.fillStyle = "#ecd9a3";
    ctx.fillRect(x + TILE_SIZE / 2 - 5, y + TILE_SIZE - 20, 10, 20);
}

function drawWheatStage5(x, y) {
    ctx.fillStyle = "#f5deb3"; // Mature wheat color
    ctx.fillRect(x + TILE_SIZE / 2 - 6, y + TILE_SIZE - 25, 12, 25);
}

// Draw the player sprite (simple character)
function drawPlayer() {
    const x = player.x - cameraOffset.x;
    const y = player.y - cameraOffset.y;

    ctx.fillStyle = "#ffdbac"; // Skin color for the head
    ctx.fillRect(x, y, TILE_SIZE, TILE_SIZE); // Draw the head
    ctx.fillStyle = "#0000ff"; // Blue for the body
    ctx.fillRect(x + 8, y + 16, 16, 16); // Body (16x16)

    // Legs
    ctx.fillStyle = "#000"; // Black for legs
    ctx.fillRect(x + 8, y + 24, 6, 8); // Left leg
    ctx.fillRect(x + 18, y + 24, 6, 8); // Right leg

    // Simple face (two eyes)
    ctx.fillStyle = "#000"; // Black for eyes
    ctx.fillRect(x + 10, y + 8, 4, 4); // Left eye
    ctx.fillRect(x + 18, y + 8, 4, 4); // Right eye
}

// Camera Logic
const cameraOffset = {
    x: 0, // Initial camera offset (starts at 0)
    y: 0,
};

const followThreshold = 100;  // Distance from the center before the camera moves

// Update camera position based on player's position
function updateCamera() {
    const centerX = player.x - cameraOffset.x - canvas.width / 2;
    const centerY = player.y - cameraOffset.y - canvas.height / 2;

    // Check if the player is beyond the threshold in any direction
    if (centerX > followThreshold) {
        cameraOffset.x += (centerX - followThreshold);
    } else if (centerX < -followThreshold) {
        cameraOffset.x += (centerX + followThreshold);
    }

    if (centerY > followThreshold) {
        cameraOffset.y += (centerY - followThreshold);
    } else if (centerY < -followThreshold) {
        cameraOffset.y += (centerY + followThreshold);
    }

    // Ensure camera does not go out of bounds
    cameraOffset.x = Math.max(0, Math.min(cameraOffset.x, worldWidth * TILE_SIZE - canvas.width));
    cameraOffset.y = Math.max(0, Math.min(cameraOffset.y, worldHeight * TILE_SIZE - canvas.height));
}

// Update crops' growth stages over time
function updateCrops() {
    for (let y = 0; y < worldHeight; y++) {
        for (let x = 0; x < worldWidth; x++) {
            const tile = world[y][x];
            if (tile.crop) {
                tile.crop.growthTime++;

                // Each stage takes 600 frames
                if (tile.crop.growthTime >= 600) {
                    tile.crop.growthTime = 0;
                    if (tile.crop.growthStage < crops[tile.crop.type].growthStages - 1) {
                        tile.crop.growthStage++;
                    }
                }
            }
        }
    }
}

// Implement tilling logic
function tillTile(x, y) {
    const tile = world[y][x];

    // Check if the tile is dirt and not tilled
    if (tile.type === 'dirt' && !tile.tilled) {
        // Check if the tile is near water
        if (isNearWater(x, y, 5)) {
            tile.tilled = true;
        } else {
            console.log('Tile must be near water to be tilled.');
        }
    }
}

// Check if a tile is near water within a certain distance
function isNearWater(x, y, distance) {
    for (let offsetY = -distance; offsetY <= distance; offsetY++) {
        for (let offsetX = -distance; offsetX <= distance; offsetX++) {
            const checkX = x + offsetX;
            const checkY = y + offsetY;
            if (checkX >= 0 && checkX < worldWidth && checkY >= 0 && checkY < worldHeight) {
                if (world[checkY][checkX].type === 'water') {
                    return true;
                }
            }
        }
    }
    return false;
}

// Implement planting logic
function plantCrop(x, y, cropType) {
    const tile = world[y][x];
    if (tile.tilled && !tile.crop) {
        tile.crop = {
            type: cropType,
            growthStage: 0,
            growthTime: 0,
        };

        // Reduce the seed count in the inventory
        if (inventory[selectedHotbarIndex].quantity > 0) {
            inventory[selectedHotbarIndex].quantity--;
            if (inventory[selectedHotbarIndex].quantity === 0) {
                inventory[selectedHotbarIndex] = null;
            }
        }
    } else {
        console.log('Cannot plant here.');
    }
}

// Implement harvesting logic
function harvestCrop(x, y) {
    const tile = world[y][x];
    if (tile.crop) {
        const cropInfo = crops[tile.crop.type];
        if (tile.crop.growthStage === cropInfo.growthStages - 1) {
            // Harvest the crop
            console.log(`Harvested ${cropInfo.name}!`);

            // Remove the crop from the tile
            tile.crop = null;

            // Add harvested item to inventory
            addItemToInventory(cropInfo.name.toLowerCase(), 1);
        } else {
            console.log('Crop is not ready to harvest.');
        }
    }
}

// Add item to inventory
function addItemToInventory(itemName, quantity) {
    // Find if item exists in inventory
    let itemFound = false;
    for (let i = 0; i < inventory.length; i++) {
        if (inventory[i] && inventory[i].item === itemName) {
            inventory[i].quantity += quantity;
            itemFound = true;
            break;
        }
    }

    // If item not found and there is empty slot, add new item
    if (!itemFound) {
        for (let i = 0; i < inventory.length; i++) {
            if (!inventory[i]) {
                inventory[i] = { item: itemName, quantity: quantity };
                break;
            }
        }
    }
}

// Draw the hotbar UI
function drawHotbar() {
    const slotSize = 48;
    const padding = 4;
    const hotbarWidth = slotSize * 9 + padding * 10;
    const hotbarHeight = slotSize + padding * 2;

    // Position the hotbar in the bottom left corner
    const x = 10; // 10 pixels from the left
    const y = canvas.height - hotbarHeight - 10; // 10 pixels from the bottom

    // Draw hotbar background with rounded corners and blur effect
    ctx.save();
    ctx.globalAlpha = 0.5; // Slightly transparent
    ctx.fillStyle = '#333';
    ctx.beginPath();
    ctx.moveTo(x + 10, y);
    ctx.lineTo(x + hotbarWidth - 10, y);
    ctx.quadraticCurveTo(x + hotbarWidth, y, x + hotbarWidth, y + 10);
    ctx.lineTo(x + hotbarWidth, y + hotbarHeight - 10);
    ctx.quadraticCurveTo(x + hotbarWidth, y + hotbarHeight, x + hotbarWidth -10, y + hotbarHeight);
    ctx.lineTo(x + 10, y + hotbarHeight);
    ctx.quadraticCurveTo(x, y + hotbarHeight, x, y + hotbarHeight -10);
    ctx.lineTo(x, y + 10);
    ctx.quadraticCurveTo(x, y, x + 10, y);
    ctx.fill();
    ctx.restore();

    // Draw slots
    for (let i = 0; i < 9; i++) {
        const slotX = x + padding + i * (slotSize + padding);
        const slotY = y + padding;

        // Highlight selected slot
        if (i === selectedHotbarIndex) {
            ctx.strokeStyle = '#fff';
            ctx.lineWidth = 2;
        } else {
            ctx.strokeStyle = '#888';
            ctx.lineWidth = 1;
        }

        // Draw slot background
        ctx.fillStyle = '#555';
        ctx.fillRect(slotX, slotY, slotSize, slotSize);

        // Draw slot border
        ctx.strokeRect(slotX, slotY, slotSize, slotSize);

        // Draw item icon (simple representation)
        if (inventory[i]) {
            ctx.fillStyle = '#fff';
            ctx.font = '12px Arial';
            ctx.fillText(inventory[i].item, slotX + 5, slotY + 20);

            // Draw quantity
            ctx.fillStyle = '#ff0';
            ctx.font = '12px Arial';
            ctx.fillText('x' + inventory[i].quantity, slotX + 5, slotY + 40);
        }
    }
}

// Clear the canvas before each frame
function clearCanvas() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
}

// Game loop
function gameLoop() {
    clearCanvas();
    movePlayer();
    updateCamera();
    updateCrops();
    drawWorld();
    drawPlayer();
    drawHotbar();
    requestAnimationFrame(gameLoop);
}

// Generate the world and start the game loop
generateWorld();
gameLoop();


fix the grass texture and make it easier on the eyes. also fix the water collision because it only works from 2 sides. also add in textures for the hoe, harveter, and wheat, and make better textures for the growth stages.