ScopeJS - El Framework que te va a enamorar 💜

The Framework That Makes Magic ✨

ScopeJS is that developer friend you always wanted: reliable, lightweight, and never complicates your life. Perfect for when you want to create something great without drama.

✨ Components without hassle 🚀 Classy modals 🛣️ Router that actually works ⚡ Only 15KB (as it should be!)

Super Easy Installation

You don't need to be a development ninja. With ScopeJS, you're creating marvels in 2 minutes 🎯

1

The Classic (Copy & Paste)

For those who prefer it simple: copy, paste and fly 🚀

<!-- En el <head> de tu HTML -->
<script src="https://unpkg.com/@pablotheblink/scopejs@2.0.8/js/ScopeJS.js"></script>

<script>
  // Las funciones están disponibles globalmente
  const MiComponente = ScopeJS.Component({
    controller: class {
      constructor() {
        this.mensaje = "¡Hola Mundo!";
      }
    },
    render() {
      return `<h1>${this.mensaje}</h1>`;
    }
  });

  // Renderizar cuando la página cargue
  window.addEventListener('load', () => {
    const container = document.getElementById('app');
    MiComponente.render(container);
  });
</script>
✅ Zero configuration ✅ No complications ✅ Works even in your grandma's browser
2

The Modern (For cool kids)

For those who like to show off with ES6 modules and bundlers 😎

<!-- En el <head> de tu HTML -->
<script type="module">
  import { Component, Modal, Router } from 'https://unpkg.com/@pablotheblink/scopejs@2.0.8/js/ScopeJS.js';

  const MiComponente = Component({
    controller: class {
      constructor() {
        this.mensaje = "¡Hola Mundo!";
      }
    },
    render() {
      return `<h1>${this.mensaje}</h1>`;
    }
  });

  // Renderizar cuando la página cargue
  window.addEventListener('load', () => {
    const container = document.getElementById('app');
    MiComponente.render(container);
  });
</script>
🚀 Tree shaking (sounds fancy) 🚀 Selective imports 🚀 Perfect for large projects

More Ways to Get It

🌐 CDN (The Fast One)

Straight from the cloud, faster than your morning coffee:

<script src="https://unpkg.com/@pablotheblink/scopejs@2.0.8/js/ScopeJS.js"></script>

📦 NPM (The Professional)

For serious projects that deserve the best:

npm install @pablotheblink/scopejs

Basic HTML Structure

Here's a complete example of how to structure your HTML page:

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Mi App con ScopeJS</title>
  
  <!-- Opción 1: Script normal -->
  <script src="js/ScopeJS.js"></script>
  
  <!-- Opción 2: ES6 Module -->
  <!-- <script type="module" src="js/app.js"></script> -->
</head>
<body>
  <div id="app">
    <!-- Tu aplicación se renderizará aquí -->
  </div>

  <script>
    // Tu código de la aplicación aquí
    const App = ScopeJS.Component({
      controller: class {
        constructor() {
          this.titulo = "Mi Primera App ScopeJS";
          this.contador = 0;
        }
        
        incrementar() {
          this.contador++;
          this.apply();
        }
      },
      
      render() {
        return `
          <div style="text-align: center; padding: 2rem;">
            <h1>${this.titulo}</h1>
            <p>Contador: ${this.contador}</p>
            <button onclick="incrementar()">
              Incrementar
            </button>
          </div>
        `;
      }
    });

    // Inicializar cuando la página cargue
    window.addEventListener('load', () => {
      const container = document.getElementById('app');
      App.render(container);
    });
  </script>
</body>
</html>

💡 Tips from the House

  • Are you new? Start with the classic method, don't complicate your life
  • Already experienced? Go wild with ES6 modules
  • Going to production? Minify the file to make it fly
  • Compatibility: Works in all modern browsers (if you have IE6, we need to talk)
  • Size: Only ~15KB minified (smaller than an Instagram photo)

Smart Components

Create pieces of code that work like a Swiss watch: precise, elegant and reusable. Because life is too short to write repetitive code 🕰️

What Magic Do Components Have?

Components in ScopeJS are like smart LEGO bricks that encapsulate everything you need:

  • Brain: Controllers with logic that actually works
  • Pretty face: HTML templates that make you fall in love
  • Style: CSS that doesn't fight with the rest
  • Personality: Events that respond as they should
  • Memory: State that updates automagically

What They're For (Spoiler: Everything)

🧩

Cool Widgets

Buttons, cards, forms... Everything you need to impress.

📊

Epic Dashboards

Charts, metrics and panels that bring data to life.

🎨

Luxury Interfaces

Complex layouts that communicate with each other like magic.

