Home › DNA 3D Viewer
⚠️ Research Use Only. Not validated for clinical diagnostic use. 3D structures are predictions and require experimental validation.
3D DNA Structure Viewer
Input any DNA sequence — select A, B, or Z-DNA — visualize the 3D helix structure in real time.
Drag to rotate · Scroll to zoom · Right-click to pan · Click atoms to measure distance
View:
Default
Major Groove
Minor Groove
Top-Down
Side
Measure:
Distance
Reset
Understanding DNA Helix Structures
DNA exists in three major conformations depending on the environmental conditions. The 3D viewer above generates real coordinates using standard helix parameters from Saenger (1984), allowing you to visualize the differences between A-DNA, B-DNA, and Z-DNA directly in your browser.
🔬
B-DNA (Physiological)
The most common form found in living cells. Right-handed helix with 10.5 base pairs per turn, 3.4 Å rise per bp, and 10.0 Å radius. Features asymmetric major and minor grooves.
🧫
A-DNA (Dehydrated)
Found under dehydrated conditions. Wider (11.5 Å radius) with 11 bp per turn and 2.6 Å rise. The major groove is deep and narrow; the minor groove is wide and shallow.
⟳
Z-DNA (Left-Handed)
A left-handed helix that forms in GC-rich regions under high salt conditions. Narrower (9.0 Å) with 12 bp per turn. Associated with gene regulation and chromatin remodeling.
The double helix is held together by hydrogen bonds between complementary base pairs: A pairs with T through two hydrogen bonds, while G pairs with C through three. The aromatic bases stack vertically through pi-pi interactions, stabilizing the helix interior. The major groove (wider) is where most DNA-binding proteins read the sequence, while the minor groove (narrower) is targeted by small-molecule binders.
×
Sign in
Access your VigyanLLM account
Don't have an account? Register
// ─── STATE ────────────────────────────────────────
let viewer = null;
let currentData = null;
// ─── INIT ──────────────────────────────────────────
function initViewer() {
// DNA type selector
document.querySelectorAll('.dna-type-btn').forEach(btn => {
btn.addEventListener('click', function() {
document.querySelectorAll('.dna-type-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
updateStats();
});
});
// Build button
document.getElementById('buildBtn').addEventListener('click', buildStructure);
// Input changes update stats
document.getElementById('seqInput').addEventListener('input', updateStats);
// Toggle changes re-render if structure exists
['showBackbone','showBases','showHbonds','showLabels','showPrimerHL'].forEach(id => {
document.getElementById(id).addEventListener('change', function() {
if (currentData) buildStructure();
});
});
// Style/color changes re-render
document.getElementById('styleSelect').addEventListener('change', function() {
if (currentData) buildStructure();
});
document.getElementById('colorSelect').addEventListener('change', function() {
if (currentData) buildStructure();
});
// Mobile menu
var ham = document.getElementById('hamburger');
var mm = document.getElementById('mobile-menu');
if (ham) ham.addEventListener('click', function() {
this.classList.toggle('active');
mm.classList.toggle('open');
});
// Initial stats
updateStats();
// Auto-build — wait for 3Dmol to load
waitFor3Dmol();
}
function waitFor3Dmol() {
if (typeof $3Dmol !== 'undefined') {
buildStructure();
} else {
setTimeout(waitFor3Dmol, 100);
}
}
document.addEventListener('DOMContentLoaded', initViewer);
// ─── UPDATE STATS ──────────────────────────────────
function updateStats() {
var seq = document.getElementById('seqInput').value.toUpperCase().replace(/[^ATGC]/g, '');
var dnaType = getSelectedType();
var params = window.DNAViewer.DNA_TYPES[dnaType];
var gc = seq.length > 0 ? Math.round((seq.split('').filter(b => b==='G'||b==='C').length / seq.length) * 100) : 0;
var turns = seq.length > 0 ? (seq.length / params.basesPerTurn).toFixed(1) : '0';
document.getElementById('statLen').textContent = seq.length;
document.getElementById('statGC').textContent = gc + '%';
document.getElementById('statTurns').textContent = turns;
}
function getSelectedType() {
var active = document.querySelector('.dna-type-btn.active');
return active ? active.getAttribute('data-type') : 'B-DNA';
}
// ─── BUILD STRUCTURE ──────────────────────────────
function buildStructure() {
var seq = document.getElementById('seqInput').value;
var dnaType = getSelectedType();
var fwd = document.getElementById('fwdPrimer').value;
var rev = document.getElementById('revPrimer').value;
var errEl = document.getElementById('errorMsg');
errEl.style.display = 'none';
// Validate sequence
var val = window.DNAViewer.validateSequence(seq);
if (!val.valid) {
errEl.textContent = val.error;
errEl.style.display = 'block';
return;
}
// Validate primers
if (fwd) {
var fwdVal = window.DNAViewer.validatePrimer(fwd, val.cleaned);
if (!fwdVal.valid) {
errEl.textContent = 'Forward primer: ' + fwdVal.error;
errEl.style.display = 'block';
return;
}
}
if (rev) {
var revVal = window.DNAViewer.validatePrimer(rev, val.cleaned);
if (!revVal.valid) {
errEl.textContent = 'Reverse primer: ' + revVal.error;
errEl.style.display = 'block';
return;
}
}
try {
currentData = window.DNAViewer.generatePDB(val.cleaned, dnaType, fwd, rev);
renderViewer();
showStats();
updateStats();
} catch (e) {
errEl.textContent = 'Error generating structure: ' + e.message;
errEl.style.display = 'block';
console.error('DNA generation error:', e);
}
}
// ─── RENDER VIEWER ────────────────────────────────
function renderViewer() {
var container = document.getElementById('viewer-3d');
container.innerHTML = '';
try {
viewer = $3Dmol.createViewer(container, {
backgroundColor: '#0a0a1a',
antialias: true,
disableFog: true
});
// Add PDB model
var model = viewer.addModel(currentData.pdb, 'pdb');
// Apply style
applyStyle(model);
// Center and zoom — use viewportProperty for auto-fit
viewer.zoomTo();
// Rotate to show helix from side view
viewer.rotate(90, 'y');
viewer.zoom(1.6);
viewer.render();
// Resize handler
window.addEventListener('resize', function() {
if (viewer) {
var w = container.clientWidth;
var h = container.clientHeight;
viewer.resize();
viewer.render();
}
});
} catch (e) {
console.error('3Dmol.js init failed:', e);
container.innerHTML = '🧬
3D rendering requires WebGL
Try Chrome, Firefox, or Safari
';
}
}
// ─── APPLY STYLE ───────────────────────────────────
function applyStyle(model) {
if (!viewer || !currentData) return;
var style = document.getElementById('styleSelect').value;
var colorBy = document.getElementById('colorSelect').value;
var showBB = document.getElementById('showBackbone').checked;
var showBP = document.getElementById('showBases').checked;
var showLBL = document.getElementById('showLabels').checked;
var showPH = document.getElementById('showPrimerHL').checked;
// Clear everything
viewer.setStyle({}, {});
viewer.removeAllLabels();
var baseColors = { A: '#3B82F6', T: '#EF4444', G: '#22C55E', C: '#EAB308' };
// Determine atom style based on mode
var atomStyle;
if (style === 'stick') {
atomStyle = { stick: { radius: 0.25, colorscheme: 'Jmol' } };
} else if (style === 'line') {
atomStyle = { line: { linewidth: 3, colorscheme: 'Jmol' } };
} else if (style === 'cartoon') {
atomStyle = { cartoon: { color: 'spectrum', opacity: 0.95, tubes: true } };
} else {
atomStyle = { sphere: { scale: 0.5, colorscheme: 'Jmol' }, stick: { radius: 0.18, colorscheme: 'Jmol' } };
}
// Apply base style to all atoms
viewer.setStyle({}, atomStyle);
// Override backbone atoms (P and sugar) if backbone toggle is on
if (showBB) {
var bbAtoms = { atom: ['P', "C4'"] };
var bbStyle;
if (style === 'stick') {
bbStyle = { stick: { radius: 0.3, color: '#c8c8d4' } };
} else if (style === 'line') {
bbStyle = { line: { color: '#c8c8d4', linewidth: 3.5 } };
} else if (style === 'cartoon') {
bbStyle = { cartoon: { color: '#c8c8d4', opacity: 0.95, tubes: true } };
} else {
bbStyle = { sphere: { scale: 0.65, color: '#c8c8d4' }, stick: { radius: 0.2, color: '#a8a8b4' } };
}
viewer.setStyle(bbAtoms, bbStyle);
}
// Override colors based on color mode
if (colorBy === 'base') {
['A','T','G','C'].forEach(function(base) {
var sel = { resn: base };
var s;
if (style === 'stick') s = { stick: { radius: 0.25, color: baseColors[base] } };
else if (style === 'line') s = { line: { color: baseColors[base], linewidth: 3 } };
else s = { sphere: { scale: 0.5, color: baseColors[base] }, stick: { radius: 0.18, color: baseColors[base] } };
viewer.setStyle(sel, s);
});
} else if (colorBy === 'strand') {
var s1, s2;
if (style === 'stick') {
s1 = { stick: { radius: 0.25, color: '#22D3EE' } };
s2 = { stick: { radius: 0.25, color: '#F97316' } };
} else if (style === 'line') {
s1 = { line: { color: '#22D3EE', linewidth: 3 } };
s2 = { line: { color: '#F97316', linewidth: 3 } };
} else {
s1 = { sphere: { scale: 0.5, color: '#22D3EE' }, stick: { radius: 0.18, color: '#22D3EE' } };
s2 = { sphere: { scale: 0.5, color: '#F97316' }, stick: { radius: 0.18, color: '#F97316' } };
}
viewer.setStyle({ chain: 'A' }, s1);
viewer.setStyle({ chain: 'B' }, s2);
} else if (colorBy === 'region') {
// Default uniform color
var us;
if (style === 'stick') us = { stick: { radius: 0.25, color: '#94A3B8' } };
else if (style === 'line') us = { line: { color: '#94A3B8', linewidth: 3 } };
else us = { sphere: { scale: 0.5, color: '#94A3B8' }, stick: { radius: 0.18, color: '#94A3B8' } };
viewer.setStyle({}, us);
// Primer highlights (most specific — apply last)
if (showPH && currentData.fwdRange) {
var ps;
if (style === 'stick') ps = { stick: { radius: 0.35, color: '#F59E0B' } };
else ps = { sphere: { scale: 0.7, color: '#F59E0B' }, stick: { radius: 0.25, color: '#F59E0B' } };
for (var i = currentData.fwdRange[0]; i <= currentData.fwdRange[1]; i++) {
viewer.setStyle({ chain: 'A', resi: i + 1 }, ps);
}
}
if (showPH && currentData.revRange) {
var rs;
if (style === 'stick') rs = { stick: { radius: 0.35, color: '#EF4444' } };
else rs = { sphere: { scale: 0.7, color: '#EF4444' }, stick: { radius: 0.25, color: '#EF4444' } };
for (var i = currentData.revRange[0]; i <= currentData.revRange[1]; i++) {
viewer.setStyle({ chain: 'B', resi: currentData.sequence.length - i }, rs);
}
}
}
// Labels
if (showLBL) {
var seqUpper = currentData.sequence;
for (var i = 0; i < Math.min(seqUpper.length, 200); i += 2) {
var z = i * currentData.params.rise;
var theta = i * (currentData.params.twist * Math.PI / 180);
var r = currentData.params.radius - 5.5;
var x = r * Math.cos(theta);
var y = r * Math.sin(theta);
viewer.addLabel(seqUpper[i], {
position: { x: x, y: y, z: z },
fontSize: 14,
fontColor: baseColors[seqUpper[i]] || '#ffffff',
backgroundColor: 'rgba(0,0,0,0.7)',
backgroundOpacity: 0.7,
padding: 3,
borderRadius: 4,
font: 'arial'
});
}
}
viewer.render();
}
// ─── VIEW PRESETS ──────────────────────────────────
function setView(preset) {
if (!viewer) return;
viewer.zoomTo();
switch (preset) {
case 'default':
viewer.rotate(90, 'y');
viewer.zoom(1.6);
break;
case 'major':
viewer.rotate(45, 'y');
viewer.zoom(1.4);
break;
case 'minor':
viewer.rotate(-45, 'y');
viewer.zoom(1.4);
break;
case 'top':
viewer.rotate(0, 'y');
viewer.rotate(90, 'x');
viewer.zoom(1.6);
break;
case 'side':
viewer.rotate(90, 'y');
viewer.zoom(1.6);
break;
}
viewer.render();
}
function resetView() {
if (viewer) {
viewer.zoomTo();
viewer.rotate(90, 'y');
viewer.zoom(1.6);
viewer.render();
}
}
// ─── MEASURE ───────────────────────────────────────
function toggleMeasure() {
alert('Click-to-measure: select two atoms to measure distance in Å. Coming soon!');
}
// ─── STATS DISPLAY ────────────────────────────────
function showStats() {
if (!currentData) return;
document.getElementById('statsBar').style.display = 'grid';
document.getElementById('sLength').textContent = currentData.stats.helixLength;
document.getElementById('sTurns').textContent = currentData.stats.turns;
document.getElementById('sAtoms').textContent = currentData.stats.totalAtoms;
document.getElementById('sType').textContent = currentData.dnaType;
document.getElementById('sFwdPrimer').textContent = currentData.stats.fwdPrimer || '—';
document.getElementById('sRevPrimer').textContent = currentData.stats.revPrimer || '—';
}
// ─── EXPORT ────────────────────────────────────────
function exportPNG() {
if (!viewer) return;
try {
var png = viewer.pngURI();
var link = document.createElement('a');
link.download = 'dna-structure-' + getSelectedType().replace('-','') + '.png';
link.href = png;
link.click();
} catch (e) {
console.error('PNG export failed:', e);
alert('PNG export failed. Try a different browser.');
}
}
function exportPDB() {
if (!currentData) return;
try {
var blob = new Blob([currentData.pdb], { type: 'text/plain' });
var link = document.createElement('a');
link.download = 'dna-structure-' + getSelectedType().replace('-','') + '.pdb';
link.href = URL.createObjectURL(blob);
link.click();
URL.revokeObjectURL(link.href);
} catch (e) {
console.error('PDB export failed:', e);
}
}