{"id":5652,"date":"2026-03-06T22:33:21","date_gmt":"2026-03-07T01:33:21","guid":{"rendered":"https:\/\/fisica2.fica.unsl.edu.ar\/?page_id=5652"},"modified":"2026-04-18T18:23:25","modified_gmt":"2026-04-18T21:23:25","slug":"campo_electrico_potencial_electrico","status":"publish","type":"page","link":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/","title":{"rendered":"campo_electrico_potencial_electrico"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"5652\" class=\"elementor elementor-5652\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-dbd906b elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"dbd906b\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-34ff481\" data-id=\"34ff481\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9a0bad8 elementor-widget elementor-widget-html\" data-id=\"9a0bad8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"es\">\r\n<head>\r\n    <meta charset=\"UTF-8\">\r\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n    <title>FLUXAR - Simulacion Fisica Precisa<\/title>\r\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Space+Grotesk:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">\r\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\r\n    <style>\r\n        :root {\r\n            --bg-primary: #05080f;\r\n            --bg-secondary: #0f1520;\r\n            --bg-tertiary: #1a2332;\r\n            --text-primary: #e8edf5;\r\n            --text-secondary: #8b9cb8;\r\n            --accent-positive: #ef4444;\r\n            --accent-negative: #3b82f6;\r\n            --accent-field: #f97316;\r\n            --accent-vector: #eab308;\r\n            --border-color: #2d3a4f;\r\n            --panel-bg: rgba(15, 21, 32, 0.95);\r\n        }\r\n        \r\n        * { margin: 0; padding: 0; box-sizing: border-box; }\r\n        \r\n        body {\r\n            font-family: 'Space Grotesk', sans-serif;\r\n            background: var(--bg-primary);\r\n            color: var(--text-primary);\r\n            overflow: hidden;\r\n        }\r\n        \r\n        #canvas-container {\r\n            position: fixed;\r\n            top: 0; left: 0;\r\n            width: 100%; height: 100%;\r\n            z-index: 1;\r\n        }\r\n        \r\n        .control-panel {\r\n            position: fixed;\r\n            top: 20px; left: 20px;\r\n            width: 320px;\r\n            max-height: calc(100vh - 40px);\r\n            background: var(--panel-bg);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 16px;\r\n            z-index: 100;\r\n            backdrop-filter: blur(20px);\r\n            overflow-y: auto;\r\n            scrollbar-width: thin;\r\n        }\r\n        \r\n        .panel-header {\r\n            padding: 20px;\r\n            border-bottom: 1px solid var(--border-color);\r\n            background: linear-gradient(135deg, rgba(249, 115, 22, 0.08), transparent);\r\n        }\r\n        \r\n        .panel-header h1 { font-size: 1.2rem; font-weight: 700; }\r\n        .panel-header p { font-size: 0.75rem; color: var(--text-secondary); margin-top: 4px; }\r\n        \r\n        .panel-section {\r\n            padding: 16px 20px;\r\n            border-bottom: 1px solid var(--border-color);\r\n        }\r\n        \r\n        .section-title {\r\n            font-size: 0.7rem;\r\n            font-weight: 500;\r\n            text-transform: uppercase;\r\n            letter-spacing: 0.1em;\r\n            color: var(--text-secondary);\r\n            margin-bottom: 12px;\r\n        }\r\n        \r\n        .toggle-row {\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: space-between;\r\n            padding: 8px 0;\r\n        }\r\n        \r\n        .toggle-label {\r\n            font-size: 0.85rem;\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 8px;\r\n        }\r\n        \r\n        .toggle-label .dot {\r\n            width: 8px; height: 8px;\r\n            border-radius: 50%;\r\n        }\r\n        \r\n        .toggle-switch {\r\n            position: relative;\r\n            width: 44px; height: 24px;\r\n            background: var(--bg-tertiary);\r\n            border-radius: 12px;\r\n            cursor: pointer;\r\n            transition: background 0.3s ease;\r\n        }\r\n        \r\n        .toggle-switch.active { background: var(--accent-field); }\r\n        \r\n        .toggle-switch::after {\r\n            content: '';\r\n            position: absolute;\r\n            top: 3px; left: 3px;\r\n            width: 18px; height: 18px;\r\n            background: var(--text-primary);\r\n            border-radius: 50%;\r\n            transition: transform 0.3s ease;\r\n        }\r\n        \r\n        .toggle-switch.active::after { transform: translateX(20px); }\r\n        \r\n        .slider-control { margin: 12px 0; }\r\n        \r\n        .slider-header {\r\n            display: flex;\r\n            justify-content: space-between;\r\n            margin-bottom: 8px;\r\n        }\r\n        \r\n        .slider-value {\r\n            font-family: 'JetBrains Mono', monospace;\r\n            font-size: 0.8rem;\r\n            color: var(--accent-field);\r\n            background: rgba(249, 115, 22, 0.15);\r\n            padding: 2px 8px;\r\n            border-radius: 4px;\r\n        }\r\n        \r\n        input[type=\"range\"] {\r\n            width: 100%;\r\n            height: 6px;\r\n            background: var(--bg-tertiary);\r\n            border-radius: 3px;\r\n            outline: none;\r\n            -webkit-appearance: none;\r\n        }\r\n        \r\n        input[type=\"range\"]::-webkit-slider-thumb {\r\n            -webkit-appearance: none;\r\n            width: 18px; height: 18px;\r\n            background: var(--accent-field);\r\n            border-radius: 50%;\r\n            cursor: pointer;\r\n        }\r\n        \r\n        .charge-list { max-height: 220px; overflow-y: auto; margin-bottom: 12px; }\r\n        \r\n        .charge-item {\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 10px;\r\n            padding: 10px;\r\n            background: var(--bg-tertiary);\r\n            border-radius: 8px;\r\n            margin-bottom: 8px;\r\n        }\r\n        \r\n        .charge-indicator {\r\n            width: 12px; height: 12px;\r\n            border-radius: 50%;\r\n            flex-shrink: 0;\r\n        }\r\n        \r\n        .charge-indicator.positive { background: var(--accent-positive); box-shadow: 0 0 10px var(--accent-positive); }\r\n        .charge-indicator.negative { background: var(--accent-negative); box-shadow: 0 0 10px var(--accent-negative); }\r\n        \r\n        .charge-input {\r\n            width: 70px;\r\n            background: var(--bg-secondary);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 6px;\r\n            padding: 6px 10px;\r\n            color: var(--text-primary);\r\n            font-family: 'JetBrains Mono', monospace;\r\n            font-size: 0.85rem;\r\n        }\r\n        \r\n        .charge-input:focus { outline: none; border-color: var(--accent-field); }\r\n        \r\n        .btn-remove {\r\n            width: 28px; height: 28px;\r\n            background: rgba(239, 68, 68, 0.2);\r\n            border: none;\r\n            border-radius: 6px;\r\n            color: var(--accent-positive);\r\n            cursor: pointer;\r\n            display: flex;\r\n            align-items: center;\r\n            justify-content: center;\r\n            transition: background 0.2s;\r\n        }\r\n        \r\n        .btn-remove:hover { background: rgba(239, 68, 68, 0.4); }\r\n        \r\n        .btn-group { display: flex; gap: 8px; margin-top: 12px; }\r\n        \r\n        .btn {\r\n            flex: 1;\r\n            padding: 10px 16px;\r\n            border: none;\r\n            border-radius: 8px;\r\n            font-family: 'Space Grotesk', sans-serif;\r\n            font-size: 0.85rem;\r\n            font-weight: 500;\r\n            cursor: pointer;\r\n            transition: all 0.2s;\r\n        }\r\n        \r\n        .btn-primary { background: var(--accent-field); color: white; }\r\n        .btn-primary:hover { background: #ea580c; transform: translateY(-1px); }\r\n        .btn-secondary { background: var(--bg-tertiary); color: var(--text-primary); border: 1px solid var(--border-color); }\r\n        .btn-secondary:hover { background: var(--border-color); }\r\n        \r\n        .preset-buttons { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }\r\n        \r\n        .preset-btn {\r\n            padding: 8px;\r\n            background: var(--bg-tertiary);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 6px;\r\n            color: var(--text-primary);\r\n            font-size: 0.8rem;\r\n            cursor: pointer;\r\n            transition: all 0.2s;\r\n        }\r\n        \r\n        .preset-btn:hover, .preset-btn.active { background: var(--accent-field); border-color: var(--accent-field); }\r\n        \r\n        .info-panel {\r\n            position: fixed;\r\n            top: 20px; right: 20px;\r\n            width: 280px;\r\n            background: var(--panel-bg);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 16px;\r\n            z-index: 100;\r\n            backdrop-filter: blur(20px);\r\n            padding: 20px;\r\n        }\r\n        \r\n        .info-row {\r\n            display: flex;\r\n            justify-content: space-between;\r\n            padding: 8px 0;\r\n            border-bottom: 1px solid rgba(45, 58, 79, 0.5);\r\n        }\r\n        \r\n        .info-row:last-child { border-bottom: none; }\r\n        .info-label { font-size: 0.85rem; color: var(--text-secondary); }\r\n        .info-value { font-family: 'JetBrains Mono', monospace; font-size: 0.85rem; }\r\n        \r\n        .vector-display {\r\n            margin-top: 12px;\r\n            padding: 12px;\r\n            background: var(--bg-tertiary);\r\n            border-radius: 8px;\r\n        }\r\n        \r\n        .vector-components {\r\n            display: grid;\r\n            grid-template-columns: repeat(3, 1fr);\r\n            gap: 8px;\r\n            margin-top: 8px;\r\n        }\r\n        \r\n        .vector-comp { text-align: center; padding: 6px; background: var(--bg-secondary); border-radius: 4px; }\r\n        .vector-comp-label { font-size: 0.7rem; color: var(--text-secondary); }\r\n        .vector-comp-value { font-family: 'JetBrains Mono', monospace; font-size: 0.8rem; color: var(--accent-vector); }\r\n        \r\n        .logo-container {\r\n            position: fixed;\r\n            bottom: 20px; right: 20px;\r\n            z-index: 100;\r\n            padding: 12px 16px;\r\n            background: var(--panel-bg);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 12px;\r\n            backdrop-filter: blur(20px);\r\n        }\r\n        \r\n        .logo-text { font-weight: 700; font-size: 1rem; }\r\n        .logo-text span { color: var(--accent-field); }\r\n        .logo-tagline { font-size: 0.65rem; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.15em; }\r\n        \r\n        .instructions {\r\n            position: fixed;\r\n            bottom: 20px;\r\n            left: 50%;\r\n            transform: translateX(-50%);\r\n            z-index: 100;\r\n            padding: 10px 20px;\r\n            background: var(--panel-bg);\r\n            border: 1px solid var(--border-color);\r\n            border-radius: 30px;\r\n            backdrop-filter: blur(20px);\r\n            font-size: 0.8rem;\r\n            color: var(--text-secondary);\r\n        }\r\n        \r\n        .instructions strong { color: var(--text-primary); }\r\n        \r\n        .logo-box {\r\n            position: fixed;\r\n            bottom: 20px;\r\n            right: 20px;\r\n            display: flex;\r\n            align-items: center;\r\n            gap: 10px;\r\n            background: rgba(22, 27, 34, 0.9);\r\n            padding: 10px 14px;\r\n            border-radius: 8px;\r\n            border: 1px solid var(--border-color);\r\n            z-index: 100;\r\n        }\r\n        .logo-img { width: 100px; }\r\n        .logo-text { font-size: 0.7rem; line-height: 1.3; color: var(--text-muted); }\r\n        .logo-text b { display: block; color: var(--text-main); font-weight: 600; }\r\n    <\/style>\r\n<\/head>\r\n<body>\r\n    <div id=\"canvas-container\"><\/div>\r\n    \r\n    <!-- Panel de Control -->\r\n    <div class=\"control-panel\">\r\n        <div class=\"panel-header\">\r\n            <h1>Campo Electrico y Potencial<\/h1>\r\n            <p>Simulacion interactiva 3D<\/p>\r\n        <\/div>\r\n        \r\n        <div class=\"panel-section\">\r\n            <div class=\"section-title\">Visualizacion<\/div>\r\n            <div class=\"toggle-row\">\r\n                <span class=\"toggle-label\"><span class=\"dot\" style=\"background: var(--accent-field);\"><\/span>Lineas de campo<\/span>\r\n                <div class=\"toggle-switch active\" id=\"tglFieldLines\"><\/div>\r\n            <\/div>\r\n            <div class=\"toggle-row\">\r\n                <span class=\"toggle-label\"><span class=\"dot\" style=\"background: linear-gradient(45deg, #3b82f6, #22c55e);\"><\/span>Superficies Eq.<\/span>\r\n                <div class=\"toggle-switch active\" id=\"tglEquipotential\"><\/div>\r\n            <\/div>\r\n            <div class=\"toggle-row\">\r\n                <span class=\"toggle-label\"><span class=\"dot\" style=\"background: var(--accent-vector);\"><\/span>Vector en Sonda<\/span>\r\n                <div class=\"toggle-switch active\" id=\"tglVector\"><\/div>\r\n            <\/div>\r\n            <div class=\"toggle-row\">\r\n                <span class=\"toggle-label\"><span class=\"dot\" style=\"background: #22c55e;\"><\/span>Punto de medicion<\/span>\r\n                <div class=\"toggle-switch active\" id=\"tglProbe\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n        \r\n        <div class=\"panel-section\">\r\n            <div class=\"section-title\">Parametros<\/div>\r\n            <div class=\"slider-control\">\r\n                <div class=\"slider-header\">\r\n                    <span class=\"slider-label\">Superficies<\/span>\r\n                    <span class=\"slider-value\" id=\"valSurface\">6<\/span>\r\n                <\/div>\r\n                <input type=\"range\" min=\"2\" max=\"12\" value=\"6\" id=\"sldSurface\">\r\n            <\/div>\r\n            <div class=\"slider-control\">\r\n                <div class=\"slider-header\">\r\n                    <span class=\"slider-label\">Lineas por carga<\/span>\r\n                    <span class=\"slider-value\" id=\"valLines\">12<\/span>\r\n                <\/div>\r\n                <input type=\"range\" min=\"6\" max=\"24\" value=\"12\" id=\"sldLines\">\r\n            <\/div>\r\n        <\/div>\r\n        \r\n        <div class=\"panel-section\">\r\n            <div class=\"section-title\">Configuracion de Cargas<\/div>\r\n            <div class=\"preset-buttons\">\r\n                <button class=\"preset-btn\" id=\"preset1\">1 Carga<\/button>\r\n                <button class=\"preset-btn active\" id=\"preset2\">Dipolo<\/button>\r\n                <button class=\"preset-btn\" id=\"preset3\">Triada<\/button>\r\n                <button class=\"preset-btn\" id=\"preset4\">Cuadrupolo<\/button>\r\n            <\/div>\r\n            <div class=\"charge-list\" id=\"chargeListContainer\"><\/div>\r\n            <div class=\"btn-group\">\r\n                <button class=\"btn btn-primary\" id=\"btnAddPos\">+ Positiva<\/button>\r\n                <button class=\"btn btn-primary\" id=\"btnAddNeg\">- Negativa<\/button>\r\n            <\/div>\r\n        <\/div>\r\n        \r\n        <div class=\"panel-section\">\r\n            <div class=\"btn-group\" style=\"margin-top:0;\">\r\n                <button class=\"btn btn-secondary\" id=\"btnReset\">Restablecer<\/button>\r\n                <button class=\"btn btn-secondary\" id=\"btnClear\">Limpiar<\/button>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n    \r\n    <!-- Panel de Informaci\u00f3n -->\r\n    <div class=\"info-panel\" id=\"infoPanel\">\r\n        <div class=\"section-title\">Punto de Medicion (Sonda)<\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">Posicion (x, y, z)<\/span>\r\n            <span class=\"info-value\" id=\"infoPos\">0.0, 0.0, 0.0<\/span>\r\n        <\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">Potencial (V)<\/span>\r\n            <span class=\"info-value\" id=\"infoV\">0.00<\/span>\r\n        <\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">|E| Magnitud<\/span>\r\n            <span class=\"info-value\" id=\"infoEMag\">0.00<\/span>\r\n        <\/div>\r\n        <div class=\"info-row\">\r\n            <span class=\"info-label\">Longitud Vector<\/span>\r\n            <span class=\"info-value\" id=\"infoArrowLen\">0.00<\/span>\r\n        <\/div>\r\n        <div class=\"vector-display\">\r\n            <div class=\"info-label\">Vector Campo E (N\/C)<\/div>\r\n            <div class=\"vector-components\">\r\n                <div class=\"vector-comp\">\r\n                    <div class=\"vector-comp-label\">Ex<\/div>\r\n                    <div class=\"vector-comp-value\" id=\"infoEx\">0.0<\/div>\r\n                <\/div>\r\n                <div class=\"vector-comp\">\r\n                    <div class=\"vector-comp-label\">Ey<\/div>\r\n                    <div class=\"vector-comp-value\" id=\"infoEy\">0.0<\/div>\r\n                <\/div>\r\n                <div class=\"vector-comp\">\r\n                    <div class=\"vector-comp-label\">Ez<\/div>\r\n                    <div class=\"vector-comp-value\" id=\"infoEz\">0.0<\/div>\r\n                <\/div>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n    \r\n    <div class=\"instructions\">\r\n        <strong>Scroll Suave<\/strong> activado | <strong>Arrastra<\/strong> cargas o sonda | Vector proporcional a |E|\r\n    <\/div>\r\n    \r\n    <div class=\"logo-box\">\r\n        <a href=\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/FISAR_SIM\/\" target=\"_blank\">\r\n    <img decoding=\"async\" src=\"FISAR_SIM_1\" alt=\"Logo\" class=\"logo-img\"><\/a>\r\n    <div class=\"logo-text\"><b>FICA UNSL<\/b>Simulaciones Interactivas<\/div>\r\n<\/div>\r\n\r\n    <script type=\"importmap\">\r\n    {\r\n        \"imports\": {\r\n            \"three\": \"https:\/\/unpkg.com\/three@0.160.0\/build\/three.module.js\",\r\n            \"three\/addons\/\": \"https:\/\/unpkg.com\/three@0.160.0\/examples\/jsm\/\"\r\n        }\r\n    }\r\n    <\/script>\r\n    \r\n    <script type=\"module\">\r\n        import * as THREE from 'three';\r\n        import { OrbitControls } from 'three\/addons\/controls\/OrbitControls.js';\r\n        \r\n        \/\/ --- Constantes y Estado ---\r\n        const K = 8.99e9;\r\n        let scene, camera, renderer, controls;\r\n        let charges = [];\r\n        let fieldLinesGroup, equipotentialGroup, probeGroup;\r\n        let probeMesh = null;\r\n        let probeArrow = null; \r\n        let raycaster, mouse;\r\n        let isDragging = false;\r\n        let draggedObject = null;\r\n        let dragPlane = new THREE.Plane(new THREE.Vector3(0, 1, 0), 0);\r\n        \r\n        \/\/ Estado para Zoom Suave\r\n        let goalZoomDistance = 0;\r\n        const zoomStep = 1.5; \/\/ Cu\u00e1nto se mueve por clic del scroll\r\n        const zoomLerpFactor = 0.1; \/\/ Suavidad (0.1 = suave, 1.0 = instant\u00e1neo)\r\n        \r\n        const settings = {\r\n            showFieldLines: true,\r\n            showEquipotential: true,\r\n            showProbeVector: true,\r\n            showProbe: true,\r\n            surfaceCount: 6,\r\n            lineDensity: 12\r\n        };\r\n\r\n        \/\/ --- Inicializaci\u00f3n ---\r\n        init();\r\n        animate();\r\n\r\n        function init() {\r\n            \/\/ Escena\r\n            scene = new THREE.Scene();\r\n            scene.background = new THREE.Color(0x05080f);\r\n            \r\n            \/\/ C\u00e1mara\r\n            camera = new THREE.PerspectiveCamera(55, window.innerWidth \/ window.innerHeight, 0.1, 1000);\r\n            camera.position.set(10, 8, 10);\r\n            \r\n            \/\/ Renderer\r\n            renderer = new THREE.WebGLRenderer({ antialias: true });\r\n            renderer.setSize(window.innerWidth, window.innerHeight);\r\n            renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));\r\n            document.getElementById('canvas-container').appendChild(renderer.domElement);\r\n            \r\n            \/\/ Controles Orbitales\r\n            controls = new OrbitControls(camera, renderer.domElement);\r\n            controls.enableDamping = true;\r\n            controls.dampingFactor = 0.05;\r\n            controls.rotateSpeed = 0.5;\r\n            \r\n            \/\/ DESACTIVAR ZOOM NATIVO para usar nuestro sistema suave\r\n            controls.enableZoom = false; \r\n            \r\n            \/\/ Inicializar variables de zoom\r\n            goalZoomDistance = camera.position.length();\r\n            \r\n            \/\/ Raycaster\r\n            raycaster = new THREE.Raycaster();\r\n            mouse = new THREE.Vector2();\r\n            \r\n            \/\/ Grupos\r\n            fieldLinesGroup = new THREE.Group();\r\n            equipotentialGroup = new THREE.Group();\r\n            probeGroup = new THREE.Group();\r\n            scene.add(fieldLinesGroup);\r\n            scene.add(equipotentialGroup);\r\n            scene.add(probeGroup);\r\n            \r\n            \/\/ Luces\r\n            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);\r\n            scene.add(ambientLight);\r\n            const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);\r\n            dirLight.position.set(10, 20, 10);\r\n            scene.add(dirLight);\r\n            \r\n            \/\/ Grid y Ejes\r\n            const gridHelper = new THREE.GridHelper(30, 30, 0x1a2332, 0x111827);\r\n            scene.add(gridHelper);\r\n            createAxes();\r\n            \r\n            \/\/ Crear sonda\r\n            createProbe();\r\n            \r\n            \/\/ Cargar Preset\r\n            loadPreset(2);\r\n            \r\n            \/\/ Event Listeners\r\n            setupEventListeners();\r\n            window.addEventListener('resize', onWindowResize);\r\n        }\r\n\r\n        function createAxes() {\r\n            const axesMat = [\r\n                new THREE.LineBasicMaterial({ color: 0xef4444 }),\r\n                new THREE.LineBasicMaterial({ color: 0x22c55e }),\r\n                new THREE.LineBasicMaterial({ color: 0x3b82f6 })\r\n            ];\r\n            const points = [\r\n                [new THREE.Vector3(0,0,0), new THREE.Vector3(15,0,0)],\r\n                [new THREE.Vector3(0,0,0), new THREE.Vector3(0,15,0)],\r\n                [new THREE.Vector3(0,0,0), new THREE.Vector3(0,0,15)]\r\n            ];\r\n            points.forEach((p, i) => {\r\n                const geo = new THREE.BufferGeometry().setFromPoints(p);\r\n                scene.add(new THREE.Line(geo, axesMat[i]));\r\n            });\r\n        }\r\n\r\n        function createProbe() {\r\n            const group = new THREE.Group();\r\n            const geo = new THREE.SphereGeometry(0.2, 32, 32);\r\n            const mat = new THREE.MeshPhongMaterial({ color: 0x22c55e, emissive: 0x22c55e, emissiveIntensity: 0.4 });\r\n            const sphere = new THREE.Mesh(geo, mat);\r\n            group.add(sphere);\r\n            \r\n            const ringGeo = new THREE.TorusGeometry(0.3, 0.02, 16, 100);\r\n            const ringMat = new THREE.MeshBasicMaterial({ color: 0x22c55e, transparent: true, opacity: 0.6 });\r\n            const ring = new THREE.Mesh(ringGeo, ringMat);\r\n            ring.rotation.x = Math.PI \/ 2;\r\n            group.add(ring);\r\n            \r\n            \/\/ Flecha din\u00e1mica\r\n            const arrowDir = new THREE.Vector3(1, 0, 0);\r\n            const arrowOrigin = new THREE.Vector3(0, 0, 0);\r\n            probeArrow = new THREE.ArrowHelper(arrowDir, arrowOrigin, 1, 0xeab308, 0.3, 0.15);\r\n            group.add(probeArrow);\r\n            \r\n            group.position.set(3, 0, 0);\r\n            probeMesh = group;\r\n            probeMesh.userData.isProbe = true;\r\n            probeGroup.add(probeMesh);\r\n        }\r\n\r\n        function addCharge(q, x, z) {\r\n            const chargeObj = {\r\n                id: Date.now() + Math.random(),\r\n                q: q,\r\n                position: new THREE.Vector3(x, 0, z),\r\n                mesh: null\r\n            };\r\n            \r\n            const group = new THREE.Group();\r\n            const color = q > 0 ? 0xef4444 : 0x3b82f6;\r\n            \r\n            const sphereGeo = new THREE.SphereGeometry(0.4, 32, 32);\r\n            const sphereMat = new THREE.MeshPhongMaterial({ \r\n                color: color, \r\n                emissive: color, \r\n                emissiveIntensity: 0.3,\r\n                shininess: 50\r\n            });\r\n            const sphere = new THREE.Mesh(sphereGeo, sphereMat);\r\n            group.add(sphere);\r\n            \r\n            const glowGeo = new THREE.SphereGeometry(0.55, 32, 32);\r\n            const glowMat = new THREE.MeshBasicMaterial({ color: color, transparent: true, opacity: 0.15 });\r\n            group.add(new THREE.Mesh(glowGeo, glowMat));\r\n            \r\n            const sign = q > 0 ? \"+\" : \"-\";\r\n            const canvas = document.createElement('canvas');\r\n            canvas.width = 128; canvas.height = 128;\r\n            const ctx = canvas.getContext('2d');\r\n            ctx.fillStyle = \"white\";\r\n            ctx.font = \"bold 100px Arial\";\r\n            ctx.textAlign = \"center\";\r\n            ctx.textBaseline = \"middle\";\r\n            ctx.fillText(sign, 64, 64);\r\n            \r\n            const texture = new THREE.CanvasTexture(canvas);\r\n            const spriteMat = new THREE.SpriteMaterial({ map: texture, transparent: true });\r\n            const sprite = new THREE.Sprite(spriteMat);\r\n            sprite.scale.set(0.5, 0.5, 0.5);\r\n            sprite.position.y = 0.6;\r\n            group.add(sprite);\r\n            \r\n            group.position.copy(chargeObj.position);\r\n            group.userData.chargeRef = chargeObj;\r\n            \r\n            chargeObj.mesh = group;\r\n            charges.push(chargeObj);\r\n            scene.add(group);\r\n            \r\n            updateVisualization();\r\n            updateChargeList();\r\n            return chargeObj;\r\n        }\r\n\r\n        function removeCharge(id) {\r\n            const index = charges.findIndex(c => c.id === id);\r\n            if (index !== -1) {\r\n                scene.remove(charges[index].mesh);\r\n                charges.splice(index, 1);\r\n                updateVisualization();\r\n                updateChargeList();\r\n            }\r\n        }\r\n\r\n        function updateChargeValue(id, newQ) {\r\n            const charge = charges.find(c => c.id === id);\r\n            if (charge) {\r\n                charge.q = newQ;\r\n                const color = newQ > 0 ? 0xef4444 : 0x3b82f6;\r\n                const mesh = charge.mesh.children[0];\r\n                mesh.material.color.setHex(color);\r\n                mesh.material.emissive.setHex(color);\r\n                \r\n                const sign = newQ > 0 ? \"+\" : \"-\";\r\n                const canvas = document.createElement('canvas');\r\n                canvas.width = 128; canvas.height = 128;\r\n                const ctx = canvas.getContext('2d');\r\n                ctx.fillStyle = \"white\";\r\n                ctx.font = \"bold 100px Arial\";\r\n                ctx.textAlign = \"center\";\r\n                ctx.textBaseline = \"middle\";\r\n                ctx.fillText(sign, 64, 64);\r\n                \r\n                const sprite = charge.mesh.children[2];\r\n                sprite.material.map.dispose();\r\n                sprite.material.map = new THREE.CanvasTexture(canvas);\r\n                \r\n                updateVisualization();\r\n            }\r\n        }\r\n\r\n        function calculateField(position) {\r\n            const E = new THREE.Vector3(0, 0, 0);\r\n            for (const c of charges) {\r\n                const r = new THREE.Vector3().subVectors(position, c.position);\r\n                const rMag = r.length();\r\n                if (rMag < 0.5) continue;\r\n                \r\n                const Emag = K * Math.abs(c.q) \/ (rMag * rMag);\r\n                const dir = r.normalize();\r\n                \r\n                if (c.q > 0) E.add(dir.multiplyScalar(Emag));\r\n                else E.sub(dir.multiplyScalar(Emag));\r\n            }\r\n            return E;\r\n        }\r\n\r\n        function calculatePotential(position) {\r\n            let V = 0;\r\n            for (const c of charges) {\r\n                const r = new THREE.Vector3().subVectors(position, c.position);\r\n                const rMag = r.length();\r\n                if (rMag < 0.5) continue;\r\n                V += K * c.q \/ rMag;\r\n            }\r\n            return V;\r\n        }\r\n\r\n        function updateVisualization() {\r\n            generateFieldLines();\r\n            generateEquipotentialSurfaces();\r\n            updateProbeInfo();\r\n        }\r\n\r\n        function generateFieldLines() {\r\n            while(fieldLinesGroup.children.length > 0) {\r\n                const obj = fieldLinesGroup.children[0];\r\n                if(obj.geometry) obj.geometry.dispose();\r\n                if(obj.material) obj.material.dispose();\r\n                fieldLinesGroup.remove(obj);\r\n            }\r\n            if (!settings.showFieldLines) return;\r\n\r\n            const stepSize = 0.1;\r\n            const maxSteps = 300;\r\n\r\n            charges.forEach(charge => {\r\n                if (charge.q === 0) return;\r\n                \r\n                const isPositive = charge.q > 0;\r\n                const numLines = settings.lineDensity;\r\n                \r\n                for (let i = 0; i < numLines; i++) {\r\n                    const phi = Math.acos(1 - 2 * (i + 0.5) \/ numLines);\r\n                    const theta = Math.PI * (1 + Math.sqrt(5)) * i;\r\n                    \r\n                    const startDir = new THREE.Vector3(\r\n                        Math.sin(phi) * Math.cos(theta),\r\n                        Math.cos(phi),\r\n                        Math.sin(phi) * Math.sin(theta)\r\n                    );\r\n                    \r\n                    const points = [];\r\n                    let pos = charge.position.clone().add(startDir.clone().multiplyScalar(0.5));\r\n                    \r\n                    for (let s = 0; s < maxSteps; s++) {\r\n                        points.push(pos.clone());\r\n                        \r\n                        const E = calculateField(pos);\r\n                        const Emag = E.length();\r\n                        if (Emag < 1e2) break;\r\n                        \r\n                        const dir = E.normalize();\r\n                        if (!isPositive) dir.negate();\r\n                        \r\n                        pos.add(dir.multiplyScalar(stepSize));\r\n                        \r\n                        let reachedEnd = false;\r\n                        for (const other of charges) {\r\n                            if (other.id === charge.id) continue;\r\n                            if (pos.distanceTo(other.position) < 0.5) reachedEnd = true;\r\n                        }\r\n                        if (reachedEnd || pos.length() > 20) break;\r\n                    }\r\n                    \r\n                    if (points.length > 2) {\r\n                        const curve = new THREE.CatmullRomCurve3(points);\r\n                        const tubeGeo = new THREE.TubeGeometry(curve, points.length, 0.007, 8, false);\r\n                        const tubeMat = new THREE.MeshBasicMaterial({ color: 0xf97316, transparent: true, opacity: 0.7 });\r\n                        fieldLinesGroup.add(new THREE.Mesh(tubeGeo, tubeMat));\r\n                    }\r\n                }\r\n            });\r\n        }\r\n\r\n        function generateEquipotentialSurfaces() {\r\n            while(equipotentialGroup.children.length > 0) {\r\n                const obj = equipotentialGroup.children[0];\r\n                if(obj.geometry) obj.geometry.dispose();\r\n                if(obj.material) obj.material.dispose();\r\n                equipotentialGroup.remove(obj);\r\n            }\r\n            if (!settings.showEquipotential) return;\r\n\r\n            charges.forEach(charge => {\r\n                const isPositive = charge.q > 0;\r\n                \r\n                for (let i = 1; i <= settings.surfaceCount; i++) {\r\n                    const r = 0.6 + i * 0.5;\r\n                    const hue = isPositive ? 0.0 : 0.6;\r\n                    const color = new THREE.Color().setHSL(hue, 0.8, 0.5);\r\n                    \r\n                    const sphereGeo = new THREE.SphereGeometry(r, 32, 32);\r\n                    const sphereMat = new THREE.MeshBasicMaterial({\r\n                        color: color,\r\n                        transparent: true,\r\n                        opacity: 0.08,\r\n                        side: THREE.DoubleSide\r\n                    });\r\n                    const sphere = new THREE.Mesh(sphereGeo, sphereMat);\r\n                    sphere.position.copy(charge.position);\r\n                    equipotentialGroup.add(sphere);\r\n                    \r\n                    const wireMat = new THREE.MeshBasicMaterial({\r\n                        color: color,\r\n                        transparent: true,\r\n                        opacity: 0.2,\r\n                        wireframe: true\r\n                    });\r\n                    const wire = new THREE.Mesh(sphereGeo.clone(), wireMat);\r\n                    wire.position.copy(charge.position);\r\n                    equipotentialGroup.add(wire);\r\n                }\r\n            });\r\n        }\r\n\r\n        function updateProbeInfo() {\r\n            if (!probeMesh || !probeArrow) return;\r\n            \r\n            const pos = probeMesh.position;\r\n            const E = calculateField(pos);\r\n            const Emag = E.length();\r\n            const V = calculatePotential(pos);\r\n            \r\n            document.getElementById('infoPos').textContent = `${pos.x.toFixed(1)}, ${pos.y.toFixed(1)}, ${pos.z.toFixed(1)}`;\r\n            document.getElementById('infoV').textContent = V.toExponential(2);\r\n            document.getElementById('infoEMag').textContent = Emag.toExponential(2);\r\n            document.getElementById('infoEx').textContent = E.x.toExponential(2);\r\n            document.getElementById('infoEy').textContent = E.y.toExponential(2);\r\n            document.getElementById('infoEz').textContent = E.z.toExponential(2);\r\n            \r\n            if (settings.showProbeVector) {\r\n                if (Emag > 100) {\r\n                    probeArrow.visible = true;\r\n                    \r\n                    \/\/ DIRECCI\u00d3N\r\n                    const dir = E.clone().normalize();\r\n                    \r\n                    \/\/ LONGITUD PROPORCIONAL\r\n                    \/\/ Usamos escala logar\u00edtmica para que los cambios sean visibles\r\n                    \/\/ pero no excesivos. F\u00f3rmula: len = log10(E) * factor\r\n                    \/\/ Restamos un offset para que E=100 (1e2) empiece en 0 aprox.\r\n                    const logMag = Math.log10(Emag);\r\n                    let arrowLength = (logMag - 1.5) * 1.2; \r\n                    \r\n                    \/\/ Limitamos estrictamente para que no atraviese la vista\r\n                    arrowLength = Math.max(0.5, Math.min(arrowLength, 5.0));\r\n                    \r\n                    document.getElementById('infoArrowLen').textContent = arrowLength.toFixed(2) + \" uds.\";\r\n                    \r\n                    probeArrow.setDirection(dir);\r\n                    probeArrow.setLength(arrowLength, arrowLength * 0.25, arrowLength * 0.15);\r\n                    \r\n                } else {\r\n                    probeArrow.visible = false;\r\n                    document.getElementById('infoArrowLen').textContent = \"0.00 (Campo d\u00e9bil)\";\r\n                }\r\n            } else {\r\n                probeArrow.visible = false;\r\n            }\r\n        }\r\n\r\n        function updateChargeList() {\r\n            const container = document.getElementById('chargeListContainer');\r\n            container.innerHTML = '';\r\n            \r\n            charges.forEach((c, index) => {\r\n                const div = document.createElement('div');\r\n                div.className = 'charge-item';\r\n                const signClass = c.q > 0 ? 'positive' : 'negative';\r\n                const valMicro = (c.q * 1e6).toFixed(1);\r\n                \r\n                div.innerHTML = `\r\n                    <div class=\"charge-indicator ${signClass}\"><\/div>\r\n                    <input type=\"number\" class=\"charge-input\" value=\"${valMicro}\" step=\"0.5\" data-id=\"${c.id}\">\r\n                    <span style=\"font-size:0.8rem; color:var(--text-secondary)\">\u00b5C<\/span>\r\n                    <button class=\"btn-remove\" data-id=\"${c.id}\">\r\n                        <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\r\n                            <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"><\/line>\r\n                            <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"><\/line>\r\n                        <\/svg>\r\n                    <\/button>\r\n                `;\r\n                container.appendChild(div);\r\n            });\r\n            \r\n            container.querySelectorAll('.charge-input').forEach(input => {\r\n                input.addEventListener('change', (e) => {\r\n                    const id = parseFloat(e.target.dataset.id);\r\n                    const newQ = parseFloat(e.target.value) * 1e-6;\r\n                    updateChargeValue(id, newQ);\r\n                });\r\n            });\r\n            \r\n            container.querySelectorAll('.btn-remove').forEach(btn => {\r\n                btn.addEventListener('click', (e) => {\r\n                    const id = parseFloat(e.currentTarget.dataset.id);\r\n                    removeCharge(id);\r\n                });\r\n            });\r\n        }\r\n\r\n        function loadPreset(num) {\r\n            charges.forEach(c => scene.remove(c.mesh));\r\n            charges = [];\r\n            \r\n            const presets = {\r\n                1: [{ q: 2e-6, x: 0, z: 0 }],\r\n                2: [{ q: 2e-6, x: -2, z: 0 }, { q: -2e-6, x: 2, z: 0 }],\r\n                3: [{ q: 2e-6, x: -2, z: -1 }, { q: 2e-6, x: 2, z: -1 }, { q: -4e-6, x: 0, z: 2 }],\r\n                4: [{ q: 2e-6, x: -2, z: -2 }, { q: -2e-6, x: 2, z: -2 }, { q: 2e-6, x: -2, z: 2 }, { q: -2e-6, x: 2, z: 2 }]\r\n            };\r\n            \r\n            presets[num].forEach(p => addCharge(p.q, p.x, p.z));\r\n            \r\n            document.querySelectorAll('.preset-btn').forEach((btn, i) => {\r\n                btn.classList.toggle('active', i === num - 1);\r\n            });\r\n        }\r\n\r\n        function handleSmoothZoom(event) {\r\n            event.preventDefault();\r\n            \r\n            \/\/ Determinar direcci\u00f3n del zoom\r\n            const zoomDirection = event.deltaY > 0 ? 1 : -1;\r\n            \r\n            \/\/ Calcular nueva distancia objetivo\r\n            let currentDistance = camera.position.length();\r\n            let targetDistance = currentDistance + (zoomDirection * zoomStep);\r\n            \r\n            \/\/ Limitar la distancia (Clamp)\r\n            targetDistance = Math.max(3, Math.min(targetDistance, 40));\r\n            \r\n            goalZoomDistance = targetDistance;\r\n        }\r\n\r\n        function updateSmoothZoom() {\r\n            const currentDistance = camera.position.length();\r\n            \r\n            \/\/ Si ya estamos cerca del objetivo, no hacer nada\r\n            if (Math.abs(currentDistance - goalZoomDistance) < 0.01) return;\r\n            \r\n            \/\/ Interpolar suavemente (Lerp)\r\n            const newDistance = THREE.MathUtils.lerp(currentDistance, goalZoomDistance, zoomLerpFactor);\r\n            \r\n            \/\/ Normalizar y escalar la posici\u00f3n de la c\u00e1mara\r\n            camera.position.normalize().multiplyScalar(newDistance);\r\n        }\r\n\r\n        function setupEventListeners() {\r\n            const canvas = renderer.domElement;\r\n            \r\n            \/\/ Listener custom para el scroll\r\n            canvas.addEventListener('wheel', handleSmoothZoom, { passive: false });\r\n            \r\n            \/\/ Toggles\r\n            document.getElementById('tglFieldLines').addEventListener('click', function() {\r\n                this.classList.toggle('active');\r\n                settings.showFieldLines = this.classList.contains('active');\r\n                fieldLinesGroup.visible = settings.showFieldLines;\r\n            });\r\n            document.getElementById('tglEquipotential').addEventListener('click', function() {\r\n                this.classList.toggle('active');\r\n                settings.showEquipotential = this.classList.contains('active');\r\n                equipotentialGroup.visible = settings.showEquipotential;\r\n            });\r\n            document.getElementById('tglVector').addEventListener('click', function() {\r\n                this.classList.toggle('active');\r\n                settings.showProbeVector = this.classList.contains('active');\r\n                updateProbeInfo();\r\n            });\r\n            document.getElementById('tglProbe').addEventListener('click', function() {\r\n                this.classList.toggle('active');\r\n                settings.showProbe = this.classList.contains('active');\r\n                probeGroup.visible = settings.showProbe;\r\n            });\r\n            \r\n            \/\/ Sliders\r\n            document.getElementById('sldSurface').addEventListener('input', function() {\r\n                settings.surfaceCount = parseInt(this.value);\r\n                document.getElementById('valSurface').textContent = this.value;\r\n                generateEquipotentialSurfaces();\r\n            });\r\n            document.getElementById('sldLines').addEventListener('input', function() {\r\n                settings.lineDensity = parseInt(this.value);\r\n                document.getElementById('valLines').textContent = this.value;\r\n                generateFieldLines();\r\n            });\r\n            \r\n            \/\/ Presets\r\n            document.getElementById('preset1').addEventListener('click', () => loadPreset(1));\r\n            document.getElementById('preset2').addEventListener('click', () => loadPreset(2));\r\n            document.getElementById('preset3').addEventListener('click', () => loadPreset(3));\r\n            document.getElementById('preset4').addEventListener('click', () => loadPreset(4));\r\n            \r\n            \/\/ Botones Add\r\n            document.getElementById('btnAddPos').addEventListener('click', () => addCharge(1e-6, (Math.random()-0.5)*4, (Math.random()-0.5)*4));\r\n            document.getElementById('btnAddNeg').addEventListener('click', () => addCharge(-1e-6, (Math.random()-0.5)*4, (Math.random()-0.5)*4));\r\n            \r\n            \/\/ Reset y Clear\r\n            document.getElementById('btnReset').addEventListener('click', () => {\r\n                camera.position.set(10, 8, 10);\r\n                controls.reset();\r\n                goalZoomDistance = camera.position.length();\r\n            });\r\n            document.getElementById('btnClear').addEventListener('click', () => {\r\n                charges.forEach(c => scene.remove(c.mesh));\r\n                charges = [];\r\n                updateVisualization();\r\n                updateChargeList();\r\n            });\r\n            \r\n            \/\/ Dragging\r\n            canvas.addEventListener('mousedown', (e) => {\r\n                mouse.x = (e.clientX \/ window.innerWidth) * 2 - 1;\r\n                mouse.y = -(e.clientY \/ window.innerHeight) * 2 + 1;\r\n                \r\n                raycaster.setFromCamera(mouse, camera);\r\n                \r\n                const allClickable = charges.map(c => c.mesh).concat([probeMesh]);\r\n                const intersects = raycaster.intersectObjects(allClickable, true);\r\n                \r\n                if (intersects.length > 0) {\r\n                    let obj = intersects[0].object;\r\n                    while(obj.parent && !obj.userData.chargeRef && !obj.userData.isProbe) {\r\n                        obj = obj.parent;\r\n                    }\r\n                    \r\n                    if (obj.userData.chargeRef || obj.userData.isProbe) {\r\n                        isDragging = true;\r\n                        draggedObject = obj;\r\n                        controls.enabled = false;\r\n                    }\r\n                }\r\n            });\r\n            \r\n            canvas.addEventListener('mousemove', (e) => {\r\n                if (!isDragging || !draggedObject) return;\r\n                \r\n                mouse.x = (e.clientX \/ window.innerWidth) * 2 - 1;\r\n                mouse.y = -(e.clientY \/ window.innerHeight) * 2 + 1;\r\n                \r\n                raycaster.setFromCamera(mouse, camera);\r\n                const intersection = new THREE.Vector3();\r\n                \r\n                if (raycaster.ray.intersectPlane(dragPlane, intersection)) {\r\n                    intersection.y = 0;\r\n                    \r\n                    if (draggedObject.userData.isProbe) {\r\n                        draggedObject.position.copy(intersection);\r\n                        updateProbeInfo();\r\n                    } else if (draggedObject.userData.chargeRef) {\r\n                        draggedObject.position.copy(intersection);\r\n                        draggedObject.userData.chargeRef.position.copy(intersection);\r\n                        updateVisualization();\r\n                    }\r\n                }\r\n            });\r\n            \r\n            canvas.addEventListener('mouseup', () => {\r\n                isDragging = false;\r\n                draggedObject = null;\r\n                controls.enabled = true;\r\n            });\r\n        }\r\n\r\n        function onWindowResize() {\r\n            camera.aspect = window.innerWidth \/ window.innerHeight;\r\n            camera.updateProjectionMatrix();\r\n            renderer.setSize(window.innerWidth, window.innerHeight);\r\n        }\r\n\r\n        function animate() {\r\n            requestAnimationFrame(animate);\r\n            \r\n            \/\/ Actualizar zoom suave en cada frame\r\n            updateSmoothZoom();\r\n            \r\n            controls.update();\r\n            renderer.render(scene, camera);\r\n        }\r\n    <\/script>\r\n    \r\n    \r\n    \r\n    \r\n    <style>\r\n  .btn-guia {\r\n    position: fixed;\r\n    bottom: 24px;\r\n    left: 24px;\r\n    z-index: 999;\r\n    background: #3fb950;\r\n    color: #0d1117;\r\n    font-family: 'Space Grotesk', sans-serif;\r\n    font-size: 0.82rem;\r\n    font-weight: 700;\r\n    letter-spacing: 1px;\r\n    text-transform: uppercase;\r\n    padding: 10px 18px;\r\n    border-radius: 8px;\r\n    border: none;\r\n    cursor: pointer;\r\n    box-shadow: 0 4px 20px rgba(63,185,80,0.35);\r\n    transition: transform 0.2s, box-shadow 0.2s;\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 8px;\r\n  }\r\n  .btn-guia:hover {\r\n    transform: translateY(-2px);\r\n    box-shadow: 0 6px 24px rgba(63,185,80,0.5);\r\n  }\r\n  .btn-guia svg { width: 15px; height: 15px; flex-shrink: 0; }\r\n  .guia-panel {\r\n    position: fixed;\r\n    bottom: 72px;\r\n    left: 24px;\r\n    width: 400px;\r\n    max-height: 70vh;\r\n    z-index: 1000;\r\n    background: #ffffff;\r\n    border: 1px solid #d0d7de;\r\n    border-radius: 12px;\r\n    box-shadow: 0 16px 48px rgba(0,0,0,0.4);\r\n    display: none;\r\n    flex-direction: column;\r\n    overflow: hidden;\r\n    font-family: 'Space Grotesk', sans-serif;\r\n  }\r\n  .guia-panel.visible { display: flex; }\r\n  .guia-header {\r\n    display: flex;\r\n    justify-content: space-between;\r\n    align-items: center;\r\n    padding: 12px 16px;\r\n    border-bottom: 1px solid #d0d7de;\r\n    flex-shrink: 0;\r\n    background: #f6f8fa;\r\n  }\r\n  .guia-header-title {\r\n    display: flex;\r\n    align-items: center;\r\n    gap: 8px;\r\n    font-size: 0.85rem;\r\n    font-weight: 700;\r\n    color: #1f2328;\r\n  }\r\n  .guia-header-title svg { width: 15px; height: 15px; color: #3fb950; }\r\n  .guia-close {\r\n    background: none;\r\n    border: none;\r\n    color: #636c76;\r\n    font-size: 1rem;\r\n    cursor: pointer;\r\n    padding: 2px 7px;\r\n    border-radius: 4px;\r\n    transition: color 0.2s, background 0.2s;\r\n    line-height: 1;\r\n  }\r\n  .guia-close:hover { color: #1f2328; background: rgba(0,0,0,0.06); }\r\n  .guia-body {\r\n    overflow-y: auto;\r\n    padding: 18px 18px 20px;\r\n    color: #1f2328;\r\n    font-size: 0.83rem;\r\n    line-height: 1.65;\r\n    background: #ffffff;\r\n  }\r\n  .guia-body::-webkit-scrollbar { width: 5px; }\r\n  .guia-body::-webkit-scrollbar-track { background: transparent; }\r\n  .guia-body::-webkit-scrollbar-thumb { background: #d0d7de; border-radius: 3px; }\r\n  .guia-section-title {\r\n    font-size: 1rem;\r\n    font-weight: 700;\r\n    color: #1f2328;\r\n    margin: 0 0 12px 0;\r\n    padding-bottom: 8px;\r\n    border-bottom: 1px solid #d0d7de;\r\n  }\r\n  .guia-block { margin-bottom: 14px; }\r\n  .guia-label {\r\n    font-size: 0.72rem;\r\n    text-transform: uppercase;\r\n    letter-spacing: 1px;\r\n    color: #636c76;\r\n    margin-bottom: 4px;\r\n  }\r\n  .guia-text { color: #1f2328; }\r\n  .guia-formula {\r\n    background: #f6f8fa;\r\n    border: 1px solid #d0d7de;\r\n    border-radius: 6px;\r\n    padding: 10px 14px;\r\n    text-align: center;\r\n    font-family: 'JetBrains Mono', monospace;\r\n    font-size: 0.88rem;\r\n    color: #0550ae;\r\n    margin: 10px 0;\r\n  }\r\n  .guia-steps { list-style: none; margin: 0; padding: 0; counter-reset: steps; }\r\n  .guia-steps li {\r\n    counter-increment: steps;\r\n    display: flex;\r\n    gap: 10px;\r\n    margin-bottom: 8px;\r\n    align-items: flex-start;\r\n    color: #1f2328;\r\n  }\r\n  .guia-steps li::before {\r\n    content: counter(steps);\r\n    background: #dafbe1;\r\n    color: #1a7f37;\r\n    font-size: 0.72rem;\r\n    font-weight: 700;\r\n    width: 20px;\r\n    height: 20px;\r\n    border-radius: 50%;\r\n    display: flex;\r\n    align-items: center;\r\n    justify-content: center;\r\n    flex-shrink: 0;\r\n    margin-top: 1px;\r\n    border: 1px solid #1a7f37;\r\n  }\r\n  .guia-result {\r\n    background: #dafbe1;\r\n    border-left: 3px solid #1a7f37;\r\n    border-radius: 0 6px 6px 0;\r\n    padding: 10px 14px;\r\n    color: #1f2328;\r\n    font-size: 0.82rem;\r\n    margin-top: 10px;\r\n  }\r\n  .guia-params {\r\n    background: #f6f8fa;\r\n    border: 1px solid #d0d7de;\r\n    border-radius: 6px;\r\n    padding: 10px 14px;\r\n    font-size: 0.8rem;\r\n    color: #1f2328;\r\n  }\r\n  .guia-params span { color: #0550ae; font-family: 'JetBrains Mono', monospace; }\r\n  .var { font-family: 'JetBrains Mono', monospace; }\r\n  .var.pos { color: #cf222e; }\r\n  .var.neg { color: #0550ae; }\r\n  .var.neu { color: #7d4e00; }\r\n  .var.ok  { color: #1a7f37; }\r\n<\/style>\r\n\r\n<div class=\"guia-panel\" id=\"guiaPanel\">\r\n  <div class=\"guia-header\">\r\n    <div class=\"guia-header-title\">\r\n      <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\"\/><path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\"\/><\/svg>\r\n      Gu\u00eda de uso\r\n    <\/div>\r\n    <button class=\"guia-close\" onclick=\"toggleGuia()\">\u2715<\/button>\r\n  <\/div>\r\n\r\n  <div class=\"guia-body\">\r\n\r\n    <!--\u2605 BORRAR DESDE AQUI \u2605-->\r\n\r\n\r\n<div style=\"font-family: Arial, sans-serif; line-height: 1.6; color: #333;\">\r\n<h3 style=\"color: #0056b3;\"> <strong><span style=\"font-size: 16px; color: #000080;\">Campo El\u00e9ctrico y Potencial El\u00e9ctrico<\/span><\/strong><strong><span style=\"font-size: 16px; color: #000080;\">     <\/span><span style=\"font-size: 16px; color: #ff0000;\"><\/span><\/strong><\/h3>\r\n<span style=\"font-size: 16px;\"><strong>Objetivo:<\/strong> Explorar la relaci\u00f3n geom\u00e9trica y f\u00edsica entre el campo el\u00e9ctrico (vectorial) y el potencial el\u00e9ctrico (escalar), visualizando c\u00f3mo las l\u00edneas de campo son siempre perpendiculares a las superficies equipotenciales.<\/span>\r\n\r\n<span style=\"font-size: 16px;\"><strong>Descripci\u00f3n breve:<\/strong> Simulaci\u00f3n interactiva que permite configurar arreglos de cargas puntuales para observar simult\u00e1neamente el mapa de vectores de campo y el mapa de potencial (gradiente de color o l\u00edneas equipotenciales). Facilita la comprensi\u00f3n de que el campo el\u00e9ctrico apunta en la direcci\u00f3n en la que el potencial disminuye m\u00e1s r\u00e1pidamente, permitiendo identificar regiones de alto y bajo voltaje en torno a las cargas.<\/span>\r\n<div style=\"text-align: center; margin: 20px 0;\"><span style=\"font-size: 16px;\">\\( \\mathbf{E} = -\\nabla V \\)<\/span><\/div>\r\n<span style=\"font-size: 16px;\"><strong>C\u00f3mo usar (pasos):<\/strong><\/span>\r\n<ul style=\"margin-left: 20px;\">\r\n \t<li><span style=\"font-size: 16px;\">Colocar una o m\u00e1s cargas (positivas\/negativas) en el plano de trabajo para crear una configuraci\u00f3n espec\u00edfica (ej. un dipolo).<\/span><\/li>\r\n \t<li><span style=\"font-size: 16px;\">Activar la visualizaci\u00f3n de las \"L\u00edneas de Campo\" para ver la direcci\u00f3n de la fuerza el\u00e9ctrica.<\/span><\/li>\r\n \t<li><span style=\"font-size: 16px;\">Activar la visualizaci\u00f3n de \"Superficies Equipotenciales\" (o usar un sensor de voltaje) para trazar l\u00edneas de igual potencial.<\/span><\/li>\r\n \t<li><span style=\"font-size: 16px;\">Mover un sensor de prueba por el espacio para obtener lecturas num\u00e9ricas de la intensidad del campo (\\(E\\)) y el valor del potencial (\\(V\\)) en puntos espec\u00edficos.<\/span><\/li>\r\n \t<li><span style=\"font-size: 16px;\">Observar c\u00f3mo las l\u00edneas de campo cruzan las l\u00edneas equipotenciales formando siempre \u00e1ngulos de \\(90^\\circ\\).<\/span><\/li>\r\n<\/ul>\r\n<span style=\"font-size: 16px;\"><strong>Par\u00e1metros ajustables:<\/strong> N\u00famero de cargas, valor y signo de cada carga (\\(q\\)), posici\u00f3n de las cargas, visualizaci\u00f3n de malla (grid), mostrar\/ocultar valores de voltaje, mostrar\/ocultar vectores de campo y escala de colores para el potencial.<\/span>\r\n<p style=\"background-color: #f8f9fa; padding: 15px; border-left: 5px solid #0056b3;\"><span style=\"font-size: 16px;\"><strong>Resultados esperados \/ observaciones:<\/strong> Las l\u00edneas de campo nacen en cargas positivas (alto potencial) y mueren en cargas negativas (bajo potencial). Las superficies equipotenciales rodean a las cargas y nunca se cruzan entre s\u00ed. Se verifica visualmente que el campo el\u00e9ctrico es el gradiente negativo del potencial, lo que significa que las cargas positivas \"bajan\" por la pendiente del potencial.<\/span><\/p>\r\n\r\n<\/div>\r\n\r\n\r\n   <!--\u2605 BORRAR HASTA AQUI \u2605-->\r\n\r\n  <\/div>\r\n<\/div>\r\n\r\n<button class=\"btn-guia\" onclick=\"toggleGuia()\">\r\n  <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z\"\/><path d=\"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z\"\/><\/svg>\r\n  Gu\u00eda de uso\r\n<\/button>\r\n\r\n<script>\r\n  function toggleGuia() {\r\n    document.getElementById('guiaPanel').classList.toggle('visible');\r\n  }\r\n<\/script>\r\n\r\n    \r\n    \r\n    \r\n    \r\n    \r\n    \r\n    \r\n    \r\n    \r\n    \r\n<\/body>\r\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>FLUXAR &#8211; Simulacion Fisica Precisa Campo Electrico y Potencial Simulacion interactiva 3D Visualizacion Lineas de campo Superficies Eq. Vector en Sonda Punto de medicion Parametros&hellip;<\/p>\n","protected":false},"author":7,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"class_list":["post-5652","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>campo_electrico_potencial_electrico - F\u00edsica 2<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"campo_electrico_potencial_electrico - F\u00edsica 2\" \/>\n<meta property=\"og:description\" content=\"FLUXAR &#8211; Simulacion Fisica Precisa Campo Electrico y Potencial Simulacion interactiva 3D Visualizacion Lineas de campo Superficies Eq. Vector en Sonda Punto de medicion Parametros&hellip;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/\" \/>\n<meta property=\"og:site_name\" content=\"F\u00edsica 2\" \/>\n<meta property=\"article:modified_time\" content=\"2026-04-18T21:23:25+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data1\" content=\"3 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/index.php\\\/campo_electrico_potencial_electrico\\\/\",\"url\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/index.php\\\/campo_electrico_potencial_electrico\\\/\",\"name\":\"campo_electrico_potencial_electrico - F\u00edsica 2\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/#website\"},\"datePublished\":\"2026-03-07T01:33:21+00:00\",\"dateModified\":\"2026-04-18T21:23:25+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/index.php\\\/campo_electrico_potencial_electrico\\\/#breadcrumb\"},\"inLanguage\":\"es-AR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/index.php\\\/campo_electrico_potencial_electrico\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/index.php\\\/campo_electrico_potencial_electrico\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Inicio\",\"item\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"campo_electrico_potencial_electrico\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/#website\",\"url\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/\",\"name\":\"F\u00edsica 2\",\"description\":\"FICA - UNSL\",\"publisher\":{\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es-AR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/#organization\",\"name\":\"SAC- Secretar\u00eda General FICA\",\"url\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es-AR\",\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/wp-content\\\/uploads\\\/2021\\\/11\\\/SG-Logo.png\",\"contentUrl\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/wp-content\\\/uploads\\\/2021\\\/11\\\/SG-Logo.png\",\"width\":4483,\"height\":1231,\"caption\":\"SAC- Secretar\u00eda General FICA\"},\"image\":{\"@id\":\"https:\\\/\\\/fisica2.fica.unsl.edu.ar\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"campo_electrico_potencial_electrico - F\u00edsica 2","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/","og_locale":"es_ES","og_type":"article","og_title":"campo_electrico_potencial_electrico - F\u00edsica 2","og_description":"FLUXAR &#8211; Simulacion Fisica Precisa Campo Electrico y Potencial Simulacion interactiva 3D Visualizacion Lineas de campo Superficies Eq. Vector en Sonda Punto de medicion Parametros&hellip;","og_url":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/","og_site_name":"F\u00edsica 2","article_modified_time":"2026-04-18T21:23:25+00:00","twitter_card":"summary_large_image","twitter_misc":{"Tiempo de lectura":"3 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/","url":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/","name":"campo_electrico_potencial_electrico - F\u00edsica 2","isPartOf":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#website"},"datePublished":"2026-03-07T01:33:21+00:00","dateModified":"2026-04-18T21:23:25+00:00","breadcrumb":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/#breadcrumb"},"inLanguage":"es-AR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/campo_electrico_potencial_electrico\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Inicio","item":"https:\/\/fisica2.fica.unsl.edu.ar\/"},{"@type":"ListItem","position":2,"name":"campo_electrico_potencial_electrico"}]},{"@type":"WebSite","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#website","url":"https:\/\/fisica2.fica.unsl.edu.ar\/","name":"F\u00edsica 2","description":"FICA - UNSL","publisher":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fisica2.fica.unsl.edu.ar\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es-AR"},{"@type":"Organization","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#organization","name":"SAC- Secretar\u00eda General FICA","url":"https:\/\/fisica2.fica.unsl.edu.ar\/","logo":{"@type":"ImageObject","inLanguage":"es-AR","@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#\/schema\/logo\/image\/","url":"https:\/\/fisica2.fica.unsl.edu.ar\/wp-content\/uploads\/2021\/11\/SG-Logo.png","contentUrl":"https:\/\/fisica2.fica.unsl.edu.ar\/wp-content\/uploads\/2021\/11\/SG-Logo.png","width":4483,"height":1231,"caption":"SAC- Secretar\u00eda General FICA"},"image":{"@id":"https:\/\/fisica2.fica.unsl.edu.ar\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages\/5652","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/comments?post=5652"}],"version-history":[{"count":40,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages\/5652\/revisions"}],"predecessor-version":[{"id":7109,"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/pages\/5652\/revisions\/7109"}],"wp:attachment":[{"href":"https:\/\/fisica2.fica.unsl.edu.ar\/index.php\/wp-json\/wp\/v2\/media?parent=5652"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}