Created
August 29, 2025 13:58
-
-
Save 0187773933/678d64f401ff92c68cfd6fc81a5ef199 to your computer and use it in GitHub Desktop.
Human Neurobiology - Lab 2
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Human Neurobio - Lab 2</title> | |
<style> | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
min-height: 100vh; | |
padding: 20px; | |
} | |
.container { | |
max-width: 1200px; | |
margin: 0 auto; | |
background: rgba(255, 255, 255, 0.95); | |
border-radius: 20px; | |
padding: 30px; | |
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); | |
} | |
h1 { | |
text-align: center; | |
color: #764ba2; | |
margin-bottom: 10px; | |
font-size: 2.5em; | |
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); | |
} | |
.subtitle { | |
text-align: center; | |
color: #666; | |
margin-bottom: 30px; | |
font-size: 1.1em; | |
} | |
.controls { | |
display: flex; | |
gap: 20px; | |
margin-bottom: 30px; | |
flex-wrap: wrap; | |
justify-content: center; | |
align-items: center; | |
} | |
.input-group { | |
display: flex; | |
gap: 10px; | |
flex: 1; | |
min-width: 300px; | |
max-width: 500px; | |
} | |
input[type="text"] { | |
flex: 1; | |
padding: 12px 20px; | |
border: 2px solid #ddd; | |
border-radius: 10px; | |
font-size: 16px; | |
transition: all 0.3s; | |
} | |
input[type="text"]:focus { | |
outline: none; | |
border-color: #667eea; | |
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); | |
} | |
button { | |
padding: 12px 24px; | |
border: none; | |
border-radius: 10px; | |
font-size: 16px; | |
font-weight: 600; | |
cursor: pointer; | |
transition: all 0.3s; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
.submit-btn { | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
color: white; | |
} | |
.submit-btn:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2); | |
} | |
.toggle-btn { | |
background: #ff6b6b; | |
color: white; | |
} | |
.toggle-btn:hover { | |
background: #ff5252; | |
} | |
.reset-btn { | |
background: #48dbfb; | |
color: white; | |
} | |
.reset-btn:hover { | |
background: #0abde3; | |
} | |
.stats { | |
display: flex; | |
gap: 20px; | |
margin-bottom: 20px; | |
justify-content: center; | |
flex-wrap: wrap; | |
} | |
.stat-card { | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
color: white; | |
padding: 15px 25px; | |
border-radius: 10px; | |
text-align: center; | |
min-width: 150px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
} | |
.stat-label { | |
font-size: 0.9em; | |
opacity: 0.9; | |
margin-bottom: 5px; | |
} | |
.stat-value { | |
font-size: 1.8em; | |
font-weight: bold; | |
} | |
.sections-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
gap: 20px; | |
margin-top: 20px; | |
} | |
.section { | |
background: white; | |
border-radius: 15px; | |
padding: 20px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
transition: transform 0.3s; | |
} | |
.section:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15); | |
} | |
.section-title { | |
font-size: 1.2em; | |
font-weight: bold; | |
color: #764ba2; | |
margin-bottom: 15px; | |
padding-bottom: 10px; | |
border-bottom: 2px solid #f0f0f0; | |
} | |
.items-list { | |
list-style: none; | |
} | |
.item { | |
padding: 8px 12px; | |
margin: 5px 0; | |
border-radius: 8px; | |
transition: all 0.3s; | |
position: relative; | |
overflow: hidden; | |
} | |
.item.found { | |
background: linear-gradient(135deg, #55efc4 0%, #00b894 100%); | |
color: white; | |
animation: slideIn 0.5s ease-out; | |
} | |
.item.hidden { | |
background: #f0f0f0; | |
color: transparent; | |
user-select: none; | |
position: relative; | |
cursor: text; | |
} | |
.item.hidden input { | |
width: 100%; | |
background: transparent; | |
border: none; | |
padding: 0; | |
font-size: inherit; | |
font-family: inherit; | |
color: #333; | |
outline: none; | |
} | |
.item.hidden input::placeholder { | |
color: #ccc; | |
} | |
.item.hidden.incorrect { | |
animation: shake 0.3s; | |
} | |
@keyframes shake { | |
0%, 100% { transform: translateX(0); } | |
25% { transform: translateX(-5px); } | |
75% { transform: translateX(5px); } | |
} | |
@keyframes slideIn { | |
from { | |
opacity: 0; | |
transform: translateX(-20px); | |
} | |
to { | |
opacity: 1; | |
transform: translateX(0); | |
} | |
} | |
.feedback { | |
position: fixed; | |
top: 20px; | |
right: 20px; | |
padding: 15px 25px; | |
border-radius: 10px; | |
color: white; | |
font-weight: 600; | |
z-index: 1000; | |
animation: slideInRight 0.5s ease-out; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); | |
} | |
.feedback.success { | |
background: linear-gradient(135deg, #55efc4 0%, #00b894 100%); | |
} | |
.feedback.error { | |
background: linear-gradient(135deg, #ff6b6b 0%, #ee5a24 100%); | |
} | |
.feedback.info { | |
background: linear-gradient(135deg, #48dbfb 0%, #0abde3 100%); | |
} | |
@keyframes slideInRight { | |
from { | |
opacity: 0; | |
transform: translateX(100px); | |
} | |
to { | |
opacity: 1; | |
transform: translateX(0); | |
} | |
} | |
.completion-message { | |
text-align: center; | |
padding: 30px; | |
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); | |
color: white; | |
border-radius: 15px; | |
margin-top: 20px; | |
font-size: 1.5em; | |
font-weight: bold; | |
animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0%, 100% { | |
transform: scale(1); | |
} | |
50% { | |
transform: scale(1.02); | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>🧠 Human Neurobiology - Lab 2</h1> | |
<div class="stats"> | |
<div class="stat-card"> | |
<div class="stat-label">Progress</div> | |
<div class="stat-value" id="progress">0/73</div> | |
</div> | |
<div class="stat-card"> | |
<div class="stat-label">Percentage</div> | |
<div class="stat-value" id="percentage">0%</div> | |
</div> | |
</div> | |
<div class="controls"> | |
<div class="input-group"> | |
<input type="text" id="answerInput" placeholder="Type an anatomical structure..." autofocus> | |
</div> | |
<button class="toggle-btn" id="toggleBtn" onclick="toggleAnswers()">Show All</button> | |
<button class="reset-btn" onclick="resetGame()">Reset</button> | |
</div> | |
<div id="completionMessage" style="display: none;" class="completion-message"> | |
🎉 Congratulations! You've completed all items! 🎉 | |
</div> | |
<div class="sections-grid" id="sectionsGrid"></div> | |
</div> | |
<script> | |
const studyData = { | |
"5 Lobes of Cerebrum": [ | |
"Frontal lobe", | |
"Parietal lobe", | |
"Temporal lobe", | |
"Occipital lobe", | |
"Limbic lobe" | |
], | |
"Subdivisions of Frontal lobe": [ | |
"Precentral gyrus and sulcus", | |
"Superior frontal gyrus", | |
"Middle frontal gyrus", | |
"Inferior frontal gyrus", | |
"Anterior paracentral lobule", | |
"Superior frontal sulci" , | |
"Inferior frontal sulci" | |
], | |
"Subdivisions of Parietal lobe": [ | |
"Intraparietal sulcus", | |
"Superior parietal lobule", | |
"Angular gyrus", | |
"Supramarginal gyrus", | |
"Precuneus", | |
"Postcentral gyrus", | |
"Postcentral sulcus", | |
"Posterior paracentral lobule" | |
], | |
"Subdivisions of Occipital lobe": [ | |
"Cuneus", | |
"Occipitotemporal gyrus" , | |
"Lateral occipital gyri", | |
"Lingual gyrus", | |
], | |
"Subdivisions of Temporal lobe": [ | |
"Occipitotemporal sulcus" , | |
"Superior temporal gyri" , | |
"Middle temporal gyri" , | |
"Inferior temporal gyri", | |
"Superior temporal sulci", | |
"Inferior temporal sulci", | |
], | |
"Limbic lobe": [ | |
"Cingulate gyrus", | |
"Uncus" , | |
"Parahippocampal gyrus", | |
], | |
"Fissures and Sulci": [ | |
"Longitudinal fissure", | |
"Central sulcus", | |
"Lateral sulcus", | |
"Preoccipital notch", | |
"Parietooccipital sulcus", | |
"Cingulate sulcus", | |
"Collateral sulcus" | |
], | |
"Insula cortex": [ | |
"Parietal operculae" , | |
"Temporal operculae" , | |
"Frontal operculae" | |
], | |
"Meninges": [ | |
"Dura mater", | |
"Arachnoid mater", | |
"Subarachnoid space", | |
"Pia mater" | |
], | |
"Functional Areas": [ | |
"Broca", | |
"Wernicke", | |
"Primary motor cortex", | |
"Premotor area", | |
"Prefrontal cortex", | |
"Primary auditory cortex", | |
"Auditory association area", | |
"Primary visual cortex", | |
"Visual association area", | |
"Primary somatosensory cortex", | |
"Somatosensory association area" | |
] | |
}; | |
let foundItems = new Set(); | |
let showingAnswers = false; | |
function normalizeAnswer(answer) { | |
return answer.toLowerCase() | |
.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, "") | |
.replace(/\s+/g, " ") | |
.trim(); | |
} | |
function initializeGame() { | |
renderSections(); | |
updateStats(); | |
} | |
function renderSections() { | |
const grid = document.getElementById('sectionsGrid'); | |
grid.innerHTML = ''; | |
for (const [section, items] of Object.entries(studyData)) { | |
const sectionDiv = document.createElement('div'); | |
sectionDiv.className = 'section'; | |
const title = document.createElement('div'); | |
title.className = 'section-title'; | |
title.textContent = section; | |
const list = document.createElement('ul'); | |
list.className = 'items-list'; | |
items.forEach((item, index) => { | |
const li = document.createElement('li'); | |
li.className = 'item'; | |
li.dataset.item = normalizeAnswer(item); | |
li.dataset.answer = item; | |
li.dataset.index = index; | |
li.dataset.section = section; | |
if (foundItems.has(normalizeAnswer(item))) { | |
li.classList.add('found'); | |
li.textContent = item; | |
} else { | |
li.classList.add('hidden'); | |
// Create input field for direct typing | |
const input = document.createElement('input'); | |
input.type = 'text'; | |
input.placeholder = '???'; | |
input.dataset.index = index; | |
input.dataset.section = section; | |
// Check answer on every keystroke | |
const checkDirectAnswer = () => { | |
const userAnswer = normalizeAnswer(input.value); | |
if (!userAnswer) return; | |
// Check if answer belongs to this section | |
const sectionItems = items.map(i => normalizeAnswer(i)); | |
let foundItem = null; | |
for (let i = 0; i < items.length; i++) { | |
if (normalizeAnswer(items[i]) === userAnswer && !foundItems.has(userAnswer)) { | |
foundItem = items[i]; | |
break; | |
} | |
} | |
if (foundItem) { | |
foundItems.add(normalizeAnswer(foundItem)); | |
// Find the correct li element for this item and update it | |
const allLis = list.querySelectorAll('.item'); | |
allLis.forEach(li => { | |
if (normalizeAnswer(li.dataset.answer) === normalizeAnswer(foundItem)) { | |
li.classList.remove('hidden'); | |
li.classList.add('found'); | |
li.textContent = foundItem; | |
} | |
}); | |
showFeedback('success', `Correct! Found "${foundItem}"`); | |
updateStats(); | |
checkCompletion(); | |
// Clear this input and move to next | |
input.value = ''; | |
setTimeout(() => { | |
const nextInput = findNextInput(input); | |
if (nextInput) { | |
nextInput.focus(); | |
} | |
}, 100); | |
} | |
}; | |
// Real-time checking on input | |
input.addEventListener('input', checkDirectAnswer); | |
// Handle special keys | |
input.addEventListener('keydown', (e) => { | |
if (e.key === 'Enter') { | |
e.preventDefault(); | |
const nextInput = findNextInput(input); | |
if (nextInput) { | |
nextInput.focus(); | |
} | |
} else if (e.key === 'ArrowDown') { | |
e.preventDefault(); | |
const nextInput = findNextInputVertical(input, 1); | |
if (nextInput) nextInput.focus(); | |
} else if (e.key === 'ArrowUp') { | |
e.preventDefault(); | |
const nextInput = findNextInputVertical(input, -1); | |
if (nextInput) nextInput.focus(); | |
} else if (e.key === 'ArrowRight' && input.selectionStart === input.value.length) { | |
e.preventDefault(); | |
const nextInput = findNextInput(input); | |
if (nextInput) nextInput.focus(); | |
} else if (e.key === 'ArrowLeft' && input.selectionStart === 0) { | |
e.preventDefault(); | |
const prevInput = findPrevInput(input); | |
if (prevInput) prevInput.focus(); | |
} | |
}); | |
li.appendChild(input); | |
} | |
list.appendChild(li); | |
}); | |
sectionDiv.appendChild(title); | |
sectionDiv.appendChild(list); | |
grid.appendChild(sectionDiv); | |
} | |
} | |
function checkAnswer() { | |
const input = document.getElementById('answerInput'); | |
const answer = normalizeAnswer(input.value); | |
if (!answer) return; | |
let found = false; | |
for (const items of Object.values(studyData)) { | |
for (const item of items) { | |
if (normalizeAnswer(item) === answer && !foundItems.has(answer)) { | |
foundItems.add(answer); | |
found = true; | |
showFeedback('success', `Correct! Found "${item}"`); | |
break; | |
} | |
} | |
if (found) break; | |
} | |
if (!found) { | |
if (foundItems.has(answer)) { | |
showFeedback('info', 'Already found this one!'); | |
} else { | |
// Don't show error for partial matches while typing | |
return; | |
} | |
} | |
input.value = ''; | |
renderSections(); | |
updateStats(); | |
checkCompletion(); | |
} | |
function updateStats() { | |
const total = Object.values(studyData).flat().length; | |
const found = foundItems.size; | |
const percentage = Math.round((found / total) * 100); | |
document.getElementById('progress').textContent = `${found}/${total}`; | |
document.getElementById('percentage').textContent = `${percentage}%`; | |
} | |
function checkCompletion() { | |
const total = Object.values(studyData).flat().length; | |
if (foundItems.size === total) { | |
document.getElementById('completionMessage').style.display = 'block'; | |
} | |
} | |
function toggleAnswers() { | |
showingAnswers = !showingAnswers; | |
const btn = document.getElementById('toggleBtn'); | |
btn.textContent = showingAnswers ? 'Hide All' : 'Show All'; | |
document.querySelectorAll('.item.hidden input').forEach(input => { | |
if (showingAnswers) { | |
input.placeholder = input.closest('.item').dataset.answer; | |
input.style.fontStyle = 'italic'; | |
} else { | |
input.placeholder = '???'; | |
input.style.fontStyle = 'normal'; | |
} | |
}); | |
} | |
function resetGame() { | |
if (confirm('Are you sure you want to reset your progress?')) { | |
foundItems.clear(); | |
document.getElementById('completionMessage').style.display = 'none'; | |
renderSections(); | |
updateStats(); | |
showFeedback('info', 'Game reset!'); | |
} | |
} | |
function showFeedback(type, message) { | |
const existing = document.querySelector('.feedback'); | |
if (existing) existing.remove(); | |
const feedback = document.createElement('div'); | |
feedback.className = `feedback ${type}`; | |
feedback.textContent = message; | |
document.body.appendChild(feedback); | |
setTimeout(() => feedback.remove(), 3000); | |
} | |
// Enter key to submit | |
document.getElementById('answerInput').addEventListener('keyup', (e) => { | |
checkAnswer(); | |
}); | |
function findNextInput(currentInput) { | |
const allInputs = Array.from(document.querySelectorAll('.item.hidden input')); | |
const currentIndex = allInputs.indexOf(currentInput); | |
if (currentIndex < allInputs.length - 1) { | |
return allInputs[currentIndex + 1]; | |
} | |
return null; | |
} | |
function findPrevInput(currentInput) { | |
const allInputs = Array.from(document.querySelectorAll('.item.hidden input')); | |
const currentIndex = allInputs.indexOf(currentInput); | |
if (currentIndex > 0) { | |
return allInputs[currentIndex - 1]; | |
} | |
return null; | |
} | |
function findNextInputVertical(currentInput, direction) { | |
const allInputs = Array.from(document.querySelectorAll('.item.hidden input')); | |
const sections = document.querySelectorAll('.section'); | |
const currentRect = currentInput.getBoundingClientRect(); | |
let bestMatch = null; | |
let bestDistance = Infinity; | |
allInputs.forEach(input => { | |
if (input === currentInput) return; | |
const rect = input.getBoundingClientRect(); | |
// Check if it's in the direction we want (up or down) | |
if (direction > 0 && rect.top <= currentRect.top) return; | |
if (direction < 0 && rect.top >= currentRect.top) return; | |
// Calculate distance | |
const verticalDistance = Math.abs(rect.top - currentRect.top); | |
const horizontalDistance = Math.abs(rect.left - currentRect.left); | |
const totalDistance = Math.sqrt(verticalDistance ** 2 + horizontalDistance ** 2); | |
if (totalDistance < bestDistance) { | |
bestDistance = totalDistance; | |
bestMatch = input; | |
} | |
}); | |
return bestMatch; | |
} | |
// Initialize game on load | |
initializeGame(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment