feat: 增强版验证码全套实现 — 16种类型生成器/加密/风控/站点管理/平台后端/前端SDK/UI

- 核心新增: ICON_CLICK(PNG图标方案,预渲染资源)/SCRATCH/JIGSAW/CURVE_SLIDER(V1-V3)/ANGLE/CURVE_DRAW/WORD_ORDER_CLICK/PROOF_OF_WORK 等生成器
- 图标点选: classpath PNG 加载替代运行时字体渲染(Linux容器无emoji字体),提示条图作为 templateImage 返回前端
- 新增模块: crypto(AES+RSA)/obfuscator(背景乱序/噪声/扭曲)/risk(风控/IP黑名单/限流)/site(站点管理)/ml(轨迹规则引擎)
- 平台后端: 站点管理/验证码API(generate/verify/secondary-verify)/统计/ML轨迹学习
- 前端SDK: TPCaptcha兼容,支持全部新型号渲染与交互
- 工具: tools/icon-render 图标预渲染工具
This commit is contained in:
abcv7
2026-08-26 09:58:15 +08:00
parent d56958727c
commit dbe9b58b0c
115 changed files with 10365 additions and 36 deletions
@@ -0,0 +1,191 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>史诗质感 - 真·双剑与盾行为验证 (锐利光环版)</title>
<style>
body {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #0f172a;
font-family: system-ui, -apple-system, sans-serif;
margin: 0;
overflow: hidden;
}
.captcha-container {
position: relative;
width: 180px;
height: 180px;
margin-bottom: 40px;
}
.captcha-icon {
width: 100%;
height: 100%;
overflow: visible;
}
/* --- 1. 盾牌过渡 --- */
.shield-shard {
transform-origin: 50px 50px;
transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1), fill 0.4s ease, opacity 0.5s ease;
}
/* --- 2. 纯净空心脉冲 --- */
.ward-group {
transition: opacity 0.4s ease;
}
.ward-pulse {
transform-origin: 50px 50px;
animation: pulse-ward 2s cubic-bezier(0.1, 0.7, 0.3, 1) infinite;
}
.ward-pulse.delay {
animation-delay: 1s;
}
/* 移除了夸张的缩放和粗细变化,改为更清爽的光圈扩散 */
@keyframes pulse-ward {
0% { transform: scale(0.6); opacity: 1; stroke-width: 6px; }
100% { transform: scale(1.8); opacity: 0; stroke-width: 1px; }
}
/* --- 3. 巨剑插入动画 --- */
.sword-slide {
transform: translateY(-85px);
opacity: 0;
transition: transform 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.4), opacity 0.4s ease;
}
.sword-anchor-a { transform-origin: 50px 50px; transform: rotate(-45deg); }
.sword-anchor-b { transform-origin: 50px 50px; transform: rotate(45deg); }
/* --- 4. 状态控制 --- */
.state-wait .ward-group { opacity: 1; }
.state-wait .shield-shard {
fill: url(#metalBlueGrad);
transform: translate(0, 0) scale(1) rotate(0deg);
opacity: 1;
/* 【核心修复】:移除发光,改回黑色的物理实体阴影,保证盾牌边缘极其锐利 */
filter: drop-shadow(0 6px 8px rgba(0,0,0,0.6));
}
.state-success .ward-group { opacity: 0; }
.state-success .shield-shard {
fill: url(#metalGreenGrad);
transform: translate(0, 0) scale(1) rotate(0deg);
opacity: 1;
filter: drop-shadow(0 6px 8px rgba(0,0,0,0.6));
}
.state-success .sword-slide { transform: translateY(-15px); opacity: 1; }
.state-fail .ward-group { opacity: 0; }
.state-fail .shield-shard { fill: url(#metalRedGrad); opacity: 0.9; filter: none;}
.state-fail .shard-tl { transform: translate(-25px, -30px) scale(0.9) rotateX(30deg) rotateY(-20deg) rotateZ(-15deg); opacity: 0.7; }
.state-fail .shard-tr { transform: translate(25px, -30px) scale(0.9) rotateX(30deg) rotateY(20deg) rotateZ(15deg); opacity: 0.7; }
.state-fail .shard-b { transform: translate(0, 35px) scale(0.8) rotateX(-20deg) rotateZ(5deg); opacity: 0.5; }
.controls { display: flex; gap: 15px; }
.controls button {
padding: 12px 24px; font-size: 14px; font-weight: bold; cursor: pointer;
border: 2px solid transparent; border-radius: 8px; background: #1e293b; color: #f1f5f9;
transition: all 0.2s ease;
}
.controls button:hover { background: #334155; transform: translateY(-2px); }
.controls button:active { transform: translateY(1px); }
</style>
</head>
<body>
<div class="captcha-container">
<svg id="captcha-svg" class="captcha-icon state-wait" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="metalBlueGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#3B82F6" /><stop offset="50%" stop-color="#1E40AF" /><stop offset="100%" stop-color="#60A5FA" />
</linearGradient>
<linearGradient id="metalGreenGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#10B981" /><stop offset="50%" stop-color="#047857" /><stop offset="100%" stop-color="#34D399" />
</linearGradient>
<linearGradient id="metalRedGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#EF4444" /><stop offset="50%" stop-color="#B91C1C" /><stop offset="100%" stop-color="#F87171" />
</linearGradient>
<linearGradient id="bladeLight" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#f8fafc" /><stop offset="100%" stop-color="#94a3b8" />
</linearGradient>
<linearGradient id="bladeDark" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#64748b" /><stop offset="100%" stop-color="#334155" />
</linearGradient>
<linearGradient id="goldGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FDE047" /><stop offset="50%" stop-color="#EAB308" /><stop offset="100%" stop-color="#A16207" />
</linearGradient>
<filter id="swordShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="3" dy="5" stdDeviation="2.5" flood-color="#000000" flood-opacity="0.7"/>
</filter>
<filter id="cleanMagicGlow" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="2" result="blur" />
<feMerge>
<feMergeNode in="blur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<g id="epic-sword" filter="url(#swordShadow)">
<polygon points="43,26 50,26 50,115" fill="url(#bladeLight)" />
<polygon points="50,26 57,26 50,115" fill="url(#bladeDark)" />
<rect x="45" y="4" width="10" height="22" fill="#1e293b" />
<path d="M 45 6 L 55 10 M 45 12 L 55 16 M 45 18 L 55 22 M 45 24 L 55 28" stroke="#475569" stroke-width="2" />
<polygon points="20,22 50,26 80,22 80,27 50,32 20,27" fill="#713F12" />
<polygon points="20,22 50,26 80,22 50,24" fill="url(#goldGrad)" />
<polygon points="50,-6 57,0 50,6 43,0" fill="url(#goldGrad)" />
<polygon points="50,-6 57,0 50,6" fill="rgba(0,0,0,0.25)" />
</g>
</defs>
<g class="ward-group" filter="url(#cleanMagicGlow)">
<circle class="ward-pulse" cx="50" cy="50" r="35" fill="none" stroke="#38BDF8" stroke-linecap="round" />
<circle class="ward-pulse delay" cx="50" cy="50" r="35" fill="none" stroke="#38BDF8" stroke-linecap="round" />
</g>
<g class="shield-main-group">
<path class="shield-shard shard-tl" d="M 50 12 L 18 28 L 18 52 L 50 48 Z" fill="url(#metalBlueGrad)" />
<path class="shield-shard shard-tr" d="M 50 12 L 82 28 L 82 52 L 50 48 Z" fill="url(#metalBlueGrad)" />
<path class="shield-shard shard-b" d="M 18 52 C 18 78 50 92 50 92 C 50 92 82 78 82 52 L 50 48 Z" fill="url(#metalBlueGrad)" />
</g>
<g class="sword-anchor-a">
<g class="sword-slide">
<use href="#epic-sword" />
</g>
</g>
<g class="sword-anchor-b">
<g class="sword-slide">
<use href="#epic-sword" />
</g>
</g>
</svg>
</div>
<div class="controls">
<button onclick="changeState('state-wait')" style="border-color: #3B82F6;">🛡️ 结界维持中...</button>
<button onclick="changeState('state-success')" style="border-color: #10B981; color: #10B981;">⚔️ 史诗验证成功</button>
<button onclick="changeState('state-fail')" style="border-color: #EF4444; color: #EF4444;">💥 盾牌碎裂</button>
</div>
<script>
function changeState(newStateClass) {
const svg = document.getElementById('captcha-svg');
svg.classList.remove('state-wait', 'state-success', 'state-fail');
svg.classList.add(newStateClass);
}
</script>
</body>
</html>