这次旅行,去的是传说中的“中国最美十大海岛”之一,嵛山岛。 出发之前还是挺期待的。 毕竟这种地方,网上随便一搜都是各种大片:蓝蓝的海水、层层叠叠的山、远处的海岛,还有站在山顶一眼望过去的壮阔海景。 结果真正到了以后才发现—— 旅行这种东西,真的很看天气。 登岛 刚开始的时候,天气其实还可以。 一路上看看风景,吹吹海风,感觉整个人都慢慢放松下来了。 岛上的风景和城市里完全不一样。 没有那么多高楼,也没有那么嘈杂的声音,视线一下子就开阔了很多。 一路走走停停,看到喜欢的地方就拍拍照片。 上山 在山脚下,天气看起来其实还行。 但是随着海拔越来越高,周围慢慢就开始白了起来。 远处的山看不清了。 海也看不见了。 甚至走到一些地方的时候,前面十几二十米的东西都开始变得模糊。 一开始还只是有一点雾气,后来直接变成了“雾锁山顶”。 到了山顶之后,远处基本就看不到了,而且那天风还特别的大,呼呼的吹 本来应该能看到很远的海面,结果全被白茫茫的雾气挡住。 站在那里甚至有一种:“我是不是来到了云里面?” 的感觉。 当然,没看到完整的山海全貌,还是有一点遗憾的。 毕竟难得来一次嵛山岛,还是很想亲眼看看网上照片里的那种壮阔海景。 网上那些“站在山顶俯瞰大海”的画面,我是一张都没看到。 这里就是最有名的大天湖和小天湖哈哈 最出片的地方 去海边 到了海边之后,感觉又完全不一样了。 海风吹过来,整个人舒服了很多。 相比于山顶的时候,海边更加适合慢慢待着。 没有必要一直赶着去什么景点,也不用一直拿着相机拍。 代画小人,一元一个,童叟无欺 看日落 到了傍晚,我们又准备等日落。 这时候其实已经开始期待了。 想着白天山顶虽然没看到完整的海景,那晚上总得让我看个日落吧? 结果…… 云又来了。 太阳慢慢往下落的时候,天空已经被云层挡住了。 能看到一点点夕阳的光,但是想象中的那种“太阳落到海平面”的画面,还是没有等到。 树荫下 岛上有一个炮台酒吧,晚上的时候会有很多年轻人在这唱歌喝酒. 吹吹海风,聊聊天,看看旁边的海。 那一刻其实特别轻松惬意。 旅行有时候就是这样。 不一定非要去很多地方,也不一定每一分钟都安排得满满当当。 有时候找个树荫坐下来,吹一会儿海风,就已经很放松了。 蓝天白云海风树荫 回程 山顶的大雾,让我没有看到嵛山岛完整的山海全貌。 傍晚的云层,又把期待已久的日落挡住了。 旅行本来就不可能每一次都遇到最好的天气,也不可能每一次都看到网上照片里的“最佳机位”。 ...
逛 福州·第十五届潮柚漫展
算起来,我去漫展也有一段时间了。 不过如果要问我到底算什么身份…… 摄影师?算是吧。 集邮党?也算。 二次元爱好者?这个应该更准确一点。 相机挂着,手机揣着,然后看到好看的 Cos 就走不动路。 这次去的是 福州·第十五届潮柚次元动漫嘉年华。 展会在 2026 年 7 月 24 日到 26 日举行,地点还是大家比较熟悉的福州海峡国际会展中心。 出发,目标:拍照 + 集邮 一边拍,一边逛,一边集邮。 你永远不知道下一秒会在场馆哪个角落遇到谁。 我的漫展日常 “老师,可以拍几张吗?” “老师,可以集个邮吗!” “谢谢老师!” “老师,你看一下” “老师,需要反图吗,加个微信吧” 这句话我感觉已经快变成摄影师的固定台词了。 但我其实不只是来拍照的 虽然每次都背着相机,看起来像个摄影师。 但我觉得自己还是更像一个普通的漫展爱好者。 因为我也喜欢集邮。 遇到认识的老师,拍张照; 遇到喜欢的 Cos,拍张照; 遇到以前见过的老师,再拍张照。 有时候甚至不是为了出片。 就是觉得: “啊,这次又遇到了。” 那就拍一张留个纪念。 我觉得这也是漫展比较有意思的一点。 几年以后再翻回这些照片,你可能已经记不起当天具体发生了什么。 但是看到照片的时候,还是会想起来: “哦,这个漫展我去过。” “那天我好像还在这里拍了一整天。” “当时这个老师还在这里。” 这种感觉其实挺好的。 漫展里的各种瞬间 漫展最让我喜欢的,其实不一定是舞台或者嘉宾。 有时候就是一些很普通的小瞬间。 路边正在整理假发的 Coser。 拿着痛包到处逛的游客。 第一次鼓起勇气找人拍照的人。 还有背着相机、在人群里面到处找角度的摄影师。 这些东西放在一起,才组成了我印象里的漫展。 ...
MoeKoe Music Mobile酷狗音乐第三方移动端播放器
# MoeKoe Music Mobile 一款开源、简洁、高颜值的第三方酷狗音乐移动端播放器 基于 Expo / React Native 构建,是 [MoeKoeMusic](https://github.com/iAJue/MoeKoeMusic) 桌面版的移动端实现 🌎 GitHub仓库 | 📦️ 下载安装包 | 💬 访问博客 | 🏠 项目主页 一款开源、简洁、高颜值的第三方酷狗音乐移动端播放器 基于 Expo / React Native 构建,是 MoeKoeMusic 桌面版的移动端实现 ✨ 特性 🎵 无需自建服务器 — 酷狗 API 适配层直接直连官方,开箱即用,不依赖外部 API 地址 🏠 首页推荐 — 每日推荐、精选歌单、排行榜 🧭 发现页 — 分类歌单、新歌速递等内容探索 🔍 搜索 — 快速检索歌曲、歌单、专辑 📀 歌单 / 专辑 / 排行榜 — 完整的详情页与曲目列表 🎧 播放器 — 滚动歌词、播放队列、迷你播放条(MiniPlayer)、后台播放 🎚️ 音质检测 — 自动探测并选择可用音质 📱 手机号登录 — 同步酷狗账号的收藏与歌单 🌗 深色模式 — 跟随系统自动切换明暗主题 📝 Todo List [x] 首页每日推荐 / 精选歌单 / 排行榜 [x] 发现页分类内容浏览 [x] 搜索歌曲、歌单、专辑 [x] 歌单 / 专辑 / 排行榜详情页 [x] 播放器:滚动歌词、播放队列、迷你播放条、后台播放 [x] 音质检测与自动选择 [x] 手机号登录 [x] 账号密码登录 [x] 扫码登录(其他设备) [x] 我喜欢 / 收藏同步 [x] 用户歌单管理(创建 / 收藏 / 编辑) [ ] 通知栏 / 锁屏播放控制 [ ] 歌曲详情浏览 [ ] 桌面歌词 [ ] 听歌识曲 [ ] 平板与横屏适配 [ ] 性能优化 📸 预览 🚀 快速开始 环境要求 Node.js ≥ 22 Git iOS 模拟器 / Android 模拟器,或安装了开发版客户端的真机 开发运行 # 克隆仓库(包含 api submodule) git clone --recurse-submodules https://github.com/MoeKoeMusic/MoeKoeMusic-Mobile.git cd MoeKoeMusic-Mobile # 安装依赖 npm install npm --prefix api install # 生成移动端 API 入口(api/ 更新后需重新执行) npm run generate:mobile-api # 启动开发服务器 npx expo start 如果克隆时遗漏了 submodule,可执行 git submodule update --init 补齐。 ...
MoeKoe Music浏览器插件版本,开箱即用
MoeKoe Music Extension MoeKoe Music 浏览器插件版,基于 MoeKoeMusic Web 构建,并在浏览器扩展内完成 API 路由兼容。 🌎 GitHub仓库 特性 点击浏览器插件图标后打开独立窗口运行 MoeKoeMusic。 无需用户配置 API 地址,也无需额外启动本地 API 服务。 保留 MoeKoeMusic 原有 Web 页面与交互,兼容浏览器扩展运行环境。 快速开始 环境要求 Node.js 20 或更高版本 Git Chrome / Edge 等 Chromium 内核浏览器 安装依赖 git submodule update --init --recursive npm install npm run install:app npm run install:app 会分别安装 MoeKoeMusic 与 MoeKoeMusic/api 的依赖。安装后建议检查子模块工作区,避免把上游 lockfile 的非预期变化提交进去。 构建扩展 npm run build 构建产物会输出到: dist/extension 安装到浏览器 打开 chrome://extensions 或 edge://extensions。 启用“开发者模式”。 点击“加载已解压的扩展程序”。 选择本项目下的 dist/extension 目录。 不要加载源码目录 extension,否则浏览器会提示清单或背景脚本加载失败。 ...
MoeKoe Music 插件市场设计
在做插件市场之前,先有的是 MoeKoe 的普通插件系统。 当时我想解决的问题不是某一个具体功能,而是一个更通用的问题:播放器里总会冒出很多小需求,有些人想改界面,有些人想加一个工具弹窗,有些人想接自己的服务。如果每个想法都往主程序里塞,主程序会越来越重,也越来越难维护。 所以我一开始给插件系统定的方向很明确:主程序只提供插件运行环境和管理入口,具体功能交给插件自己做。插件能独立安装、独立卸载,坏了也尽量不要影响播放器本体。 上一篇我写的是 MoeKoeMusic-Plugins 这个插件登记仓库。那边解决的是“插件市场的数据怎么产生”:用户用 Issue 提交,Action 校验,维护者审核,通过后写进 plugins.json。 但光有登记仓库还不够。真正对用户来说,插件市场不是 GitHub 上的一份 JSON,而是客户端里一个能看、能搜、能安装、能更新的入口。 所以这篇就换到 MoeKoe Music 主项目里,专门聊客户端的插件市场部分。 为什么选 Chrome Extension 这一套 MoeKoe 是 Electron 应用,Electron 本身就有加载扩展的能力。既然底层已经能跑 Chrome Extension,那就没必要再从零设计一套插件格式。 这样做有几个好处: 第一,插件作者不用学一套完全陌生的格式。manifest.json、popup.html、background.js 都是浏览器扩展里很常见的概念。 第二,插件天然有清单文件。主程序可以先读 manifest.json,判断插件名称、版本、描述、权限、弹窗入口、最低支持版本这些信息。 第三,Electron 可以直接加载插件目录,不需要我自己写一个脚本沙箱。 展示、搜索、分页和状态 插件市场不是只要能安装就行,还要能快速判断: 这个插件是干什么的 我有没有装过 我装的是不是旧版本 这个插件有没有更高版本要求 它有没有联网、文件访问、本地二进制这些风险点 分页,搜索,更新,状态 所以市场卡片里展示的不只是“安装”按钮。 确保插件目录存在 调用Electron下载安装、卸旧版、装新版 注册插件相关 IPC 加载 Chrome 扩展 加载 Native Host 索引和授权系统 已安装插件 插件管理页里的“已安装插件”不是只读 Electron 当前加载的扩展。它会把两类信息合并: session.defaultSession.getAllExtensions() 拿到已加载扩展 scanExtensions() 扫描磁盘插件目录,读取 manifest、图标、popup、Native Host 声明 前端拿到这些字段后,就能显示: 插件名称、描述、版本、作者 图标 是否是 MoeKoe 适配插件 当前客户端版本是否低于插件 minversion 是否有 popup 设置页 是否声明了本地二进制程序 Native Host 这是2.0版本新增的插件功能. 插件系统里最需要小心的是 Native Host,也就是插件附带本地可执行程序的能力。 普通前端插件再怎么折腾,大多还是在浏览器扩展模型里。但本地程序不一样。它一旦启动,就具备普通桌面程序的系统访问能力。 ...
# MoeKoeMusic-Plugins Design Philosophy
When I first started building the MoeKoe Music plugin ecosystem, there was no online plugin marketplace feature yet. Later, based on community suggestions, the plugin marketplace came into being [Add official/community plugin repositories to extend product functionality] If plugins can be developed by the community, how should the plugin marketplace be managed? The most straightforward approach would be to pull all plugin source code into a single monorepo. But the more I thought about it, the more awkward it felt. Each plugin has its own author, its own release cadence, its own build process. Stuffing them all into the official repo would not only drive up maintenance costs but also blur the lines of responsibility. ...
I'm making 18+ games with losing "equipment drop" 🔞
Continuing from: 《同一个动画,我用三种技术栈实现的区别?》 WebGL Rock-Paper-Scissors Mini Game (Anime Style) The rules are pretty standard: Rock > Scissors Scissors > Paper Paper > Rock But the fun part is: Losing means taking off clothes. Yep, it’s that straightforward. The Origin Was Actually “I Wanted to Study Sprite Sheets” At first, I had no intention of making a game at all. I just wanted to study: atlas sprite layer compositing animation clipping Stuff like that. Then I thought: “There’s gotta be a real use case, right?” ...
What are the differences when I implement the same animation with three tech stacks?
Recently I did a rather interesting little experiment. I implemented a small anime character animation effect using three different approaches: WebGL Canvas 2D Pure DOM + CSS The effect itself isn’t complicated: Eye blinking Eyebrow/lower eyelid联动 Sweat droplet gently swaying Ahoge (hair antenna) swinging But the really interesting part isn’t actually “making it work.” It’s: When implementing the same thing with three different tech stacks, how different are they really? ...
Kill the person who writes code by hand
Lately, while I’m coding, I have a strange feeling. Not that I can’t code or don’t want to. But— It feels like I’m becoming less and less necessary. Previously, for a feature from requirement to launch, the path was basically this: I understand the requirement → design the solution → write code → debug → fix bugs → launch What does it look like now? I describe the requirement → AI writes the code → AI fixes the bugs → I glance at it → launch ...
履行一场二十年的约定
This story sounds like something out of a TV drama, but it actually happened to me. I’m someone who’s very sentimental. Due to family reasons, I left that place at an early age. The concept of “growing up together (childhood friends)” has always been vague to me—and because of this, I’ve always envied those who could grow up side by side with deep affection. After growing up, I always felt like I was constantly drifting. Habitually leaving early, abandoning my friends behind. ...