Basic Example: Counter

Component Code

import { Component } from './js/ScopeJS.js';

// Definir el componente
const Counter = Component({
    // Lógica del controlador
    controller: class {
        constructor() {
            this.count = 0;
            this.step = 1;
        }
        
        increment() {
            this.count += this.step;
            this.apply(); // Re-renderizar
        }
        
        decrement() {
            this.count -= this.step;
            this.apply();
        }
        
        reset() {
            this.count = 0;
            this.apply();
        }
    },
    
    // Template HTML
    render() {
        return `
            <div class="counter-widget">
                <h3>Contador: ${this.count}</h3>
                <div class="controls">
                    <button onclick="decrement()">-</button>
                    <button onclick="increment()">+</button>
                </div>
                <button onclick="reset()">Reset</button>
            </div>
        `;
    },
    
    // Estilos CSS scoped
    style: `
        padding: 1rem;
        border: 2px solid #9333ea;
        border-radius: 0.5rem;
        text-align: center;
        background: white;
    `,
    
    // Tag personalizado
    tagName: 'my-counter'
});

// Usar el componente
const container = document.getElementById('app');
Counter.render(container);

Preview

Contador: 0

Advanced Example: To-Do List

Interactive List

import { Component } from './js/ScopeJS.js';

const TodoList = Component({
    controller: class {
        constructor() {
            this.todos = [];
            this.newTodo = '';
            this.filter = 'all';
        }
        
        addTodo() {
            if (this.newTodo.trim()) {
                this.todos.push({
                    id: Date.now(),
                    text: this.newTodo,
                    completed: false
                });
                this.newTodo = '';
                this.apply();
            }
        }
        
        toggleTodo(id) {
            const todo = this.todos.find(t => t.id == id);
            if (todo) {
                todo.completed = !todo.completed;
                this.apply();
            }
        }
        
        deleteTodo(id) {
            this.todos = this.todos.filter(t => t.id != id);
            this.apply();
        }
        
        get filteredTodos() {
            if (this.filter === 'completed') {
                return this.todos.filter(t => t.completed);
            }
            if (this.filter === 'active') {
                return this.todos.filter(t => !t.completed);
            }
            return this.todos;
        }
    },
    
    render() {
        return `
            <div class="todo-app">
                <h3>Lista de Tareas</h3>
                
                <div class="add-todo">
                    <input type="text" model="newTodo" 
                           placeholder="Nueva tarea...">
                    <button onclick="addTodo()">Agregar</button>
                </div>
                
                <div class="filters">
                    <button onclick="filter='all'; apply()" 
                            class="${this.filter === 'all' ? 'active' : ''}">
                        Todas
                    </button>
                    <button onclick="filter='active'; apply()" 
                            class="${this.filter === 'active' ? 'active' : ''}">
                        Activas
                    </button>
                    <button onclick="filter='completed'; apply()" 
                            class="${this.filter === 'completed' ? 'active' : ''}">
                        Completadas
                    </button>
                </div>
                
                <ul class="todo-list">
                    ${this.filteredTodos.map(todo => `
                        <li class="todo-item ${todo.completed ? 'completed' : ''}">
                            <input type="checkbox" 
                                   ${todo.completed ? 'checked' : ''} 
                                   onclick="toggleTodo(${todo.id})">
                            <span>${todo.text}</span>
                            <button onclick="deleteTodo(${todo.id})">❌</button>
                        </li>
                    `).join('')}
                </ul>
            </div>
        `;
    },
    
    style: `
        padding: 1rem;
        border: 2px solid #9333ea;
        border-radius: 0.5rem;
        background: white;
    `,
    
    tagName: 'todo-list'
});

Interactive Demo

