Carta Astral
Albert Boada
Psicoastrología
Persona A
Persona B
Calculando sinastría...
Datos de nacimiento
Calculando carta astral...
Persona A
Persona B
Aspectos cruzados
| A | Aspecto | B | Orbe |
|---|
Neología · Método Boada
Albert Boada · Psicoastrología
Interpretación de Pareja
Generando interpretación...
Si quieres saber más, envía un mail: astrologos.00@gmail.com
⏳ Momento Vital · ¿En qué punto están los amantes?
Calculando momento vital...
Datos de nacimiento
Año de la Revolución Solar
Calculando revolución solar...
Neología · Método Boada
Albert Boada · Psicoastrología
☀️ Revolución Solar · Tu Año Personal
Generando informe anual...
Si quieres saber más, envía un mail: astrologos.00@gmail.com
Datos de nacimiento
Calculando carta nodal...
Posiciones planetarias · Carta Nodal
| ☉ | Planeta | ☌ | Grado Nodal | Casa |
|---|
✨ Registro de Vidas Pasadas
Leyendo el registro del alma...
Posiciones planetarias
| ☉ | Planeta | ☌ | Grado | Casa | R |
|---|
Punto de la Edad
—
Neología · Método Boada
Albert Boada · Psicoastrología
Punto de la Edad · Momento Vital
Analizando tu momento vital...
Si quieres saber más, envía un mail: astrologos.00@gmail.com
Neología · Método Boada
Albert Boada · Psicoastrología
Interpretación Neología
Generando interpretación...
Si quieres saber más, envía un mail: astrologos.00@gmail.com
Neología · Método Boada
Albert Boada · Psicoastrología
' + subtitulo + '
' : ''}
${titulo}
${body}
Si quieres saber más, envía un mail: astrologos.00@gmail.com
`;
const win = window.open('', '_blank');
win.document.open();
win.document.write(html);
win.document.close();
}
// ================================================================
// CARTA NODAL — Método Huber
// ================================================================
async function interpretarNodal() {
if (!window._nodalData) { alert('Primero calcula la carta nodal'); return; }
const nodal = window._nodalData;
const radix = window._lastData;
const nombre = (document.getElementById('nd-name') ? document.getElementById('nd-name').value : '') || 'el consultante';
const SIGN_NAMES_FULL = ['Aries','Tauro','Géminis','Cáncer','Leo','Virgo','Libra','Escorpio','Sagitario','Capricornio','Acuario','Piscis'];
const PLANET_NAMES_FULL = ['Sol','Luna','Mercurio','Venus','Marte','Júpiter','Saturno','Urano','Neptuno','Plutón'];
const NN = nodal.NN_natal;
const nnSign = SIGN_NAMES_FULL[Math.floor(NN / 30)];
const nnDeg = (NN % 30).toFixed(1);
const nnCasa = nodal.planets_nodal.find(p => {
const arc = ((NN - nodal.AC_nodal) % 360 + 360) % 360;
return Math.floor(arc / 30) + 1;
});
const nnHouse = (() => {
const arc = ((NN - nodal.AC_nodal) % 360 + 360) % 360;
return Math.floor(arc / 30) + 1;
})();
const NS = (NN + 180) % 360;
const nsSign = SIGN_NAMES_FULL[Math.floor(NS / 30)];
const nsHouse = (() => {
const arc = ((NS - nodal.AC_nodal) % 360 + 360) % 360;
return Math.floor(arc / 30) + 1;
})();
// Planetas y sus posiciones en la nodal
let planetasDesc = `PLANETAS EN LA CARTA NODAL:\n`;
nodal.planets_nodal.forEach(p => {
const sIdx = Math.floor(p.lon / 30);
const deg = (p.lon % 30).toFixed(1);
planetasDesc += `- ${PLANET_NAMES_FULL[p.idx]}: ${SIGN_NAMES_FULL[sIdx]} ${deg}° · Casa nodal ${p.casa_nodal}\n`;
});
// Aspectos al eje nodal (NN y NS)
let aspectosEje = `ASPECTOS AL EJE NODAL (tensiones y dones kármicos):\n`;
const ASP_NAMES = ['Conjunción','Sextil','Cuadratura','Trígono','Inconjunto','Oposición'];
const ASP_GRADOS = [0, 60, 90, 120, 150, 180];
const ASP_ORBE = [8, 4, 6, 6, 3, 8];
const ASP_TIPO = ['tensión','armonía','tensión','armonía','neutro','armonía'];
nodal.planets_nodal.forEach(p => {
[NN, NS].forEach((nodo, ni) => {
let dis = Math.abs(p.lon - nodo);
if (dis > 180) dis = 360 - dis;
ASP_GRADOS.forEach((aspG, ai) => {
const orb = Math.abs(dis - aspG);
if (orb <= ASP_ORBE[ai]) {
aspectosEje += `- ${PLANET_NAMES_FULL[p.idx]} en ${ASP_NAMES[ai]} con ${ni===0?'Nodo Norte':'Nodo Sur'} (${ASP_TIPO[ai]}, orbe ${orb.toFixed(1)}°)\n`;
}
});
});
});
const userPrompt = `Genera el informe de Vidas Pasadas del Método Boada para ${nombre}.
DATOS DE LA CARTA NODAL:
- Nodo Norte: ${nnSign} ${nnDeg}° · Casa ${nnHouse} (escenario principal de vidas pasadas)
- Nodo Sur: ${nsSign} · Casa ${nsHouse} (misión de esta vida)
${planetasDesc}
${aspectosEje}
Escribe en español. Sigue exactamente la estructura del sistema: EL ALMA QUE LLEGA → QUIÉN FUISTE → LO QUE TRAES → LAS HERIDAS SIN CERRAR → TU MISIÓN EN ESTA VIDA. Sin argot astrológico. Tono cálido, evocador y respetuoso.`;
const section = document.getElementById('nodal-interp-section');
section.style.display = 'block';
document.getElementById('nodal-interp-loading').style.display = 'block';
document.getElementById('nodal-interp-content').innerHTML = '';
document.getElementById('btn-nodal-interp').disabled = true;
document.getElementById('nodal-interp-pdf-wrap').style.display = 'none';
try {
const resp = await fetch('https://xeni-b118678e.base44.app/functions/interpretNeologia', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ system: NODAL_SYSTEM, carta: userPrompt })
});
if (!resp.ok) throw new Error('Error servidor: ' + resp.status);
const result = await resp.json();
if (result.error) throw new Error(result.error);
const texto = result.interpretation || result.text || '';
const html = texto.split('\n').filter(l => l.trim()).map(function(l) {
if (l.startsWith('## ') || l.startsWith('# ')) return '' + l.replace(/^#+\s*/,'') + '
'; if (l.trim().startsWith('**') && l.trim().endsWith('**')) return '' + l.replace(/\*\*/g,'') + '
'; return '' + l.replace(/\*\*(.*?)\*\*/g,'$1') + '
'; }).join(''); document.getElementById('nodal-interp-content').innerHTML = html; window._nodalInterpContent = texto; document.getElementById('nodal-interp-pdf-wrap').style.display = 'block'; } catch(e) { document.getElementById('nodal-interp-content').innerHTML = 'Error: ' + e.message + '
'; } finally { document.getElementById('nodal-interp-loading').style.display = 'none'; document.getElementById('btn-nodal-interp').disabled = false; } } function exportNodalPDF() { const nombre = (document.getElementById('nd-name') ? document.getElementById('nd-name').value : '') || 'consultante'; const texto = window._nodalInterpContent || ''; if (!texto) return; const { jsPDF } = window.jspdf; const doc = new jsPDF({ unit: 'mm', format: 'a4' }); const W = doc.internal.pageSize.getWidth(); const M = 18; let y = 18; // Header doc.setFillColor(106, 27, 154); doc.rect(0, 0, W, 28, 'F'); if (window._logoB64) { try { doc.addImage(window._logoB64, 'PNG', M, 4, 22, 20); } catch(e) {} } doc.setTextColor(255,255,255); doc.setFontSize(13); doc.setFont('helvetica','bold'); doc.text('Registro de Vidas Pasadas', W/2, 12, { align: 'center' }); doc.setFontSize(10); doc.setFont('helvetica','normal'); doc.text(nombre + ' · Método Boada', W/2, 20, { align: 'center' }); y = 36; doc.setTextColor(30,10,50); const lines = texto.split('\n').filter(l => l.trim()); for (const line of lines) { const clean = line.replace(/\*\*/g,'').replace(/^#+\s*/,''); const isTitle = line.startsWith('#') || (line.trim().startsWith('**') && line.trim().endsWith('**')); if (isTitle) { doc.setFontSize(11); doc.setFont('helvetica','bold'); doc.setTextColor(106, 27, 154); } else { doc.setFontSize(9.5); doc.setFont('helvetica','normal'); doc.setTextColor(30,10,50); } const wrapped = doc.splitTextToSize(clean, W - M*2); if (y + wrapped.length * 5 > 280) { doc.addPage(); y = 16; } doc.text(wrapped, M, y); y += wrapped.length * (isTitle ? 6 : 5) + (isTitle ? 2 : 1); } // Footer doc.setFontSize(8); doc.setTextColor(150,100,180); doc.text('Neología · Albert Boada · Psicoastrología', W/2, 290, { align: 'center' }); doc.save('vidas_pasadas_' + nombre.replace(/\s+/g,'_') + '.pdf'); } function resetNodal() { document.getElementById('nodal-wrap').style.display = 'none'; document.getElementById('nodal-form').style.display = 'block'; } async function calcularNodal() { const name = document.getElementById('nd-name').value.trim(); const surname = document.getElementById('nd-surname').value.trim(); const day = parseInt(document.getElementById('nd-day').value); const month = parseInt(document.getElementById('nd-month').value); const year = parseInt(document.getElementById('nd-year').value); const hour = parseInt(document.getElementById('nd-hour').value); const min = parseInt(document.getElementById('nd-min').value); const city = document.getElementById('nd-city').value.trim(); const errEl = document.getElementById('nd-error'); errEl.style.display = 'none'; if (!day || !month || !year || isNaN(hour) || isNaN(min) || !city) { errEl.textContent = 'Por favor, completa todos los campos.'; errEl.style.display = 'block'; return; } document.getElementById('nd-loading').style.display = 'block'; try { const resp = await fetch('https://xeni-b118678e.base44.app/functions/calcChart3', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ day, month, year, hour, minute: min, city }) }); const data = await resp.json(); if (data.error) throw new Error(data.error); document.getElementById('nd-loading').style.display = 'none'; document.getElementById('nodal-form').style.display = 'none'; const nodalData = computeNodalChart(data); const fullName = [name, surname].filter(Boolean).join(' ') || 'Carta Nodal'; document.getElementById('nd-chart-title').textContent = '\u263d Carta Nodal \u00b7 ' + fullName; document.getElementById('nd-chart-sub').textContent = day+'/'+month+'/'+year+' '+String(hour).padStart(2,'0')+':'+String(min).padStart(2,'0')+' \u00b7 '+city; window._nodalData = nodalData; window._lastData = data; drawNodalChart(nodalData, data); fillNodalTable(nodalData, data); fillCrossAxisInfo(nodalData, data); document.getElementById('nodal-wrap').style.display = 'block'; document.getElementById('nodal-interp-section').style.display = 'none'; document.getElementById('nodal-interp-content').innerHTML = ''; } catch(e) { document.getElementById('nd-loading').style.display = 'none'; errEl.textContent = 'Error: ' + e.message; errEl.style.display = 'block'; } } function computeNodalChart(radix) { // El backend devuelve northNode o trueNode const nn_lon = radix.northNode !== undefined ? radix.northNode : radix.trueNode !== undefined ? radix.trueNode : (() => { throw new Error('Nodo Norte no disponible en los datos del backend'); })(); // AC nodal = grado exacto del Nodo Norte en la radix const AC_nodal = nn_lon; // Casas iguales de 30°, empezando desde AC_nodal en sentido directo (antihorario zodiacal) const cusps = []; for (let i = 0; i < 12; i++) { cusps.push(((AC_nodal + i * 30) % 360 + 360) % 360); } // Los planetas NO cambian de posición en el zodíaco — solo se recalcula su casa nodal const planets_nodal = radix.planets.map((p, idx) => { const lon = typeof p === 'object' ? p.lon : p; // Casa nodal: en qué casa de 30° cae este planeta respecto al AC nodal const arcFromAC = ((lon - AC_nodal) % 360 + 360) % 360; const casa = Math.floor(arcFromAC / 30) + 1; return { lon, lon_nodal: lon, casa_nodal: casa, idx }; }); return { AC_nodal, cusps, planets_nodal, AC_natal: radix.houses[0], NN_natal: nn_lon }; } function drawNodalChart(nodal, radix) { const dpr = window.devicePixelRatio || 1; const SZ = Math.min(window.innerWidth, window.innerHeight, 520); const cv = document.getElementById('nd-canvas'); cv.width = SZ * dpr; cv.height = SZ * dpr; cv.style.width = SZ + 'px'; cv.style.height = SZ + 'px'; const ctx = cv.getContext('2d'); ctx.scale(dpr, dpr); const cx = SZ / 2, cy = SZ / 2; const R = SZ / 2 * 0.85; // ── Fórmulas AstroNex NodalChart ──────────────────────────────── // offsets_plan_degree(lon) = (180 - NN) + lon → planetas // get_sign_cusps()[h] = 30*h - offset (offset = 30 - NN%30) // d_radial_lines angle = 180 - sign_cusp → divisiones de signos // get_sign_offsets (glifos) = sign_base + 30*i + 15, pero en HTML = eso - 90 // donde sign_base = (11 - ascIdx)*30 + offset - 90 // get_cross_offset = 180 + NN → cúspides de casas // ───────────────────────────────────────────────────────────────── const NN = nodal.NN_natal; const ascIdx = Math.floor(NN / 30); // índice signo del NN (0=Aries…) const offset = 30 - (NN % 30); // grados hasta siguiente inicio signo // Ángulo canvas de un planeta (longitud zodiacal real) const offPlan = lon => r2a(((180 - NN) + lon + 360) % 360); // Ángulo canvas de una cúspide de casa const offCusp = lon => r2a(((180 + NN) - lon + 360) % 360); // Ángulo canvas de una división de signo (d_radial_lines: 180 - sign_cusp) const offSignDiv = h => r2a(((180 - (30*h - offset)) % 360 + 360) % 360); // Ángulo canvas del centro del glifo del signo i // = centro del sector i = 180 + offset - 30*i - 15 const offSignGlyph = i => r2a(((180 + offset - 30*i - 15) % 360 + 360) % 360); const rvi = R * R_VERYINNER; const ri = R * R_INNER; const rri = R * R_RULEDINNER; const rro = R * R_RULEDOUTER; const rrm = R * R_RULEDMID; const rpl = R * R_PL; const rasp = R * R_ASP; ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, SZ, SZ); // Tinte lila muy suave para distinguir de la radix ctx.fillStyle = 'rgba(180,150,255,0.06)'; ctx.beginPath(); ctx.arc(cx, cy, rro, 0, 2 * PI); ctx.fill(); function circle(r, col, lw) { ctx.beginPath(); ctx.arc(cx, cy, r, 0, 2 * PI); ctx.strokeStyle = col; ctx.lineWidth = lw; ctx.stroke(); } circle(rrm, '#dde', 0.6); circle(rro, '#aab', 0.9); circle(rri, '#aab', 0.9); // Rulers — desde el NN, avanzando en el sentido de offPlan for (let t = 0; t < 360; t++) { const ang = offPlan(NN + t); const o = t % 10 === 0 ? rro * 0.032 : t % 5 === 0 ? rro * 0.020 : rro * 0.008; ctx.beginPath(); ctx.moveTo(cx + rro * Math.cos(ang), cy + rro * Math.sin(ang)); ctx.lineTo(cx + (rro + o) * Math.cos(ang), cy + (rro + o) * Math.sin(ang)); ctx.strokeStyle = '#888'; ctx.lineWidth = t % 10 === 0 ? 1.4 : t % 5 === 0 ? 0.9 : 0.4; ctx.stroke(); const ii = t % 10 === 0 ? rri * 0.034 : t % 5 === 0 ? rri * 0.022 : rri * 0.008; ctx.beginPath(); ctx.moveTo(cx + rri * Math.cos(ang), cy + rri * Math.sin(ang)); ctx.lineTo(cx + (rri - ii) * Math.cos(ang), cy + (rri - ii) * Math.sin(ang)); ctx.strokeStyle = '#888'; ctx.lineWidth = t % 10 === 0 ? 1.4 : t % 5 === 0 ? 0.9 : 0.4; ctx.stroke(); } // Divisiones de signos — AstroNex: angle = 180 - (30*h - offset) for (let h = 0; h < 12; h++) { const ang = offSignDiv(h); ctx.beginPath(); ctx.moveTo(cx + rri * Math.cos(ang), cy + rri * Math.sin(ang)); ctx.lineTo(cx + rro * 1.01 * Math.cos(ang), cy + rro * 1.01 * Math.sin(ang)); ctx.strokeStyle = '#aab'; ctx.lineWidth = 0.6; ctx.stroke(); } // SIGNOS vectoriales — AstroNex get_sign_offsets - 90 (ajuste HTML canvas) const ringH = rro - rri; const signScale = (ringH * 0.80) / 38; const signRad = (rri + rro) / 2; for (let i = 0; i < 12; i++) { const rotRad = offSignGlyph(i); // Signo que aparece en el sector i: orden inverso desde el signo del NN const sigIdx = ((ascIdx - i) % 12 + 12) % 12; const glyph = GLYPHS.signs[SIGN_NAMES[sigIdx]]; if (!glyph) continue; const col = ZCOL[SIGN_EL[sigIdx]]; const ex = glyph.e; const gx = cx + signRad * Math.cos(rotRad), gy = cy + signRad * Math.sin(rotRad); ctx.save(); ctx.translate(gx, gy); ctx.rotate(rotRad + PI / 2); ctx.translate(-(ex[0] + ex[2] / 2) * signScale, -(ex[1] + ex[3] / 2) * signScale); ctx.scale(signScale, signScale); ctx.fillStyle = col; ctx.beginPath(); for (const seg of glyph.p) { const cseg = seg.c; switch (seg.t) { case 0: ctx.moveTo(cseg[0], cseg[1]); break; case 1: ctx.lineTo(cseg[0], cseg[1]); break; case 2: ctx.bezierCurveTo(cseg[0], cseg[1], cseg[2], cseg[3], cseg[4], cseg[5]); break; case 3: ctx.closePath(); break; } } ctx.fill(); ctx.restore(); } // CÚSPIDES — AstroNex get_cross_offset = 180 + NN → offCusp const cfont = CUSP_FONT * rro * MAGICK; const cwidths = [1.4, 0.5, 0.5]; for (let i = 0; i < 12; i++) { const ha = offCusp(nodal.cusps[i]); ctx.beginPath(); ctx.moveTo(cx + rri * Math.cos(ha), cy + rri * Math.sin(ha)); ctx.lineTo(cx + (rri + (rro - rri) * 0.25) * Math.cos(ha), cy + (rri + (rro - rri) * 0.25) * Math.sin(ha)); ctx.strokeStyle = HCOLS[i % 3]; ctx.lineWidth = cwidths[i % 3]; ctx.stroke(); ctx.beginPath(); ctx.moveTo(cx + rro * Math.cos(ha), cy + rro * Math.sin(ha)); ctx.lineTo(cx + rro * 1.055 * Math.cos(ha), cy + rro * 1.055 * Math.sin(ha)); ctx.strokeStyle = HCOLS[i % 3]; ctx.lineWidth = cwidths[i % 3]; ctx.stroke(); const hnum_r = rro * 1.10; const isCardinal = [0, 3, 6, 9].includes(i); ctx.font = isCardinal ? `bold ${cfont * 0.85}px sans-serif` : `bold ${cfont}px Astrodotbasic`; ctx.fillStyle = HCOLS[i % 3]; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.fillText(CNAMES[i], cx + hnum_r * Math.cos(ha), cy + hnum_r * Math.sin(ha)); } // ASPECTOS entre longitudes zodiacales reales de los planetas // NN: en la carta nodal se posiciona con la longitud del AC natal (= offPlan(AC_natal)) // Esto lo coloca en la zona del IC nodal, igual que en AstroNex const AC_natal_lon = nodal.AC_natal; const plons = [...nodal.planets_nodal.map(p => p.lon), AC_natal_lon]; const aspects = []; for (let i = 0; i < plons.length; i++) { for (let j = i + 1; j < plons.length; j++) { let dis = Math.abs(plons[i] - plons[j]); if (dis > 180) dis = 360 - dis; let nsig = Math.floor(dis / 30), orb = dis % 30; if (orb > 20) { nsig++; orb = 30 - orb; } nsig = nsig % 12; const pc1 = PLANCLASS[i] ?? 1, pc2 = PLANCLASS[j] ?? 1, acl = ASPCLASS[nsig]; const o1 = ORBS[pc1][acl], o2 = ORBS[pc2][acl]; if (orb <= o1 * 1.1 || orb <= o2 * 1.1) { aspects.push({ i, j, nsig, p1: offPlan(plons[i]), p2: offPlan(plons[j]), f1: orb / o1, f2: orb / o2, col: ASP_COLS[nsig] }); } } } const gw = aspects.filter(asp => asp.f1 > 1 && asp.f2 > 1); const rest = aspects.filter(asp => !(asp.f1 > 1 && asp.f2 > 1)); const conj = rest.filter(asp => asp.nsig === 0); const uni = rest.filter(asp => asp.nsig !== 0 && (asp.f1 > 1 || asp.f2 > 1)); const fusus = rest.filter(asp => asp.nsig !== 0 && asp.f1 <= 1 && asp.f2 <= 1); const orange = '#e07020'; for (const asp of gw) { const x1=cx+rasp*Math.cos(asp.p1), y1=cy+rasp*Math.sin(asp.p1); const x2=cx+rasp*Math.cos(asp.p2), y2=cy+rasp*Math.sin(asp.p2); ctx.save(); ctx.setLineDash([10,5]); ctx.strokeStyle=asp.col; ctx.lineWidth=0.5; ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); ctx.restore(); } for (const asp of conj) { const x1=cx+rasp*Math.cos(asp.p1), y1=cy+rasp*Math.sin(asp.p1); const x2=cx+rasp*Math.cos(asp.p2), y2=cy+rasp*Math.sin(asp.p2); ctx.save(); ctx.strokeStyle=orange; ctx.lineWidth=2.5; ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke(); ctx.restore(); } for (const asp of uni) { const x1=cx+rasp*Math.cos(asp.p1), y1=cy+rasp*Math.sin(asp.p1); const x2=cx+rasp*Math.cos(asp.p2), y2=cy+rasp*Math.sin(asp.p2); const [sx,sy,ex2,ey2] = asp.f1' + 'DC Nodal (\u2606 Nodo Sur): ' + nsD + '\u00b0 ' + nsS + '
' + 'Casas iguales de 30\u00b0 desde el Nodo Norte. Los planetas mantienen su posici\u00f3n zodiacal exacta.'; }