diff --git a/conf/bd.sql b/conf/bd.sql
new file mode 100644
index 0000000..fe44ff0
--- /dev/null
+++ b/conf/bd.sql
@@ -0,0 +1,89 @@
+-- Creación de la base de datos
+CREATE DATABASE IF NOT EXISTS boletos_db;
+USE boletos_db;
+
+-- Tabla de salas
+CREATE TABLE IF NOT EXISTS salas (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    nombre VARCHAR(100) NOT NULL,
+    filas INT NOT NULL,
+    asientos_por_fila INT NOT NULL
+);
+
+-- Tabla de boletos
+CREATE TABLE IF NOT EXISTS boletos (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    id_sala INT NOT NULL,
+    fila INT NOT NULL,
+    numero INT NOT NULL,
+    precio DECIMAL(10,2) NOT NULL,
+    estado ENUM('disponible', 'vendido') DEFAULT 'disponible',
+    FOREIGN KEY (id_sala) REFERENCES salas(id),
+    UNIQUE KEY unique_asiento (id_sala, fila, numero)
+);
+
+-- Tabla de ventas
+CREATE TABLE IF NOT EXISTS ventas (
+    id VARCHAR(36) PRIMARY KEY,
+    fecha DATETIME NOT NULL,
+    nombre_cliente VARCHAR(100) NOT NULL,
+    total DECIMAL(10,2) NOT NULL
+);
+
+select * from ventas;
+
+select * from venta_boletos;
+
+select * from boletos;
+
+-- Tabla relacional venta-boletos
+CREATE TABLE IF NOT EXISTS venta_boletos (
+    id INT AUTO_INCREMENT PRIMARY KEY,
+    id_venta VARCHAR(36) NOT NULL,
+    id_boleto INT NOT NULL,
+    FOREIGN KEY (id_venta) REFERENCES ventas(id),
+    FOREIGN KEY (id_boleto) REFERENCES boletos(id),
+    UNIQUE KEY unique_venta_boleto (id_venta, id_boleto)
+);
+
+-- Insertar una sala de ejemplo
+INSERT INTO salas (id, nombre, filas, asientos_por_fila) 
+VALUES (1, 'Sala Principal', 10, 15);
+
+-- Procedimiento para inicializar boletos
+DELIMITER //
+CREATE PROCEDURE InicializaBoletos(IN sala_id INT, IN precio DECIMAL(10,2))
+BEGIN
+    DECLARE i INT DEFAULT 1;
+    DECLARE j INT DEFAULT 1;
+    DECLARE total_filas INT DEFAULT 0;
+    DECLARE total_asientos INT DEFAULT 0;
+    
+    -- Obtener dimensiones de la sala
+    SELECT filas, asientos_por_fila INTO total_filas, total_asientos
+    FROM salas WHERE id = sala_id;
+    
+    -- Depuración: Verificar valores obtenidos
+    SELECT CONCAT('Filas:', total_filas, ' Asientos:', total_asientos) AS Debug_Info;
+    
+    -- Si no se encuentran filas/asientos, salir del procedimiento
+    IF total_filas = 0 OR total_asientos = 0 THEN
+        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Sala no encontrada o sin dimensiones definidas';
+    END IF;
+
+    -- Eliminar boletos existentes de la sala
+    DELETE FROM boletos WHERE id_sala = sala_id;
+    
+    -- Crear nuevos boletos
+    SET i = 1;
+    WHILE i <= total_filas DO
+        SET j = 1;
+        WHILE j <= total_asientos DO
+            INSERT INTO boletos (id_sala, fila, numero, precio, estado)
+            VALUES (sala_id, i, j, precio, 'disponible');
+            SET j = j + 1;
+        END WHILE;
+        SET i = i + 1;
+    END WHILE;
+END //
+DELIMITER ;
\ No newline at end of file
diff --git a/controlador/VendedorController.php b/controlador/VendedorController.php
new file mode 100644
index 0000000..4d60fab
--- /dev/null
+++ b/controlador/VendedorController.php
@@ -0,0 +1,48 @@
+<?php
+
+require_once '../modelo/BaseDatos.php';
+require_once '../modelo/Sala.php';
+require_once '../modelo/Boleto.php';
+require_once '../modelo/Venta.php';
+
+class VendedorController {
+    private $baseDatos;
+    private $sala;
+    
+    public function __construct($baseDatos) {
+        $this->baseDatos = $baseDatos;
+    }
+    
+    public function cargarSala($idSala) {
+        $this->sala = $this->baseDatos->cargarSala($idSala);
+        return $this->sala;
+    }
+    
+    public function mostrarDisponibilidadAsientos() {
+        if ($this->sala) {
+            return $this->sala->disponibilidadAsientos();
+        }
+        return null;
+    }
+    
+    public function seleccionarBoletos($idsBoletos) {
+        if ($this->sala) {
+            return $this->sala->obtenerBoletosPorId($idsBoletos);
+        }
+        return [];
+    }
+    
+    public function procesarVenta($boletos, $nombreCliente) {
+        $venta = new Venta($nombreCliente);
+        $venta->agregarBoletos($boletos);
+        
+        if (count($venta->getBoletos()) > 0) {
+            $resultado = $this->baseDatos->guardarVenta($venta);
+            if ($resultado) {
+                return $venta->generarComprobante();
+            }
+        }
+        
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/controlador/asientos.php b/controlador/asientos.php
new file mode 100644
index 0000000..fd8c6e4
--- /dev/null
+++ b/controlador/asientos.php
@@ -0,0 +1,38 @@
+<?php
+// api/asientos.php - API para obtener el mapa de asientos
+session_start();
+
+require_once '../modelo/BaseDatos.php';
+require_once '../modelo/Sala.php';
+require_once '../modelo/Boleto.php';
+require_once '../modelo/Venta.php';
+require_once 'VendedorController.php';
+
+header('Content-Type: application/json');
+
+// Conexión a base de datos
+$db = new BaseDatos('localhost:3306', 'root', '481037', 'boletos_db');
+
+// Inicializar el controlador
+$vendedorController = new VendedorController($db);
+
+// Cargar sala (solo hay una sala con id=1)
+$sala = $vendedorController->cargarSala(1);
+
+// Si no hay sala, podríamos inicializarla para desarrollo
+if (!$sala) {
+    $sala = new Sala(1, 'Sala Principal');
+    $sala->inicializarBoletos(10, 15, 50.00); // 10 filas, 15 asientos por fila, $50 cada uno
+}
+
+// Obtener mapa de asientos
+$mapaAsientos = $vendedorController->mostrarDisponibilidadAsientos();
+
+// Preparar respuesta
+$response = [
+    'success' => true,
+    'mapa' => $mapaAsientos,
+    'precio' => 50.00 // Agregamos el precio de los boletos a la respuesta
+];
+
+echo json_encode($response);
\ No newline at end of file
diff --git a/controlador/comprobante.php b/controlador/comprobante.php
new file mode 100644
index 0000000..7c544d9
--- /dev/null
+++ b/controlador/comprobante.php
@@ -0,0 +1,17 @@
+<?php
+// comprobante.php - Lógica de servidor para el comprobante de venta
+session_start();
+
+// Verificar si hay un comprobante en la sesión
+if (!isset($_SESSION['comprobante'])) {
+    header('Location: ../vista/index.html');
+    exit;
+}
+
+// Obtener el comprobante de la sesión
+$comprobante = $_SESSION['comprobante'];
+
+// Devolver datos en formato JSON para ser consumidos por JavaScript
+header('Content-Type: application/json');
+echo json_encode($comprobante);
+?>
\ No newline at end of file
diff --git a/controlador/venta.php b/controlador/venta.php
new file mode 100644
index 0000000..f976d92
--- /dev/null
+++ b/controlador/venta.php
@@ -0,0 +1,71 @@
+<?php
+// api/venta.php - API para procesar ventas
+session_start();
+
+require_once '../modelo/BaseDatos.php';
+require_once '../modelo/Sala.php';
+require_once '../modelo/Boleto.php';
+require_once '../modelo/Venta.php';
+require_once 'VendedorController.php';
+
+header('Content-Type: application/json');
+
+// Verificar método de solicitud
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+    echo json_encode(['success' => false, 'mensaje' => 'Método no permitido']);
+    exit;
+}
+
+// Obtener datos JSON del cuerpo de la solicitud
+$data = json_decode(file_get_contents('php://input'), true);
+
+if (!$data || !isset($data['asientos']) || !isset($data['nombre_cliente'])) {
+    echo json_encode(['success' => false, 'mensaje' => 'Datos incompletos']);
+    exit;
+}
+
+// Extraer datos
+$idsBoletos = $data['asientos'];
+$nombreCliente = $data['nombre_cliente'];
+
+// Validar que haya asientos seleccionados
+if (empty($idsBoletos)) {
+    echo json_encode(['success' => false, 'mensaje' => 'No se han seleccionado asientos']);
+    exit;
+}
+
+// Conexión a base de datos
+$db = new BaseDatos('localhost:3306', 'root', '481037', 'boletos_db');
+
+// Inicializar el controlador
+$vendedorController = new VendedorController($db);
+
+// Cargar la sala (agregando esta línea)
+$vendedorController->cargarSala(1); // O el ID de sala correspondiente
+
+// Seleccionar boletos
+$boletosSeleccionados = $vendedorController->seleccionarBoletos($idsBoletos);
+
+if (count($boletosSeleccionados) == 0) {
+    echo json_encode(['success' => false, 'mensaje' => 'No se han seleccionado asientos disponibles']);
+    exit;
+}
+
+// Procesar venta
+$comprobante = $vendedorController->procesarVenta($boletosSeleccionados, $nombreCliente);
+
+if (!$comprobante) {
+    echo json_encode(['success' => false, 'mensaje' => 'Error al procesar la venta. Intente nuevamente']);
+    exit;
+}
+
+// Guardar comprobante en sesión
+$_SESSION['comprobante'] = $comprobante;
+
+// Respuesta exitosa
+echo json_encode([
+    'success' => true, 
+    'mensaje' => 'Venta procesada con éxito',
+    'redirect' => '../vista/comprobante.html',
+    'comprobante' => $comprobante
+]);
\ No newline at end of file
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..968cc46
--- /dev/null
+++ b/index.php
@@ -0,0 +1,5 @@
+<?php
+// Redirigir a la página principal del sistema
+header("Location: vista/index.html");
+exit();
+?>
diff --git a/modelo/BaseDatos.php b/modelo/BaseDatos.php
new file mode 100644
index 0000000..c27b5a1
--- /dev/null
+++ b/modelo/BaseDatos.php
@@ -0,0 +1,94 @@
+<?php
+require_once 'Sala.php';
+require_once 'Boleto.php';
+require_once 'Venta.php';
+
+class BaseDatos {
+    private $conexion;
+    
+    public function __construct($host, $usuario, $password, $nombreBD) {
+        $this->conexion = new mysqli($host, $usuario, $password, $nombreBD);
+        
+        if ($this->conexion->connect_error) {
+            die("Error de conexión: " . $this->conexion->connect_error);
+        }
+    }
+    
+    public function cargarSala($idSala) {
+        $sala = null;
+        $query = "SELECT id, nombre FROM salas WHERE id = ?";
+        $stmt = $this->conexion->prepare($query);
+        $stmt->bind_param("i", $idSala);
+        $stmt->execute();
+        $result = $stmt->get_result();
+        
+        if ($fila = $result->fetch_assoc()) {
+            $sala = new Sala($fila['id'], $fila['nombre']);
+            
+            // Cargar boletos de la sala
+            $queryBoletos = "SELECT id, fila, numero, precio, estado FROM boletos WHERE id_sala = ?";
+            $stmtBoletos = $this->conexion->prepare($queryBoletos);
+            $stmtBoletos->bind_param("i", $idSala);
+            $stmtBoletos->execute();
+            $resultBoletos = $stmtBoletos->get_result();
+            
+            $boletos = [];
+            while ($filaBoleto = $resultBoletos->fetch_assoc()) {
+                $boleto = new Boleto($filaBoleto['id'], $filaBoleto['fila'], $filaBoleto['numero'], $filaBoleto['precio']);
+                if ($filaBoleto['estado'] === 'vendido') {
+                    $boleto->marcarComoVendido();
+                }
+                $boletos[] = $boleto;
+            }
+            
+            // Asignar boletos a la sala
+            $sala->setBoletos($boletos);
+        }
+        
+        return $sala;
+    }
+    
+    public function guardarVenta($venta) {
+        // Iniciar transacción
+        $this->conexion->begin_transaction();
+        
+        try {
+            // Insertar venta
+            $query = "INSERT INTO ventas (id, fecha, nombre_cliente, total) VALUES (?, ?, ?, ?)";
+            $stmt = $this->conexion->prepare($query);
+            $id = $venta->getId();
+            $fecha = $venta->getFecha();
+            $nombreCliente = $venta->getNombreCliente();
+            $total = $venta->getTotal();
+            $stmt->bind_param("sssd", $id, $fecha, $nombreCliente, $total);
+            $stmt->execute();
+            
+            // Actualizar estado de boletos
+            foreach ($venta->getBoletos() as $boleto) {
+                $queryBoleto = "UPDATE boletos SET estado = 'vendido' WHERE id = ?";
+                $stmtBoleto = $this->conexion->prepare($queryBoleto);
+                $idBoleto = $boleto->getId();
+                $stmtBoleto->bind_param("i", $idBoleto);
+                $stmtBoleto->execute();
+                
+                // Insertar relación venta-boleto
+                $queryRelacion = "INSERT INTO venta_boletos (id_venta, id_boleto) VALUES (?, ?)";
+                $stmtRelacion = $this->conexion->prepare($queryRelacion);
+                $stmtRelacion->bind_param("si", $id, $idBoleto);
+                $stmtRelacion->execute();
+            }
+            
+            // Confirmar transacción
+            $this->conexion->commit();
+            return true;
+        } catch (Exception $e) {
+            // Revertir transacción en caso de error
+            $this->conexion->rollback();
+            return false;
+        }
+    }
+    
+    public function cerrarConexion() {
+        $this->conexion->close();
+    }
+}
\ No newline at end of file
diff --git a/modelo/Boleto.php b/modelo/Boleto.php
new file mode 100644
index 0000000..bec7a82
--- /dev/null
+++ b/modelo/Boleto.php
@@ -0,0 +1,46 @@
+<?php
+class Boleto {
+    private $id;
+    private $fila;
+    private $numero;
+    private $precio;
+    private $estado; // 'disponible' o 'vendido'
+    
+    public function __construct($id, $fila, $numero, $precio) {
+        $this->id = $id;
+        $this->fila = $fila;
+        $this->numero = $numero;
+        $this->precio = $precio;
+        $this->estado = 'disponible';
+    }
+    
+    // Getters y setters
+    public function getId() {
+        return $this->id;
+    }
+    
+    public function getFila() {
+        return $this->fila;
+    }
+    
+    public function getNumero() {
+        return $this->numero;
+    }
+    
+    public function getPrecio() {
+        return $this->precio;
+    }
+    
+    public function getEstado() {
+        return $this->estado;
+    }
+    
+    public function marcarComoVendido() {
+        $this->estado = 'vendido';
+        return true;
+    }
+    
+    public function estaDisponible() {
+        return $this->estado === 'disponible';
+    }
+}
\ No newline at end of file
diff --git a/modelo/Sala.php b/modelo/Sala.php
new file mode 100644
index 0000000..b1ea1af
--- /dev/null
+++ b/modelo/Sala.php
@@ -0,0 +1,62 @@
+<?php
+require_once 'Boleto.php';
+
+class Sala {
+    private $id;
+    private $nombre;
+    private $boletos = [];
+    
+    public function __construct($id, $nombre) {
+        $this->id = $id;
+        $this->nombre = $nombre;
+    }
+    
+    public function getId() {
+        return $this->id;
+    }
+    
+    public function getNombre() {
+        return $this->nombre;
+    }
+    
+    public function inicializarBoletos($filas, $asientosPorFila, $precio) {
+        $this->boletos = [];
+        $contador = 1;
+        
+        for ($i = 1; $i <= $filas; $i++) {
+            for ($j = 1; $j <= $asientosPorFila; $j++) {
+                $this->boletos[] = new Boleto($contador, $i, $j, $precio);
+                $contador++;
+            }
+        }
+    }
+    
+    public function obtenerBoletos() {
+        return $this->boletos;
+    }
+    
+    public function obtenerBoletosPorEstado($estado) {
+        return array_filter($this->boletos, function($boleto) use ($estado) {
+            return $boleto->getEstado() === $estado;
+        });
+    }
+    
+    public function obtenerBoletosPorId($ids) {
+        return array_filter($this->boletos, function($boleto) use ($ids) {
+            return in_array($boleto->getId(), $ids);
+        });
+    }
+    
+    public function disponibilidadAsientos() {
+        $mapa = [];
+        foreach ($this->boletos as $boleto) {
+            $mapa[$boleto->getFila()][$boleto->getNumero()] = $boleto->getEstado();
+        }
+        return $mapa;
+    }
+    
+    // Setter para asignar boletos desde la base de datos
+    public function setBoletos($boletos) {
+        $this->boletos = $boletos;
+    }
+}
\ No newline at end of file
diff --git a/modelo/Venta.php b/modelo/Venta.php
new file mode 100644
index 0000000..1df14ae
--- /dev/null
+++ b/modelo/Venta.php
@@ -0,0 +1,69 @@
+<?php
+require_once 'Boleto.php';
+
+class Venta {
+    private $id;
+    private $fecha;
+    private $boletos = [];
+    private $total;
+    private $nombreCliente;
+    
+    public function __construct($nombreCliente) {
+        $this->id = bin2hex(random_bytes(8));
+        date_default_timezone_set('America/Mexico_City');
+        $this->fecha = date('Y-m-d H:i:s');
+        $this->nombreCliente = $nombreCliente;
+        $this->total = 0;
+    }
+    
+    public function getId() {
+        return $this->id;
+    }
+    
+    public function getFecha() {
+        return $this->fecha;
+    }
+    
+    public function getNombreCliente() {
+        return $this->nombreCliente;
+    }
+    
+    public function agregarBoletos($boletos) {
+        foreach ($boletos as $boleto) {
+            if ($boleto->estaDisponible()) {
+                $this->boletos[] = $boleto;
+                $this->total += $boleto->getPrecio();
+                $boleto->marcarComoVendido();
+            }
+        }
+    }
+    
+    public function generarComprobante() {
+        $comprobante = [
+            'id_venta' => $this->id,
+            'fecha' => $this->fecha,
+            'cliente' => $this->nombreCliente,
+            'boletos' => [],
+            'total' => $this->total
+        ];
+        
+        foreach ($this->boletos as $boleto) {
+            $comprobante['boletos'][] = [
+                'id' => $boleto->getId(),
+                'fila' => $boleto->getFila(),
+                'numero' => $boleto->getNumero(),
+                'precio' => $boleto->getPrecio()
+            ];
+        }
+        
+        return $comprobante;
+    }
+    
+    public function getTotal() {
+        return $this->total;
+    }
+    
+    public function getBoletos() {
+        return $this->boletos;
+    }
+}
\ No newline at end of file
diff --git a/vista/comprobante.html b/vista/comprobante.html
new file mode 100644
index 0000000..69b427d
--- /dev/null
+++ b/vista/comprobante.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="es">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Comprobante de Venta</title>
+    <link rel="stylesheet" href="css/comprobante.css">
+</head>
+<body>
+    <div class="container">
+        <h1>Comprobante de Venta</h1>
+        
+        <div class="comprobante" id="comprobante-imprimible">
+            <div class="header">
+                <h2>Boletos para Concierto - Sala Principal</h2>
+            </div>
+            
+            <div class="info-venta">
+                <div>
+                    <div class="info-item">
+                        <span class="info-label">Nº de Venta:</span>
+                        <span id="id-venta"></span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">Fecha:</span>
+                        <span id="fecha-venta"></span>
+                    </div>
+                </div>
+                <div>
+                    <div class="info-item">
+                        <span class="info-label">Cliente:</span>
+                        <span id="cliente-venta"></span>
+                    </div>
+                </div>
+            </div>
+            
+            <h3>Detalle de Boletos</h3>
+            <table>
+                <thead>
+                    <tr>
+                        <th>#</th>
+                        <th>Ubicación</th>
+                        <th>Precio</th>
+                    </tr>
+                </thead>
+                <tbody id="detalle-boletos">
+                    <!-- El contenido de la tabla se generará dinámicamente con JavaScript -->
+                </tbody>
+            </table>
+            
+            <div class="total">
+                Total: $<span id="total-venta"></span>
+            </div>
+            
+            <div style="margin-top: 40px; font-size: 14px; text-align: center;">
+                <p>¡Gracias por su compra!</p>
+                <p>Este comprobante es su entrada oficial para el evento.</p>
+                <p>Por favor, preséntelo en la entrada del concierto.</p>
+            </div>
+        </div>
+        
+        <div class="acciones">
+            <a href="index.html" class="btn">Volver a Ventas</a>
+            <button class="btn btn-print" onclick="imprimirComprobante()">Imprimir Comprobante</button>
+        </div>
+    </div>
+    
+    <script src="js/comprobante.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/vista/css/comprobante.css b/vista/css/comprobante.css
new file mode 100644
index 0000000..bd3d2c1
--- /dev/null
+++ b/vista/css/comprobante.css
@@ -0,0 +1,81 @@
+body {
+    font-family: Arial, sans-serif;
+    margin: 0;
+    padding: 20px;
+    background-color: #f5f5f5;
+}
+.container {
+    max-width: 800px;
+    margin: 0 auto;
+    background-color: #fff;
+    padding: 20px;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+h1, h2 {
+    color: #333;
+}
+.comprobante {
+    border: 1px solid #ddd;
+    padding: 20px;
+    border-radius: 4px;
+    margin: 20px 0;
+}
+.header {
+    border-bottom: 2px solid #333;
+    padding-bottom: 10px;
+    margin-bottom: 20px;
+}
+.info-venta {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 20px;
+}
+.info-item {
+    margin-bottom: 10px;
+}
+.info-label {
+    font-weight: bold;
+}
+table {
+    width: 100%;
+    border-collapse: collapse;
+    margin-bottom: 20px;
+}
+th, td {
+    border: 1px solid #ddd;
+    padding: 8px;
+    text-align: left;
+}
+th {
+    background-color: #f8f9fa;
+}
+.total {
+    font-size: 18px;
+    font-weight: bold;
+    text-align: right;
+    margin-top: 20px;
+    padding-top: 10px;
+    border-top: 1px solid #ddd;
+}
+.acciones {
+    display: flex;
+    justify-content: space-between;
+    margin-top: 20px;
+}
+.btn {
+    background-color: #007bff;
+    color: white;
+    border: none;
+    padding: 10px 20px;
+    border-radius: 4px;
+    text-decoration: none;
+    cursor: pointer;
+    display: inline-block;
+}
+.btn-print {
+    background-color: #6c757d;
+}
+.btn:hover {
+    opacity: 0.9;
+}
\ No newline at end of file
diff --git a/vista/css/index.css b/vista/css/index.css
new file mode 100644
index 0000000..2c00741
--- /dev/null
+++ b/vista/css/index.css
@@ -0,0 +1,131 @@
+
+
+body {
+    font-family: Arial, sans-serif;
+    margin: 0;
+    padding: 20px;
+    background-color: #f5f5f5;
+}
+.container {
+    max-width: 1200px;
+    margin: 0 auto;
+    background-color: #fff;
+    padding: 20px;
+    border-radius: 8px;
+    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+}
+h1, h2 {
+    color: #333;
+}
+.mensaje {
+    background-color: #f8d7da;
+    color: #721c24;
+    padding: 10px;
+    margin-bottom: 20px;
+    border-radius: 4px;
+    display: none;
+}
+.sala {
+    margin: 20px 0;
+    text-align: center;
+}
+.escenario {
+    background-color: #ddd;
+    padding: 10px;
+    margin-bottom: 30px;
+    border-radius: 4px;
+    text-align: center;
+    font-weight: bold;
+}
+.filas {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    gap: 10px;
+}
+.fila {
+    display: flex;
+    gap: 10px;
+    align-items: center;
+}
+.numero-fila {
+    width: 30px;
+    text-align: center;
+    font-weight: bold;
+}
+.asientos {
+    display: flex;
+    gap: 5px;
+}
+.asiento {
+    width: 35px;
+    height: 35px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    border-radius: 5px;
+    cursor: pointer;
+    user-select: none;
+    font-size: 12px;
+}
+.disponible {
+    background-color: #28a745;
+    color: white;
+}
+.vendido {
+    background-color: #dc3545;
+    color: white;
+    cursor: not-allowed;
+}
+.seleccionado {
+    background-color: #007bff;
+    color: white;
+}
+.form-group {
+    margin-bottom: 15px;
+}
+label {
+    display: block;
+    margin-bottom: 5px;
+    font-weight: bold;
+}
+input[type="text"] {
+    width: 100%;
+    padding: 8px;
+    border: 1px solid #ddd;
+    border-radius: 4px;
+    box-sizing: border-box;
+}
+.btn {
+    background-color: #007bff;
+    color: white;
+    border: none;
+    padding: 10px 20px;
+    border-radius: 4px;
+    cursor: pointer;
+}
+.btn:hover {
+    background-color: #0069d9;
+}
+.resumen {
+    margin-top: 20px;
+    padding: 15px;
+    background-color: #f8f9fa;
+    border-radius: 4px;
+}
+.leyenda {
+    display: flex;
+    gap: 15px;
+    margin-top: 20px;
+    justify-content: center;
+}
+.leyenda-item {
+    display: flex;
+    align-items: center;
+    gap: 5px;
+}
+.leyenda-color {
+    width: 20px;
+    height: 20px;
+    border-radius: 3px;
+}
\ No newline at end of file
diff --git a/vista/index.html b/vista/index.html
new file mode 100644
index 0000000..3e903b5
--- /dev/null
+++ b/vista/index.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="es">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Sistema de Venta de Boletos</title>
+    <link rel="stylesheet" href="css/index.css">
+    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
+</head>
+<body>
+    <div class="container">
+        <h1>Sistema de Venta de Boletos para Concierto</h1>
+        
+        <div id="mensajeAlerta" class="alert alert-warning d-none" role="alert"></div>
+        
+        <div class="sala">
+            <h2>Selección de Asientos - Sala Principal</h2>
+            <div class="escenario">ESCENARIO</div>
+            
+            <div class="filas" id="mapaAsientos">
+                <!-- El mapa de asientos se cargará dinámicamente con JavaScript -->
+            </div>
+            
+            <div class="leyenda">
+                <div class="leyenda-item">
+                    <div class="leyenda-color" style="background-color: #28a745;"></div>
+                    <span>Disponible</span>
+                </div>
+                <div class="leyenda-item">
+                    <div class="leyenda-color" style="background-color: #007bff;"></div>
+                    <span>Seleccionado</span>
+                </div>
+                <div class="leyenda-item">
+                    <div class="leyenda-color" style="background-color: #dc3545;"></div>
+                    <span>Vendido</span>
+                </div>
+            </div>
+        </div>
+        
+        <form id="formularioVenta">
+            <div class="form-group">
+                <label for="nombre_cliente">Nombre del Cliente:</label>
+                <input type="text" id="nombre_cliente" name="nombre_cliente" class="form-control" required>
+            </div>
+            
+            <div class="resumen" id="resumen">
+                <h3>Resumen de Selección</h3>
+                <p>Asientos seleccionados: <span id="asientosSeleccionados">Ninguno</span></p>
+                <p>Total: $<span id="totalVenta">0.00</span></p>
+                <button type="submit" id="btnVender" class="btn btn-primary">Confirmar Venta</button>
+            </div>
+            
+            <!-- Campo oculto para almacenar IDs de asientos seleccionados -->
+            <div id="asientosSeleccionadosInput"></div>
+        </form>
+    </div>
+    
+    <script src="js/index.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/vista/js/comprobante.js b/vista/js/comprobante.js
new file mode 100644
index 0000000..c538e80
--- /dev/null
+++ b/vista/js/comprobante.js
@@ -0,0 +1,80 @@
+// comprobante.js - Maneja la comunicación entre el PHP y el HTML
+
+// Cuando el documento esté listo, cargar los datos del comprobante
+document.addEventListener('DOMContentLoaded', cargarComprobante);
+
+// Función para cargar los datos del comprobante desde el servidor
+function cargarComprobante() {
+    fetch('../controlador/comprobante.php')
+        .then(response => {
+            if (!response.ok) {
+                throw new Error('Error al obtener los datos del comprobante');
+            }
+            return response.json();
+        })
+        .then(comprobante => {
+            // Llenar los datos básicos del comprobante
+            document.getElementById('id-venta').textContent = comprobante.id_venta;
+            document.getElementById('fecha-venta').textContent = comprobante.fecha;
+            document.getElementById('cliente-venta').textContent = comprobante.cliente;
+            document.getElementById('total-venta').textContent = formatearNumero(comprobante.total);
+            
+            // Generar las filas de la tabla de boletos
+            const tablaBoletos = document.getElementById('detalle-boletos');
+            let contenidoTabla = '';
+            
+            comprobante.boletos.forEach((boleto, index) => {
+                contenidoTabla += `
+                    <tr>
+                        <td>${index + 1}</td>
+                        <td>Fila ${boleto.fila}, Asiento ${boleto.numero}</td>
+                        <td>$${formatearNumero(boleto.precio)}</td>
+                    </tr>
+                `;
+            });
+            
+            tablaBoletos.innerHTML = contenidoTabla;
+        })
+        .catch(error => {
+            console.error('Error:', error);
+            alert('No se pudo cargar el comprobante. Por favor, inténtelo de nuevo.');
+            window.location.href = 'index.html';
+        });
+}
+
+// Función para imprimir el comprobante
+function imprimirComprobante() {
+    const contenido = document.getElementById('comprobante-imprimible').innerHTML;
+    const ventanaImpresion = window.open('', '_blank');
+    
+    ventanaImpresion.document.write(`
+        <html>
+        <head>
+            <title>Comprobante de Venta</title>
+            <style>
+                body { font-family: Arial, sans-serif; }
+                .header { border-bottom: 2px solid #333; padding-bottom: 10px; margin-bottom: 20px; }
+                .info-venta { display: flex; justify-content: space-between; margin-bottom: 20px; }
+                .info-item { margin-bottom: 10px; }
+                .info-label { font-weight: bold; }
+                table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
+                th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
+                th { background-color: #f8f9fa; }
+                .total { font-size: 18px; font-weight: bold; text-align: right; margin-top: 20px; padding-top: 10px; border-top: 1px solid #ddd; }
+            </style>
+        </head>
+        <body>
+            ${contenido}
+        </body>
+        </html>
+    `);
+    
+    ventanaImpresion.document.close();
+    ventanaImpresion.focus();
+    ventanaImpresion.print();
+}
+
+// Función auxiliar para formatear números con dos decimales
+function formatearNumero(numero) {
+    return Number(numero).toFixed(2);
+}
\ No newline at end of file
diff --git a/vista/js/index.js b/vista/js/index.js
new file mode 100644
index 0000000..ce74209
--- /dev/null
+++ b/vista/js/index.js
@@ -0,0 +1,206 @@
+// js/index.js - Script para manejar la interfaz de usuario y la comunicación con el backend
+
+document.addEventListener('DOMContentLoaded', function() {
+    let seleccionados = [];
+    const precioBoleto = 50.00; // Precio por boleto
+    
+    // Cargar el mapa de asientos al iniciar
+    cargarMapaAsientos();
+    
+    // Agregar manejador para el formulario
+    const formulario = document.getElementById('formularioVenta');
+    formulario.addEventListener('submit', validarYEnviarFormulario);
+    
+    // Función para cargar el mapa de asientos desde la API
+    async function cargarMapaAsientos() {
+        try {
+            const response = await fetch('../controlador/asientos.php');
+            const data = await response.json();
+            
+            if (!data.success) {
+                mostrarMensaje('Error al cargar el mapa de asientos', 'error');
+                return;
+            }
+            
+            renderizarMapaAsientos(data.mapa);
+        } catch (error) {
+            console.error('Error al cargar el mapa de asientos:', error);
+            mostrarMensaje('Error de conexión con el servidor', 'error');
+        }
+    }
+    
+    // Función para renderizar el mapa de asientos
+    function renderizarMapaAsientos(mapa) {
+        const contenedor = document.getElementById('mapaAsientos');
+        contenedor.innerHTML = '';
+        
+        Object.entries(mapa).forEach(([numeroFila, asientosEnFila]) => {
+            const filaElement = document.createElement('div');
+            filaElement.className = 'fila';
+            
+            // Crear elemento para el número de fila
+            const numeroFilaElement = document.createElement('div');
+            numeroFilaElement.className = 'numero-fila';
+            numeroFilaElement.textContent = `F${numeroFila}`;
+            filaElement.appendChild(numeroFilaElement);
+            
+            // Crear contenedor para los asientos
+            const asientosContainer = document.createElement('div');
+            asientosContainer.className = 'asientos';
+            
+            // Crear cada asiento
+            Object.entries(asientosEnFila).forEach(([numeroAsiento, estado]) => {
+                const idBoleto = ((parseInt(numeroFila) - 1) * Object.keys(asientosEnFila).length) + parseInt(numeroAsiento);
+                const asiento = document.createElement('div');
+                
+                // Determinar la clase según el estado
+                asiento.className = `asiento ${estado === 'disponible' ? 'disponible' : 'vendido'}`;
+                asiento.dataset.id = idBoleto;
+                asiento.textContent = numeroAsiento;
+                
+                asientosContainer.appendChild(asiento);
+            });
+            
+            filaElement.appendChild(asientosContainer);
+            contenedor.appendChild(filaElement);
+        });
+        
+        // Una vez que se ha renderizado, añadir los eventos
+        configurarEventosAsientos();
+    }
+    
+    // Configurar eventos para los asientos
+    function configurarEventosAsientos() {
+        const asientos = document.querySelectorAll('.asiento.disponible');
+        
+        asientos.forEach(asiento => {
+            asiento.addEventListener('click', function() {
+                const asientoId = parseInt(this.getAttribute('data-id'));
+                
+                // Verificar si ya está seleccionado
+                const indice = seleccionados.findIndex(a => a.id === asientoId);
+                
+                if (indice === -1) {
+                    // Agregar a seleccionados
+                    seleccionados.push({
+                        id: asientoId,
+                        elemento: this
+                    });
+                    this.classList.remove('disponible');
+                    this.classList.add('seleccionado');
+                } else {
+                    // Quitar de seleccionados
+                    seleccionados.splice(indice, 1);
+                    this.classList.remove('seleccionado');
+                    this.classList.add('disponible');
+                }
+                
+                actualizarResumen();
+            });
+        });
+    }
+    
+    // Función para actualizar el resumen de venta
+    function actualizarResumen() {
+        const resumenAsientos = document.getElementById('asientosSeleccionados');
+        const resumenTotal = document.getElementById('totalVenta');
+        const asientosInput = document.getElementById('asientosSeleccionadosInput');
+        
+        if (seleccionados.length === 0) {
+            resumenAsientos.textContent = 'Ninguno';
+            resumenTotal.textContent = '0.00';
+            
+            // Limpiar los inputs ocultos
+            if (asientosInput) {
+                asientosInput.innerHTML = '';
+            }
+        } else {
+            // Mostrar los asientos seleccionados
+            const detalles = seleccionados.map(asiento => {
+                const fila = Math.floor((asiento.id - 1) / 15) + 1;
+                const numero = ((asiento.id - 1) % 15) + 1;
+                return `F${fila}-${numero}`;
+            });
+            
+            resumenAsientos.textContent = detalles.join(', ');
+            resumenTotal.textContent = (seleccionados.length * precioBoleto).toFixed(2);
+            
+            // Actualizar campo oculto para el envío del formulario
+            if (asientosInput) {
+                asientosInput.innerHTML = '';
+                seleccionados.forEach(asiento => {
+                    const input = document.createElement('input');
+                    input.type = 'hidden';
+                    input.name = 'asientos[]';
+                    input.value = asiento.id;
+                    asientosInput.appendChild(input);
+                });
+            }
+        }
+    }
+    
+    // Función para validar y enviar el formulario
+    function validarYEnviarFormulario(e) {
+        e.preventDefault();
+        
+        if (seleccionados.length === 0) {
+            mostrarMensaje('Por favor, seleccione al menos un asiento.');
+            return false;
+        }
+        
+        const nombreCliente = document.getElementById('nombre_cliente').value.trim();
+        if (nombreCliente === '') {
+            mostrarMensaje('Por favor, ingrese el nombre del cliente.');
+            return false;
+        }
+        
+        // Preparar los datos para enviar
+        const asientosIds = seleccionados.map(asiento => asiento.id);
+        const datos = {
+            asientos: asientosIds,
+            nombre_cliente: nombreCliente
+        };
+        
+        // Enviar los datos mediante fetch
+        fetch('../controlador/venta.php', {
+            method: 'POST',
+            headers: {
+                'Content-Type': 'application/json'
+            },
+            body: JSON.stringify(datos)
+        })
+        .then(response => response.json())
+        .then(result => {
+            if (result.success) {
+                // Redireccionar a la página de comprobante
+                window.location.href = result.redirect || 'comprobante.php';
+            } else {
+                mostrarMensaje(result.mensaje || 'Error al procesar la venta', 'error');
+            }
+        })
+        .catch(error => {
+            console.error('Error:', error);
+            mostrarMensaje('Error de conexión con el servidor', 'error');
+        });
+        
+        return false;
+    }
+    
+    // Función para mostrar mensajes
+    function mostrarMensaje(texto, tipo = 'warning') {
+        const mensajeElement = document.getElementById('mensajeAlerta');
+        if (mensajeElement) {
+            mensajeElement.textContent = texto;
+            mensajeElement.className = `alert alert-${tipo === 'error' ? 'danger' : 'warning'}`;
+            mensajeElement.classList.remove('d-none');
+            
+            // Ocultar después de 5 segundos
+            setTimeout(() => {
+                mensajeElement.classList.add('d-none');
+            }, 5000);
+        } else {
+            // Si no existe el elemento, usar alert
+            alert(texto);
+        }
+    }
+});
\ No newline at end of file