Lista de Tareas

    What Will Blow Your Mind

    🎯

    ⚡ Surgical Rendering (Yes, it's as cool as it sounds)

    ScopeJS is not one of those heavy frameworks that updates the entire page every time you change a comma. We're smarter: we only touch what has really changed. Like a DOM surgeon.

    Ninja precision: If you change a text, only that text is updated. Nothing more.

    Maximum efficiency: If you change a CSS class, only that class is modified. Period.

    ✨ Result: Smooth animations, forms that don't reset and a user experience that makes you fall in love

    🔄

    Automatic Data Binding

    With the model attribute, data syncs itself. Pure magic!

    🎯

    Smart Events

    Event handling that works as you expect, with parameters and all

    🎨

    Encapsulated CSS

    Styles that behave well and don't bother the rest

    Super Reactive

    Efficient re-rendering only when needed. No more, no less

    Router That Won't Let You Down

    Navigation system for SPAs that works as it should: no drama, no weird bugs and all the features you need. The router you always wanted 🗺️

    Router Configuration

    Configuración Básica

    import { Router, Component } from './js/ScopeJS.js';
    
    // Definir las vistas/componentes
    const HomePage = Component({
        controller: class {
            constructor() {
                this.title = "Página de Inicio";
                this.message = "¡Bienvenido a ScopeJS!";
            }
        },
        
        render() {
            return `
                <div class="p-6 text-center">
                    <h1 class="text-3xl font-bold text-purple-800 mb-4">
                        ${this.title}
                    </h1>
                    <p class="text-gray-600">${this.message}</p>
                    <a href="/usuario/123" class="text-purple-600 hover:underline">
                        Ver perfil de usuario
                    </a>
                </div>
            `;
        }
    });
    
    const UserProfile = Component({
        controller: class {
            constructor() {
                this.userId = null;
                this.userName = "";
            }
            
            init(params) {
                this.userId = params.id;
                this.userName = `Usuario ${params.id}`;
                this.apply();
            }
        },
        
        render() {
            return `
                <div class="p-6">
                    <h1 class="text-2xl font-bold text-purple-800 mb-4">
                        Perfil de ${this.userName}
                    </h1>
                    <p class="text-gray-600 mb-4">ID: ${this.userId}</p>
                    <button onclick="history.back()" 
                            class="bg-purple-600 text-white px-4 py-2 rounded">
                        Volver
                    </button>
                </div>
            `;
        }
    });
    
    // Configurar el router
    const AppRouter = Router([
        {
            path: "/",
            component: HomePage,
            alias: "inicio"
        },
        {
            path: "/inicio",
            component: HomePage,
            alias: "home"
        },
        {
            path: "/usuario/:id",
            component: UserProfile,
            alias: "perfil-usuario",
            middleware: (params, next) => {
                // Validar que el ID sea un número
                if (isNaN(params.id)) {
                    alert("ID de usuario inválido");
                    return false;
                }
                next();
            }
        },
        {
            path: "/productos",
            alias: "catalogo-productos",
            component: Component({
                render() {
                    return `
                        <div class="p-6">
                            <h1 class="text-2xl font-bold text-purple-800 mb-4">
                                Catálogo de Productos
                            </h1>
                            <div class="grid grid-cols-2 gap-4">
                                <div class="border p-4 rounded">Producto 1</div>
                                <div class="border p-4 rounded">Producto 2</div>
                            </div>
                        </div>
                    `;
                }
            })
        }
    ]);
    
    // Renderizar el router en el DOM
    const container = document.getElementById('app');
    AppRouter.render(container);
    
    // Navegación programática
    function navigateToUser(userId) {
        AppRouter.navigate(`/usuario/${userId}`);
    }
    
    function navigateToProducts() {
        AppRouter.navigate('/productos');
    }
    
    // Escuchar cambios de ruta
    AppRouter.listen((route, params) => {
        console.log('Navegando a:', route, 'Parámetros:', params);
    });

    Programmatic Navigation

    Selecciona una ruta para ver la navegación

    Why This Router Rocks

    🔗

    Dynamic URLs

    Route parameters that actually work

    🛡️

    Middleware Inteligente

    Control de acceso y validación sin complicaciones

    📱

    SPA de Verdad

    Navegación fluida sin recargas molestas

    🎭

    Transiciones Smooth

    Cambios de vista que enamoran

    🆕 New in v2.0.8

    Nested Routes 🏗️

    Create complex applications with shared layouts and hierarchical navigation. Child routes automatically inherit the parent's path.

    Panel de Administración con Rutas Anidadas

    Configuración Jerárquica

    import { Router, Component } from './js/ScopeJS.js';
    
    // Layout Principal (Componente Padre)
    const AdminLayout = Component({
      controller: class {
        constructor() {
          this.title = "Panel Admin";
        }
      },
      
      render() {
        return `
          <div class="admin-layout">
            <nav class="navbar">
              <h2>🛡️ ${this.title}</h2>
              <div class="nav-links">
                <a href="#/admin/dashboard">📊 Dashboard</a>
                <a href="#/admin/usuarios">👥 Usuarios</a>
                <a href="#/admin/productos">📦 Productos</a>
              </div>
            </nav>
            
            <main class="content">
              <!-- Aquí se renderizan las rutas hijas -->
              <router-outlet></router-outlet>
            </main>
          </div>
        `;
      }
    });
    
    // Componente Dashboard (Hijo)
    const Dashboard = Component({
      controller: class {
        constructor() {
          this.stats = { users: 150, products: 45 };
        }
      },
      render() {
        return `
          <div>
            <h3>📊 Dashboard</h3>
            <div class="stats-grid">
              <div class="stat-card">
                <h4>👥 Usuarios</h4>
                <p>${this.stats.users}</p>
              </div>
              <div class="stat-card">
                <h4>📦 Productos</h4>
                <p>${this.stats.products}</p>
              </div>
            </div>
          </div>
        `;
      }
    });
    
    // Configuración con Rutas Anidadas
    const routes = [
      {
        path: "/",
        controller: HomePage
      },
      {
        path: "/admin",           // Ruta padre
        controller: AdminLayout,  // Layout compartido
        children: [               // Rutas hijas
          {
            path: "/dashboard",   // = "/admin/dashboard"
            controller: Dashboard
          },
          {
            path: "/usuarios",    // = "/admin/usuarios"
            controller: UsersList
          },
          {
            path: "/usuarios/:id", // = "/admin/usuarios/:id"
            controller: UserDetail
          }
        ]
      }
    ];
    
    // Inicializar Router
    const AppRouter = Router(routes, { useHash: true });
    AppRouter.render(document.getElementById('app'));

    Demostración Interactiva

    1. Navegar al layout padre:

    2. Navegar a rutas hijas (se renderizan dentro del layout):

    🎯

    Haz clic en los botones para ver las rutas anidadas en acción

    🔗

    Herencia de Paths

    Las rutas hijas heredan automáticamente el path del padre

    🎯

    Router Outlet

    Usa <router-outlet> para renderizar componentes hijos

    📊

    Layouts Compartidos

    Mantén navegación y estilos consistentes

    Smooth Navigation

    Changes only the content, not the entire layout

    The API Bible

    Everything you need to know to master ScopeJS like a code ninja. Here's the documentation you'll actually read 📚

    Component API

    Propiedad Tipo Descripción
    controller Class Clase controladora del componente
    render Function Función que retorna el HTML del componente
    style String CSS scoped para el componente
    tagName String Nombre del elemento personalizado
    postRender Function Callback ejecutado después del render

    Modal API

    Propiedad Tipo Descripción
    controller Class Controlador del modal
    render Function Función de renderizado
    hideWhenClickOverlay Boolean Cerrar al hacer clic fuera
    className String Clase CSS adicional
    referrer Element Elemento de referencia para posición
    resizable Boolean Permite redimensionar arrastrando (solo desktop)
    draggable Boolean Permite mover el modal arrastrando desde título
    windowMode Boolean Modo ventana: sin overlay, múltiples permitidos
    title String Título mostrado en la barra superior (windowMode)
    position Object Posición inicial {x, y} para windowMode

    Router API

    Método Parámetros Descripción
    navigate path, body Navegar a una ruta específica
    render container Renderizar el router en un contenedor
    listen callback Escuchar cambios de ruta
    unlisten uuid Remover listener de cambios

    Utilidades

    Función Parámetros Descripción
    enableDebugger boolean Activar/desactivar modo debug
    apply - Re-renderizar componente
    close ...args Cerrar modal (disponible en modales)

    Playground of the Gods

    Your personal sandbox to experiment with ScopeJS. Here you can break things, create wonders and learn without fear. It's your time to shine! ⚡

    Tu Editor Personal

    Aquí Pasa la Magia

    ¡Vamos! Escribe algo genial y verás cómo cobra vida aquí ✨

    💡 Trucos de Pro:

    • • Usa this.apply() después de cambiar datos
    • • El atributo model es tu mejor amigo para formularios
    • • Los eventos son tan fáciles como onclick="miMetodo()"
    • • Los estilos CSS se aplican automágicamente (sí, es magia)

    About the Author

    Pablo Martínez
    😎

    Pablo Martínez

    Full Stack developer with a bit of craziness 🤪 for creating tools that make users say "WOW!" I created ScopeJS because I was tired of heavy frameworks that turn simple projects into complicated monsters 🐉

    Si este proyecto te ha robado el corazón ❤️ (y algunos cafés ☕), considera invitarme a una pizza 🍕 para seguir creando cositas geniales

    💖 Apóyame con una donación

    Tu apoyo me ayuda a seguir desarrollando herramientas útiles y gratuitas para la comunidad

    S

    ScopeJS

    El framework que te va a enamorar 💜

    Lo Que Mola

    • Components without hassle
    • Classy modals
    • Router that actually works
    • Data binding automático

    Para Saber Más

    Los Números

    • Versión 2.0.8 (la buena)
    • Solo ~15KB (ligero como una pluma)
    • ES6+ Compatible (modernito)
    • Zero Dependencies (independiente)

    © 2025 ScopeJS. El framework JavaScript que no te va a dar dolores de cabeza 😎