diff --git a/about.html b/about.html index 115eb7f..1dfe881 100644 --- a/about.html +++ b/about.html @@ -74,7 +74,7 @@ diff --git a/data/github_repos.json b/data/github_repos.json index f372680..d77626a 100644 --- a/data/github_repos.json +++ b/data/github_repos.json @@ -15,11 +15,18 @@ }, { "name": "Home", - "stargazers_count": 2, + "stargazers_count": 3, "forks_count": 0, "description": "现代化个人主页,融合科技感与个性化元素,展示个人技术栈、开源项目和博客文章。", "html_url": "https://github.com/listener-He/Home" }, + { + "name": "auto-ip2region", + "stargazers_count": 2, + "forks_count": 0, + "description": "Auto IP2Region 是一个智能化的IP地址地理信息解析库,它结合了本地数据库和多个免费在线API服务,通过智能负载均衡和自动故障转移机制,为您提供准确、可靠的IP地理位置信息查询服务。", + "html_url": "https://github.com/listener-He/auto-ip2region" + }, { "name": "collection-complete", "stargazers_count": 2, @@ -34,6 +41,13 @@ "description": "", "html_url": "https://github.com/listener-He/keycloak-services-social-weixin" }, + { + "name": "fast-blur", + "stargazers_count": 1, + "forks_count": 0, + "description": "High-performance, lightweight data obfuscation library for Java. Offers fast, reversible data transformation without traditional encryption overhead. Ideal for caching, logging, and performance-critical applications. / 专为Java设计的高性能轻量级数据混淆库。提供快速、可逆的数据转换,无需传统加密开销。适用于缓存、日志和性能关键型应用。", + "html_url": "https://github.com/listener-He/fast-blur" + }, { "name": "Notion-Wechat-Blog", "stargazers_count": 1, diff --git a/data/github_user.json b/data/github_user.json index 5133f10..77953de 100644 --- a/data/github_user.json +++ b/data/github_user.json @@ -10,10 +10,10 @@ "blog": "https://www.hehouhui.cn", "hireable": true, "bio": "Hi, I’m Honesty—Shanghai Java/AI Dev (7+ yrs). Spring AI, LLM, TensorFlow, Faiss. Write tech content, cycle for inspiration. AI-obsessed.", - "public_repos": 165, + "public_repos": 167, "public_gists": 0, "followers": 6, "following": 12, "created_at": "2018-05-14T02:57:55Z", "updated_at": "2025-11-09T05:45:15Z" -} \ No newline at end of file +} diff --git a/js/ParticleSystem.js b/js/ParticleSystem.js deleted file mode 100644 index f934165..0000000 --- a/js/ParticleSystem.js +++ /dev/null @@ -1,369 +0,0 @@ -class ParticleSystem { - constructor(options = {}) { - this.particleCount = options.particleCount || 22000; - this.theme = options.theme || 'day'; - this.callbacks = options.callbacks || {}; - - // 动画控制相关属性 - this.scaleFactor = 1.0; - this.diffusionFactor = 1.0; - this.forwardFactor = 0.0; - this.speedFactor = 1.0; - - // 当前动画类型 - this.currentAnimation = 'saturn'; // 默认为土星动画 - - // 动画状态 - this.animationState = 'scattered'; // 默认状态为分散状态 - - this.init(); - } - - init() { - this.geometry = new THREE.BufferGeometry(); - this.positions = new Float32Array(this.particleCount * 3); - this.targets = new Float32Array(this.particleCount * 3); - this.origin = new Float32Array(this.particleCount * 3); - this.velocities = new Float32Array(this.particleCount * 3); - this.sizes = new Float32Array(this.particleCount); - this.seeds = new Float32Array(this.particleCount); - - this.simplex = new SimplexNoise(); - - // 初始化为默认的平铺散布状态 - this.initScatteredParticles(); - - this.geometry.setAttribute('position', new THREE.BufferAttribute(this.positions, 3)); - this.geometry.setAttribute('size', new THREE.BufferAttribute(this.sizes, 1)); - this.geometry.setAttribute('seed', new THREE.BufferAttribute(this.seeds, 1)); - - this.createMaterial(); - this.particleSystem = new THREE.Points(this.geometry, this.material); - - if (this.callbacks.onInit) { - this.callbacks.onInit(this.particleSystem); - } - } - - // 初始化平铺散布的粒子分布(默认状态) - initScatteredParticles() { - for (let i = 0; i < this.particleCount; i++) { - const i3 = i * 3; - - // 在一个较大的空间内随机分布粒子 - const x = (Math.random() - 0.5) * 2000; - const y = (Math.random() - 0.5) * 2000; - const z = (Math.random() - 0.5) * 2000; - - this.positions[i3] = x; - this.origin[i3] = x; - this.targets[i3] = x; - this.positions[i3 + 1] = y; - this.origin[i3 + 1] = y; - this.targets[i3 + 1] = y; - this.positions[i3 + 2] = z; - this.origin[i3 + 2] = z; - this.targets[i3 + 2] = z; - - this.sizes[i] = (Math.random() * 2.5 + 0.5) * (this.theme === 'day' ? 1.3 : 1.0); - this.seeds[i] = Math.random(); - } - } - - // 初始化土星动画的粒子分布 - initSaturnParticles() { - // 土星主体粒子数量 (约占70%) - const planetParticleCount = Math.floor(this.particleCount * 0.7); - // 土星环粒子数量 (约占30%) - const ringParticleCount = this.particleCount - planetParticleCount; - - // 初始化土星主体粒子 (球形分布) - for (let i = 0; i < planetParticleCount; i++) { - const i3 = i * 3; - const y = 1 - (i / (planetParticleCount - 1)) * 2; - const radius = Math.sqrt(1 - y * y); - const theta = i * 2.39996; - const r = 100; // 土星半径 - - const x = Math.cos(theta) * radius * r; - const z = Math.sin(theta) * radius * r; - const py = y * r; - - this.positions[i3] = x; - this.origin[i3] = x; - this.targets[i3] = x; - this.positions[i3 + 1] = py; - this.origin[i3 + 1] = py; - this.targets[i3 + 1] = py; - this.positions[i3 + 2] = z; - this.origin[i3 + 2] = z; - this.targets[i3 + 2] = z; - - this.sizes[i] = (Math.random() * 2.5 + 0.5) * (this.theme === 'day' ? 1.3 : 1.0); - this.seeds[i] = Math.random(); - } - - // 初始化土星环粒子 (圆环分布) - for (let i = planetParticleCount; i < this.particleCount; i++) { - const i3 = i * 3; - // 多个环的配置 - const ringConfigs = [ - { innerRadius: 130, outerRadius: 140 }, - { innerRadius: 150, outerRadius: 160 }, - { innerRadius: 170, outerRadius: 180 }, - { innerRadius: 190, outerRadius: 200 } - ]; - - // 分配到不同环 - const ringIndex = (i - planetParticleCount) % ringConfigs.length; - const ringConfig = ringConfigs[ringIndex]; - - // 在环内随机分布 - const angle = Math.random() * Math.PI * 2; - const radius = ringConfig.innerRadius + Math.random() * (ringConfig.outerRadius - ringConfig.innerRadius); - - const x = Math.cos(angle) * radius; - const z = Math.sin(angle) * radius; - const y = (Math.random() - 0.5) * 20; // 环有一定的厚度 - - this.positions[i3] = x; - this.origin[i3] = x; - this.targets[i3] = x; - this.positions[i3 + 1] = y; - this.origin[i3 + 1] = y; - this.targets[i3 + 1] = y; - this.positions[i3 + 2] = z; - this.origin[i3 + 2] = z; - this.targets[i3 + 2] = z; - - this.sizes[i] = (Math.random() * 1.5 + 0.5) * (this.theme === 'day' ? 1.3 : 1.0); - this.seeds[i] = Math.random(); - } - } - - createMaterial() { - const colors = this.theme === 'day' - ? {base: new THREE.Color(0x2c3e50), active: new THREE.Color(0x0055ff)} - : {base: new THREE.Color(0xFFFFFF), active: new THREE.Color(0x00FFFF)}; - - const paletteA = this.theme === 'day' ? new THREE.Color(0x6ec3ff) : new THREE.Color(0x00ffff); - const paletteB = this.theme === 'day' ? new THREE.Color(0xffb4c8) : new THREE.Color(0xff7af3); - const blending = this.theme === 'day' ? THREE.NormalBlending : THREE.AdditiveBlending; - - this.material = new THREE.ShaderMaterial({ - uniforms: { - scale: {value: window.innerHeight / 2}, - baseColor: {value: colors.base}, - activeColor: {value: colors.active}, - mixVal: {value: 0.0}, - time: {value: 0.0}, - paletteA: {value: paletteA}, - paletteB: {value: paletteB}, - nebulaIntensity: {value: 0.0} - }, - vertexShader: ` - attribute float size; - attribute float seed; - varying float vSeed; - void main() { - vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); - gl_PointSize = size * (500.0 / -mvPosition.z); - gl_Position = projectionMatrix * mvPosition; - vSeed = seed; - } - `, - fragmentShader: ` - uniform vec3 baseColor; - uniform vec3 activeColor; - uniform vec3 paletteA; - uniform vec3 paletteB; - uniform float mixVal; - uniform float time; - uniform float nebulaIntensity; - varying float vSeed; - void main() { - float r = length(gl_PointCoord - vec2(0.5)); - if (r > 0.5) discard; - vec3 baseMix = mix(baseColor, activeColor, mixVal); - float drift = 0.5 + 0.5 * sin(time * 0.15 + vSeed * 6.28318); - vec3 nebula = mix(paletteA, paletteB, drift); - vec3 finalColor = mix(baseMix, nebula, nebulaIntensity); - gl_FragColor = vec4(finalColor, 1.0); - } - `, - blending: blending, - depthTest: false, - transparent: true - }); - } - - update(time, mode, handCount, handL, handR) { - const adjustedTime = time * this.speedFactor; - this.material.uniforms.time.value = adjustedTime; - - if (this.theme === 'night') { - this.material.uniforms.nebulaIntensity.value = mode === 'UNLOCKED' ? 0.55 : 0.35; - } else { - this.material.uniforms.nebulaIntensity.value = mode === 'UNLOCKED' ? 0.22 : 0.12; - } - - let targetMix = 0; - - if (mode === 'LOCKED') { - targetMix = handCount > 0 ? 0.6 : 0.0; - const ns = 0.002 * this.diffusionFactor; - const ts = adjustedTime * 0.15; - - for (let i = 0; i < this.particleCount; i++) { - const i3 = i * 3; - const ox = this.origin[i3] * this.scaleFactor; - const oy = this.origin[i3 + 1] * this.scaleFactor; - const oz = this.origin[i3 + 2] * this.scaleFactor; - const noise = this.simplex.noise3D(ox * ns + ts, oy * ns, oz * ns + ts); - - let offX = 0, offY = 0; - if (handCount === 1) { - offX = handL.x * 0.15 * this.forwardFactor; - offY = handL.y * 0.15 * this.forwardFactor; - } - - const scale = 1 + noise * 0.3; - this.targets[i3] = ox * scale + offX; - this.targets[i3 + 1] = oy * scale + offY; - this.targets[i3 + 2] = oz * scale; - } - } else { - targetMix = 1.0; - } - - this.material.uniforms.mixVal.value += (targetMix - this.material.uniforms.mixVal.value) * 0.1; - - for (let i = 0; i < this.particleCount; i++) { - const i3 = i * 3; - const px = this.positions[i3]; - const py = this.positions[i3 + 1]; - const pz = this.positions[i3 + 2]; - - const stiff = mode === 'LOCKED' ? 0.03 : 0.05; - this.velocities[i3] += (this.targets[i3] - px) * stiff; - this.velocities[i3 + 1] += (this.targets[i3 + 1] - py) * stiff; - this.velocities[i3 + 2] += (this.targets[i3 + 2] - pz) * stiff; - - if (handCount === 1) { - const hx = handL.x; - const hy = handL.y; - const dx = hx - px; - const dy = hy - py; - const distSq = dx * dx + dy * dy; - - if (distSq < 150000) { - const f = (150000 - distSq) / 150000; - this.velocities[i3] += dx * f * 0.05; - this.velocities[i3 + 1] += dy * f * 0.05; - this.velocities[i3 + 2] += Math.sin(adjustedTime * 10 + distSq * 0.0001) * 8 * f; - } - } else if (handCount === 2) { - [handL, handR].forEach(h => { - const dx = px - h.x; - const dy = py - h.y; - const distSq = dx * dx + dy * dy; - if (distSq < 80000) { - const f = (80000 - distSq) / 80000; - this.velocities[i3] -= dx * f * 0.3; - this.velocities[i3 + 1] -= dy * f * 0.3; - this.velocities[i3 + 2] += 15 * f; - } - }); - } - - this.velocities[i3] *= 0.90; - this.velocities[i3 + 1] *= 0.90; - this.velocities[i3 + 2] *= 0.90; - - this.positions[i3] += this.velocities[i3]; - this.positions[i3 + 1] += this.velocities[i3 + 1]; - this.positions[i3 + 2] += this.velocities[i3 + 2]; - } - - this.geometry.attributes.position.needsUpdate = true; - - if (this.callbacks.onUpdate) { - this.callbacks.onUpdate(this.particleSystem); - } - - return targetMix; - } - - explode(force) { - for (let i = 0; i < this.particleCount; i++) { - this.velocities[i * 3] += (Math.random() - 0.5) * force; - this.velocities[i * 3 + 1] += (Math.random() - 0.5) * force; - this.velocities[i * 3 + 2] += (Math.random() - 0.5) * force; - } - } - - scatter() { - // 将粒子散开到随机位置 - for (let i = 0; i < this.particleCount; i++) { - const i3 = i * 3; - this.targets[i3] = (Math.random() - 0.5) * 2000; - this.targets[i3 + 1] = (Math.random() - 0.5) * 2000; - this.targets[i3 + 2] = (Math.random() - 0.5) * 2000; - } - this.animationState = 'scattered'; - } - - // 聚合粒子形成土星形状 - aggregate() { - this.initSaturnParticles(); - this.animationState = 'aggregated'; - } - - setScaleFactor(factor) { - this.scaleFactor = Math.max(0.1, Math.min(2.0, factor)); - } - - setDiffusionFactor(factor) { - this.diffusionFactor = Math.max(0.1, Math.min(3.0, factor)); - } - - setForwardFactor(factor) { - this.forwardFactor = Math.max(-2.0, Math.min(2.0, factor)); - } - - setSpeedFactor(factor) { - this.speedFactor = Math.max(0.01, Math.min(3.0, factor)); - } - - // 处理来自手势的指令 - handleGestureCommand(command, value) { - switch(command) { - case 'scale': - this.setScaleFactor(value); - break; - case 'diffusion': - this.setDiffusionFactor(value); - break; - case 'forward': - this.setForwardFactor(value); - break; - case 'speed': - this.setSpeedFactor(value); - break; - case 'explode': - this.explode(value); - break; - case 'scatter': - this.scatter(); - break; - case 'aggregate': - this.aggregate(); - break; - } - } - - dispose() { - this.geometry.dispose(); - this.material.dispose(); - } -} \ No newline at end of file diff --git a/js/StarrySky.js b/js/StarrySky.js deleted file mode 100644 index b030b46..0000000 --- a/js/StarrySky.js +++ /dev/null @@ -1,215 +0,0 @@ -/** - * Starry Sky - * - * 作者: DoWake - * 描述:使用Canvas绘制星空 - * 地址:https://github.com/DoWake/StarrySky - * 日期:2023/03/02 - */ - -const StarrySky = function () { - //Canvas元素 - let canvasElement; - //Canvas 2D对象 - let canvasContext; - //Canvas 宽度 - let canvasWidth; - //Canvas 高度 - let canvasHeight; - //星星列表 - let starList; - //星星颜色列表,rgb格式:"255, 255, 255" - let starColorList; - //星星半径大小 - let starRadius; - //焦距等级,与canvasWidth相乘,必须大于0 - let focalDistanceLevel; - //星星数量等级,与canvasWidth相乘,必须大于0 - let starCountLevel; - //星星速度等级,与焦距相乘,必须大于0 - let starSpeedLevel; - //焦距 - let focalDistance; - //星星数量 - let starCount; - //执行动画 - let rAF; - return { - //初始化 - init: function (canvas_element) { - if (canvas_element && canvas_element.nodeName === "CANVAS") { - canvasElement = canvas_element; - canvasElement.width = canvasElement.clientWidth; - canvasElement.height = canvasElement.clientHeight; - canvasElement.style.backgroundColor = "black"; - canvasContext = canvasElement.getContext("2d"); - canvasWidth = canvasElement.clientWidth; - canvasHeight = canvasElement.clientHeight; - starColorList = ["255, 255, 255"]; - starRadius = 1; - focalDistanceLevel = 0.4; - starCountLevel = 0.2; - starSpeedLevel = 0.0005; - focalDistance = canvasWidth * focalDistanceLevel; - starCount = Math.ceil(canvasWidth * starCountLevel); - starList = []; - for (let i = 0; i < starCount; i++) { - starList[i] = { - x: canvasWidth * (0.1 + 0.8 * Math.random()), - y: canvasHeight * (0.1 + 0.8 * Math.random()), - z: focalDistance * Math.random(), - color: starColorList[Math.ceil(Math.random() * 1000) % starColorList.length] - } - } - const self = this; - window.addEventListener("resize", self.throttle(function () { - canvasElement.width = canvasElement.clientWidth; - canvasElement.height = canvasElement.clientHeight; - canvasWidth = canvasElement.clientWidth; - canvasHeight = canvasElement.clientHeight; - focalDistance = canvasWidth * focalDistanceLevel; - - const starCount2 = Math.ceil(canvasWidth * starCountLevel); - if (starCount > starCount2) { - starList.splice(starCount2); - } else { - let num = starCount2 - starCount; - while (num--) { - starList.push({ - x: canvasWidth * (0.1 + 0.8 * Math.random()), - y: canvasHeight * (0.1 + 0.8 * Math.random()), - z: focalDistance * Math.random(), - color: starColorList[Math.ceil(Math.random() * 1000) % starColorList.length] - }); - } - } - starCount = Math.ceil(canvasWidth * starCountLevel); - }, 200), { passive: true }); - } else { - console.error('初始化失败,必须传入Canvas元素'); - } - }, - //设置星空背景颜色 - setSkyColor: function (sky_color = "black") { - canvasElement.style.backgroundColor = sky_color; - }, - //设置星星半径大小 - setStarRadius: function (star_radius = 1) { - starRadius = star_radius; - }, - //设置焦距等级 - setFocalDistanceLevel: function (focal_distance_level = 0.4) { - focalDistanceLevel = focal_distance_level; - focalDistance = canvasWidth * focalDistanceLevel - }, - //设置星星数量等级 - setStarCountLevel: function (star_count_level = 0.2) { - starCountLevel = star_count_level; - const starCount2 = Math.ceil(canvasWidth * starCountLevel); - if (starCount > starCount2) { - starList.splice(starCount2); - } else { - let num = starCount2 - starCount; - while (num--) { - starList.push({ - x: canvasWidth * (0.1 + 0.8 * Math.random()), - y: canvasHeight * (0.1 + 0.8 * Math.random()), - z: focalDistance * Math.random(), - color: starColorList[Math.ceil(Math.random() * 1000) % starColorList.length] - }); - } - } - starCount = Math.ceil(canvasWidth * starCountLevel); - }, - //设置星星速度等级 - setStarSpeedLevel: function (star_speed_level = 0.0005) { - starSpeedLevel = star_speed_level - }, - /** - * 设置星星颜色 - * @param {Array|String} color 星星颜色 - * @param {Boolean} mode 是否立刻同步颜色 - */ - setStarColorList: function (color, mode = false) { - if (typeof color === 'object') { - starColorList = color; - } else if (typeof color === 'string') { - starColorList.push(color); - } - if (mode) { - for (let i = 0; i < starList.length; i++) { - starList[i]["color"] = starColorList[Math.ceil(Math.random() * 1000) % starColorList.length]; - } - } - }, - //渲染 - render: function () { - const starSpeed = canvasWidth * focalDistanceLevel * starSpeedLevel; - //清空画布 - canvasContext.clearRect(0, 0, canvasWidth, canvasHeight); - //计算位置 - for (let i = 0; i < starList.length; i++) { - const star = starList[i]; - const star_x = (star["x"] - canvasWidth / 2) * (focalDistance / star["z"]) + canvasWidth / 2; - const star_y = (star["y"] - canvasHeight / 2) * (focalDistance / star["z"]) + canvasHeight / 2; - star["z"] -= starSpeed; - if (star["z"] > 0 && star["z"] <= focalDistance && star_x >= -20 && star_x <= canvasWidth + 20 && star_y >= -20 && star_y <= canvasHeight + 20) { - const star_radius = starRadius * (focalDistance / star["z"] * 0.8); - const star_opacity = 1 - 0.8 * (star["z"] / focalDistance); - canvasContext.fillStyle = "rgba(" + star["color"] + ", " + star_opacity + ")"; - canvasContext.shadowOffsetX = 0; - canvasContext.shadowOffsetY = 0; - canvasContext.shadowColor = "rgb(" + star["color"] + ")"; - canvasContext.shadowBlur = 5; - canvasContext.beginPath(); - canvasContext.arc(star_x, star_y, star_radius, 0, 2 * Math.PI); - canvasContext.fill(); - } else { - const z = focalDistance * Math.random(); - star["x"] = canvasWidth * (0.1 + 0.8 * Math.random()); - star["y"] = canvasHeight * (0.1 + 0.8 * Math.random()); - star["z"] = z; - star["color"] = starColorList[Math.ceil(Math.random() * 1000) % starColorList.length]; - } - } - const self = this; - rAF = window.requestAnimationFrame(function () { - self.render(); - }); - }, - //销毁 - destroy: function () { - window.cancelAnimationFrame(rAF); - starList = []; - canvasContext.clearRect(0, 0, canvasWidth, canvasHeight); - canvasElement.width = 0; - canvasElement.height = 0; - }, - //防抖 - debounce: function (func, time = 200) { - let timeId; - return function () { - if (timeId) { - clearTimeout(timeId); - } - timeId = setTimeout(function () { - func(); - }, time); - } - }, - //节流 - throttle: function (func, time = 200) { - let timeId = null; - let pre = 0; - return function () { - if (Date.now() - pre > time) { - clearTimeout(timeId); - pre = Date.now(); - func(); - } else { - timeId = setTimeout(func, time); - } - }; - } - } -}(); \ No newline at end of file diff --git a/js/moments.js b/js/moments.js deleted file mode 100644 index 42fde06..0000000 --- a/js/moments.js +++ /dev/null @@ -1,58 +0,0 @@ -$(document).ready(function () { - const iframe = document.getElementById('moment-frame'); - const momentsContainer = document.getElementById('moments-container'); - - function animateIframe() { - momentsContainer.style.display = 'block'; - momentsContainer.classList.add('visible'); - } - - function openMoments(url) { - if (iframe.src == null || iframe.src === '' || iframe.src !== url) { - iframe.src = url; - - iframe.onload = () => { - setTimeout(() => { - animateIframe(); - }, 300); // 延迟更自然 - }; - } else { - animateIframe(); - } - } - - // 处理瞬间链接点击事件 - $('.moments-link').on('click', function (e) { - e.preventDefault(); // 阻止默认跳转 - - // 获取链接地址 - const url = "https://moments.hehouhui.cn"; - - // 判断是否是移动端 - const isMobile = /iPhone|Android/i.test(navigator.userAgent); - - if (isMobile) { - // 移动端:直接跳转 - window.location.href = url; - } else { - // PC端:在iframe中显示 - openMoments(url); - } - }); - - // 关闭按钮点击事件 - $('.close-btn').on('click', function () { - momentsContainer.classList.remove('visible'); - setTimeout(() => { - momentsContainer.style.display = 'none'; - }, 500); // 等待动画结束后隐藏 - }); - - // 遮罩层点击事件 点击空白处关闭模拟器 - $('.overlay').on('click', function () { - momentsContainer.classList.remove('visible'); - setTimeout(() => { - momentsContainer.style.display = 'none'; - }, 500); // 等待动画结束后隐藏 - }); -}); \ No newline at end of file