<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>3D Нейтрон — ПЭММ</title>
<style>
html, body { margin: 0; padding: 0; background-color: #11141a; overflow: hidden; width: 100%; height: 100%; }
</style>
</head>
<body>
<div class="pemm-container-gold" style="max-width: 300px; margin: 20px auto; font-family: 'Roboto', sans-serif; background: #11141a; border: 1px solid #2c3440; border-radius: 8px; padding: 15px; color: #fff; box-shadow: 0 4px 15px rgba(0,0,0,0.5);">
<h3 style="margin-top: 0; text-align: center; color: #ffd700; font-size: 18px;">Строение атома гелия-4:</h3>
<!-- Вставили ваше прецизионное научное описание -->
<p style="font-size: 12px; color: #a0aec0; text-align: justify; margin-bottom: 10px; line-height: 1.4;">
вершины одного тетраэдра — протоны, вершины второго — электроны.
<b>Вращением фигуры мышкой можно превратить её в куб</b> (мезонная шуба протона).
</p>
<div style="position: relative; width: 300px; height: 550px; background: #0b0d11; border-radius: 6px; overflow: hidden;">
<canvas id="pemmCanvas" style="display: block; width: 100%; height: 100%; cursor: move;"></canvas>
</div>
</div>
<script>
(function() {
const canvas = document.getElementById('pemmCanvas');
const ctx = canvas.getContext('2d');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
// Исходная метрика из вашей страницы протона
const fm_scale = 280;
let r_muon = 0.25 * fm_scale; // 35
let r_ball_visual = 45; // Радиус шаров строго 45 из протона
let r_positron = 0.833 * fm_scale;
let dist_muon_center = (2/3) * r_positron;
let scale = dist_muon_center / Math.sqrt(3);
let angleX = 0.4;
let angleY = 0.6;
let isDragging = false;
let previousMousePosition = { x: 0, y: 0 };
// 8 вершин куба с полярной протонно-электронной расцветкой
const vertices = [
{x: -1, y: -1, z: -1, id: '1', col: '#0055ff'},
{x: -1, y: 1, z: -1, id: '2', col: '#d90429'},
{x: -1, y: 1, z: 1, id: '3', col: '#0055ff'},
{x: 1, y: 1, z: -1, id: '4', col: '#0055ff'},
{x: 1, y: 1, z: 1, id: '5', col: '#d90429'},
{x: 1, y: -1, z: -1, id: '6', col: '#d90429'},
{x: 1, y: -1, z: 1, id: '7', col: '#0055ff'},
{x: -1, y: -1, z: 1, id: '8', col: '#d90429'}
];
// Геометрическая сетка звездчатого октаэдра (Полярное разделение)
const stefanoLines = [
// Тетраэдр ЭЛЕКТРОНОВ (Синие связи)
{a: 0, b: 2, col: 'rgba(0, 85, 255, 0.4)'}, {a: 0, b: 3, col: 'rgba(0, 85, 255, 0.4)'}, {a: 0, b: 6, col: 'rgba(0, 85, 255, 0.4)'},
{a: 2, b: 3, col: 'rgba(0, 85, 255, 0.4)'}, {a: 2, b: 6, col: 'rgba(0, 85, 255, 0.4)'}, {a: 3, b: 6, col: 'rgba(0, 85, 255, 0.4)'},
// Тетраэдр ПРОТОНОВ (Красные связи)
{a: 1, b: 4, col: 'rgba(217, 4, 41, 0.4)'}, {a: 1, b: 5, col: 'rgba(217, 4, 41, 0.4)'}, {a: 1, b: 7, col: 'rgba(217, 4, 41, 0.4)'},
{a: 4, b: 5, col: 'rgba(217, 4, 41, 0.4)'}, {a: 4, b: 7, col: 'rgba(217, 4, 41, 0.4)'}, {a: 5, b: 7, col: 'rgba(217, 4, 41, 0.4)'}
];
const beta = Math.PI / 4;
const alpha = Math.atan(Math.sqrt(2));
// Проекция базовых точек куба на вертикальную полярную соосность
const baseCubePoints = vertices.map(v => {
let x1 = v.x * Math.cos(beta) - v.z * Math.sin(beta);
let z1 = v.x * Math.sin(beta) + v.z * Math.cos(beta);
let y2 = v.y * Math.cos(alpha) - z1 * Math.sin(alpha);
let z2 = v.y * Math.sin(alpha) + z1 * Math.cos(alpha);
return { x: x1, y: y2, z: z2, col: v.col, label: v.id };
});
canvas.addEventListener('mousedown', e => {
isDragging = true;
previousMousePosition = { x: e.clientX, y: e.clientY };
});
window.addEventListener('mouseup', () => isDragging = false);
canvas.addEventListener('mousemove', e => {
if (isDragging) {
const deltaX = e.clientX - previousMousePosition.x;
const deltaY = e.clientY - previousMousePosition.y;
angleY += deltaX * 0.01;
angleX += deltaY * 0.01;
previousMousePosition = { x: e.clientX, y: e.clientY };
}
});
function project(vertex, angleX, angleY, cx, cy) {
let x1 = vertex.x * Math.cos(angleY) - vertex.z * Math.sin(angleY);
let z1 = vertex.x * Math.sin(angleY) + vertex.z * Math.cos(angleY);
let y2 = vertex.y * Math.cos(angleX) - z1 * Math.sin(angleX);
let z2 = vertex.y * Math.sin(angleX) + z1 * Math.cos(angleX);
return { x: cx + x1 * scale, y: cy + y2 * scale, z: z2, id: vertex.label, col: vertex.col };
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const projected = baseCubePoints.map(v => project(v, angleX, angleY, cx, cy));
// 1. ОТРИСОВКА РЁБЕР ЗВЕЗДЧАТОГО КАРКАСА ( Stella Octangula )
ctx.lineWidth = 1.2;
stefanoLines.forEach(l => {
ctx.beginPath();
ctx.moveTo(projected[l.a].x, projected[l.a].y);
ctx.lineTo(projected[l.b].x, projected[l.b].y);
ctx.strokeStyle = l.col;
ctx.stroke();
});
// Направляющая полярная вертикальная ось через пустой центр
if (projected && projected) {
ctx.beginPath();
ctx.moveTo(projected.x, projected.y);
ctx.lineTo(projected.x, projected.y);
ctx.strokeStyle = 'rgba(255, 255, 255, 0.18)';
ctx.lineWidth = 1;
ctx.stroke();
}
// 2. СОРТИРОВКА Z-БУФЕРА ДЛЯ НЕПРОЗРАЧНОГО НАЛОЖЕНИЯ
let sortedMuons = projected.map((p, i) => ({p: p, i: i}));
sortedMuons.sort((a, b) => b.p.z - a.p.z);
// 3. ВЫВОД СИЛОВЫХ ВЕКТОРОВ И СФЕР КАРКАСА
sortedMuons.forEach(item => {
let p = item.p;
// ИЗМЕНЕНО: Непрозрачность цвета векторов поднята до 100% (1.0), толщина увеличена до 2.5
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(cx + (p.x - cx) * 2.8, cy + (p.y - cy) * 2.8);
ctx.strokeStyle = p.col === '#0055ff' ? 'rgba(0, 85, 255, 1.0)' : 'rgba(217, 4, 41, 1.0)';
ctx.lineWidth = 2.5;
ctx.stroke();
// Отрисовка плотных сфер из протона (Радиус 45, диаметр 90)
ctx.beginPath();
ctx.arc(p.x, p.y, r_ball_visual, 0, 2 * Math.PI);
// Оригинальный расчет блика радиального градиента из протона
let mG = ctx.createRadialGradient(p.x - r_muon * 0.2, p.y - r_muon * 0.2, r_muon * 0.1, p.x, p.y, r_ball_visual);
if (p.col === '#0055ff') {
mG.addColorStop(0, '#66fcf1'); // Электрон блик
mG.addColorStop(0.5, '#0055ff');
mG.addColorStop(1, '#001155');
} else {
mG.addColorStop(0, '#ff8787'); // Протон блик
mG.addColorStop(0.5, '#d90429');
mG.addColorStop(1, '#5c0f0f');
}
ctx.fillStyle = mG;
ctx.fill();
ctx.strokeStyle = 'rgba(255,255,255,0.25)';
ctx.lineWidth = 1;
ctx.stroke();
// Номера оригинальных векторов (1-8)
ctx.fillStyle = '#ffffff';
ctx.font = 'bold 10px sans-serif';
ctx.textAlign = 'center';
ctx.fillText(p.id, p.x, p.y + 3.5);
});
// Плавное автоматическое вращение вокруг полярной оси Y
if (!isDragging) { angleY += 0.002; }
requestAnimationFrame(draw);
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
draw();
})();
</script>
</body>
</html>