Skip to content

Instantly share code, notes, and snippets.

@invalidred
Created January 28, 2026 21:41
Show Gist options
  • Select an option

  • Save invalidred/99bd73e2be2e3975fbee09f66b511a83 to your computer and use it in GitHub Desktop.

Select an option

Save invalidred/99bd73e2be2e3975fbee09f66b511a83 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Resume Scoring V2 - Visualization</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
header {
text-align: center;
color: white;
margin-bottom: 30px;
}
header h1 {
font-size: 2.5rem;
margin-bottom: 10px;
}
header p {
font-size: 1.1rem;
opacity: 0.9;
}
.card {
background: white;
border-radius: 16px;
padding: 24px;
margin-bottom: 24px;
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
}
.card h2 {
color: #333;
margin-bottom: 16px;
font-size: 1.4rem;
border-bottom: 2px solid #667eea;
padding-bottom: 8px;
}
.formula {
background: #f8f9fa;
border-left: 4px solid #667eea;
padding: 16px;
margin: 16px 0;
font-family: 'Courier New', monospace;
font-size: 1rem;
border-radius: 0 8px 8px 0;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 24px;
}
.chart-container {
position: relative;
height: 300px;
}
.slider-group {
margin: 16px 0;
}
.slider-group label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: #333;
}
.slider-group input[type="range"] {
width: 100%;
height: 8px;
border-radius: 4px;
background: #ddd;
outline: none;
-webkit-appearance: none;
}
.slider-group input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: #667eea;
cursor: pointer;
}
.value-display {
text-align: right;
font-weight: bold;
color: #667eea;
font-size: 1.2rem;
}
.score-display {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
gap: 16px;
margin-top: 20px;
}
.score-box {
text-align: center;
padding: 20px 30px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
color: white;
min-width: 150px;
}
.score-box .label {
font-size: 0.9rem;
opacity: 0.9;
margin-bottom: 8px;
}
.score-box .value {
font-size: 2rem;
font-weight: bold;
}
.explanation {
color: #666;
line-height: 1.6;
margin: 12px 0;
}
.highlight {
background: #fff3cd;
padding: 2px 6px;
border-radius: 4px;
}
table {
width: 100%;
border-collapse: collapse;
margin: 16px 0;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #eee;
}
th {
background: #f8f9fa;
font-weight: 600;
color: #333;
}
.weight-input {
width: 60px;
padding: 6px;
border: 2px solid #ddd;
border-radius: 6px;
text-align: center;
font-size: 1rem;
}
.weight-input:focus {
border-color: #667eea;
outline: none;
}
.competency-score {
width: 80px;
padding: 6px;
border: 2px solid #ddd;
border-radius: 6px;
text-align: center;
}
footer {
text-align: center;
color: white;
margin-top: 30px;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>Resume Scoring V2</h1>
<p>Interactive visualization of the scoring algorithm</p>
</header>
<!-- Overview Section -->
<div class="card">
<h2>How V2 Scoring Works</h2>
<p class="explanation">
The V2 scoring algorithm combines <span class="highlight">human-defined competency weights</span>
with <span class="highlight">AI predictions</span> to produce a final resume score.
The formula balances manual assessment with machine learning insights.
</p>
<div class="formula">
Combined Score = DISC Adjustment × (0.4 × Manual Score + 0.6 × Predicted Score)
</div>
<p class="explanation">
<strong>DISC Adjustment:</strong> Based on personality fit (0.85 to 1.15 multiplier)<br>
<strong>Manual Score:</strong> Weighted average of competency scores (0-100)<br>
<strong>Predicted Score:</strong> ML model prediction based on resume content (0-100)
</p>
</div>
<!-- Interactive Calculator -->
<div class="card">
<h2>Interactive Score Calculator</h2>
<h3 style="margin: 20px 0 10px; color: #666;">Competency Scores & Weights</h3>
<table>
<thead>
<tr>
<th>Competency</th>
<th>Weight (1-5)</th>
<th>Score (0-5)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Experience</td>
<td><input type="number" class="weight-input" id="w1" value="5" min="1" max="5"></td>
<td><input type="number" class="competency-score" id="s1" value="4" min="0" max="5" step="0.5"></td>
</tr>
<tr>
<td>Education</td>
<td><input type="number" class="weight-input" id="w2" value="3" min="1" max="5"></td>
<td><input type="number" class="competency-score" id="s2" value="3" min="0" max="5" step="0.5"></td>
</tr>
<tr>
<td>Skills</td>
<td><input type="number" class="weight-input" id="w3" value="4" min="1" max="5"></td>
<td><input type="number" class="competency-score" id="s3" value="4.5" min="0" max="5" step="0.5"></td>
</tr>
<tr>
<td>Communication</td>
<td><input type="number" class="weight-input" id="w4" value="3" min="1" max="5"></td>
<td><input type="number" class="competency-score" id="s4" value="3.5" min="0" max="5" step="0.5"></td>
</tr>
</tbody>
</table>
<div class="grid">
<div class="slider-group">
<label>Predicted Score (ML Model): <span id="predictedValue" class="value-display">72</span></label>
<input type="range" id="predictedScore" min="0" max="100" value="72">
</div>
<div class="slider-group">
<label>DISC Adjustment: <span id="discValue" class="value-display">1.00</span></label>
<input type="range" id="discAdjustment" min="85" max="115" value="100">
</div>
</div>
<div class="score-display">
<div class="score-box">
<div class="label">Manual Score</div>
<div class="value" id="manualScoreDisplay">78</div>
</div>
<div class="score-box">
<div class="label">Predicted Score</div>
<div class="value" id="predictedScoreDisplay">72</div>
</div>
<div class="score-box" style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);">
<div class="label">Combined Score</div>
<div class="value" id="combinedScoreDisplay">74</div>
</div>
</div>
</div>
<!-- Charts -->
<div class="grid">
<div class="card">
<h2>Score Composition</h2>
<div class="chart-container">
<canvas id="compositionChart"></canvas>
</div>
</div>
<div class="card">
<h2>Competency Breakdown</h2>
<div class="chart-container">
<canvas id="competencyChart"></canvas>
</div>
</div>
</div>
<!-- Weight Impact Visualization -->
<div class="card">
<h2>Combined Score vs. Manual Score (at different DISC adjustments)</h2>
<p class="explanation">
This chart shows how the combined score changes as the manual score varies,
with the predicted score held constant at the current slider value.
</p>
<div class="chart-container" style="height: 350px;">
<canvas id="sensitivityChart"></canvas>
</div>
</div>
<!-- Formulas Reference -->
<div class="card">
<h2>Formula Reference</h2>
<div class="formula">
<strong>Manual Score Calculation:</strong><br><br>
manual_score = (Σ weight[i] × score[i]) / (Σ weight[i]) × 20<br><br>
<em>Where scores are 0-5 and result is scaled to 0-100</em>
</div>
<div class="formula">
<strong>Combined Score Calculation:</strong><br><br>
combined_score = disc_adjustment × (0.4 × manual_score + 0.6 × predicted_score)<br><br>
<em>Manual contributes 40%, AI prediction contributes 60%</em>
</div>
<div class="formula">
<strong>DISC Adjustment Range:</strong><br><br>
0.85 (poor fit) → 1.00 (neutral) → 1.15 (excellent fit)
</div>
</div>
<footer>
<p>WizeHire Resume Scoring V2 Visualization</p>
</footer>
</div>
<script>
// Chart instances
let compositionChart, competencyChart, sensitivityChart;
// Initialize charts
function initCharts() {
// Composition Chart (Doughnut)
const compositionCtx = document.getElementById('compositionChart').getContext('2d');
compositionChart = new Chart(compositionCtx, {
type: 'doughnut',
data: {
labels: ['Manual Score (40%)', 'Predicted Score (60%)'],
datasets: [{
data: [40, 60],
backgroundColor: ['#667eea', '#764ba2'],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'bottom'
}
}
}
});
// Competency Chart (Radar)
const competencyCtx = document.getElementById('competencyChart').getContext('2d');
competencyChart = new Chart(competencyCtx, {
type: 'radar',
data: {
labels: ['Experience', 'Education', 'Skills', 'Communication'],
datasets: [{
label: 'Weighted Score',
data: [80, 60, 90, 70],
backgroundColor: 'rgba(102, 126, 234, 0.2)',
borderColor: '#667eea',
pointBackgroundColor: '#667eea',
borderWidth: 2
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
r: {
beginAtZero: true,
max: 100
}
},
plugins: {
legend: {
display: false
}
}
}
});
// Sensitivity Chart (Line)
const sensitivityCtx = document.getElementById('sensitivityChart').getContext('2d');
sensitivityChart = new Chart(sensitivityCtx, {
type: 'line',
data: {
labels: Array.from({length: 21}, (_, i) => i * 5),
datasets: [
{
label: 'DISC = 0.85 (Poor Fit)',
data: [],
borderColor: '#e74c3c',
backgroundColor: 'transparent',
borderWidth: 2,
tension: 0.4
},
{
label: 'DISC = 1.00 (Neutral)',
data: [],
borderColor: '#3498db',
backgroundColor: 'transparent',
borderWidth: 2,
tension: 0.4
},
{
label: 'DISC = 1.15 (Excellent Fit)',
data: [],
borderColor: '#2ecc71',
backgroundColor: 'transparent',
borderWidth: 2,
tension: 0.4
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
title: {
display: true,
text: 'Manual Score'
}
},
y: {
title: {
display: true,
text: 'Combined Score'
},
min: 0,
max: 120
}
},
plugins: {
legend: {
position: 'top'
}
}
}
});
}
// Calculate scores
function calculateScores() {
// Get competency weights and scores
const weights = [
parseFloat(document.getElementById('w1').value) || 1,
parseFloat(document.getElementById('w2').value) || 1,
parseFloat(document.getElementById('w3').value) || 1,
parseFloat(document.getElementById('w4').value) || 1
];
const scores = [
parseFloat(document.getElementById('s1').value) || 0,
parseFloat(document.getElementById('s2').value) || 0,
parseFloat(document.getElementById('s3').value) || 0,
parseFloat(document.getElementById('s4').value) || 0
];
// Calculate manual score
const weightedSum = weights.reduce((sum, w, i) => sum + w * scores[i], 0);
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
const manualScore = (weightedSum / totalWeight) * 20; // Scale to 0-100
// Get predicted score and DISC adjustment
const predictedScore = parseFloat(document.getElementById('predictedScore').value);
const discAdjustment = parseFloat(document.getElementById('discAdjustment').value) / 100;
// Calculate combined score
const combinedScore = discAdjustment * (0.4 * manualScore + 0.6 * predictedScore);
// Update displays
document.getElementById('predictedValue').textContent = predictedScore;
document.getElementById('discValue').textContent = discAdjustment.toFixed(2);
document.getElementById('manualScoreDisplay').textContent = manualScore.toFixed(0);
document.getElementById('predictedScoreDisplay').textContent = predictedScore;
document.getElementById('combinedScoreDisplay').textContent = Math.min(100, combinedScore).toFixed(0);
// Update competency chart
const competencyScores = scores.map((s, i) => (s / 5) * 100 * (weights[i] / 5));
competencyChart.data.datasets[0].data = competencyScores;
competencyChart.update();
// Update sensitivity chart
const manualScoreRange = Array.from({length: 21}, (_, i) => i * 5);
sensitivityChart.data.datasets[0].data = manualScoreRange.map(m => 0.85 * (0.4 * m + 0.6 * predictedScore));
sensitivityChart.data.datasets[1].data = manualScoreRange.map(m => 1.00 * (0.4 * m + 0.6 * predictedScore));
sensitivityChart.data.datasets[2].data = manualScoreRange.map(m => 1.15 * (0.4 * m + 0.6 * predictedScore));
sensitivityChart.update();
}
// Event listeners
document.querySelectorAll('input').forEach(input => {
input.addEventListener('input', calculateScores);
});
// Initialize
initCharts();
calculateScores();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment