diff --git a/.DS_Store b/.DS_Store index 82e7966..d5b8921 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/404.html b/404.html index 471eb19..44fa8ce 100644 --- a/404.html +++ b/404.html @@ -4,6 +4,24 @@ 页面未找到 | Ray Chen + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 098be72..a12e3be 100644 --- a/README.md +++ b/README.md @@ -3,76 +3,148 @@ ![GitHub Pages](https://img.shields.io/badge/GitHub%20Pages-Deployed-brightgreen) ![License](https://img.shields.io/badge/License-MIT-blue) ![Last Commit](https://img.shields.io/github/last-commit/Rayawa/Rayawa.github.io) +![多语言](https://img.shields.io/badge/多语言-中文|英文|法文-blue) +![响应式](https://img.shields.io/badge/响应式-网页优先-green) ## 🌐 项目简介 -这是一个基于GitHub Pages部署的个人作品集网站,展示Ray Chen(Rayawa)的技术项目、摄影作品和个人简介。网站支持多语言(中文、英文、法文),采用响应式设计,适配各种设备。 +这是一个基于GitHub Pages部署的个人作品集网站,展示Ray Chen(Rayawa)的技术项目、个人作品和简介。网站采用现代化的多语言架构,支持中文、英文、法文三种语言,具有响应式设计和优雅的用户界面。 **在线访问:** [https://rayawa.github.io](https://rayawa.github.io) **主域名:** [https://rayawa.top](https://rayawa.top) ## 🚀 功能特性 -### 🌍 多语言支持 -- **中文** (`index.html`) - 默认语言 -- **英文** (`index_en.html`) - 国际访问 -- **法文** (`index_fr.html`) - 法语支持 +### 🌍 多语言架构 +- **中文版本** (`index.html`) - 主目录,默认语言 +- **英文版本** (`en/index.html`) - 独立英文目录 +- **法文版本** (`fr/index.html`) - 独立法文目录 +- **静态化翻译** - 取消动态i18n,直接填入文本,提升性能 ### 📱 响应式设计 - 移动端优先的设计理念 -- 自适应各种屏幕尺寸 +- 自适应各种屏幕尺寸(手机、平板、桌面) - 触摸友好的交互界面 +- 优化的加载性能 ### 🎨 视觉特色 -- 动态背景效果(orb动画) - 现代化的卡片式布局 -- 优雅的过渡动画 -- 暗色主题设计 +- 优雅的过渡动画和微交互 +- 暗色主题设计,护眼舒适 +- 统一的视觉语言和设计系统 ### 📊 内容模块 -1. **个人简介** - 基本信息和技术方向 -2. **项目展示** - 技术项目和作品集 -3. **摄影画廊** - 摄影作品展示 -4. **社交链接** - 联系方式和个人主页 +1. **个人简介** - 基本信息、技能和经历 +2. **项目展示** - 技术项目、开源贡献 +3. **生活分享** - 书籍、音乐等个人兴趣 +4. **仪表板** - 数据展示和统计 +5. **联系方式** - 社交链接和联系表单 -## 📁 项目结构 +## 📁 最新项目结构 ``` Rayawa.github.io/ -├── index.html # 中文主页 -├── index_en.html # 英文主页 -├── index_fr.html # 法文主页 -├── README.md # 项目说明文档 -├── favicon.ico # 网站图标 -├── ray.jpg # 个人头像 -├── gallery/ # 摄影作品 -│ └── index.html # 画廊页面 -├── projects/ # 项目展示 -│ ├── bio-project.html # 生物项目 -│ ├── gene.html # 基因项目 -│ ├── harmony-dashboard.html # Harmony仪表板 -│ ├── idv.html # IDV项目 -│ └── sweet-potato-mod.html # 红薯项目 -└── static/ # 静态资源 - ├── css/ # 样式文件 - │ ├── stylesheet.css # 主样式 - │ └── print.css # 打印样式 - ├── js/ # JavaScript文件 - │ └── mobile-enhancements.js # 移动端增强 - ├── images/ # 图片资源 - │ ├── cn.svg # 中国国旗 - │ ├── uk.svg # 英国国旗 - │ └── fr.svg # 法国国旗 - └── gallery/ # 画廊资源 +├── index.html # 中文主页(主目录) +├── thanks.html # 感谢页面 +├── 404.html # 404错误页面 +├── README.md # 项目说明文档 +├── favicon.ico # 网站图标 +├── ray.jpg # 个人头像 +│ +├── en/ # 英文版本目录 +│ ├── index.html # 英文主页 +│ ├── thanks.html # 英文感谢页面 +│ ├── life/ # 英文生活页面 +│ │ ├── books.html # 英文书籍页面 +│ │ └── piano.html # 英文钢琴页面 +│ └── projects/ # 英文项目页面 +│ ├── Hi3861.html # Hi3861项目 +│ ├── Hi3861-readme.html # Hi3861说明 +│ ├── biology.html # 生物项目 +│ ├── gene.html # 基因项目 +│ ├── idv.html # IDV项目 +│ ├── ncut_papers.html # 论文项目 +│ ├── signal.html # 信号项目 +│ ├── spm.html # SPM项目 +│ ├── xxh.html # XXH项目 +│ └── xxh_test.html # XXH测试 +│ +├── fr/ # 法文版本目录 +│ ├── index.html # 法文主页 +│ ├── thanks.html # 法文感谢页面 +│ ├── life/ # 法文生活页面 +│ │ ├── books.html # 法文书籍页面 +│ │ └── piano.html # 法文钢琴页面 +│ └── projects/ # 法文项目页面 +│ ├── Hi3861.html # Hi3861项目 +│ ├── Hi3861-readme.html # Hi3861说明 +│ ├── biology.html # 生物项目 +│ ├── gene.html # 基因项目 +│ ├── idv.html # IDV项目 +│ ├── ncut_papers.html # 论文项目 +│ ├── signal.html # 信号项目 +│ ├── spm.html # SPM项目 +│ ├── xxh.html # XXH项目 +│ └── xxh_test.html # XXH测试 +│ +├── life/ # 中文生活页面 +│ ├── books.html # 书籍页面 +│ └── piano.html # 钢琴页面 +│ +├── projects/ # 中文项目页面 +│ ├── Hi3861.html # Hi3861项目 +│ ├── Hi3861-readme.html # Hi3861说明 +│ ├── biology.html # 生物项目 +│ ├── gene.html # 基因项目 +│ ├── idv.html # IDV项目 +│ ├── ncut_papers.html # 论文项目 +│ ├── signal.html # 信号项目 +│ ├── spm.html # SPM项目 +│ ├── xxh.html # XXH项目 +│ └── xxh_test.html # XXH测试 +│ +└── static/ # 静态资源(公共组件) + ├── css/ # 样式文件 + │ ├── common.css # 通用样式 + │ ├── index.css # 主页样式 + │ ├── 404.css # 404页面样式 + │ ├── subpage.css # 子页面通用样式 + │ ├── markdown-page.css # Markdown页面样式 + │ ├── gene.css # 基因项目样式 + │ ├── hi3861.css # Hi3861项目样式 + │ ├── hi3861-readme.css # Hi3861说明样式 + │ ├── signal.css # 信号项目样式 + │ ├── spm.css # SPM项目样式 + │ ├── xxh.css # XXH项目样式 + │ ├── books.css # 书籍页面样式 + │ ├── piano.css # 钢琴页面样式 + │ └── drawing.css # 绘图页面样式 + │ + ├── js/ # JavaScript文件 + │ ├── common.js # 通用脚本 + │ ├── index.js # 主页脚本 + │ ├── navbar.js # 导航栏脚本 + │ ├── gene.js # 基因项目脚本 + │ └── xxh.js # XXH项目脚本 + │ + └── resources/ # 资源文件 + ├── idv/ # IDV项目资源 + │ └── idv.html # IDV页面 + └── bio/ # 生物项目资源 + └── agrobacterium/ # 农杆菌资源 + └── agrobacterium.html # 农杆菌页面 ``` ## 🛠️ 技术栈 - **前端**: HTML5, CSS3, JavaScript (ES6+) -- **部署**: GitHub Pages -- **图标**: SVG矢量图标 -- **字体**: 系统默认字体栈 -- **动画**: CSS3动画和过渡效果 +- **架构**: 多语言静态化架构,取消动态i18n +- **组件**: 公共组件提取,提高代码复用性 +- **部署**: GitHub Pages 自动部署 +- **图标**: SVG矢量图标,优化加载性能 +- **字体**: 系统默认字体栈,减少外部依赖 +- **动画**: CSS3动画和过渡效果,提升用户体验 +- **工具**: 自动化脚本处理多语言内容 ## 🚦 快速开始 @@ -84,53 +156,96 @@ Rayawa.github.io/ ``` 2. 本地预览: - - 使用任何HTTP服务器(如Python的SimpleHTTPServer): + - 使用Python的SimpleHTTPServer: ```bash python3 -m http.server 8000 ``` - - 或直接使用浏览器打开 `index.html` + - 或使用Node.js的http-server: + ```bash + npx http-server -p 8000 + ``` + - 或直接使用浏览器打开 `index.html`(部分功能可能需要HTTP服务器) 3. 访问 `http://localhost:8000` 查看网站 ### 部署 网站通过GitHub Pages自动部署: -- 推送到 `master` 分支 +- 推送到 `main` 或 `master` 分支 - GitHub Pages自动构建和部署 - 访问 https://rayawa.github.io +- 自定义域名:https://rayawa.top ## 📝 内容更新 -### 添加新项目 -1. 在 `projects/` 目录创建新的HTML文件 -2. 在主页面 (`index.html`) 中添加项目链接 -3. 更新其他语言版本页面 - -### 更新个人信息 -编辑对应语言的主页文件: -- `index.html` - 中文信息 -- `index_en.html` - 英文信息 -- `index_fr.html` - 法文信息 - -### 添加摄影作品 -1. 将图片添加到 `static/gallery/` 目录 -2. 更新 `gallery/index.html` 文件 - -## 🌟 项目亮点 - -### 1. 多设备适配 -- 完善的移动端体验 -- 平板和桌面端优化 -- 打印样式支持 - -### 2. 性能优化 -- 静态资源优化 -- 懒加载图片 -- 最小化HTTP请求 - -### 3. 可访问性 -- 语义化HTML结构 -- ARIA标签支持 -- 键盘导航友好 +### 添加新页面 +1. 在对应语言目录创建新的HTML文件 + - 中文页面:主目录或对应子目录 + - 英文页面:`en/` 目录下 + - 法文页面:`fr/` 目录下 + +2. 更新导航栏链接(如果需要) + - 编辑 `static/components/navbar.html` 文件 + - 确保多语言版本链接正确 + +3. 添加页面特定样式(如果需要) + - 在 `static/css/` 目录下创建新的CSS文件 + - 在HTML文件中引用正确的路径 + +### 更新多语言内容 +由于采用静态化多语言架构,需要分别更新: +- 中文内容:编辑主目录下的对应文件 +- 英文内容:编辑 `en/` 目录下的对应文件 +- 法文内容:编辑 `fr/` 目录下的对应文件 + +### 添加静态资源 +1. 公共资源:添加到 `static/` 目录下对应子目录 +2. 页面特定资源:可考虑移动到对应页面目录(未来优化方向) +3. 图片资源:优化压缩后添加到 `static/resources/` 目录 + +## 🌟 架构亮点 + +### 1. 现代化多语言架构 +- **静态化翻译**: 取消动态i18n,直接填入文本,提升加载速度 +- **目录分离**: 每种语言独立目录,结构清晰,易于维护 +- **路径优化**: 智能相对路径处理,确保跨语言链接正确 + +### 2. 组件化设计 +- **公共导航栏**: 提取到 `static/components/navbar.html`,统一维护 +- **样式模块化**: CSS按功能模块划分,提高复用性 +- **脚本组织**: JavaScript按页面功能分离,避免代码臃肿 + +### 3. 性能优化 +- **静态资源优化**: CSS和JS文件压缩和合并 +- **懒加载策略**: 图片和内容按需加载 +- **最小化请求**: 减少HTTP请求数量,提升页面速度 +- **编码规范**: UTF-8编码,确保多语言显示正确 + +### 4. 可维护性 +- **清晰目录结构**: 按语言和功能组织文件 +- **自动化脚本**: 提供重构和修复脚本,简化维护 +- **文档完善**: 详细的README和项目说明 +- **版本控制**: 完整的Git历史记录 + +### 5. 可访问性 +- **语义化HTML**: 使用正确的HTML5标签 +- **ARIA支持**: 增强屏幕阅读器兼容性 +- **键盘导航**: 支持完整的键盘操作 +- **响应式设计**: 适配各种设备和屏幕尺寸 + +## 🔧 重构特性 + +### 已完成的重构工作 +1. **i18n静态化**: 将动态翻译内容直接填入HTML,取消i18n.js依赖 +2. **目录重组**: 创建 `en/` 和 `fr/` 独立语言目录 +3. **路径修复**: 自动修复所有静态资源和链接的相对路径 +4. **组件提取**: 公共导航栏提取到 `static/components/` +5. **HTML清理**: 修复HTML标签和结构问题 + +### 待优化的方向 +1. **资源位置优化**: 将页面特定的JS/CSS移动到对应页面目录 +2. **构建流程**: 添加自动化构建和部署脚本 +3. **性能监控**: 集成性能分析和优化工具 +4. **测试覆盖**: 添加自动化测试确保多语言版本一致性 ## 🤝 贡献指南 @@ -142,6 +257,12 @@ Rayawa.github.io/ 4. 推送到分支 (`git push origin feature/AmazingFeature`) 5. 开启Pull Request +### 贡献注意事项 +- **多语言同步**: 修改功能时需同步更新所有语言版本 +- **路径处理**: 注意相对路径在不同目录下的正确性 +- **组件更新**: 修改公共组件时需测试所有使用页面 +- **编码规范**: 使用UTF-8编码,确保多语言兼容 + ## 📄 许可证 本项目采用MIT许可证 - 查看 [LICENSE](LICENSE) 文件了解详情 @@ -151,8 +272,11 @@ Rayawa.github.io/ - **GitHub**: [@Rayawa](https://github.com/Rayawa) - **网站**: [https://rayawa.top](https://rayawa.top) - **邮箱**: 通过GitHub Profile联系 +- **项目主页**: [https://rayawa.github.io](https://rayawa.github.io) --- -**最后更新**: 2025年4月7日 -**维护者**: Ray Chen (Rayawa) \ No newline at end of file +**最后更新**: 2026年4月21日 +**维护者**: Ray Chen (Rayawa) +**架构版本**: v2.0 (多语言静态化重构版) +**技术栈**: HTML5, CSS3, JavaScript, GitHub Pages \ No newline at end of file diff --git a/dashboard.html b/dashboard.html deleted file mode 100644 index 64b2ed1..0000000 --- a/dashboard.html +++ /dev/null @@ -1,404 +0,0 @@ - - - - - - 华为应用市场看板 | Ray Chen - - - - - - - - - - - - -
- -
- -
-
-
- App Icon -
-
-

华为应用市场看板

-

- - Harmony Gallery 项目组 - 制作。一个获取、处理、分析并展示鸿蒙应用市场所有应用与元服务数据的全栈项目。 -

-
-
- -
-
- 以 Rust 为基础 - 强大的数据库 - 多平台适配 - 开放原子大赛获奖作品 -
-
-
- - -
-
-
-
-
-
-
项目总访问量
-
-
totalViews
-
-
-
今日访问量
-
-
todayViews
-
-
-
鸿蒙应用总访问量
-
-
harmonyTotalViews
-
-
-
* 数据统计范围从2025-11-01T04:00:00Z至今,数据自动更新失败!上次更新{{updateTime}}。
-
- -
-
- - - 浏览器
S 站
-
- - - 浏览器
T 站
-
- - - 浏览器
R 站
-
- - - HarmonyOS
(内测)
-
- - -
-
-
-
-
- - -
-
-
-

详细介绍

-

以下内容聚焦项目目标、核心能力与技术架构。

-
- -
-
-
-
- 01 -

项目是做什么的

-
-
-

本应用是由Harmony Gallery项目组直接参与编写的鸿蒙应用。应用收集华为应用市场的公开数据,转化为直观的图表与报告。简单来说,您能在这里查看几乎所有鸿蒙应用的动态。

-

1. 数据总览与图表分析:通过榜单、饼图与折线图,直观查看应用下载量、评分趋势与市场分布。

-

2. 搜索应用与查看详情:支持按名称、评分等条件搜索排序、应用内搜索应用、分享链接搜索应用。您可查看各种应用数据与趋势图。

-

3. 数据定时自动更新:后台每30分钟同步一次数据,确保您始终获取最新数据。

-

4. 交互式操作与分享:点击图表可进行数据筛选,点击应用可进入详情页;您也可通过链接、隔空抓取或鸿蒙碰一碰便捷分享应用页面。

-

5. 投稿更新应用信息:您可通过应用市场分享与"我的"页面向应用看板投稿,协助投稿新应用或更新应用信息。

-
-
- -
-
- 02 -

网页端核心功能

-
-
-
    -
  • 1. 数据统计:展示应用总数、元服务总数、开发者总数等关键指标的统计数据。
  • -
  • 2. 下载榜:提供下载量排名前20的应用列表,以及排除华为系应用后的下载量排名。
  • -
  • 3. 应用详情:点击任意应用相关图标查看应用的详细信息,包括下载量、评分、支持设备、版本信息等。
  • -
  • 4. 趋势分析:展示应用下载量的变化趋势和增量趋势图表。
  • -
  • 5. 应用列表:详细应用信息表格,支持搜索、排序、筛选功能。
  • -
-
-
-
- - -
-
-
- - -
-
-
-

技术架构

-

项目采用现代化技术栈,确保高性能、高可用性与可维护性

-
- -
-
-
-

后端技术(Rust)

-

Rust 技术栈实现数据聚合、API 暴露、数据库访问和服务端能力编排

-
    -
  • Rust 2024 Edition:内存安全、零成本抽象、高性能
  • -
  • Axum 0.8:类型安全的 Web 框架,ergonomic API 设计
  • -
  • Tokio 1.47:异步运行时,高效并发处理
  • -
  • SQLx 0.8:编译期 SQL 检查,类型安全的数据库操作
  • -
  • Reqwest 0.12:HTTP 客户端,支持连接池与自动重试
  • -
  • Serde + TOML:序列化/反序列化,配置管理
  • -
  • Tracing:结构化日志与性能追踪
  • -
  • Tower HTTP 压缩:Brotli、Gzip、Deflate、Zstd
  • -
-
- -
-

数据库(PostgreSQL)

-

PostgreSQL 12+ 推荐 14+,强大的关系型数据库

-
    -
  • 数据表:app_info, app_metrics, app_rating, app_raw, substance 等
  • -
  • 触发器:自动化数据更新与一致性维护
  • -
  • 索引优化:查询性能提升
  • -
  • 外键级联:数据完整性保障
  • -
  • JSON 字段:灵活的数据结构支持
  • -
-
-
- -
-
-

网站前端

-
-

S 站前端

-
    -
  • 原生 JavaScript:无框架依赖,轻量高效
  • -
  • Chart.js + Date-fns:数据可视化
  • -
  • Markdown-it:Markdown 渲染
  • -
  • 响应式设计:移动端适配
  • -
-
-
-

T 站前端

-
    -
  • Vue.js:渐进式前端框架
  • -
-
-
- -
-

鸿蒙前端

-
    -
  • ArkTS:鸿蒙应用开发语言
  • -
  • ArkUI:声明式 UI 框架
  • -
  • ArkWeb:Web 容器集成
  • -
  • Stage Model:现代化工程模型
  • -
  • Hvigor:构建工具链
  • -
-
-
-
-
-
- - -
-
-
-

数据库接入

-

Harmony Gallery 项目组提供鸿蒙应用市场数据查询、统计分析等功能接口,欢迎有需要的项目与我们的数据库对接。

-
- -
- - -
-
-

⚠️ 重要提示

-

对接数据库之前需要明确告知我们,否则可能违反开源许可。

-

使用者不得在获取信息之后在本地原样存储。

-

友情链接内网站展示的任何内容均与鸿蒙应用看板无关。Harmony Gallery 项目组不负责维护友情链接内容。

-
- -
-

API 文档

-

查看完整的 API 接口文档,了解数据接入方式 -如果您有意向使用我们的数据库,请先与我们取得联系!

- -
-
-
-
-
- - -
-
-
-

联系我们

-

感谢所有为项目做出贡献的开发者与合作伙伴

-
- -
-
-

Harmony Gallery 项目组

-
-
-
shenjack
-
邮箱:3695888@qq.com
-
主要负责人
-
-
-
清霁·Rayawa
-
邮箱:rayawa.work@outlook.com
-
鸿蒙应用开发、网站制作
-
-
-
tianxiu2b2t
-
邮箱:administrator@ttb-network.top
-
T 站网页负责人
-
-
-
Harmony Gallery 官方交流群
- -
QQ 群
-
-
-
- -
-
-

致谢

-
    -
  • 项目致谢:伤心萨摩耶、HEZI641
  • -
  • 鸿蒙应用致谢:筱冉、音唯Artix
  • -
  • 感谢华为开发者联盟技术支持
  • -
-
- -
-

开源许可

- -
- GPL-3.0 License -
-
-

本项目采用 GPL-3.0 协议开源,允许自由使用、修改与分发,但衍生作品必须采用相同协议

-
-
-
-
-
-
- - - - - - - - - - - diff --git a/en/.DS_Store b/en/.DS_Store index 404d216..17169d9 100644 Binary files a/en/.DS_Store and b/en/.DS_Store differ diff --git a/en/dashboard.html b/en/dashboard.html deleted file mode 100644 index 744cbf9..0000000 --- a/en/dashboard.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - - - HmDashboard | Ray Chen - - - - - - - - - - - - -
- -
- -
-
-
- App Icon -
-
-

HmDashboard

-

- Crafted by the - Harmony Gallery Team - . A full-stack project that acquires, processes, analyzes, and visualizes all app and atomic service data from the HarmonyOS app market. -

-
-
- -
-
- Rust-Powered - Powerful Database - Multi-Platform Support - OpenAtom Contest Award Winner -
-
-
- - -
-
-
-
-
-
-
Total Project Views
-
-
totalViews
-
-
-
Today's Views
-
-
todayViews
-
-
-
Total HarmonyOS App Views
-
-
harmonyTotalViews
-
-
-
* Data statistics range from 2025-11-01T04:00:00Z to present. Auto-update failed! Last update {{updateTime}}.
-
- -
- -
-
-
-
- - -
-
-
-

Detailed Introduction

-

The following content focuses on project goals, core capabilities, and technical architecture.

-
- -
-
-
-
- 01 -

What Does This Project Do

-
-
-

This app is a HarmonyOS application directly developed by the Harmony Gallery team. It collects public data from the Huawei AppMarket and transforms it into intuitive charts and reports. Simply put, you can view the dynamics of almost all HarmonyOS apps here.

-

1. Data Overview & Chart Analysis: View app downloads, rating trends, and market distribution intuitively through rankings, pie charts, and line charts.

-

2. Search Apps & View Details: Support searching and sorting by name, rating, etc.; in-app search; share link search. You can view various app data and trend charts.

-

3. Scheduled Auto-Update: Data is synced every 30 minutes in the background, ensuring you always get the latest data.

-

4. Interactive Operations & Sharing: Click charts for data filtering, click apps to enter detail pages; you can also conveniently share app pages via links, air grab, or HarmonyOS tap-to-share.

-

5. Contribute & Update App Info: You can contribute to the app dashboard via AppMarket sharing and the "Me" page, helping submit new apps or update app information.

-
-
- -
-
- 02 -

Web Core Features

-
-
-
    -
  • 1. Data Statistics: Display statistical data for key indicators such as total number of apps, total atomic services, and total developers.
  • -
  • 2. Download Rankings: Provide a list of the top 20 apps by downloads, as well as download rankings excluding Huawei apps.
  • -
  • 3. App Details: Click any app-related icon to view detailed app information, including downloads, ratings, supported devices, version info, etc.
  • -
  • 4. Trend Analysis: Display charts of app download change trends and incremental trends.
  • -
  • 5. App List: Detailed app information table with search, sorting, and filtering capabilities.
  • -
-
-
-
- - -
-
-
- - -
-
-
-

Technology Stack

-

The project adopts a modern tech stack, ensuring high performance, high availability, and maintainability

-
- -
-
-
-

Backend (Rust)

-

Rust tech stack implementing data aggregation, API exposure, database access, and server-side capability orchestration

-
    -
  • Rust 2024 Edition: Memory safety, zero-cost abstractions, high performance
  • -
  • Axum 0.8: Type-safe web framework, ergonomic API design
  • -
  • Tokio 1.47: Async runtime, efficient concurrent processing
  • -
  • SQLx 0.8: Compile-time SQL checks, type-safe database operations
  • -
  • Reqwest 0.12: HTTP client, supports connection pooling and auto-retry
  • -
  • Serde + TOML: Serialization/deserialization, configuration management
  • -
  • Tracing: Structured logging and performance tracking
  • -
  • Tower HTTP Compression: Brotli, Gzip, Deflate, Zstd
  • -
-
- -
-

Database (PostgreSQL)

-

PostgreSQL 12+ (14+ recommended), powerful relational database

-
    -
  • Tables: app_info, app_metrics, app_rating, app_raw, substance, etc.
  • -
  • Triggers: Automated data updates and consistency maintenance
  • -
  • Index Optimization: Query performance enhancement
  • -
  • Foreign Key Cascades: Data integrity guarantees
  • -
  • JSON Fields: Flexible data structure support
  • -
-
-
- -
-
-

Web Frontend

-
-

S Site Frontend

-
    -
  • Native JavaScript: No framework dependencies, lightweight and efficient
  • -
  • Chart.js + Date-fns: Data visualization
  • -
  • Markdown-it: Markdown rendering
  • -
  • Responsive Design: Mobile adaptation
  • -
-
-
-

T Site Frontend

-
    -
  • Vue.js: Progressive frontend framework
  • -
-
-
- -
-

HarmonyOS Frontend

-
    -
  • ArkTS: HarmonyOS application development language
  • -
  • ArkUI: Declarative UI framework
  • -
  • ArkWeb: Web container integration
  • -
  • Stage Model: Modern engineering model
  • -
  • Hvigor: Build toolchain
  • -
-
-
-
-
-
- - -
-
-
-

Database Access

-

The Harmony Gallery team provides HarmonyOS app market data query, statistical analysis, and other functional interfaces. Projects in need are welcome to integrate with our database.

-
- -
- - -
-
-

⚠️ Important Notice

-

You must inform us before integrating with the database, otherwise it may violate the open source license.

-

Users must not store obtained information locally in its original form.

-

Any content displayed on friendly-linked websites is unrelated to the HarmonyOS App Dashboard. The Harmony Gallery project team is not responsible for maintaining friendly link content.

-
- -
-

API Documentation

-

View complete API documentation to understand data integration methods -If you are interested in using our database, please contact us first!

- -
-
-
-
-
- - -
-
-
-

Contact Us

-

Thanks to all developers and partners who contributed to the project

-
- -
-
-

Harmony Gallery Team

-
-
-
shenjack
-
Email: 3695888@qq.com
-
Principal
-
-
-
清霁·Rayawa
-
Email: rayawa.work@outlook.com
-
HarmonyOS App Development, Website Production
-
-
-
tianxiu2b2t
-
Email: administrator@ttb-network.top
-
T Site Web Lead
-
-
-
Harmony Gallery Official Communication Group
- -
QQ Group
-
-
-
- -
-
-

Acknowledgments

-
    -
  • Project Thanks: 伤心萨摩耶, HEZI641
  • -
  • HarmonyOS App Thanks: 筱冉, 音唯Artix
  • -
  • Thanks to Huawei Developer Alliance for technical support
  • -
-
- -
-

License

- -
- GPL-3.0 License -
-
-

This project is open-sourced under GPL-3.0 License, allowing free use, modification, and distribution, but derivative works must use the same license

-
-
-
-
-
-
- - - - - - - - - - - diff --git a/en/index.html b/en/index.html index f614634..e5372a3 100644 --- a/en/index.html +++ b/en/index.html @@ -5,13 +5,42 @@ Home | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -107,24 +136,24 @@

About Me

Despite being a science student, I have an intense curiosity about world cultures. My background in English speech competitions and two years of British Parliamentary (BP) debate provided a solid linguistic foundation. Recently, I've been learning French. From the ethereal singing of Cécile Corbel to the romantic vistas of Fontaine; from the flowing melody of "La Vaguelette" to the classic dialogues of "Romeo and Juliet"—the charm of the French language drives me deeper into its waters.

Whether building order in the world of 0s and 1s or finding patterns in the double helix of biology, I believe cross-disciplinary exploration broadens the boundaries of life. If you share a curiosity for technology, biology, or this diverse world, feel free to reach out.

Nice to meet you on this voyage called "growing up."

-

— Ray
April 12, 2026

+

— Ray
May 19, 2026

Current Focus

- +
Core Development
-

HarmonyOS 6.1.0 App Dashboard development
Personal website development

+

SmartShed project OpenHarmony + HarmonyOS full-stack development
Machine learning object detection & pruning project

Parallel Development
-

OpenHarmony (Hi3861) embedded development & systems engineering deep dive

+

HarmonyOS 6.1.0 App Dashboard development
iOS/MacOS app development
Machine learning based on OpenHarmony

@@ -163,7 +192,7 @@

About Me

Open Source Projects
-

Sweet Potato Mod · Difficult Rocket

+

Sweet Potato Mod · Difficult Rocket · Rock Paper Scissors Detection · SmartShed

@@ -255,11 +284,11 @@

My Projects

Main Projects

Projects I lead or contribute to — research, development, and open source.

-
- +
+
-

HmDashboard

+

HmDashboard

Powered by Shenjack!
A full-stack project that fetches, processes, analyzes, and displays all app and meta-service data from the HarmonyOS AppGallery.
I mainly work on the frontend web development and software development. Current main project, continuously updating…

OpenAtom Contest Award Winner @@ -286,28 +315,54 @@

Biology Projects

- -
+
+
-

Sweet Potato Mod

-

Farming meets magic!
A Minecraft mod co-developed with @teddyxlandlee, adding sweet potatoes, farming stations, grinders, Magic Cube, enchanted crops, and more.
One of my earliest projects, though it hasn't been maintained in a while.

+

Measurement of Weak Electrical Signals

+

Physics competition project. This project designs a system for measuring weak electrical signals based on Arduino embedded development. The system utilizes a suspended wire structure and the optical lever principle to achieve physical amplification, and combines signal conditioning circuits with embedded processing for data acquisition and computation. Through a normalization algorithm and multi-stage noise reduction methods, the measurement stability and anti-interference capability are improved.

- Minecraft - Mod - Java + Arduino Embedded + Communication Engineering + Physics Competition
- -
+
+
-

OpenHarmony Hi3861

-

Embedded development practice based on OpenHarmony Hi3861 dev board.
My first serious embedded project since playing with Arduino as a kid.
Still exploring…

+

SmartShed

+

An IoT smart greenhouse system based on OpenHarmony Hi3861 and HarmonyOS 6.1.0 with edge-cloud coordination.
Covers embedded sensing, MQTT communication, and full-featured HarmonyOS control terminal.

OpenHarmony - Embedded Development - Smart Life + HarmonyOS + Open Source +
+
+
+ + +
+
+

Rock Paper Scissors Detection

+

Real-time gesture recognition based on YOLO11n, validation mAP50 = 0.940.
Also includes California housing Random Forest regression, student digital behavior analysis, and other ML case studies.

+
+ Machine Learning + Object Detection + Open Source +
+
+
+ + +
+
+

Sweet Potato Mod

+

Farming meets magic!
A Minecraft mod co-developed with @teddyxlandlee, adding sweet potatoes, farming stations, grinders, Magic Cube, enchanted crops, and more.
One of my earliest projects, though it hasn't been maintained in a while.

+
+ Minecraft + Mod + Java
@@ -325,19 +380,6 @@

Difficult Rocket (Collaboration) -
-
-

Measurement of Weak Electrical Signals

-

Physics competition project. This experiment linearly converts nanoampere-level weak photocurrents sensed by sensors into voltage signals through a transimpedance amplifier circuit, and utilizes dual noise suppression techniques of metal Faraday cage shielding and terminal digital averaging filtering, achieving high signal-to-noise ratio real-time data acquisition and physical quantity quantification with Arduino and a 16-bit ADC.

-
- Arduino Embedded - Communication Engineering - Physics Competition -
-
-

-
@@ -347,6 +389,12 @@

Other Projects

Fun little things I wrote casually or for classmates and friends ()

+ +
+

OpenHarmony Hi3861

+

Embedded development practice based on Hi3861. My first serious embedded project since Arduino.

+
+

"Shou Yi Hong Qun Fang Kai Ye Yan"

@@ -495,40 +543,18 @@

Gallery

-
- -
-
-

Piano

-

Music is the art of time. Self-taught since middle school, capturing melodies at my fingertips.

-
- Piano - Music -
+
+ +
+
+

Piano

- -
-
-

Artworks

-

Capturing inspiration with a brush. Genshin fan art, character creations, and more.

-
- Art - Genshin -
-
-
- - -
-
@@ -686,7 +712,7 @@

Quick Message

- + diff --git a/en/life/books.html b/en/life/books.html index ce3a6c8..de3253c 100644 --- a/en/life/books.html +++ b/en/life/books.html @@ -4,7 +4,34 @@ Bookshelf | Ray Chen - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/life/piano.html b/en/life/piano.html index 3d0496e..16568ea 100644 --- a/en/life/piano.html +++ b/en/life/piano.html @@ -4,6 +4,33 @@ Piano | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/.DS_Store b/en/projects/.DS_Store index f287bc5..c2b6f79 100644 Binary files a/en/projects/.DS_Store and b/en/projects/.DS_Store differ diff --git a/en/projects/Hi3861-readme.html b/en/projects/Hi3861-readme.html index 0072e76..a34de37 100644 --- a/en/projects/Hi3861-readme.html +++ b/en/projects/Hi3861-readme.html @@ -3,7 +3,34 @@ - Hi3861 | Ray Chen + Hi3861 README | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/Hi3861.html b/en/projects/Hi3861.html index 9708af9..d23a5b6 100644 --- a/en/projects/Hi3861.html +++ b/en/projects/Hi3861.html @@ -4,6 +4,33 @@ Hi3861 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/RockPaperSissors.html b/en/projects/RockPaperSissors.html new file mode 100644 index 0000000..2b9c478 --- /dev/null +++ b/en/projects/RockPaperSissors.html @@ -0,0 +1,408 @@ + + + + + + Rock Paper Scissors Detection | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ Python · Machine Learning · Deep Learning +

Rock Paper Scissors Detection

+

2026 Summer Python Course Project Collection covering Python fundamentals, machine learning regression prediction, student behavior data analysis, and YOLO11n-based Rock Paper Scissors gesture recognition.

+ +
+ +
+ Rock Paper Scissors Detection Demo +
+ +
+
+ Project 1 +

Python Fundamentals Exercises

+

14 beginner exercises: comprehensive coverage of data types, control flow, functions, lists, dictionaries, and more.

+
+
+ Project 2-1 +

California Housing Prediction

+

Random Forest regression for California housing median price prediction, R² = 0.805. Verified that income and geographic location are key influencing factors.

+
+
+ Project 2-2 +

Student Behavior Analysis

+

Kaggle real-world dataset analyzing the impact of study time, screen time, etc. on CGPA, with multi-model comparison.

+
+
+ Project 3 +

YOLO11n Gesture Recognition

+

🪨📄✂️ Real-time detection of Rock/Paper/Scissors, validation set mAP50 = 0.940, millisecond-level inference.

+
+
+
+ + +
+
+ Project 1 +
+

Python Programming Fundamentals

+

Beginner-level Python programming exercises, zero third-party dependencies

+
+
+
+
+

Data Types

+
    +
  1. 1.1.py — Square of positive integer
  2. +
  3. 1.2.py — Formatted admission info output
  4. +
  5. 1.3.py — Right triangle hypotenuse length
  6. +
+
+
+

Operators & Expressions

+
    +
  1. 2.1.py — Euclidean distance between two points
  2. +
  3. 2.2.py — Sum of cubes of digits in a three-digit number
  4. +
  5. 2.3.py — Letter occurrence count (case-insensitive)
  6. +
+
+
+

Control Flow & Functions

+
    +
  1. 3.1-3.2 — Grade level / Character type
  2. +
  3. 4.1-4.2 — Digit judgment / Factorial sum
  4. +
  5. 5.1-5.2 — Function encapsulation & math calculations
  6. +
  7. 6.1-6.2 — List comprehensions / Dictionary mapping
  8. +
+
+
+
+ + +
+
+ Project 2-1 +
+

California Housing Price Prediction — Random Forest Regression

+

scikit-learn · California Housing Dataset

+
+
+ +
+
+

Dataset

+

California Housing — scikit-learn built-in dataset

+
    +
  • Samples: 20,640 block group records
  • +
  • Features: 8 (median income, house age, rooms, population, geographic location, etc.)
  • +
  • Target: MedHouseVal (median house value, $100K)
  • +
+
+
+

Model Evaluation

+
+ MSE + 0.2552 +
+
+ RMSE + 0.5052 +
+
+ + 0.8053 +
+
+
+ +
+

Top 4 Feature Importance

+

MedInc (Median Income) > AveOccup (Average Occupancy) > Latitude / Longitude (Geographic Location) > HouseAge

+

Income level is the strongest predictor for housing prices; the importance of geographic location reflects regional housing price disparities across California.

+
+ +
+ Python + scikit-learn + Random Forest + Pandas + Matplotlib +
+
+ + +
+
+ Project 2-2 +
+

Student Digital Behavior and Academic Performance Analysis

+

Kaggle real-world dataset · Linear Regression vs Random Forest

+
+
+ +
+
+

Dataset

+

Student Lifestyle and Academic Performance (Kaggle)

+
    +
  • 12 fields: Age, Branch, Study_Hours, Sleep_Hours, Screen_Time, Gym, Diet, Attendance, Stress, Residence, Internal_Marks, CGPA
  • +
  • Target variable: CGPA (Grade Point Average, 0~10)
  • +
  • Excluded Internal_Marks to prevent data leakage
  • +
+
+
+

Data Cleaning Pipeline

+
    +
  • Field selection → Deduplication
  • +
  • Numeric fields: Median imputation for missing values
  • +
  • Categorical fields: Mode imputation
  • +
  • Outlier filtering (reasonable ranges for age, study hours, etc.)
  • +
  • Categorical variables: One-hot encoding (drop_first)
  • +
+
+
+ +
+
+

Visual Analysis (6 Charts)

+
+
+
+
+

Screen Time Distribution

+

Right-skewed distribution; most students spend 3–8 hours on screens daily

+
+
+

Study Hours vs CGPA

+

Clear positive correlation; students studying 6–8h/day tend to have higher CGPA

+
+
+

Top 3 Feature Importance

+

Study Hours > Attendance > Screen Time

+
+
+ +
+ Python + Linear Regression + Random Forest + Pandas + Seaborn + EDA +
+
+ + +
+
+ Project 3 +
+

Rock Paper Scissors Gesture Recognition — YOLO11n

+

🪨📄✂️ Ultralytics · PyTorch · Object Detection

+
+
+ +
+
+

Dataset

+

rock-paper-scissors-sxsw (Roboflow v11)

+
    +
  • Total 15,874 images
  • +
  • Training set 14,966 / Validation set 588 / Test set 320
  • +
  • 3 classes: Paper, Rock, Scissors
  • +
  • Input size: 640×640
  • +
+
+
+

Data Augmentation

+

7 augmented versions generated per original image:

+
    +
  • Horizontal flip (50%), random rotation ±12°
  • +
  • Shear ±2°, brightness/exposure ±25%
  • +
  • Gaussian blur 0~1.5px, salt-and-pepper noise 1%
  • +
+
+
+ +
+

Training Configuration

+
+
+
ModelYOLO11n (2.58M params)
+
Epochs50
+
Batch16
+
+
+
OptimizerAdamW
+
Training Time~3.07h
+
GPURTX 5060 (8GB)
+
+
+
+ + +
+
+

Evaluation Results

+
+
+
+
+

Validation Set

+
+ mAP50 (All) + 0.940 +
+
+ mAP50-95 + 0.697 +
+
+ Precision (P) + 0.942 +
+
+ Recall (R) + 0.891 +
+
+ Inference Speed + < 2.1ms +
+
+
+

Test Set

+
+ mAP50 (All) + 0.934 +
+
+ mAP50-95 + 0.693 +
+
+ Precision (P) + 0.898 +
+
+ Recall (R) + 0.920 +
+
+
+ + +
+

Per-Class Performance

+
+
+

📄 Paper

+
Val mAP500.936
+
Test mAP500.904
+
+
+

🪨 Rock

+
Val mAP500.943
+
Test mAP500.951
+
+
+

✂️ Scissors

+
Val mAP500.940
+
Test mAP500.947
+
+
+
+ + +
+
+

Application Modes

+
+
+
+
+

Single Image Inference

+

Recognize gestures from any photo; results are annotated with bounding boxes + labels and saved to the output directory.

+
+ predict.py +
+
+
+

Real-time Camera Detection

+

Captures from system camera (1280×720) in real-time with millisecond-level per-frame inference; displays FPS in window, press Q to exit.

+
+ detect.py +
+
+
+

Evaluation Scripts

+

Validation set evaluation, test set evaluation, dataset download utility — full coverage from training to deployment pipeline.

+
+ evaluate.py / test.py +
+
+
+ +
+ Python + PyTorch + YOLO11n + Ultralytics + OpenCV + Roboflow + CUDA +
+
+ + + + + + + + diff --git a/en/projects/SmartShed.html b/en/projects/SmartShed.html new file mode 100644 index 0000000..a45461e --- /dev/null +++ b/en/projects/SmartShed.html @@ -0,0 +1,855 @@ + + + + + + SmartShed Smart Greenhouse | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ Course Design Report · 2025-2026 Spring Semester +

OpenHarmony-Powered Smart Agriculture
— A Smart Greenhouse Control Terminal Based on Hi3861 & HarmonyOS

+

From sensor data acquisition to real-time mobile control — a complete smart agriculture IoT system.
Two dev boards each doing their job, MQTT message relay, a full-featured HarmonyOS terminal.

+ +
+ + +
+
+

Project Overview

+

Course Design Report for 2025-2026 Spring Semester — Presented by Ray Chen (Chen Zirui)

+
+
+

What Is Smart Shed?

+

+ Smart Shed (Smart Greenhouse) is a smart agriculture IoT control system built on Open Source OpenHarmony and Huawei HarmonyOS NEXT. + Simply put: two development boards handle sensing and controlling environmental parameters, communicating in real-time with a mobile app via MQTT, + ultimately achieving automatic monitoring and intelligent regulation of temperature, humidity, light intensity, and soil moisture inside the greenhouse. +

+
+
+ + Embedded Side +

OpenHarmony + Hi3861 × 2
Sensor sampling & actuator control

+
+
+ + Server Side +

EMQX MQTT Broker
Message relay & Topic routing dispatch

+
+
+ + App Side +

HarmonyOS NEXT (API23)
Mate 70 Pro+ / MatePad Pro

+
+
+
+
+ + + + +
+
+
+

01 · Project Overview & Tech Stack

+

Overall architecture, challenges faced, and innovations made

+
+
+ + +
+
+

System Architecture: Software-Hardware Co-Design, Vertical Integration

+

Embedded side collects data → Server side relays messages → Mobile side displays and controls

+
+
+
+

Embedded Side

+

OpenHarmony 1.0 Release
+ Rayawa/rgb @ HiSilicon-Hi3861
+ Rayawa/soi @ HiSilicon-Hi3861
+ Sensor sampling + OLED display
PWM/GPIO actuator control

+
+
+
+

Server Side

+

MQTT 5.0 WebSocket
+ wss://broker.emqx.io:8084
+ @MQTTX
+ Public network message relay
Topic routing dispatch

+
+
+
+

App Side

+

HarmonyOS 6.1.0 (API23)
+ Smart Shed @ Mate 70 Pro+
+ Smart Shed @ MatePad Pro 12.2
+ Real-time data display
Manual / Smart dual-mode

+
+
+
+ + +
+
+

Technical Challenges

+

Problems actually encountered during development

+
+
+
+

Embedded Side

+
    +
  • Lots of driver interface version compatibility issues
  • +
  • I2C bus concurrent multi-device access causes conflicts
  • +
  • LiteOS-M thread stack size and priorities need constant tweaking
  • +
+
+
+

App Side

+
    +
  • The original docs were based on API7 JavaUI — way too outdated
  • +
  • The old code only ran on specific tablets; switching devices broke the layout completely
  • +
  • The original design had four separate systems for one expansion board's components — massive refactoring needed
  • +
+
+
+

Communication Layer

+
    +
  • MQTT transmission isn't very stable, and error messages are vague
  • +
  • The Hi3861 WiFi module is aging — poor load capacity
  • +
  • The app-side send/receive mechanism was bare-bones, almost no error handling, debugging by pure guesswork
  • +
+
+
+
+ + +
+
+

Innovations

+
+
+
+

Dual-Board Separated Architecture

+

The environment sensing board (RGB) and soil actuation board (SOI) are physically isolated and logically decoupled — each handles its own duties while working together seamlessly.

+
+
+

Zero-Dependency MQTT Client

+

The HarmonyOS side builds MQTT packets entirely from scratch starting from TCP Socket — zero third-party library dependencies.

+
+
+

HDS Advanced Visual System

+

Integrated HarmonyOS official Design System component library: immersive navigation, gravity animations, light-field backgrounds.

+
+
+

Manual / Smart Dual Mode

+

Manual mode gives you free adjustment of levels; Smart mode makes automatic decisions based on thresholds, with a background thread running safely at all times.

+
+
+

Glass Form Factor Adaptation

+

Built an additional watch-side Glass app form factor with immersive materials and gaseous animation effects.

+
+
+

Reliability Guarantees

+

Auto offline detection (5s timeout), exponential backoff reconnection on disconnect, GlobalLogBus logging bus as a comprehensive safety net.

+
+
+
+ + +
+
+

Tech Stack

+
+
+
+

Embedded (Hi3861)

+
+ Hi3861 + HiSilicon + OpenHarmony 1.0 + LiteOS-M + CMSIS-RTOS + C + GPIO + PWM + I2C + ADC + AHT20 + SSD1306 + Paho MQTT + lwIP + Wi-Fi STA +
+
+
+

Server (Communication)

+
+ MQTT 5.0 + WebSocket Secure + EMQX Broker + TCP Socket + JSON + Pub/Sub + Topic Routing +
+
+
+

App (HarmonyOS)

+
+ HarmonyOS 6.1.0 + API23 + ArkTS + ArkUI + Stage Model + @StorageLink + @ObjectLink + HDS + UIDesignKit + Glass Form +
+
+
+
+
+ + + + +
+
+
+

02 · MQTT Server

+

Pub/Sub architecture principles and data flow design

+
+
+ + +
+
+

Publish/Subscribe (Pub/Sub) Architecture

+

MQTT is a lightweight messaging protocol purpose-built for low-bandwidth IoT scenarios

+
+
+

Three-Party Collaboration Mechanism

+
+
+ Publisher +

+ The embedded Hi3861 acts as publisher, packaging sensor data into JSON and sending it to designated Topics. +

+
+
+ Broker Relay +

+ EMQX serves as the MQTT Broker, receiving messages and forwarding them to corresponding subscribers per Topic rules. +

+
+
+ Subscriber +

+ The HarmonyOS App receives sensor data after subscribing to relevant Topics, and can also issue control commands. +

+
+
+
+
+ + +
+
+

Data Flow Design

+

How data travels from hardware all the way to your phone, and how operations get sent back to hardware for execution

+
+
+ +
+

Upstream: Sensor Data → Mobile Display

+
+
+
+
+

① Sensor Sampling

+

Sensors on the expansion board collect raw data → ADC reads light/soil moisture, I2C reads AHT20 temp & humidity

+
+
+
+
+
+

② Package & Send

+

Hi3861 converts data to JSON format and sends it to EMQX Broker via MQTT PUBLISH packet

+
+
+
+
+
+

③ Route & Dispatch

+

Upon receiving the message, EMQX distributes it to subscribed clients according to Topic rules

+
+
+
+
+
+

④ Refresh UI

+

HarmonyOS receives and parses the message → @StorageLink updates state → UI numbers refresh / Smart mode evaluates thresholds

+
+
+
+
+ +
+

Downstream: User Action → Hardware Execution

+
+
+
+
+

① User Action or Auto Trigger

+

Drag sliders to adjust levels in manual mode, or threshold exceeded in Smart mode auto-generates control commands

+
+
+
+
+
+

② Package & Dispatch

+

HarmonyOS converts control commands into MQTT packets, dispatched through EMQX

+
+
+
+
+
+

③ Hardware Execution

+

Hi3861 parses topic and payload upon receiving the message → controls GPIO/PWM output → fan/water pump/grow light activates

+
+
+
+
+
+
+
+ + + + +
+
+
+

03 · Hi3861 Embedded Side

+

OpenHarmony LiteOS-M + CMSIS-RTOS multi-threading, developed in pure C

+
+
+ + +
+
+

Two Dev Boards, Each with Its Own Job

+
+
+
+

RGB Board (Environment Sensing)

+

Responsible for "seeing the environment" and "local display"

+
+ Sensors +
    +
  • AHT20 Temperature & Humidity Sensor — I2C reads temperature and humidity
  • +
  • Photoresistor — ADC reads light intensity (0~4095)
  • +
+
+
+ Actuators +
    +
  • RGB Tri-color LED — GPIO10/11/12 ⇒ PWM1/2/3 controls brightness
  • +
+
+
+ Local Display +

SSD1306 OLED (128×64) refreshes temperature, humidity, and light data in real time

+
+
+
+

SOI Board (Soil Actuation)

+

Responsible for "sensing soil" and "getting work done"

+
+ Sensors +
    +
  • Soil Moisture Sensor (replacement install) — ADC reads soil water content
  • +
+
+
+ Actuators +
    +
  • OLED Display — local status printing
  • +
  • Fan — PWM controls rotation speed
  • +
  • Water Pump — GPIO controls on/off
  • +
+
+
+
+
+ + +
+
+

Project Structure

+

Big picture split by function, details split by module — clean and maintainable

+
+
+
+

common/ Shared Layer

+

Wi-Fi connection, MQTT communication, OLED drivers all live here. I2C mutex lock is also managed here to prevent multiple threads from fighting over the bus.

+
+
+

modules/ Business Layer

+

Split into two subdirectories:

+
    +
  • sensors/ — headers and programs for AHT20, light intensity, soil moisture sensors
  • +
  • actuators/ — control programs for fans, grow lights, water pumps
  • +
+
+
+

boards/ Build Layer

+

Unified management of .gn build files for both dev boards. Conditional compilation dynamically enables modules per board config — adding a new board just means adding one gn file.

+
+
+
+ + +
+
+

Multi-Threading Architecture

+

CMSIS-RTOS manages parallel tasks under the LiteOS-M real-time kernel

+
+
+

Main Thread Entry Point

+
    +
  • After system boot, SYS_RUN creates the main thread from smart_shed_all.c, stack size 8KB
  • +
  • The main thread initializes and spawns all sub-threads in sequence: sensor sampling, actuator control, MQTT communication, OLED display
  • +
  • Conditional compilation dynamically enables corresponding modules per board configuration, unified scheduling entry point
  • +
+
+
+

Six Sub-Threads Running in Parallel

+

Each functional module runs independently inside the LiteOS kernel, each with its own stack space (4KB~8KB) and priority — none block each other:

+
+
+ + Air Temp & Humidity Sampling +

AHT20 / I2C

+
+
+ + Light Intensity Detection +

ADC Sampling

+
+
+ + Soil Moisture Reading +

ADC Sampling

+
+
+ + Fan / LED / Water Pump +

GPIO/PWM Control

+
+
+ + OLED Display Refresh +

SSD1306 Rendering

+
+
+ + MQTT Network Communication +

Paho Publish/Subscribe

+
+
+
+
+

I2C Mutex Lock: Solving Bus Conflicts

+

The AHT20 temperature/humidity sensor and OLED display share the same I2C0 bus (GPIO13 & GPIO14). If two threads access it simultaneously, things break. The solution:

+
+
+ Conflict Scenario +

The temp/humidity sampling thread and OLED refresh thread read/write I2C0 simultaneously, causing data corruption

+
+
+ Solution +

Use i2c0_lock/unlock mutex lock, acquire before every read/write and release after — guarantees only one device occupies the bus at any given moment

+
+
+
+
+ + +
+
+

Hardware Connection Mapping

+
+
+
+

SOI Board (Soil Actuation)

+
+
+ OLED + Status printout + I2C0-0x78 GPIO13&14 + oled_ssd1306.c +
+
+ Soil Moisture + External probe + ADC_CH4 + soil_moisture_task.c +
+
+ Water Pump + External pump + P06 + water_pump_task.c +
+
+ Fan + External fan + P08 + fan_task.c +
+
+
+
+

RGB Board (Environment Sensing)

+
+
+ OLED + Status printout + I2C0-0x78 GPIO13&14 + oled_ssd1306.c +
+
+ Temp/Humidity Sensor + Detect air parameters + I2C0-0x44 + temp_and_hum_task.c +
+
+ Photoresistor + Detect light intensity + ADC_CH4 + light_intensity_task.c +
+
+ Tri-color LED RGB + Greenhouse lighting control + GPIO10/11/12=>PWM1/2/3 + led_task.c +
+
+
+
+
+ + +
+
+

Network & Communication

+

Connect Wi-Fi → TCP established → MQTT sends/receives → actuators spring to action

+
+
+

Communication Flow

+
+
+
+
+

Connect Wi-Fi

+

Connect to SSID "Rayawa", get IP via DHCP then enter lwIP TCP communication

+
+
+
+
+
+

MQTT Encode/Decode

+

Paho library only handles packet encoding/decoding; the full TCP Socket lifecycle must be managed manually

+
+
+
+
+
+

Report Sensor Data

+

Sensor data reported to EMQX Broker in JSON format

+
+
+
+
+
+

Execute Control Commands

+

Upon receiving a PUBLISH packet, parse topic and payload using MQTTDeserialize_publish(), then set global variables via mqtt_apply_command(). Actuator threads continuously read these variables to control GPIO/PWM, driving fans, pumps, and other devices

+
+
+
+
+
+
+ + + + +
+
+
+

04 · HarmonyOS App Side

+

ArkTS · Stage Model · HDS Advanced Visuals · Self-Implemented MQTT Client

+
+
+ + +
+
+

Smart Shed App

+

A full-featured control terminal running on Mate 70 Pro+ and MatePad Pro

+
+
+

Feature Overview

+
+
+ Manual Mode +

+ Drag sliders to adjust fan (0-3 levels), water pump (0-3 levels), grow light (0-100%). Auto-syncs current levels to the dev board when entering the page, supports haptic feedback. +

+
+
+ Smart Mode +

+ Set upper/lower threshold limits for temperature/humidity/light/soil moisture. Periodically polls sensor data and auto-triggers control when out of range. Background resident thread, safely destroyed on page exit to prevent leaks. +

+
+
+ Real-time Monitoring +

+ MQTT callback receives sensor data, @StorageLink state management drives ArkUI auto-refresh of displayed numbers. +

+
+
+ Debug Panel +

+ GlobalLogBus event bus records communication status, user actions, and error info for easy troubleshooting. +

+
+
+
+
+ + +
+
+

App Project Structure (Stage Model)

+

Layered architecture built on ArkTS

+
+
+
+

AppScope/

+

Unified entry point for app-level global resources and Hvigor build scripts.

+
+
+

view/ & pages/

+

ArkTS-built UI layer, containing complete interfaces for manual/smart dual-mode and debug panel.

+
+
+

service/

+

Encapsulates MQTT client (MqttReceiverClient.ts), TCP Socket direct connection for bidirectional communication, zero third-party dependencies.

+
+
+

viewmodel/

+

Core data structures and state models ensuring reactive binding between UI and data.

+
+
+
+ + +
+
+

MqttReceiverClient.ts — Building an MQTT Client From Scratch

+
+
+

Why Build It Yourself?

+

+ The HarmonyOS side uses zero third-party MQTT libraries — it hand-crafts packets entirely from scratch starting at TCP Socket level. This gives complete control over the entire communication process, making issues much easier to diagnose. +

+
+
+
+

Protocol Layer

+
    +
  • Manually concatenates Fixed Header + Variable Header + Payload
  • +
  • Implements core packets: CONNECT / PUBLISH / SUBSCRIBE / PINGREQ
  • +
  • 60s KeepAlive heartbeat for connection persistence
  • +
  • MQTT 5.0 over WSS direct connection to EMQX public Broker
  • +
+
+
+

Reliability Guarantees

+
    +
  • Auto-reconnect on disconnect + exponential backoff
  • +
  • Single TCP connection with multi-Topic subscription & routing dispatch
  • +
  • @StorageLink state management decoupled from ArkUI
  • +
  • GlobalLogBus logging bus records complete communication trail
  • +
+
+
+
+

State & Methods

+
+
+ Control State +

Centrally manages fan levels, pump levels, grow light brightness; @StorageLink shares state across pages.

+
+
+ Parameter Passing +

Sensor data and control commands transmitted reliably over MQTT layer in unified format.

+
+
+ Log Sync +

GlobalLogBus uniformly collects communication status, operation records, and exception info.

+
+
+ Lifecycle +

Create connection on page enter, destroy threads and release resources on page exit — zero memory leaks.

+
+
+
+
+ + +
+
+

UI Design: HDS + ArkUI

+

Not just functional — it has to look good too

+
+
+

HDS Core Components

+
+
+ HdsNav Navigation Bar +

Immersive light-field top navigation with frosted glass blur effect

+
+
+ PressShadow Gravity Animation +

Elastic deformation on button press + light field diffusion feedback

+
+
+ SpringMotion Spring Animation +

Staggered delay entry, spring-curve animations for smooth onboarding experience

+
+
+
+
+

Visual Style

+
+
+ Dark Light Field +

Flowing light background runs through the entire interface, dark mode atmosphere maxed out

+
+
+ Dual-Column Layout +

Tablet-adaptive dual-column layout balancing information density and visual harmony

+
+
+
+
+
+

Animation: Gravity Field

+

Gravity field effects during page transitions, natural attraction-repulsion animations between elements.

+
+
+

Animation: Light Field

+

Flowing light background + dual-column dark global light field, dynamic light/shadow flows with interaction changes.

+
+
+

Animation: Transitions

+

Fade in/out + elastic animations, SpringMotion spring-curve silky transitions.

+
+
+
+

Responsive Layout

+

ArkUI responsive grid system automatically adapts to phone and tablet form factors:

+
+
+ Phone +

Single-column vertical scroll, stacked card display

+
+
+ Tablet +

Dual-column side-by-side, making full use of widescreen space

+
+
+
+
+ + +
+
+

Smart Shed Glass

+

Smartwatch form factor — immersive materials + gaseous animations

+
+
+
+

Glass Form Features

+
    +
  • Immersive Material — interface blends into watch face glass texture
  • +
  • Gaseous Animations — light and airy transition effects
  • +
  • Gravity Transitions — maintains consistent interaction language with the main App
  • +
  • Dual-edge Flowing Light — dynamic decorative elements on both sides of the watch face
  • +
+
+
+

HdsButtons Custom Component

+

Custom button component system based on HDS specifications, unifying visual presentation and touch feedback for all interactive elements in Glass form. Supports multiple sizes and state styles (default/pressed/disabled), works great on small screens too.

+
+
+
+
+
+ + + + + + + diff --git a/en/projects/bio.html b/en/projects/bio.html deleted file mode 100644 index 6bf52bc..0000000 --- a/en/projects/bio.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - Biology Projects | Ray Chen - - - - - - - - - - -
-
-
-

Biology Projects

-

Papers and experiment records in biology, including PCR, protein hypotheses, carbon assimilation review, orange-plate experiments, and an interactive Agrobacterium web demo.

-
- -
-
-

PCR Laboratory

-

Pioneering the first PCR experiment in high school, bringing advanced biology experiments into the classroom. -Exploring optimal reagent dosages for classroom experiments through pre-experiments and template quantity experiments.

-
-
-
-
-
- PCR凝胶电泳结果 -
-
Gel electrophoresis shows clear bands, confirming successful target gene amplification. -Compared with the standard marker, the length is approximately 600bp, matching experimental expectations.
-
-
-
-
-
- -
-
-

Experimental Design

-

Detailed PCR experimental design including primer design, thermal cycling parameters, and reaction system optimization. Practical for high school biology classrooms, providing reference for future experiments.

- -
-
-
-
- -
-
-

Final Lab Report

-

Complete experimental records, data analysis, and conclusions validating the effectiveness of the experimental design.

- -
-
-
-
-
- -
-
-

Thesis Archive

-

Records of research and reflection, including completed papers and works in progress.

-
- -
-
-
- C3植物光合作用论文 -
-
-
- Draft - 2024.6.8 -
-

Molecular Biology Research on the Calvin Cycle

-

This paper deeply deconstructs the complex biochemical process of C4 plant carbon assimilation from a molecular structure perspective. By systematizing and visualizing the energy conversion and substance metabolism processes in the dark reaction, it provides a precise micro-level model for understanding how autotrophic organisms efficiently convert inorganic carbon, revealing the logical beauty of biochemical processes.

- -
-
-
-
- 酿酒酵母橙色平板实验论文 -
-
-
- Draft - 2026.03.08 -
-

Analysis and Verification of Orange Plate Discoloration in Yeast Experiments

-

Addressing the occasional abnormal color change of culture media in microbial cultivation, this paper successfully traced the source of environmental contamination factors through rigorous controlled experiments. This research not only solved a specific experimental technical problem, but its core significance lies in establishing standardized error analysis and laboratory quality control procedures, emphasizing the importance of rigorous attitude and procedural compliance in scientific practice.

- -
-
-
-
- -
-
-
- 农杆菌转化示意图 -
-
-
-

Exploring Biological Processes Through Interactive Development

-

Transforming complex genetic engineering workflows into intuitive web interactions, making learning vivid and engaging. The Agrobacterium transformation web app demonstrates how to build biology teaching tools with code.

- Launch Simulation -
-
-
-
- - - - - - - - diff --git a/en/projects/biology.html b/en/projects/biology.html index 58d7de0..8da7646 100644 --- a/en/projects/biology.html +++ b/en/projects/biology.html @@ -4,6 +4,33 @@ Biology Projects | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -80,8 +107,8 @@

Thesis Archive

Completed 2024.6.23
-

Pathogenic Mechanisms and Genetic Properties of Prion Proteins

-

This study systematically explores the pathogenic mechanisms and genetic properties of prion proteins (PrP^Sc), focusing on their molecular mechanism of inducing misfolding in normal prion proteins (PrP^C) through conformational conversion, and discusses the species barrier effect of prions in cross-species transmission and their potential impact on public health.

+

On the Conjecture of Proteins as Genetic Material in Extremely, Extremely Special Organisms

+

This paper boldly challenges the absolute authority of the biological "central dogma." Based on the self-replicating properties of prions and reverse transcription mechanisms, it rigorously explores the possibility of proteins as primitive genetic carriers. This research aims to broaden the boundaries of thinking about biological evolution and the nature of heredity, providing a highly forward-looking hypothetical framework for the study of life forms in extreme environments.

@@ -98,8 +125,8 @@

Pathogenic Mechanisms and Genetic Properties of Prion Proteins

Draft 2024.6.8
-

On the Conjecture of Proteins as Genetic Material in Extremely, Extremely Special Organisms

-

This paper boldly challenges the absolute authority of the biological "central dogma." Based on the self-replicating properties of prions and reverse transcription mechanisms, it rigorously explores the possibility of proteins as primitive genetic carriers. This research aims to broaden the boundaries of thinking about biological evolution and the nature of heredity, providing a highly forward-looking hypothetical framework for the study of life forms in extreme environments.

+

Molecular Biology Research on the Calvin Cycle in C3 Plants

+

This paper provides an in-depth analysis of the Calvin cycle, the core carbon fixation pathway in C3 plants. It systematically examines the molecular mechanisms of carbon assimilation, including the catalytic properties and regulation of key enzymes such as Rubisco, as well as the energy conversion processes involving ATP and NADPH. This research aims to enhance understanding of photosynthetic efficiency limitations in C3 plants and explore potential directions for improving crop yields through biochemical approaches.

diff --git a/en/projects/gene.html b/en/projects/gene.html index 94a4236..ecd1c59 100644 --- a/en/projects/gene.html +++ b/en/projects/gene.html @@ -5,8 +5,35 @@ - 基因工程:农杆菌转化法交互实验室 | Ray Chen - + Genetic Engineering Interactive Lab | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/idv.html b/en/projects/idv.html index 07e70b6..357b2b7 100644 --- a/en/projects/idv.html +++ b/en/projects/idv.html @@ -3,10 +3,35 @@ - 第五人格,启动! | Ray Chen - + Identity V Rank Calculator | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/en/projects/ncut_papers.html b/en/projects/ncut_papers.html index 447194b..6383a72 100644 --- a/en/projects/ncut_papers.html +++ b/en/projects/ncut_papers.html @@ -4,6 +4,33 @@ Academic Papers | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/signal.html b/en/projects/signal.html new file mode 100644 index 0000000..cc17895 --- /dev/null +++ b/en/projects/signal.html @@ -0,0 +1,138 @@ + + + + + + Weak Signal Measurement | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+

Measurement of Weak Electrical Signals

+

Weak electrical signal measurement system design based on Arduino embedded development

+
+ +
+
+

Abstract

+
+
+
+

This paper presents an Arduino-based system for weak electrical signal measurement, addressing low sensitivity and environmental interference. The system combines mechanical amplification with signal conditioning and Arduino-based embedded processing for data acquisition and computation. A normalized algorithm and multi-stage noise reduction methods are applied to improve stability and robustness. The system structure, hardware implementation, software algorithms, calibration methods, and error sources along with uncertainties are analyzed and evaluated, and the system performance is verified through experimental procedures. In addition, a cost analysis is conducted to demonstrate its economic feasibility. Application scenarios and limitations are also discussed. Results show that the system can achieve stable measurement of weak electrical signals with practical value.

+

Keywords: Arduino; Weak Electrical Signal; Trans-impedance Amplifier; PSD Sensor; Uncertainty Assessment

+ +
+
+ Paper document +
+
+
+ +
+
+ +
+

Project Files

+

Design documents and engineering resources

+
+
+ +
+
+ + + + + + + diff --git a/en/projects/spm.html b/en/projects/spm.html index c3f62ff..be22521 100644 --- a/en/projects/spm.html +++ b/en/projects/spm.html @@ -4,6 +4,33 @@ Sweet Potato Mod | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/xxh.html b/en/projects/xxh.html index d953c7b..cf20081 100644 --- a/en/projects/xxh.html +++ b/en/projects/xxh.html @@ -4,6 +4,33 @@ XXH Test | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/en/projects/xxh_test.html b/en/projects/xxh_test.html index 4d4f7b9..dabee81 100644 --- a/en/projects/xxh_test.html +++ b/en/projects/xxh_test.html @@ -4,6 +4,24 @@ XXH Test | Ray Chen + + + + + + + + + + + + + + + + + + diff --git a/en/thanks.html b/en/thanks.html index 87c91e8..aee8671 100644 --- a/en/thanks.html +++ b/en/thanks.html @@ -4,6 +4,33 @@ Acknowledgements | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43,7 +70,7 @@

Teachers

Classmates

-
义乌学社hjz、jdh、ljy、lzq、whn、wth、wyx、yyzy、zrq、zxy (in alphabetical order)
My Best FriendsAndyGao、bzy、lyx、ywx、lxr、wjy、ydx、lmd、lyc
9B208xxh、rjp、ldy、ddk
+
义乌学社hjz、jdh、ljy、lzq、whn、wth、wyx、yyzy、zrq、zxy (in alphabetical order)
My Best FriendsAndyGao、bzy、lyx、ywx、lxr、wjy、ydx、lmd、lyc、zhy
9B208xxh、rjp、ldy、ddk
diff --git a/fr/.DS_Store b/fr/.DS_Store index c6c96dc..622ca7a 100644 Binary files a/fr/.DS_Store and b/fr/.DS_Store differ diff --git a/fr/dashboard.html b/fr/dashboard.html deleted file mode 100644 index f31a0d4..0000000 --- a/fr/dashboard.html +++ /dev/null @@ -1,406 +0,0 @@ - - - - - - Tableau de bord HmDashboard | Ray Chen - - - - - - - - - - - - -
- -
- -
-
-
- App Icon -
-
-

HmDashboard

-

- Créé par - l'équipe Harmony Gallery - . Un projet full-stack qui acquiert, traite, analyse et visualise toutes les données des applications et services atomiques du marché des applications HarmonyOS. -

-
-
- -
-
- Fondation Rust - Base de Données Puissante - Support Multi-Plateforme - Lauréat du Concours OpenAtom -
-
-
- - -
-
-
-
-
-
-
Vues Totales du Projet
-
-
totalViews
-
-
-
Vues du Jour
-
-
todayViews
-
-
-
Vues Totales des Apps HarmonyOS
-
-
harmonyTotalViews
-
-
-
* Plage de statistiques de données de 2025-11-01T04:00:00Z à présent. Échec de la mise à jour automatique ! Dernière mise à jour {{updateTime}}.
-
- -
- -
-
-
-
- - -
-
-
-

Introduction Détaillée

-

Le contenu suivant se concentre sur les objectifs du projet, les capacités de base et l'architecture technique.

-
- -
-
-
-
- 01 -

À quoi Sert ce Projet

-
-
-

Cette application est une application HarmonyOS développée directement par l'équipe Harmony Gallery. Elle collecte les données publiques du marché des applications Huawei et les transforme en graphiques et rapports intuitifs. En bref, vous pouvez consulter ici la dynamique de presque toutes les applications HarmonyOS.

-

1. Aperçu des Données & Analyse Graphique : Consultez intuitivement les téléchargements, les tendances de notation et la distribution du marché via des classements, des graphiques circulaires et des graphiques linéaires.

-

2. Rechercher des Apps & Voir les Détails : Prise en charge de la recherche et du tri par nom, notation, etc. ; recherche in-app ; recherche par lien de partage. Vous pouvez consulter diverses données d'application et graphiques de tendance.

-

3. Mise à Jour Automatique Planifiée : Les données sont synchronisées toutes les 30 minutes en arrière-plan, vous garantissant toujours les données les plus récentes.

-

4. Opérations Interactives & Partage : Cliquez sur les graphiques pour filtrer les données, cliquez sur les applications pour accéder aux pages de détail ; vous pouvez également partager facilement les pages d'application via des liens, la saisie en l'air ou le tap-to-share HarmonyOS.

-

5. Contribuer & Mettre à Jour les Infos : Vous pouvez contribuer au tableau de bord des applications via le partage AppMarket et la page "Moi", en aidant à soumettre de nouvelles applications ou à mettre à jour les informations des applications.

-
-
- -
-
- 02 -

Fonctions Web Principales

-
-
-
    -
  • 1. Statistiques de Données : Affichage des données statistiques des indicateurs clés tels que le nombre total d'applications, le total des services atomiques et le total des développeurs.
  • -
  • 2. Classements de Téléchargement : Fournit la liste des 20 meilleures applications par téléchargements, ainsi que les classements de téléchargements hors applications Huawei.
  • -
  • 3. Détails de l'Application : Cliquez sur n'importe quelle icône d'application pour voir les informations détaillées, y compris les téléchargements, les évaluations, les appareils pris en charge, les informations de version, etc.
  • -
  • 4. Analyse des Tendances : Affichage des graphiques de tendances d'évolution et de tendance incrémentale des téléchargements d'applications.
  • -
  • 5. Liste des Applications : Tableau détaillé des informations d'application avec fonctions de recherche, tri et filtrage.
  • -
-
-
-
- - -
-
-
- - -
-
-
-

Stack Technique

-

Le projet adopte une stack technique moderne, garantissant haute performance, haute disponibilité et maintenabilité

-
- -
-
-
-

Backend (Rust)

-

Stack Rust implémentant l'agrégation de données, l'exposition API, l'accès base de données et l'orchestration des capacités côté serveur

-
    -
  • Rust 2024 Edition : Sécurité mémoire, abstractions à coût zéro, haute performance
  • -
  • Axum 0.8 : Framework web typé, conception API ergonomique
  • -
  • Tokio 1.47 : Runtime asynchrone, traitement concurrent efficace
  • -
  • SQLx 0.8 : Vérifications SQL à la compilation, opérations BDD typées
  • -
  • Reqwest 0.12 : Client HTTP, prise en charge du pooling de connexions et du retry automatique
  • -
  • Serde + TOML : Sérialisation/désérialisation, gestion configuration
  • -
  • Tracing : Journalisation structurée et suivi performance
  • -
  • Compression Tower HTTP : Brotli, Gzip, Deflate, Zstd
  • -
-
- -
-

Base de Données (PostgreSQL)

-

PostgreSQL 12+ (14+ recommandé), puissante base de données relationnelle

-
    -
  • Tables : app_info, app_metrics, app_rating, app_raw, substance, etc.
  • -
  • Déclencheurs : Mises à jour automatiques et maintenance de cohérence
  • -
  • Optimisation Index : Amélioration performance requêtes
  • -
  • Cascades Clés Étrangères : Garanties intégrité données
  • -
  • Champs JSON : Support structure données flexible
  • -
-
-
- -
-
-

Frontend Web

-
-

Frontend Site S

-
    -
  • JavaScript Natif : Sans dépendances framework, léger et efficace
  • -
  • Chart.js + Date-fns : Visualisation données
  • -
  • Markdown-it : Rendu Markdown
  • -
  • Design Responsive : Adaptation mobile
  • -
-
-
-

Frontend Site T

-
    -
  • Vue.js : Framework frontend progressif
  • -
-
-
- -
-

Frontend HarmonyOS

-
    -
  • ArkTS : Langage développement applications HarmonyOS
  • -
  • ArkUI : Framework UI déclaratif
  • -
  • ArkWeb : Intégration conteneur Web
  • -
  • Stage Model : Modèle ingénierie moderne
  • -
  • Hvigor : Chaîne outils build
  • -
-
-
-
-
-
- - -
-
-
-

Accès Base de Données

-

L'équipe Harmony Gallery fournit des interfaces fonctionnelles de requête de données, d'analyse statistique et autres pour le marché des applications HarmonyOS. Les projets nécessiteux sont invités à s'intégrer à notre base de données.

-
- -
- - -
-
-

⚠️ Avis Important

-

Vous devez nous informer avant de vous intégrer à la base de données, sinon cela peut violer la licence open source.

-

Les utilisateurs ne doivent pas stocker localement les informations obtenues sous leur forme originale.

-

Tout contenu affiché sur les sites liés amicalement n'a aucun rapport avec le Tableau de Bord des Applications HarmonyOS. L'équipe du projet Harmony Gallery n'est pas responsable de la maintenance du contenu des liens amicaux.

-
- -
-

Documentation API

-

Consultez la documentation API complète pour comprendre les méthodes d'intégration de données -Si vous souhaitez utiliser notre base de données, veuillez d'abord nous contacter !

- -
-
-
-
-
- - -
-
-
-

Contactez-nous

-

Merci à tous les développeurs et partenaires ayant contribué au projet

-
- -
-
-

Équipe Harmony Gallery

-
-
-
shenjack
-
Email: 3695888@qq.com
-
Responsable Principal
-
-
-
清霁·Rayawa
-
Email: rayawa.work@outlook.com
-
Développement App HarmonyOS, Production du Site
-
-
-
tianxiu2b2t
-
Email: administrator@ttb-network.top
-
Responsable Web Site T
-
-
-
Groupe de Communication Officiel Harmony Gallery
- -
Groupe QQ
-
-
-
- -
-
-

Remerciements

-
    -
  • Remerciements Projet : 伤心萨摩耶, HEZI641
  • -
  • Remerciements App HarmonyOS : 筱冉, 音唯Artix
  • -
  • Merci à l'Alliance des Développeurs Huawei pour le support technique
  • -
-
- -
-

Licence

- -
- Licence GPL-3.0 -
-
-

Ce projet est open-sourcé sous licence GPL-3.0, permettant utilisation, modification et distribution gratuites, mais les œuvres dérivées doivent utiliser la même licence

-
-
-
-
-
-
- - - - - - - - - - - diff --git a/fr/index.html b/fr/index.html index 3ade81c..d8de096 100644 --- a/fr/index.html +++ b/fr/index.html @@ -5,13 +5,42 @@ Accueil | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -107,24 +136,24 @@

À propos de moi

Bien qu'étudiant en sciences, j'ai une immense curiosité pour les cultures du monde. Mon parcours dans les concours d'éloquence en anglais et deux ans de débat parlementaire britannique (BP) m'ont donné une base linguistique solide. Récemment, j'apprends le français. Du chant éthéré de Cécile Corbel aux paysages romantiques de Fontaine ; de la mélodie de "La Vaguelette" aux dialogues classiques de "Roméo et Juliette" — le charme de la langue française me pousse à explorer ses profondeurs.

Qu'il s'agisse de construire l'ordre dans le monde des 0 et des 1 ou de trouver des schémas dans la double hélice de la biologie, je crois que l'exploration transdisciplinaire élargit les frontières de la vie. Si vous partagez cette curiosité, n'hésitez pas à me contacter.

Ravi de vous rencontrer dans ce voyage nommé « grandir ».

-

— Ray
12 avril 2026

+

— Ray
19 mai 2026

Focus actuel

- +
Développement principal
-

Développement HmDashboard HarmonyOS 6.1.0
Développement du site personnel

+

Projet SmartShed développement full-stack OpenHarmony + HarmonyOS
Projet de détection d'objets et d'élagage en machine learning

Développement parallèle
-

Développement embarqué OpenHarmony (Hi3861) & approfondissement de l'ingénierie système

+

Développement HmDashboard HarmonyOS 6.1.0
Développement d'applis iOS/MacOS
Machine learning basé sur OpenHarmony

@@ -163,7 +192,7 @@

À propos de moi

Projets open source
-

Sweet Potato Mod · Difficult Rocket

+

Sweet Potato Mod · Difficult Rocket · Rock Paper Scissors Detection · SmartShed

@@ -255,11 +284,11 @@

Mes projets

Projets principaux

Projets que je dirige ou auxquels je contribue — recherche, développement et open source.

-
- +
+
-

HmDashboard

+

HmDashboard

Powered by Shenjack !
Un projet full-stack qui récupère, traite, analyse et affiche toutes les données d'applications et de méta-services de l'AppGallery HarmonyOS.
Je travaille principalement sur le développement web frontend et logiciel. Projet principal actuel, en mise à jour continue…

Lauréat du Concours OpenAtom @@ -286,28 +315,54 @@

Projets de biologie

- -
+
+
-

Sweet Potato Mod

-

L'agriculture rencontre la magie !
Un mod Minecraft co-développé avec @teddyxlandlee, ajoutant des patates douces, des stations agricoles, des broyeurs, des Cubes magiques, des cultures enchantées, etc.
L'un de mes premiers projets, mais plus maintenu depuis un moment.

+

Mesure de Signaux Électriques Faibles

+

Projet de compétition de physique. Ce projet conçoit un système de mesure de signaux électriques faibles basé sur le développement embarqué avec Arduino. Le système utilise une structure à fil suspendu et le principe du levier optique pour réaliser une amplification physique, et combine des circuits de conditionnement de signal avec un traitement embarqué pour l’acquisition et le calcul des données. Grâce à un algorithme de normalisation et à des méthodes de réduction de bruit à plusieurs niveaux, la stabilité de mesure et la capacité d’anti-interférence sont améliorées.

- Minecraft - Mod - Java + Arduino embarqué + Génie des communications + Concours de physique
- -
+
+
-

OpenHarmony Hi3861

-

Pratique de développement embarqué basée sur la carte Hi3861 d'OpenHarmony.
Mon premier vrai projet embarqué depuis l'Arduino quand j'étais petit. Toujours en exploration…

+

SmartShed

+

Système IoT de serre intelligente basé sur Hi3861 + OpenHarmony et HarmonyOS NEXT avec coordination edge-cloud.
Couvre la collecte embarquée, la communication MQTT et le terminal de contrôle HarmonyOS complet.

OpenHarmony - Développement embarqué - Vie intelligente + HarmonyOS + Open Source +
+
+
+ + +
+
+

Détection Pierre-Feuille-Ciseaux

+

Reconnaissance de gestes en temps réel basée sur YOLO11n, mAP50 validation = 0.940.
Inclut aussi la régression Random Forest pour les prix immobiliers californiens, l'analyse du comportement numérique des étudiants, etc.

+
+ Machine Learning + Détection d'objets + Open Source +
+
+
+ + +
+
+

Sweet Potato Mod

+

L'agriculture rencontre la magie !
Un mod Minecraft co-développé avec @teddyxlandlee, ajoutant des patates douces, des stations agricoles, des broyeurs, des Cubes magiques, des cultures enchantées, etc.
L'un de mes premiers projets, mais plus maintenu depuis un moment.

+
+ Minecraft + Mod + Java
@@ -325,19 +380,6 @@

Difficult Rocket (Collaboration) -
-
-

Mesure de Signaux Électriques Faibles

-

Projet de compétition de physique. Cette expérience convertit linéairement les faibles photocourants de niveau nanoampère détectés par les capteurs en signaux de tension via un circuit d'amplificateur à transimpédance, et utilise la double technique de suppression du bruit par blindage en cage de Faraday métallique et filtrage numérique moyen terminal, atteignant une acquisition de données en temps réel à haut rapport signal-sur-bruit et une quantification des grandeurs physiques avec Arduino et un ADC 16 bits.

-
- Arduino embarqué - Génie des communications - Concours de physique -
-
-

-
@@ -347,6 +389,12 @@

Autres projets

Des petits trucs sympas écrits au hasard ou pour des camarades et amis ()

+ +
+

OpenHarmony Hi3861

+

Pratique de développement embarqué basée sur Hi3861. Mon premier vrai projet depuis Arduino.

+
+

"Shou Yi Hong Qun Fang Kai Ye Yan"

@@ -495,40 +543,18 @@

Galerie

-
- -
-
-

Piano

-

La musique est l'art du temps. Autodidacte au collège, capturant des mélodies du bout des doigts.

-
- Piano - Musique -
+
+ +
+
+

Piano

- -
-
-

Œuvres

-

Capturer l'inspiration au pinceau. Fan art Genshin, créations de personnages, et plus encore.

-
- Dessin - Genshin -
-
-
- - -
-
@@ -686,7 +712,7 @@

Message rapide

- + diff --git a/fr/life/books.html b/fr/life/books.html index 6c78ddc..32e79ca 100644 --- a/fr/life/books.html +++ b/fr/life/books.html @@ -4,7 +4,34 @@ Bibliothèque | Ray Chen - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/life/piano.html b/fr/life/piano.html index 07443b6..f64816b 100644 --- a/fr/life/piano.html +++ b/fr/life/piano.html @@ -4,6 +4,33 @@ Piano | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/Hi3861-readme.html b/fr/projects/Hi3861-readme.html index 47d9a5b..b11ec14 100644 --- a/fr/projects/Hi3861-readme.html +++ b/fr/projects/Hi3861-readme.html @@ -3,7 +3,34 @@ - Hi3861 | Ray Chen + Hi3861 README | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/Hi3861.html b/fr/projects/Hi3861.html index 8ddeaf5..920d62d 100644 --- a/fr/projects/Hi3861.html +++ b/fr/projects/Hi3861.html @@ -4,6 +4,33 @@ Hi3861 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/RockPaperSissors.html b/fr/projects/RockPaperSissors.html new file mode 100644 index 0000000..271fcdf --- /dev/null +++ b/fr/projects/RockPaperSissors.html @@ -0,0 +1,408 @@ + + + + + + Détection Pierre-Papier-Ciseaux | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ Python · Machine Learning · Deep Learning +

Détection Pierre-Papier-Ciseaux

+

Collection de projets du cours Python été 2026, couvrant les bases de la syntaxe Python, la prédiction par régression en Machine Learning, l'analyse des données de comportement étudiant, et la reconnaissance de gestes Pierre-Papier-Ciseaux basée sur YOLO11n.

+ +
+ +
+ Démo de détection Pierre-Papier-Ciseaux +
+ +
+
+ Project 1 +

Exercices de base Python

+

14 exercices d'introduction : types de données, contrôle de flux, fonctions, listes et dictionnaires — couverture complète des bases syntaxiques.

+
+
+ Project 2-1 +

Prédiction des prix immobiliers

+

Régression par Random Forest pour prédire le prix médian des logements en Californie, R² = 0,805. Confirmation que le revenu et la localisation géographique sont les facteurs d'influence clés.

+
+
+ Project 2-2 +

Analyse du comportement étudiant

+

Jeu de données réel Kaggle, analyse de l'impact du temps d'étude et du temps d'écran sur le CGPA, comparaison multi-modèles.

+
+
+ Project 3 +

Reconnaissance de gestes YOLO11n

+

🪨📄✂️ Détection en temps réel de Ciseaux/Pierre/Feuille, mAP50 sur l'ensemble de validation = 0,940, inférence à l'échelle de la milliseconde.

+
+
+
+ + +
+
+ Project 1 +
+

Fondamentaux de la programmation Python

+

Exercices de programmation Python de niveau débutant, sans dépendances tierces

+
+
+
+
+

Types de données

+
    +
  1. 1.1.py — Carré d'un entier positif
  2. +
  3. 1.2.py — Sortie formatée des informations d'admission
  4. +
  5. 1.3.py — Longueur de l'hypoténuse d'un triangle rectangle
  6. +
+
+
+

Opérateurs & expressions

+
    +
  1. 2.1.py — Distance euclidienne entre deux points
  2. +
  3. 2.2.py — Somme des cubes des chiffres d'un nombre à trois chiffres
  4. +
  5. 2.3.py — Nombre d'occurrences d'une lettre (insensible à la casse)
  6. +
+
+
+

Contrôle de flux & fonctions

+
    +
  1. 3.1-3.2 — Niveau de note / Type de caractère
  2. +
  3. 4.1-4.2 — Détermination du nombre de chiffres / Somme factorielle
  4. +
  5. 5.1-5.2 — Encapsulation de fonctions et calculs mathématiques
  6. +
  7. 6.1-6.2 — Compréhensions de liste / Mappage de dictionnaire
  8. +
+
+
+
+ + +
+
+ Project 2-1 +
+

Prédiction des prix immobiliers en Californie — Régression Random Forest

+

scikit-learn · California Housing Dataset

+
+
+ +
+
+

Jeu de données

+

California Housing — Jeu de données intégré à scikit-learn

+
    +
  • Taille de l'échantillon : 20 640 enregistrements de quartiers
  • +
  • Nombre de caractéristiques : 8 (revenu médian, âge du logement, nombre de pièces, population, localisation géographique, etc.)
  • +
  • Cible : MedHouseVal (prix médian du logement, $100K)
  • +
+
+
+

Évaluation du modèle

+
+ MSE + 0.2552 +
+
+ RMSE + 0.5052 +
+
+ + 0.8053 +
+
+
+ +
+

Top 4 de l'importance des caractéristiques

+

MedInc (revenu médian) > AveOccup (occupation moyenne) > Latitude / Longitude (localisation géographique) > HouseAge

+

Le niveau de revenu est le facteur prédictif le plus fort pour les prix immobiliers ; l'importance de la localisation reflète les écarts de prix entre différentes régions de Californie.

+
+ +
+ Python + scikit-learn + Random Forest + Pandas + Matplotlib +
+
+ + +
+
+ Project 2-2 +
+

Analyse du comportement numérique et de la performance académique des étudiants

+

Jeu de données réel Kaggle · Régression linéaire vs Random Forest

+
+
+ +
+
+

Jeu de données

+

Student Lifestyle and Academic Performance (Kaggle)

+
    +
  • 12 champs : Age, Branch, Study_Hours, Sleep_Hours, Screen_Time, Gym, Diet, Attendance, Stress, Residence, Internal_Marks, CGPA
  • +
  • Variable cible : CGPA (moyenne cumulative, 0~10)
  • +
  • Exclusion de Internal_Marks pour éviter les fuites de données
  • +
+
+
+

Processus de nettoyage des données

+
    +
  • Sélection des champs → Déduplication
  • +
  • Champs numériques : imputation par la médiane des valeurs manquantes
  • +
  • Champs catégoriels : imputation par le mode
  • +
  • Filtrage des valeurs aberrantes (plages raisonnables pour l'âge, le temps d'étude, etc.)
  • +
  • Variables catégorielles : encodage one-hot (drop_first)
  • +
+
+
+ +
+
+

Analyse visuelle (6 graphiques)

+
+
+
+
+

Distribution du temps d'écran

+

Distribution asymétrique à droite, la majorité des étudiants passent 3~8 heures par jour devant un écran

+
+
+

Temps d'étude vs CGPA

+

Corrélation positive claire, les étudiants étudiant 6~8 h/jour ont généralement un CGPA plus élevé

+
+
+

Top 3 de l'importance des caractéristiques

+

Temps d'étude > Taux d'assiduité > Temps d'écran

+
+
+ +
+ Python + Linear Regression + Random Forest + Pandas + Seaborn + EDA +
+
+ + +
+
+ Project 3 +
+

Reconnaissance de gestes Pierre-Papier-Ciseaux — YOLO11n

+

🪨📄✂️ Ultralytics · PyTorch · Détection d'objets

+
+
+ +
+
+

Jeu de données

+

rock-paper-scissors-sxsw (Roboflow v11)

+
    +
  • Total de 15 874 images
  • +
  • Ensemble d'entraînement 14 966 / Validation 588 / Test 320
  • +
  • 3 classes : Paper (Feuille), Rock (Pierre), Scissors (Ciseaux)
  • +
  • Taille d'entrée : 640×640
  • +
+
+
+

Augmentation des données

+

Génération de 7 versions augmentées par image originale :

+
    +
  • Retournement horizontal (50%), rotation aléatoire ±12°
  • +
  • Cisaillement ±2°, luminosité/exposition ±25%
  • +
  • Flou gaussien 0~1,5 px, bruit poivre-et-sel 1%
  • +
+
+
+ +
+

Configuration d'entraînement

+
+
+
ModèleYOLO11n (2.58M params)
+
Epochs50
+
Batch16
+
+
+
OptimiseurAdamW
+
Durée d'entraînement~3.07h
+
GPURTX 5060 (8GB)
+
+
+
+ + +
+
+

Résultats d'évaluation

+
+
+
+
+

Ensemble de validation

+
+ mAP50 (global) + 0.940 +
+
+ mAP50-95 + 0.697 +
+
+ Précision (P) + 0.942 +
+
+ Rappel (R) + 0.891 +
+
+ Vitesse d'inférence + < 2.1ms +
+
+
+

Ensemble de test

+
+ mAP50 (global) + 0.934 +
+
+ mAP50-95 + 0.693 +
+
+ Précision (P) + 0.898 +
+
+ Rappel (R) + 0.920 +
+
+
+ + +
+

Performance par classe

+
+
+

📄 Paper

+
Validation mAP500.936
+
Test mAP500.904
+
+
+

🪨 Rock

+
Validation mAP500.943
+
Test mAP500.951
+
+
+

✂️ Scissors

+
Validation mAP500.940
+
Test mAP500.947
+
+
+
+ + +
+
+

Modes d'application

+
+
+
+
+

Inférence sur image unique

+

Reconnaissance sur n'importe quelle photo de geste, les résultats sont annotés sous forme de boîte englobante + étiquette, sauvegardés dans le répertoire de sortie.

+
+ predict.py +
+
+
+

Détection en temps réel par caméra

+

Utilisation de la caméra système (1280×720) pour une capture en temps réel, inférence à l'échelle de la milliseconde par image, affichage du taux de trames FPS dans la fenêtre, appuyez sur Q pour quitter.

+
+ detect.py +
+
+
+

Scripts d'évaluation

+

Évaluation sur l'ensemble de validation, évaluation sur l'ensemble de test, outil de téléchargement du jeu de données, couverture complète du flux d'entraînement au déploiement.

+
+ evaluate.py / test.py +
+
+
+ +
+ Python + PyTorch + YOLO11n + Ultralytics + OpenCV + Roboflow + CUDA +
+
+ + + + + + + + \ No newline at end of file diff --git a/fr/projects/SmartShed.html b/fr/projects/SmartShed.html new file mode 100644 index 0000000..336babb --- /dev/null +++ b/fr/projects/SmartShed.html @@ -0,0 +1,924 @@ + + + + + + SmartShed — Serre Intelligente | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ Rapport de cours · Semestre printemps 2025-2026 +

OpenHarmony au service de l'agriculture intelligente
— Terminal de contrôle de serre basé sur Hi3861 et HarmonyOS

+

De la collecte des capteurs au contrôle en temps réel sur mobile, un système IoT complet pour l'agriculture intelligente.
Deux cartes de développement à tâches distinctes, relayage MQTT, terminal HarmonyOS pleinement fonctionnel.

+ +
+ + +
+
+

Présentation générale du projet

+

Rapport de conception du cours du second semestre de l'année 2025-2026, présenté par : Chen Zirui (Ray Chen)

+
+
+

Qu'est-ce que Smart Shed ?

+

+ Smart Shed (Serre Intelligente) est un système complet de contrôle IoT pour l'agriculture intelligente, basé sur OpenHarmony et HarmonyOS NEXT de Huawei. + En bref : deux cartes de développement s'occupent de percevoir et de contrôler les paramètres environnementaux, communiquent en temps réel avec l'application mobile via le protocole MQTT, + et permettent finalement le monitoring automatique et le pilotage intelligent de la température, de l'humidité, de la luminosité et de l'humidité du sol dans la serre. +

+
+
+ + Côté embarqué +

OpenHarmony + Hi3861 × 2
Collecte capteurs & contrôle actionneurs

+
+
+ + Côté serveur +

EMQX MQTT Broker
Relayage de messages & routage par Topic

+
+
+ + Côté application +

HarmonyOS NEXT (API23)
Mate 70 Pro+ / MatePad Pro

+
+
+
+
+ + + + +
+
+
+

01 · Vue d'ensemble & Stack technique

+

Architecture globale, défis techniques rencontrés, innovations apportées

+
+
+ + +
+
+

Architecture système : collaboration logiciel-matériel, intégration verticale

+

Côté embarqué collecte les données → Serveur relaie les messages → Mobile affiche et contrôle

+
+
+
+

Côté embarqué

+

OpenHarmony 1.0 Release
+ Rayawa/rgb @ HiSilicon-Hi3861
+ Rayawa/soi @ HiSilicon-Hi3861
+ Collecte capteurs + affichage OLED
Contrôle PWM/GPIO des actionneurs

+
+
+
+

Côté serveur

+

MQTT 5.0 WebSocket
+ wss://broker.emqx.io:8084
+ @MQTTX
+ Relayage de messages public
Routage distribué par Topic

+
+
+
+

Côté application

+

HarmonyOS 6.1.0 (API23)
+ Smart Shed @ Mate 70 Pro+
+ Smart Shed @ MatePad Pro 12.2
+ Affichage de données en temps réel
Modes Manuel / Intelligent

+
+
+
+ + +
+
+

Défis techniques

+

Problèmes réellement rencontrés durant le développement

+
+
+
+

Côté embarqué

+
    +
  • Nombreux problèmes de compatibilité des versions d'interface de pilotes
  • +
  • L'accès concurrent multi-périphériques au bus I2C provoque des conflits
  • +
  • L'espace de pile et la priorité des threads LiteOS-M nécessitent de nombreux réglages itératifs
  • +
+
+
+

Côté application

+
    +
  • La documentation originale était basée sur JavaUI API7, bien trop ancienne
  • +
  • Le code original ne fonctionnait que sur une tablette spécifique ; changement d'appareil = interface en désordre
  • +
  • Une seule carte d'extension pouvait gérer un seul composant, mais quatre systèmes avaient été conçus : refonte massive requise
  • +
+
+
+

Couche communication

+
    +
  • Le transport MQTT n'est pas très stable, et les messages d'erreur sont peu explicites
  • +
  • Le module WiFi du Hi3861 est vieillissant, capacité de charge faible
  • +
  • Le mécanisme d'envoi/réception côté application était rudimentaire, quasi sans gestion d'erreurs : tout se faisait au feeling
  • +
+
+
+
+ + +
+
+

Innovations

+
+
+
+

Architecture double carte séparée

+

Carte de perception environnementale (RGB) et carte d'exécution sol (SOI) isolées physiquement et découplées logiquement : chacune gère son domaine tout en collaborant.

+
+
+

Client MQTT zéro dépendance

+

Côté HarmonyOS, les paquets MQTT sont entièrement construits manuellement depuis TCP Socket, sans aucune dépendance tierce.

+
+
+

Système visuel avancé HDS

+

Intégration de la bibliothèque officielle HarmonyOS Design System : navigation immersive, effets gravitationnels, arrière-plan lumineux.

+
+
+

Modes Manuel / Intelligent

+

Mode Manuel : ajustement libre des niveaux. Mode Intelligent : décision automatique selon les seuils, thread résident sécurisé en arrière-plan.

+
+
+

Adaptation forme Glass

+

Application supplémentaire sous forme Glass pour montre connectée, avec matériaux immersifs et animations gazeuses.

+
+
+

Garantie de fiabilité

+

Détection automatique hors ligne (timeout 5s), reconnexion avec recul exponentiel, bus de journalisation GlobalLogBus comme filet de sécurité global.

+
+
+
+ + +
+
+

Stack technique

+
+
+
+

Embarqué (Hi3861)

+
+ Hi3861 + HiSilicon + OpenHarmony 1.0 + LiteOS-M + CMSIS-RTOS + C + GPIO + PWM + I2C + ADC + AHT20 + SSD1306 + Paho MQTT + lwIP + Wi-Fi STA +
+
+
+

Serveur (Communication)

+
+ MQTT 5.0 + WebSocket Secure + EMQX Broker + TCP Socket + JSON + Pub/Sub + Routage Topic +
+
+
+

Application (HarmonyOS)

+
+ HarmonyOS 6.1.0 + API23 + ArkTS + ArkUI + Modèle Stage + @StorageLink + @ObjectLink + HDS + UIDesignKit + Forme Glass +
+
+
+
+
+ + + + +
+
+
+

02 · Serveur MQTT

+

Principe de l'architecture Pub/Sub et conception du flux de données

+
+
+ + +
+
+

Architecture Pub/Sub (Publication/Abonnement)

+

MQTT est un protocole léger de messagerie, conçu spécifiquement pour les scénarios IoT à faible bande passante

+
+
+

Mécanisme de collaboration tripartite

+
+
+ Publisher Émetteur +

+ Le côté embarqué Hi3861 agit en tant qu'émetteur, encapsule les données des capteurs en JSON et les envoie vers le Topic désigné. +

+
+
+ Broker Relais +

+ EMQX agit en tant que Broker MQTT : après réception d'un message, il le transfère aux abonnés correspondants selon les règles de Topic. +

+
+
+ Subscriber Abonné +

+ L'application HarmonyOS, une fois abonnée aux Topics concernés, reçoit les données des capteurs et peut également envoyer des commandes de contrôle. +

+
+
+
+
+ + +
+
+

Conception du flux de données

+

Comment les données transitent du matériel jusqu'au mobile, et comment les commandes reviennent vers le matériel pour exécution

+
+
+ +
+

Montant : données capteurs → affichage mobile

+
+
+
+
+

① Échantillonnage capteurs

+

Les capteurs de la carte d'extension collectent les données brutes → lecture ADC de luminosité/humidité du sol, lecture I2C de AHT20 température/humidité

+
+
+
+
+
+

② Encapsulation & envoi

+

Le Hi3861 convertit les données en format JSON et les envoie au Broker EMQX via un paquet MQTT PUBLISH

+
+
+
+
+
+

③ Routage distribué

+

EMQX reçoit le message et le distribue aux clients abonnés selon les règles de Topic

+
+
+
+
+
+

④ Rafraîchissement de l'interface

+

HarmonyOS reçoit et analyse le message → mise à jour d'état via @StorageLink → rafraîchissement des chiffres UI / jugement des seuils en mode intelligent

+
+
+
+
+ +
+

Descendant : action utilisateur → exécution matérielle

+
+
+
+
+

① Action utilisateur ou déclenchement automatique

+

Mode Manuel : glisser le curseur pour régler le niveau. Mode Intelligent : génération automatique de commande si dépassement de seuil

+
+
+
+
+
+

② Encapsulation & envoi

+

HarmonyOS convertit la commande de contrôle en paquet MQTT, qui est distribué via EMQX

+
+
+
+
+
+

③ Exécution matérielle

+

Après réception du message, le Hi3861 analyse le sujet et le contenu → contrôle des sorties GPIO/PWM → actionnement ventilateur/pompe/lumière

+
+
+
+
+
+
+
+ + + + +
+
+
+

03 · Côté embarqué Hi3861

+

OpenHarmony LiteOS-M + multithread CMSIS-RTOS, développement entièrement en C

+
+
+ + +
+
+

Deux cartes de développement, chacune sa mission

+
+
+
+

Carte RGB (Perception environnementale)

+

Responsable de « voir l'environnement » et « afficher localement »

+
+ Capteurs +
    +
  • Capteur AHT20 température/humidité — Lecture I2C de température et humidité
  • +
  • Photo-résistance — Lecture ADC de l'intensité lumineuse (0~4095)
  • +
+
+
+ Actionneurs +
    +
  • LED RGB trichromatique — GPIO10/11/12 => PWM1/2/3 pour contrôle de luminosité
  • +
+
+
+ Affichage local +

OLED SSD1306 (128×64) avec rafraîchissement en temps réel des données de température, humidité et luminosité

+
+
+
+

Carte SOI (Exécution sol)

+

Responsable de « mesurer le sol » et « agir »

+
+ Capteurs +
    +
  • Capteur d'humidité du sol (installation par remplacement) — Lecture ADC de l'humidité du sol
  • +
+
+
+ Actionneurs +
    +
  • Écran OLED — Impression d'état local
  • +
  • Ventilateur — Contrôle PWM de la vitesse
  • +
  • Pompe — Contrôle GPIO marche/arrêt
  • +
+
+
+
+
+ + +
+
+

Structure du projet

+

Grandes fonctions séparées, petits modules divisés : clair et facile à maintenir

+
+
+
+

common/ Couche commune

+

Connexion Wi-Fi, communication MQTT, pilote OLED : tout est ici. Le mutex I2C est aussi géré ici pour éviter que plusieurs threads ne s'accaparent le bus.

+
+
+

modules/ Couche métier

+

Divisée en deux sous-répertoires :

+
    +
  • sensors/ — Fichiers d'en-tête et programmes des capteurs AHT20, intensité lumineuse, humidité du sol
  • +
  • actuators/ — Programmes de contrôle ventilateur, lumière complémentaire, pompe
  • +
+
+
+

boards/ Couche de build

+

Les fichiers de build .gn des deux cartes sont gérés de manière unifiée. La compilation conditionnelle active dynamiquement les modules selon la carte : ajouter une nouvelle carte = ajouter simplement un fichier gn.

+
+
+
+ + +
+
+

Architecture multithread

+

CMSIS-RTOS gère les tâches parallèles sous le noyau temps réel LiteOS-M

+
+
+

Point d'entrée du thread principal

+
    +
  • Au démarrage du système, SYS_RUN crée le thread principal smart_shed_all.c, avec une pile de 8 Ko
  • +
  • Le thread initialise séquentiellement et lance tous les sous-threads : collecte capteurs, contrôle actionneurs, communication MQTT, affichage OLED
  • +
  • La compilation conditionnelle active dynamiquement les modules correspondants selon la configuration de la carte, avec un point d'ordonnancement unifié
  • +
+
+
+

Six sous-threads travaillant en parallèle

+

Chaque module fonctionnel tourne indépendamment dans le noyau LiteOS, avec son propre espace de pile (4Ko~8Ko) et sa priorité, sans blocage mutuel :

+
+
+ + Collecte température/humidité air +

AHT20 / I2C

+
+
+ + Détection luminosité +

Échantillonnage ADC

+
+
+ + Lecture humidité du sol +

Échantillonnage ADC

+
+
+ + Ventilateur/LED/Pompe +

Contrôle GPIO/PWM

+
+
+ + Rafraîchissement affichage OLED +

Rendu SSD1306

+
+
+ + Communication réseau MQTT +

Publication/Abonnement Paho

+
+
+
+
+

Mutex I2C : résolution des conflits de bus

+

Le capteur AHT20 et l'écran OLED partagent le même bus I2C0 (GPIO13 & GPIO14). Si deux threads y accèdent simultanément, ça coince. Solution :

+
+
+ Scénario de conflit +

Le thread de collecte temp./humid. et le thread de rafraîchissement OLED lisent et écrivent simultanément sur I2C0, provoquant une corruption des données

+
+
+ Solution +

Utiliser le mutex i2c0_lock/unlock : verrouillage/déverrouillage avant et après chaque lecture/écriture, garantissant qu'un seul périphérique occupe le bus à un instant donné

+
+
+
+
+ + +
+
+

Correspondance des connexions matérielles

+
+
+
+

Carte SOI (Exécution sol)

+
+
+ OLED + Impression d'état + I2C0-0x78 GPIO13&14 + oled_ssd1306.c +
+
+ Humidité du sol + Sonde externe + ADC_CH4 + soil_moisture_task.c +
+
+ Pompe + Pompe externe + P06 + water_pump_task.c +
+
+ Ventilateur + Ventilateur externe + P08 + fan_task.c +
+
+
+
+

Carte RGB (Perception environnementale)

+
+
+ OLED + Impression d'état + I2C0-0x78 GPIO13&14 + oled_ssd1306.c +
+
+ Capteur temp./humid. + Détection paramètres air + I2C0-0x44 + temp_and_hum_task.c +
+
+ Photo-résistance + Détection intensité lumineuse + ADC_CH4 + light_intensity_task.c +
+
+ LED RGB trichrome + Contrôle éclairage serre + GPIO10/11/12=>PWM1/2/3 + led_task.c +
+
+
+
+
+ + +
+
+

Réseau et communication

+

Connexion Wi-Fi → TCP établi → MQTT envoie/reçoit → Les actionneurs bougent

+
+
+

Flux de communication

+
+
+
+
+

Connexion Wi-Fi

+

Connexion au SSID "Rayawa", obtention d'une IP via DHCP puis passage en communication TCP lwIP

+
+
+
+
+
+

Encodage/décodage MQTT

+

La bibliothèque Paho gère uniquement l'encodage/décodage des paquets ; le cycle de vie complet du Socket TCP doit être géré manuellement

+
+
+
+
+
+

Envoi des données capteurs

+

Les données des capteurs sont transmises au Broker EMQX au format JSON

+
+
+
+
+
+

Exécution des commandes de contrôle

+

Réception d'un paquet PUBLISH → analyse du sujet et de la charge utile via MQTTDeserialize_publish() → définition des variables globales via mqtt_apply_command(). Les threads d'actionneurs lisent continuellement ces variables pour contrôler les sorties GPIO/PWM, faisant fonctionner ventilateur, pompe, etc.

+
+
+
+
+
+
+ + + + +
+
+
+

04 · Application HarmonyOS

+

ArkTS · Modèle Stage · Visuels avancés HDS · Client MQTT auto-implémenté

+
+
+ + +
+
+

Smart Shed App

+

Terminal de contrôle pleinement fonctionnel tournant sur Mate 70 Pro+ et MatePad Pro

+
+
+

Aperçu des fonctionnalités

+
+
+ Mode Manuel +

+ Glisser le curseur pour régler ventilateur (0-3 niveaux), pompe (0-3 niveaux), lumière complémentaire (0-100%). Synchronisation automatique du niveau actuel vers la carte à l'entrée de page, support retour haptique. +

+
+
+ Mode Intelligent +

+ Définir les seuils min/max de température, humidité, luminosité et humidité du sol. Polling périodique des données capteurs, déclenchement automatique du contrôle en cas de dépassement. Thread résident en arrière-plan, destruction sécurisée à la sortie de page contre les fuites mémoire. +

+
+
+ Monitoring temps réel +

+ Callback MQTT réceptionnant les données capteurs, gestion d'état @StorageLink pilotant le rafraîchissement automatique des chiffres ArkUI. +

+
+
+ Panneau de debug +

+ Bus d'événements GlobalLogBus enregistrant l'état de communication, les actions utilisateur et les messages d'erreur, pratique pour diagnostiquer les problèmes. +

+
+
+
+
+ + +
+
+

Structure du projet App (Modèle Stage)

+

Architecture en couches basée sur ArkTS

+
+
+
+

AppScope/

+

Point d'entrée unifié pour les ressources globales de l'application et les scripts de build Hvigor.

+
+
+

view/ & pages/

+

Couche UI construite en ArkTS, incluant l'interface complète des modes Manuel/Intelligent et du panneau de debug.

+
+
+

service/

+

Encapsulation du client MQTT (MqttReceiverClient.ts), connexion directe TCP Socket pour communication bidirectionnelle, zéro dépendance tierce.

+
+
+

viewmodel/

+

Structures de données centrales et modèles d'état, assurant la liaison réactive entre UI et données.

+
+
+
+ + +
+
+

MqttReceiverClient.ts — Client MQTT écrit depuis zéro

+
+
+

Pourquoi l'avoir écrit soi-même ?

+

+ Côté HarmonyOS, aucune bibliothèque MQTT tierce n'a été utilisée : les paquets ont été entièrement construits à la main depuis TCP Socket. Cela donne un contrôle total sur l'ensemble du processus de communication, et facilite grandement le diagnostic en cas de problème. +

+
+
+
+

Couche protocole

+
    +
  • Assemblage manuel de Fixed Header + Variable Header + Payload
  • +
  • Implémentation des paquets principaux CONNECT / PUBLISH / SUBSCRIBE / PINGREQ
  • +
  • Heartbeat KeepAlive toutes les 60s pour maintien de connexion
  • +
  • MQTT 5.0 over WSS connexion directe au Broker public EMQX
  • +
+
+
+

Garantie de fiabilité

+
    +
  • Reconnexion automatique en cas de coupure + recul exponentiel
  • +
  • Connexion TCP unique, abonnement multi-Topic et routage distribué
  • +
  • Gestion d'état @StorageLink et découplage vis-à-vis d'ArkUI
  • +
  • Bus de journalisation GlobalLogBus traçant l'intégralité des communications
  • +
+
+
+
+

États et méthodes

+
+
+ États de contrôle +

Gestion centralisée des niveaux de ventilateur, pompe et luminosité LED, partage d'état inter-pages via @StorageLink.

+
+
+ Transmission de paramètres +

Données capteurs et commandes de contrôle transmises de manière fiable via un format unifié dans la couche MQTT.

+
+
+ Synchronisation des logs +

GlobalLogBus collecte de manière unifiée l'état de communication, les enregistrements d'opérations et les informations d'anomalies.

+
+
+ Cycle de vie +

Création de la connexion à l'entrée de page, destruction du thread et libération des ressources à la sortie : zéro fuite mémoire.

+
+
+
+
+ + +
+
+

Design UI : HDS + ArkUI

+

Non seulement fonctionnel, mais aussi beau

+
+
+

Composants clés HDS

+
+
+ HdsNav Barre de navigation +

Navigation supérieure immersive à champ lumineux, effet flou glassmorphism

+
+
+ PressShadow Effet gravitationnel +

Déformation élastique à l'appui + diffusion du champ lumineux en retour tactile

+
+
+ SpringMotion Animation ressort +

Entrée échelonnée avec délai, courbe ressort pour une expérience fluide

+
+
+
+
+

Style visuel

+
+
+ Champ lumineux sombre +

Arrière-plan lumineux fluide traversant toute l'interface, ambiance maximale en mode sombre

+
+
+ Mise en page double colonne +

Adaptation tablette en double colonne, équilibre entre densité d'information et harmonie visuelle

+
+
+
+
+
+

Animation : champ gravitationnel

+

Effet de champ gravitationnel lors des transitions de page, animations d'attraction/répulsion naturelles entre éléments.

+
+
+

Animation : champ lumineux

+

Arrière-plan lumineux fluide + champ lumineux global sombre double colonne, ombres dynamiques variant avec les interactions.

+
+
+

Animation : transition

+

Fondu + animation élastique, courbe SpringMotion pour des transitions soyeuses.

+
+
+
+

Mise en page responsive

+

Système de grille responsive ArkUI, adaptation automatique aux deux facteurs de forme mobile et tablette :

+
+
+ Version mobile +

Colonne unique défilement vertical, cartes empilées

+
+
+ Version tablette +

Double colonne côte à côte, exploitation optimale de l'espace large

+
+
+
+
+ + +
+
+

Smart Shed Glass

+

Forme montre connectée — Matériaux immersifs + Animations gazeuses

+
+
+
+

Caractéristiques de la forme Glass

+
    +
  • Matériaux immersifs — L'interface fusionne avec la texture en verre du cadran
  • +
  • Animations gazeuses — Transitions légères et aériennes
  • +
  • Transition gravitationnelle — Conservation du même langage d'interaction que l'App principale
  • +
  • Lumière fluide double bordure — Décoration dynamique sur les côtés du cadran
  • +
+
+
+

Composants personnalisés HdsButtons

+

Système de composants boutons personnalisés basé sur les spécifications HDS, unifiant l'apparence visuelle et le retour tactile de tous les éléments interactifs sous la forme Glass. Supporte plusieurs tailles et styles d'état (par défaut/appuyé/désactivé), agréable à utiliser sur petit écran.

+
+
+
+
+ + + + +
+
+
+

05 · Questions fréquentes & Conclusion

+

Ce que vous vous posez peut-être, et ce que ce projet m'a apporté

+
+
+ + +
+
+

Questions fréquentes

+
+
+
+

Pourquoi avoir choisi OpenHarmony plutôt qu'Arduino/ESP32 ?

+

OpenHarmony offre un vrai RTOS (LiteOS-M) avec ordonnancement préemptif, gestion multithread native et un écosystème matériel Huawei mature. Arduino/ESP32, c'est bien pour prototyper, mais dès qu'on veut faire du multitâche sérieux avec mutex, piles configurables et compilation conditionnelle, on atteint vite les limites. Et puis, travailler avec un système d'exploitation complet plutôt qu'un simple framework, c'est une expérience d'apprentissage totalement différente.

+
+
+

Combien de temps a pris le développement ?

+

Environ 6 semaines au total : 2 semaines pour la partie embarquée (drivers, multithread, MQTT), 3 semaines pour l'App HarmonyOS (refonte complète depuis JavaUI API7 vers ArkTS API23, implémentation MQTT from scratch, design HDS), et 1 semaine pour l'intégration, les tests et la rédaction du rapport. Le plus long a été la refonte côté application — le code legacy était vraiment difficile à migrer.

+
+
+

Le plus gros challenge technique ?

+

Sans hésiter : le conflit de bus I2C. AHT20 et SSD1306 partagent le même bus I2C0, et quand le thread de collecte et celui d'affichage y accèdent en même temps, c'est le chaos. La solution paraît simple (un mutex), mais trouver la source du bug a pris presque 2 jours de debug avec un oscilloscope logique. Ensuite, écrire un client MQTT entier depuis zéro en ArkTS a aussi été un bon défi — surtout la gestion de la reconnexion et du cycle de vie des threads.

+
+
+

Quels outils de debug avez-vous utilisés ?

+

Côté embarqué : oscilloscope logique USB pour tracer le bus I2C, serial print sur UART0 pour les logs, et MQTTX pour visualiser les messages en temps réel. Côté HarmonyOS : DevEco Studio avec son debugger intégré, HiLog pour les logs système, et le panneau GlobalLogBus intégré à l'App pour suivre toute l'activité MQTT en direct. L'outil le plus précieux ? Probablement MQTTX — pouvoir voir exactement ce qui passe sur le broker en temps réel a sauvé pas mal de soirées.

+
+
+

Ce projet pourrait-il être utilisé en conditions réelles ?

+

Pour un prototype de cours, il est déjà assez abouti. Mais pour un déploiement réel, il manque quelques choses : authentification MQTT (actuellement sans mot de passe), persistance des seuils de mode intelligent (stockés en mémoire volatile), et une UI de configuration initiale (SSID/mot de passe WiFi actuellement codés en dur). Le hardware aussi : le Hi3861 n'est pas certifié industriel, et les capteurs bas coût manquent de calibration. Mais l'architecture logicielle est solide — ces améliorations seraient relativement simples à intégrer.

+
+
+

Qu'avez-vous appris grâce à ce projet ?

+

Beaucoup plus que prévu. Sur le plan technique : programmation système embarquée, RTOS, protocoles IoT, développement d'application mobile moderne. Sur le plan méthodologique : comment architecturer un système distribué de bout en bout, gérer la complexité avec des couches propres, et documenter correctement. Et surtout : la patience face aux bugs matériels qui ne s'expliquent pas, et la satisfaction de voir un système complet fonctionner de bout en bout — du capteur jusqu'à l'écran du téléphone.

+
+
+
+ + +
+
+

Bilan du projet

+
+
+

Un projet de A à Z

+

+ De la première ligne de code à la présentation finale, SmartShed a été un voyage complet à travers l'écosystème HarmonyOS/OpenHarmony. + J'ai touché à presque chaque couche d'un système IoT : drivers matériels, RTOS, protocoles réseau, développement d'application mobile, + design d'interface utilisateur, et même un peu de devOps avec la chaîne de build GN/Ninja. +

+

+ Si je devais retenir une chose, c'est que la complexité se gère par l'architecture. Au début, j'ai essayé de tout mettre dans un seul fichier + — résultat : cauchemar de maintenance. Après refactorisation en couches (common/modules/boards) et adoption du modèle Stage côté App, + chaque modification devient ciblée et prévisible. +

+

+ Merci d'avoir lu jusqu'ici. Si ce projet vous inspire ou si vous avez des questions, n'hésitez pas à me contacter + ou à explorer le code source sur GitHub — il est entièrement open-source. +

+
+
+
+
+ + + + + + + diff --git a/fr/projects/bio.html b/fr/projects/bio.html deleted file mode 100644 index 131ba4e..0000000 --- a/fr/projects/bio.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - Projets de biologie | Ray Chen - - - - - - - - - - -
-
-
-

Projets de biologie

-

Papiers et traces expérimentales en biologie : PCR, hypothèses protéiques, revue d'assimilation du carbone, expériences orange-plate, et une démo web interactive Agrobacterium.

-
- -
-
-

Laboratoire PCR

-

Pionnier de la première expérience PCR au lycée, introduisant des expériences de biologie avancées en classe. -Exploration des dosages optimaux de réactifs pour les expériences en classe grâce à des pré-expériences et des expériences de quantité de matrice.

-
-
-
-
-
- PCR凝胶电泳结果 -
-
L'électrophorèse sur gel montre des bandes claires, confirmant l'amplification réussie du gène cible. -Comparé au marqueur standard, la longueur est d'environ 600 pb, conforme aux attentes expérimentales.
-
-
-
-
-
- -
-
-

Conception expérimentale

-

Conception expérimentale PCR détaillée incluant la conception d'amorces, les paramètres de cyclage thermique et l'optimisation du système de réaction. Pratique pour les cours de biologie au lycée, fournissant une référence pour les expériences futures.

- -
-
-
-
- -
-
-

Rapport de laboratoire final

-

Enregistrements expérimentaux complets, analyse des données et conclusions validant l'efficacité de la conception expérimentale.

- -
-
-
-
-
- -
-
-

Archives des thèses

-

Enregistrements de recherche et de réflexion, incluant des articles terminés et des travaux en cours.

-
- -
-
-
- C3植物光合作用论文 -
-
-
- Brouillon - 2024.6.8 -
-

Recherche en biologie moléculaire sur le cycle de Calvin

-

Cet article déconstruit en profondeur le processus biochimique complexe de l'assimilation du carbone chez les plantes C4 dans une perspective de structure moléculaire. En systématisant et visualisant les processus de conversion énergétique et de métabolisme des substances dans la réaction sombre, il fournit un modèle précis à l'échelle microscopique pour comprendre comment les organismes autotrophes convertissent efficacement le carbone inorganique, révélant la beauté logique des processus biochimiques.

- -
-
-
-
- 酿酒酵母橙色平板实验论文 -
-
-
- Brouillon - 2026.03.08 -
-

Analyse et vérification du changement de couleur orange des plaques dans les expériences sur la levure

-

Face au changement de couleur anormal occasionnel des milieux de culture en microbiologie, cet article a retracé avec succès l'origine des facteurs de contamination environnementale grâce à des expériences contrôlées rigoureuses. Cette recherche ne se contente pas de résoudre un problème technique expérimental spécifique ; son importance fondamentale réside dans l'établissement de procédures normalisées d'analyse des erreurs et de contrôle qualité en laboratoire, soulignant l'importance d'une attitude rigoureuse et du respect des procédures dans la pratique scientifique.

- -
-
-
-
- -
-
-
- 农杆菌转化示意图 -
-
-
-

Explorer les processus biologiques grâce au développement interactif

-

Transformer des flux de génie génétique complexes en interactions web intuitives, rendant l'apprentissage vivant et engageant. L'application web de transformation par Agrobacterium démontre comment construire des outils d'enseignement de la biologie avec du code.

- Lancer la simulation -
-
-
-
- - - - - - - - diff --git a/fr/projects/biology.html b/fr/projects/biology.html index 2bbe79a..1d80576 100644 --- a/fr/projects/biology.html +++ b/fr/projects/biology.html @@ -3,7 +3,34 @@ - Projets de biologie | Ray Chen + Projets de Biologie | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -80,8 +107,8 @@

Archives des thèses

Terminé 2024.6.23
-

Mécanismes pathogènes et propriétés génétiques des protéines prions

-

Cette étude explore systématiquement les mécanismes pathogènes et les propriétés génétiques des protéines prions (PrP^Sc), en se concentrant sur leur mécanisme moléculaire d'induction du mauvais repliement des protéines prions normales (PrP^C) par conversion conformationnelle, et discute de l'effet de barrière d'espèce des prions dans la transmission inter-espèces et de leur impact potentiel sur la santé publique.

+

Sur la conjecture des protéines comme matériel génétique dans des organismes extrêmement, extrêmement spéciaux

+

Cet article remet audacieusement en cause l'autorité absolue du « dogme central » de la biologie. Sur la base des propriétés d'auto-réplication des prions et des mécanismes de transcription inverse, il explore rigoureusement la possibilité des protéines comme vecteurs génétiques primitifs. Cette recherche vise à élargir les frontières de la réflexion sur l'évolution biologique et la nature de l'hérédité, fournissant un cadre hypothétique très prospectif pour l'étude des formes de vie dans des environnements extrêmes.

@@ -98,8 +125,8 @@

Mécanismes pathogènes et propriétés génétiques des protéines prionsBrouillon 2024.6.8

-

Sur la conjecture des protéines comme matériel génétique dans des organismes extrêmement, extrêmement spéciaux

-

Cet article remet audacieusement en cause l'autorité absolue du « dogme central » de la biologie. Sur la base des propriétés d'auto-réplication des prions et des mécanismes de transcription inverse, il explore rigoureusement la possibilité des protéines comme vecteurs génétiques primitifs. Cette recherche vise à élargir les frontières de la réflexion sur l'évolution biologique et la nature de l'hérédité, fournissant un cadre hypothétique très prospectif pour l'étude des formes de vie dans des environnements extrêmes.

+

Recherche en biologie moléculaire sur le cycle de Calvin chez les plantes C3

+

Cet article propose une analyse approfondie du cycle de Calvin, la voie centrale de fixation du carbone chez les plantes C3. Il examine systématiquement les mécanismes moléculaires de l'assimilation du carbone, y compris les propriétés catalytiques et la régulation d'enzymes clés telles que la Rubisco, ainsi que les processus de conversion énergétique impliquant l'ATP et le NADPH. Cette recherche vise à approfondir la compréhension des limitations de l'efficacité photosynthétique chez les plantes C3 et à explorer les directions potentielles pour améliorer les rendements culturaux par des approches biochimiques.

diff --git a/fr/projects/gene.html b/fr/projects/gene.html index 90e30b3..6301d91 100644 --- a/fr/projects/gene.html +++ b/fr/projects/gene.html @@ -5,8 +5,35 @@ - 基因工程:农杆菌转化法交互实验室 | Ray Chen - + Laboratoire Interactif de Génie Génétique | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/idv.html b/fr/projects/idv.html index eb852be..1962bc7 100644 --- a/fr/projects/idv.html +++ b/fr/projects/idv.html @@ -3,10 +3,35 @@ - 第五人格,启动! | Ray Chen - + Calculateur de Rang Identity V | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/fr/projects/ncut_papers.html b/fr/projects/ncut_papers.html index a772375..95900b2 100644 --- a/fr/projects/ncut_papers.html +++ b/fr/projects/ncut_papers.html @@ -3,7 +3,34 @@ - Travaux universitaires | Ray Chen + Travaux Universitaires | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/signal.html b/fr/projects/signal.html new file mode 100644 index 0000000..c8e3461 --- /dev/null +++ b/fr/projects/signal.html @@ -0,0 +1,138 @@ + + + + + + Mesure de Signaux Faibles | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+

Mesure de Signaux Électriques Faibles

+

Conception d'un système de mesure de signaux électriques faibles basé sur le développement embarqué Arduino

+
+ +
+
+

Résumé

+
+
+
+

Cet article présente un système basé sur Arduino pour la mesure de signaux électriques faibles, abordant les problèmes de faible sensibilité et d'interférences environnementales. Le système combine l'amplification mécanique avec le conditionnement de signal et le traitement embarqué Arduino pour l'acquisition et le calcul des données. Un algorithme de normalisation et des méthodes de réduction du bruit à plusieurs étapes sont appliqués pour améliorer la stabilité et la robustesse. La structure du système, la mise en œuvre matérielle, les algorithmes logiciels, les méthodes d'étalonnage, ainsi que les sources d'erreur et les incertitudes sont analysées et évaluées, et les performances du système sont vérifiées par des procédures expérimentales. De plus, une analyse des coûts est réalisée pour démontrer sa faisabilité économique. Les scénarios d'application et les limites sont également discutés. Les résultats montrent que le système peut réaliser une mesure stable des signaux électriques faibles avec une valeur pratique.

+

Mots-clés : Arduino; Signal Électrique Faible; Amplificateur Transimpédance; Capteur PSD; Évaluation de l'Incertitude

+ +
+
+ Document de l'article +
+
+
+ +
+
+ +
+

Fichiers du projet

+

Documents de conception et ressources techniques

+
+
+ +
+
+ + + + + + + diff --git a/fr/projects/spm.html b/fr/projects/spm.html index e531f43..4448179 100644 --- a/fr/projects/spm.html +++ b/fr/projects/spm.html @@ -4,6 +4,33 @@ Sweet Potato Mod | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/xxh.html b/fr/projects/xxh.html index 5d3334b..1f5f7ef 100644 --- a/fr/projects/xxh.html +++ b/fr/projects/xxh.html @@ -4,6 +4,33 @@ Test XXH | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fr/projects/xxh_test.html b/fr/projects/xxh_test.html index 059b32e..615bee3 100644 --- a/fr/projects/xxh_test.html +++ b/fr/projects/xxh_test.html @@ -4,6 +4,24 @@ Test XXH | Ray Chen + + + + + + + + + + + + + + + + + + diff --git a/fr/thanks.html b/fr/thanks.html index 5a3ec31..a666bc7 100644 --- a/fr/thanks.html +++ b/fr/thanks.html @@ -4,6 +4,33 @@ Remerciements | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43,7 +70,7 @@

Professeurs

Camarades

-
义乌学社hjz、jdh、ljy、lzq、whn、wth、wyx、yyzy、zrq、zxy (par ordre alphabétique)
Mes amisAndyGao、bzy、lyx、ywx、lxr、wjy、ydx、lmd、lyc
9B208xxh、rjp、ldy、ddk
+
义乌学社hjz、jdh、ljy、lzq、whn、wth、wyx、yyzy、zrq、zxy (par ordre alphabétique)
Mes amisAndyGao、bzy、lyx、ywx、lxr、wjy、ydx、lmd、lyc、zhy
9B208xxh、rjp、ldy、ddk
diff --git a/index.html b/index.html index 6a199ec..489424b 100644 --- a/index.html +++ b/index.html @@ -5,13 +5,42 @@ 首页 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -53,11 +82,11 @@

你好,这里是 Ray !

Ray汐 · 清霁Ray · Rayawa

-

通信在读 | 鸿蒙开发者 | 跨界极客 | 影像创作者

-

核心目前专注HarmonyOS应用开发与Hi3861嵌入式开发。

-

支线Web构建、Rust与Java学习、法语进阶中,未来计划向生物信息学探路。

+

通信在读 | 软件开发者 | 跨界极客 | 影像创作者

+

核心目前专注开源鸿蒙全栈开发与机器学习。

+

支线Web构建、Swift、Rust与Java学习、法语进阶中,未来计划向生物信息学探路。

摄影与生活风景摄影与无人机航拍,用快门捕捉通信之外的频率。

-

生活J'apprends le français;热爱听音乐;跑步骑行中;在提瓦特、塔卫二与罗德岛切换;音游在线,每天赚费沉底石头人()。

+

生活J'apprends le français;热爱听音乐;跑步骑行中;在提瓦特、罗德岛与海特洛切换;音游在线,每天赚费沉底石头人()。

@@ -98,40 +127,40 @@

关于我

三四年级的时候,Arduino的C语言是我接触的第一个正经编程语言,也是人生第一次体验“嵌入式开发”。虽然起初只是做流水呼吸灯、抢答器这类小物件,但后来我成功做出了一辆带云台的超声波避障小车。这辆小车不仅登上了当年的校报,后来还捐赠给了学校进行展示。

再后来,2018年我参加了丝绸之路国际青少年大赛机器人竞赛,做了一个智能鱼食投喂机。之后开始学C++并投身信息学奥赛。升入初中后,我又参与制做了一个烤地瓜模组的项目,还有人找我们签合同购买源码将模组上架网易版本。虽然那份合同现已过期,项目也因学业而搁置,但现在想起来还是充满回忆。

高中几乎三年没碰代码,都在做生物学相关的研究。去年九月份,我踏入了鸿蒙的大门,成为了鸿蒙开发者,开始参与鸿蒙应用看板项目。转眼间半年过去了,这个项目也算是积累了一定的知名度。现在我也正持续推进这个项目的进度:鸿蒙应用看板App已经进入邀请测试阶段,预计很快就能上架;未来还计划将其扩展至 macOS 与 Android 平台。

-

除了应用层,我目前也在钻研OpenHarmony Hi3861嵌入式开发。对我来说,这不只是在调硬件,更是为了从底层逻辑上透彻理解设备侧能力与系统工程。在网页开发上,我搭建了个人网站、模组站、第五人格站以及农杆菌转化法实验站点。现在的我,程序方面涉猎C、C++、Java、Rust、HTML、ArkTS、Swift和openGauss数据库。对我来说参与各种项目是一种我特别感兴趣的娱乐,未来我还会做更多的开发,全面提升自己的语言能力。

+

除了应用层,我目前也在钻研OpenHarmony Hi3861嵌入式开发。之前简单的做了一些开发板的单独开发,现在在做结合HarmonyOS应用的智慧大棚项目。对我来说,这不只是在调硬件,更是为了从底层逻辑上透彻理解设备侧能力与系统工程。最近开始学习机器学习,已经做了基本的回归预测和目标检测,未来打算继续深入。在网页开发上,我搭建了个人网站、模组站、第五人格站以及农杆菌转化法实验站点。现在的我,程序方面涉猎C、C++、Java、Rust、HTML、ArkTS、Swift和openGauss数据库。对我来说参与各种项目是一种我特别感兴趣的娱乐,未来我还会做更多的开发,全面提升自己的语言能力。

生物学是我探索世界的另一扇窗。高中时期遇见的两位非常优秀的生物老师,是我与这门学科结缘的关键。她们不仅教会了我知识,更以卓越的专业素养,将我从一个单纯的爱好者,培养成了能够独立思考的研究者。在老师的指导下,我带领高中开创了首届PCR实验,把高等的实验内容带到了高中课堂。我自己写了几篇感兴趣话题的小论文,还和同学一起撰写过一篇关于蛋白质在极特殊生物中作为遗传因子的设想。虽然现在因为主攻编程,碳同化综述和一些橙色平板研究项目的实验记录暂时搁置了,但我发现用代码去阐述生物学也十分有趣。生物学或许是我的一种“遗憾美”,如果有机会,未来我也希望能向生物信息学方向探路。

在代码之外,我热爱跑步与骑行,相机和无人机则是出门必备。对我而言,摄影的乐趣远不止于最后那张照片,更在于切换视角时的构图巧思、尝试不同的叙事风格,以及在既有基础上推陈出新的创作过程。

在兴趣爱好方面,我以前有小号六级证书,但很明显现在不会吹了()。初中时自学的钢琴,现在也能弹几首曲子。此外,我还喜欢模拟飞行和玩魔方:最喜欢的是四阶,其次是五魔方。音乐也是我人生中不可割舍的一部分。无论是在通勤路上,还是在编写代码、调试网页与硬件的专注时刻,音乐不仅是滤除杂音的背景,更是与我灵感同频的共振。我还是F1的铁杆观众,梅赛德斯奔驰AMG是我的主队,最喜欢的车手是刘易斯·汉密尔顿。虽然我依旧钟情于保时捷911与AMG这种纯粹的性能机器,但也时刻关注着国产新能源的前沿发展。

-

我是一个重度的机圈与数码发烧友,周围很多同学朋友在换新设备的时候时常会找我导购。我日常反复横跳在苹果的硬核科技与华为的创新美学之间,只要有发布会,直播间里肯定少不了我,安卓阵营中最喜欢的则则是vivo。电脑方面,我是ARM架构与Apple Silicon的忠实拥护者。虽然目前仍有诸多不便,但MacBook的超高续航比与轻便体验,精准切中了我对代码编写与影像创作的核心生产力要求。至于摄影,我喜欢哈苏、索尼与大疆,它们是我记录世界时不可或缺的延伸。

-

游戏方面,我是Minecraft的老玩家,也算一名“原学家”(大概)。近期正在玩明日方舟和明日方舟:终末地;同时也活跃于Arcaea、Phigros等音游,有时候还打打milthm、舞萌、lanota、rizline。在第五人格中,我曾在36赛季打到巅峰七阶31星,拿到了三个疯眼A牌(最高A47)和若干B牌(虽然目前已退游)。皇室战争里我爱玩石头人体系,主力卡组是自己配的克隆石卡组。

+

我是一个重度的机圈与数码发烧友,周围很多同学朋友在换新设备的时候时常会找我导购。我日常反复横跳在苹果的硬核科技与华为的创新美学之间,只要有发布会,直播间里肯定少不了我,安卓阵营中最喜欢的则是vivo。电脑方面,我是ARM架构与Apple Silicon的忠实拥护者。虽然目前仍有诸多不便,但MacBook的超高续航比与轻便体验,精准切中了我对代码编写与影像创作的核心生产力要求。至于摄影,我喜欢哈苏、索尼与大疆,它们是我记录世界时不可或缺的延伸。

+

游戏方面,我是Minecraft的老玩家,也算一名“原学家”(大概)。近期正在玩明日方舟和异环;同时也活跃于Arcaea、Phigros等音游,有时候还打打milthm、舞萌、lanota、rizline。在第五人格中,我曾在36赛季打到巅峰七阶31星,拿到了三个疯眼A牌(最高A47)和若干B牌(虽然目前已退游)。皇室战争里我爱玩石头人体系,主力卡组是自己配的克隆石卡组。

身为理科生,我却对世界文化怀有极强的好奇心,也很乐意了解各个国家的风土人情。中小学时期的英语演讲比赛与两年英国议会制辩论(BP)的经历,为我打下了坚实的语言基础。最近我也在学习法语。从Cécile Corbel的空灵吟唱,到枫丹水国的浪漫景致;从《清涟》的悠扬旋律,到《罗密欧与朱丽叶》的经典对白——法语的魅力正不断驱使着我,向这门语言的更深处漫溯。

无论是在 0 与 1 的代码世界里构建秩序,还是在双螺旋的生物蓝图中寻找规律,我始终相信,跨界的探索能让生命拥有更宽广的边界。如果你也对技术、生物或这个多元的世界充满好奇,欢迎随时与我交流。

很高兴认识你,在这段名为“成长”的航程中。

-

——Ray
2026.4.10

+

——Ray
2026.5.19

@@ -234,7 +263,7 @@

关于我

游戏
-

Minecraft · 第五人格 · 原神 · 明日方舟 · 明日方舟:终末地 · 皇室战争 · 多端音游(Arcaea, Phigros为主)

+

Minecraft · 第五人格 · 原神 · 明日方舟 · 异环 · 皇室战争 · 多端音游(Arcaea, Phigros为主)

@@ -255,12 +284,12 @@

我的项目

主要项目

我主导或参与的项目,涵盖科研实验、开发与开源贡献等。

-
- +
+
-

华为应用市场看板

-

Powered by Shenjack!
一个获取、处理、分析并展示鸿蒙应用市场所有应用与元服务数据的全栈项目。
我主要在做这个项目的前端网页开发与软件开发。当前主线,持续更新中……

+

华为应用市场看板

+

Powered by Shenjack!
一个获取、处理、分析并展示鸿蒙应用市场所有应用与元服务数据的全栈项目。
当前主线,持续更新中……

开放原子大赛获奖作品
@@ -286,6 +315,45 @@

生物学项目

+ +
+
+

微弱电信号测量

+

物理竞赛课题,本项目设计了一个基于Arduino嵌入式开发的测量微弱电信号的系统。系统利用悬丝结构与光杠杆原理实现物理放大,并结合信号调理电路与嵌入式处理完成数据采集与计算。通过归一化算法和多级降噪方法,提高了测量稳定性与抗干扰能力。

+
+ Arduino嵌入式 + 通信工程 + 物理竞赛 +
+
+
+ + +
+
+

智慧大棚 SmartShed

+

基于OpenHarmony Hi3861与HarmonyOS 6.1.0的端云协同智慧大棚物联网控制系统。
涵盖嵌入式采集、MQTT 通信、鸿蒙全功能控制终端。

+
+ 开源鸿蒙 + HarmonyOS + 开源项目 +
+
+
+ + +
+
+

石头剪刀布检测

+

基于YOLO11n的实时手势识别项目,验证集mAP50 = 0.940。
同时包含加州房价随机森林回归预测、学生数字行为分析等机器学习案例。

+
+ 机器学习 + 目标检测 + 开源项目 +
+
+
+
@@ -299,19 +367,6 @@

Sweet Potato Mod

- -
-
-

OpenHarmony Hi3861

-

基于OpenHarmony Hi3861开发板的嵌入式开发实践。
除了小时候玩的Arduino之外的第一个正经嵌入式开发项目,正在探索中……

-
- OpenHarmony - 嵌入式开发 - 智慧生活 -
-
-
-
@@ -325,19 +380,6 @@

Difficult Rocket(协作开发) -
-
-

微弱电信号测量

-

物理竞赛课题。本实验通过跨阻放大电路将传感器感应到的纳安级微弱光电流线性转换为电压信号,并利用金属法拉第笼屏蔽与终端数字平均滤波双重抑噪技术 ,由Arduino配合16位ADC实现高信噪比的实时数据采集与物理量量化。

-
- Arduino嵌入式 - 通信工程 - 物理竞赛 -
-
-

-
@@ -347,6 +389,12 @@

其他项目

随手写的或者各种帮同学朋友写的好玩东西()

+ +
+

OpenHarmony Hi3861

+

基于Hi3861的嵌入式开发实践,除了Arduino之外的第一个正经嵌入式项目。

+
+

《寿怡红群芳开夜宴》

@@ -494,40 +542,18 @@

摄影与生活

-
- -
-
-

钢琴

-

音乐是时间的艺术。初中自学,记录指尖流淌的旋律。

-
- 钢琴 - 音乐 -
-
-
- - -
-
-

绘画作品

-

用画笔记录灵感与想象。原神同人、角色创作等。

-
- 绘画 - 原神 -
+
+ +
+
+

钢琴

- -
-
@@ -685,7 +711,7 @@

快捷消息

- + diff --git a/life/books.html b/life/books.html index e50e122..02cf96c 100644 --- a/life/books.html +++ b/life/books.html @@ -4,6 +4,33 @@ 书单 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/life/drawing.html b/life/drawing.html deleted file mode 100644 index 4633be0..0000000 --- a/life/drawing.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - 绘画作品 | Ray Chen - - - - - - - - - - - -
-
-
-

绘画作品

-

用画笔记录灵感与想象

-
- - -
- - - - - - diff --git a/life/piano.html b/life/piano.html index 41bd7dc..711b5bd 100644 --- a/life/piano.html +++ b/life/piano.html @@ -4,6 +4,33 @@ 钢琴 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/.DS_Store b/projects/.DS_Store index 0bf4197..7f5d923 100644 Binary files a/projects/.DS_Store and b/projects/.DS_Store differ diff --git a/projects/Hi3861-readme.html b/projects/Hi3861-readme.html index 7e38c49..f773f1e 100644 --- a/projects/Hi3861-readme.html +++ b/projects/Hi3861-readme.html @@ -3,7 +3,34 @@ - Hi3861 | Ray Chen + Hi3861 README | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/Hi3861.html b/projects/Hi3861.html index 0b232cb..65b7ab9 100644 --- a/projects/Hi3861.html +++ b/projects/Hi3861.html @@ -4,6 +4,33 @@ Hi3861 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/RockPaperSissors.html b/projects/RockPaperSissors.html new file mode 100644 index 0000000..2a29df1 --- /dev/null +++ b/projects/RockPaperSissors.html @@ -0,0 +1,408 @@ + + + + + + 石头剪刀布检测 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ Python · Machine Learning · Deep Learning +

石头剪刀布检测

+

2026 暑期 Python 课程项目合集,覆盖 Python 基础语法、机器学习回归预测、学生行为数据分析,以及基于 YOLO11n 的石头剪刀布手势识别。

+ +
+ +
+ Rock Paper Scissors Detection Demo +
+ +
+
+ Project 1 +

Python 基础练习

+

14 个入门练习:数据类型、流程控制、函数、列表与字典等基础语法全覆盖。

+
+
+ Project 2-1 +

加州房价预测

+

随机森林回归预测加州房价中位数,R² = 0.805。验证收入与地理位置是核心影响因素。

+
+
+ Project 2-2 +

学生行为分析

+

Kaggle 真实数据集,分析学习时间、屏幕时间等对 CGPA 的影响,多模型对比。

+
+
+ Project 3 +

YOLO11n 手势识别

+

🪨📄✂️ 实时检测剪刀/石头/布,验证集 mAP50 = 0.940,毫秒级推理。

+
+
+
+ + +
+
+ Project 1 +
+

Python 程序设计基础

+

入门级 Python 编程练习,零第三方依赖

+
+
+
+
+

数据类型

+
    +
  1. 1.1.py — 正整数平方
  2. +
  3. 1.2.py — 格式化输出录取信息
  4. +
  5. 1.3.py — 直角三角形斜边长
  6. +
+
+
+

运算符 & 表达式

+
    +
  1. 2.1.py — 两点间欧几里得距离
  2. +
  3. 2.2.py — 三位数各位立方和
  4. +
  5. 2.3.py — 字母出现次数(不区分大小写)
  6. +
+
+
+

流程控制 & 函数

+
    +
  1. 3.1-3.2 — 成绩等级 / 字符类型
  2. +
  3. 4.1-4.2 — 位数判断 / 阶乘求和
  4. +
  5. 5.1-5.2 — 函数封装与数学计算
  6. +
  7. 6.1-6.2 — 列表推导式 / 字典映射
  8. +
+
+
+
+ + +
+
+ Project 2-1 +
+

加州房价预测 — 随机森林回归

+

scikit-learn · California Housing Dataset

+
+
+ +
+
+

数据集

+

California Housing — scikit-learn 内置数据集

+
    +
  • 样本量:20,640 条街区数据
  • +
  • 特征数:8 个(收入中位数、房龄、房间数、人口、地理位置等)
  • +
  • 目标:MedHouseVal(房价中位数,$100K)
  • +
+
+
+

模型评估

+
+ MSE + 0.2552 +
+
+ RMSE + 0.5052 +
+
+ + 0.8053 +
+
+
+ +
+

特征重要性 Top 4

+

MedInc(收入中位数) > AveOccup(平均居住人数) > Latitude / Longitude(地理位置) > HouseAge

+

收入水平是房价的最强预测因子,地理位置的重要性反映了加州不同区域的房价差异。

+
+ +
+ Python + scikit-learn + Random Forest + Pandas + Matplotlib +
+
+ + +
+
+ Project 2-2 +
+

学生数字行为与学习表现分析

+

Kaggle 真实数据集 · 线性回归 vs 随机森林

+
+
+ +
+
+

数据集

+

Student Lifestyle and Academic Performance(Kaggle)

+
    +
  • 12 个字段:Age, Branch, Study_Hours, Sleep_Hours, Screen_Time, Gym, Diet, Attendance, Stress, Residence, Internal_Marks, CGPA
  • +
  • 目标变量:CGPA(绩点,0~10)
  • +
  • 排除 Internal_Marks 避免数据泄漏
  • +
+
+
+

数据清洗流程

+
    +
  • 字段筛选 → 去重
  • +
  • 数值字段:中位数填充缺失值
  • +
  • 分类字段:众数填充
  • +
  • 异常值过滤(年龄、学习时间等合理范围)
  • +
  • 分类变量:独热编码(drop_first)
  • +
+
+
+ +
+
+

可视化分析(6 张图表)

+
+
+
+
+

屏幕时间分布

+

右偏态分布,大部分学生每日屏幕时间 3~8 小时

+
+
+

学习时间 vs CGPA

+

清晰的正相关,学习 6~8h/天的学生 CGPA 普遍更高

+
+
+

特征重要性 Top 3

+

学习时间 > 出勤率 > 屏幕时间

+
+
+ +
+ Python + Linear Regression + Random Forest + Pandas + Seaborn + EDA +
+
+ + +
+
+ Project 3 +
+

石头剪刀布手势识别 — YOLO11n

+

🪨📄✂️ Ultralytics · PyTorch · 目标检测

+
+
+ +
+
+

数据集

+

rock-paper-scissors-sxsw(Roboflow v11)

+
    +
  • 总计 15,874 张图片
  • +
  • 训练集 14,966 / 验证集 588 / 测试集 320
  • +
  • 3 个类别:Paper(布)、Rock(石头)、Scissors(剪刀)
  • +
  • 输入尺寸:640×640
  • +
+
+
+

数据增强

+

每张原图生成 7 个增强版本:

+
    +
  • 水平翻转(50%)、随机旋转 ±12°
  • +
  • 剪切 ±2°、亮度/曝光 ±25%
  • +
  • 高斯模糊 0~1.5px、椒盐噪声 1%
  • +
+
+
+ +
+

训练配置

+
+
+
模型YOLO11n (2.58M params)
+
Epochs50
+
Batch16
+
+
+
优化器AdamW
+
训练耗时~3.07h
+
GPURTX 5060 (8GB)
+
+
+
+ + +
+
+

评估结果

+
+
+
+
+

验证集

+
+ mAP50(全部) + 0.940 +
+
+ mAP50-95 + 0.697 +
+
+ 精确率 (P) + 0.942 +
+
+ 召回率 (R) + 0.891 +
+
+ 推理速度 + < 2.1ms +
+
+
+

测试集

+
+ mAP50(全部) + 0.934 +
+
+ mAP50-95 + 0.693 +
+
+ 精确率 (P) + 0.898 +
+
+ 召回率 (R) + 0.920 +
+
+
+ + +
+

各类别性能

+
+
+

📄 Paper

+
验证 mAP500.936
+
测试 mAP500.904
+
+
+

🪨 Rock

+
验证 mAP500.943
+
测试 mAP500.951
+
+
+

✂️ Scissors

+
验证 mAP500.940
+
测试 mAP500.947
+
+
+
+ + +
+
+

应用模式

+
+
+
+
+

单张图片推理

+

对任意手势照片进行识别,识别结果以边界框 + 标签形式标注,保存到输出目录。

+
+ predict.py +
+
+
+

实时摄像头检测

+

调用系统摄像头(1280×720)实时捕获,每帧推理毫秒级,窗口显示 FPS 帧率,按 Q 键退出。

+
+ detect.py +
+
+
+

评估脚本

+

验证集评估、测试集评估、数据集下载工具,完整覆盖训练到部署全流程。

+
+ evaluate.py / test.py +
+
+
+ +
+ Python + PyTorch + YOLO11n + Ultralytics + OpenCV + Roboflow + CUDA +
+
+ + + + + + + + diff --git a/projects/SmartShed.html b/projects/SmartShed.html new file mode 100644 index 0000000..24a099c --- /dev/null +++ b/projects/SmartShed.html @@ -0,0 +1,855 @@ + + + + + + 智慧大棚 SmartShed | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ 2025-2026学年第二学期课设报告 +

开源鸿蒙赋能智慧农业
—— 基于Hi3861与HarmonyOS的智慧大棚控制终端

+

从传感器采集到手机端实时控制,一套完整的智慧农业物联网系统。
两块开发板各司其职,MQTT 消息中转,HarmonyOS 全功能终端。

+ +
+ + +
+
+

项目总体介绍

+

2025-2026 学年第二学期课程设计报告,汇报人:陈梓睿(Ray Chen)

+
+
+

什么是 Smart Shed?

+

+ Smart Shed(智慧大棚)是一套基于开源鸿蒙 OpenHarmony华为鸿蒙 HarmonyOS NEXT的智慧农业物联网控制系统。 + 简单来说就是:两块开发板负责感知和控制环境参数,通过 MQTT 协议跟手机 App 实时通信, + 最终实现温室里温度、湿度、光照、土壤水分的自动监测与智能调控。 +

+
+
+ + 嵌入式端 +

OpenHarmony + Hi3861 × 2
传感器采集 & 执行器控制

+
+
+ + 服务端 +

EMQX MQTT Broker
消息中转 & Topic 路由分发

+
+
+ + 应用端 +

HarmonyOS NEXT (API23)
Mate 70 Pro+ / MatePad Pro

+
+
+
+
+ + + + +
+
+
+

01 · 项目总览与技术栈

+

整体架构、踩过的坑、做了哪些创新

+
+
+ + +
+
+

系统架构:软硬协同、垂直整合

+

嵌入式端采集数据 → 服务端中转消息 → 手机端显示与控制

+
+
+
+

嵌入式端

+

OpenHarmony 1.0 Release
+ Rayawa/rgb @ HiSilicon-Hi3861
+ Rayawa/soi @ HiSilicon-Hi3861
+ 传感器采集 + OLED 显示
PWM/GPIO 执行控制

+
+
+
+

服务端

+

MQTT 5.0 WebSocket
+ wss://broker.emqx.io:8084
+ @MQTTX
+ 公网消息中转
Topic 路由分发

+
+
+
+

应用端

+

HarmonyOS 6.1.0 (API23)
+ Smart Shed @ Mate 70 Pro+
+ Smart Shed @ MatePad Pro 12.2
+ 实时数据显示
手动 / 智能双模式

+
+
+
+ + +
+
+

技术难点

+

开发过程中实际遇到的问题

+
+
+
+

嵌入式端

+
    +
  • 驱动接口版本兼容问题多
  • +
  • I2C 总线多设备并发访问会冲突
  • +
  • LiteOS-M 线程栈空间和优先级需要反复调
  • +
+
+
+

应用端

+
    +
  • 原文档基于 API7 的 JavaUI,太老了
  • +
  • 原代码只能在特定平板上跑,换设备界面就乱
  • +
  • 原来一个扩展板只能跑一个元件却设计了四套体系,重构量很大
  • +
+
+
+

通信层

+
    +
  • MQTT 传输不太稳定,报错信息也不明显
  • +
  • Hi3861 WiFi 模块老化了,负载能力差
  • +
  • 应用侧收发机制写得简陋,几乎没有错误处理,调试全靠猜
  • +
+
+
+
+ + +
+
+

创新点

+
+
+
+

双板分离架构

+

环境感知板(RGB)和土壤执行板(SOI)物理隔离、逻辑解耦,各管各的又互相配合。

+
+
+

零依赖 MQTT 客户端

+

HarmonyOS 端完全从 TCP Socket 开始手搓 MQTT 报文,不依赖任何第三方库。

+
+
+

HDS 高级视觉体系

+

集成鸿蒙官方 Design System 组件库:沉浸式导航、引力动效、光场背景。

+
+
+

手动 / 智能双模式

+

手动模式自由调档位;智能模式根据阈值自动决策,后台线程安全常驻运行。

+
+
+

Glass 形态适配

+

额外做了手表端的 Glass 应用形态,沉浸式材质加气态动效。

+
+
+

可靠性保障

+

离线自动检测(5s 超时)、断线指数退避重连、GlobalLogBus 日志总线全方位兜底。

+
+
+
+ + +
+
+

技术栈

+
+
+
+

嵌入式 (Hi3861)

+
+ Hi3861 + HiSilicon + OpenHarmony 1.0 + LiteOS-M + CMSIS-RTOS + C + GPIO + PWM + I2C + ADC + AHT20 + SSD1306 + Paho MQTT + lwIP + Wi-Fi STA +
+
+
+

服务端 (通信)

+
+ MQTT 5.0 + WebSocket Secure + EMQX Broker + TCP Socket + JSON + Pub/Sub + Topic 路由 +
+
+
+

应用端 (HarmonyOS)

+
+ HarmonyOS 6.1.0 + API23 + ArkTS + ArkUI + Stage 模型 + @StorageLink + @ObjectLink + HDS + UIDesignKit + Glass 形态 +
+
+
+
+
+ + + + +
+
+
+

02 · MQTT 服务端

+

发布/订阅架构原理与数据流设计

+
+
+ + +
+
+

发布/订阅(Pub/Sub)架构

+

MQTT 是一种轻量级的消息协议,专门为物联网低带宽场景设计的

+
+
+

三方协作机制

+
+
+ Publisher 发布者 +

+ 嵌入式端 Hi3861 作为发布者,把传感器数据打包成 JSON 发到指定 Topic。 +

+
+
+ Broker 中转站 +

+ EMQX 充当 MQTT Broker,接收消息后按 Topic 规则转发给对应的订阅者。 +

+
+
+ Subscriber 订阅者 +

+ HarmonyOS App 订阅相关 Topic 后就能收到传感器数据,同时也能下发控制指令。 +

+
+
+
+
+ + +
+
+

数据流设计

+

数据怎么从硬件一路跑到手机上,以及操作怎么传回硬件执行

+
+
+ +
+

上行:传感器数据 → 手机显示

+
+
+
+
+

① 传感器采样

+

扩展板上的传感器采集原始数据 → ADC 读光照/土壤湿度,I2C 读 AHT20 温湿度

+
+
+
+
+
+

② 打包发送

+

Hi3861 把数据转成 JSON 格式,通过 MQTT PUBLISH 报文发给 EMQX Broker

+
+
+
+
+
+

③ 路由分发

+

EMQX 收到消息后按 Topic 规则分发给已订阅的客户端

+
+
+
+
+
+

④ 刷新界面

+

HarmonyOS 接收并解析消息 → @StorageLink 更新状态 → UI 数字刷新 / 智能模式判断阈值

+
+
+
+
+ +
+

下行:用户操作 → 硬件执行

+
+
+
+
+

① 用户操作或自动触发

+

手动模式拖滑块调档位,或者智能模式下阈值越界自动生成控制指令

+
+
+
+
+
+

② 打包下发

+

HarmonyOS 把控制指令转成 MQTT 报文,经 EMQX 分发出去

+
+
+
+
+
+

③ 硬件执行

+

Hi3861 收到消息后解析主题和内容 → 控制 GPIO/PWM 输出 → 风扇/水泵/补光灯动作

+
+
+
+
+
+
+
+ + + + +
+
+
+

03 · Hi3861 嵌入式端

+

OpenHarmony LiteOS-M + CMSIS-RTOS 多线程,纯 C 语言开发

+
+
+ + +
+
+

两块开发板各司其职

+
+
+
+

RGB 板(环境感知)

+

负责"看环境"和"本地显示"

+
+ 传感器 +
    +
  • AHT20 温湿度传感器 — I2C 读取温度与湿度
  • +
  • 光敏电阻 — ADC 读取光照强度 (0~4095)
  • +
+
+
+ 执行器 +
    +
  • RGB 三色灯 — GPIO10/11/12 => PWM1/2/3 控制亮度
  • +
+
+
+ 本地显示 +

SSD1306 OLED (128×64) 实时刷新温湿度和光照数据

+
+
+
+

SOI 板(土壤执行)

+

负责"测土壤"和"干活"

+
+ 传感器 +
    +
  • 土壤湿度传感器(替换安装)— ADC 读取土壤水分
  • +
+
+
+ 执行器 +
    +
  • OLED 显示屏 — 本地状态打印
  • +
  • 风扇 — PWM 控制转速
  • +
  • 水泵 — GPIO 控制开关
  • +
+
+
+
+
+ + +
+
+

项目结构

+

大分功能、小分模块,清晰好维护

+
+
+
+

common/ 公共层

+

Wi-Fi 连接、MQTT 通信、OLED 驱动都放这里。I2C 互斥锁也在这里管理,防止多线程抢总线。

+
+
+

modules/ 业务层

+

分两个子目录:

+
    +
  • sensors/ — AHT20、光强、土壤湿度传感器的头文件和程序
  • +
  • actuators/ — 风扇、补光灯、水泵的控制程序
  • +
+
+
+

boards/ 构建层

+

两个开发板的 .gn 构建文件统一管理。条件编译按板卡动态启用模块,加新板子只需加个 gn 文件

+
+
+
+ + +
+
+

多线程架构

+

CMSIS-RTOS 管理 LiteOS-M 实时内核下的并行任务

+
+
+

主线程入口

+
    +
  • 系统启动后由 SYS_RUN 创建主线程 smart_shed_all.c,栈大小 8KB
  • +
  • 主线程依次初始化并拉起所有子线程:传感器采集、执行器控制、MQTT 通信、OLED 显示
  • +
  • 条件编译按板卡配置动态启用对应模块,统一的调度入口
  • +
+
+
+

六个子线程并行工作

+

每个功能模块独立运行在 LiteOS 内核中,各自有栈空间(4KB~8KB)和优先级,互不阻塞:

+
+
+ + 空气温湿度采集 +

AHT20 / I2C

+
+
+ + 光照检测 +

ADC 采样

+
+
+ + 土壤湿度读取 +

ADC 采样

+
+
+ + 风扇/LED/水泵 +

GPIO/PWM 控制

+
+
+ + OLED 显示刷新 +

SSD1306 渲染

+
+
+ + MQTT 网络通信 +

Paho 发布/订阅

+
+
+
+
+

I2C 互斥锁:解决总线冲突

+

AHT20 温湿度传感器和 OLED 显示屏共用 I2C0 总线(GPIO13 & GPIO14),两个线程同时访问就会出问题。解决办法:

+
+
+ 冲突场景 +

温湿度采集线程和 OLED 刷新线程同时读写 I2C0,导致数据错乱

+
+
+ 解决方案 +

i2c0_lock/unlock 互斥锁,每次读写前后加锁解锁,保证同一时刻只有一个设备占用总线

+
+
+
+
+ + +
+
+

硬件连接映射

+
+
+
+

SOI 板(土壤执行)

+
+
+ OLED + 状态打印 + I2C0-0x78 GPIO13&14 + oled_ssd1306.c +
+
+ 土壤湿度 + 外接探头 + ADC_CH4 + soil_moisture_task.c +
+
+ 水泵 + 外接水泵 + P06 + water_pump_task.c +
+
+ 风扇 + 外接风扇 + P08 + fan_task.c +
+
+
+
+

RGB 板(环境感知)

+
+
+ OLED + 状态打印 + I2C0-0x78 GPIO13&14 + oled_ssd1306.c +
+
+ 温湿度传感器 + 检测空气参数 + I2C0-0x44 + temp_and_hum_task.c +
+
+ 光敏电阻 + 检测光照强度 + ADC_CH4 + light_intensity_task.c +
+
+ 三色灯 RGB + 大棚光照控制 + GPIO10/11/12=>PWM1/2/3 + led_task.c +
+
+
+
+
+ + +
+
+

网络与通信

+

Wi-Fi 连上 → TCP 通了 → MQTT 收发 → 执行器动起来

+
+
+

通信流程

+
+
+
+
+

连 Wi-Fi

+

连接 SSID "Rayawa",DHCP 拿到 IP 后进入 lwIP TCP 通信

+
+
+
+
+
+

MQTT 编解码

+

Paho 库只管报文的编解码,TCP Socket 的完整生命周期得自己管理

+
+
+
+
+
+

上报传感器数据

+

传感器数据以 JSON 格式上报到 EMQX Broker

+
+
+
+
+
+

执行控制指令

+

收到 PUBLISH 报文后用 MQTTDeserialize_publish() 解析主题和负载,再通过 mqtt_apply_command() 设置全局变量。执行器线程持续读这些变量来控制 GPIO/PWM,驱动风扇、水泵等设备工作

+
+
+
+
+
+
+ + + + +
+
+
+

04 · HarmonyOS 应用端

+

ArkTS · Stage 模型 · HDS 高级视觉 · 自实现 MQTT 客户端

+
+
+ + +
+
+

Smart Shed App

+

跑在 Mate 70 Pro+ 和 MatePad Pro 上的全功能控制终端

+
+
+

功能一览

+
+
+ 手动模式 +

+ 拖滑块调风扇(0-3档)、水泵(0-3档)、补光灯(0-100%)。进页面自动同步当前档位到开发板,支持触觉反馈。 +

+
+
+ 智能模式 +

+ 设定温度/湿度/光照/土壤湿度的上下限阈值。定时轮询传感器数据,超范围就自动触发控制。后台常驻线程,退出页面安全销毁防泄漏。 +

+
+
+ 实时监控 +

+ MQTT 回调收传感器数据,@StorageLink 状态管理驱动 ArkUI 自动刷新数字显示。 +

+
+
+ 调试面板 +

+ GlobalLogBus 事件总线记录通信状态、用户操作和错误信息,方便排查问题。 +

+
+
+
+
+ + +
+
+

App 项目结构(Stage 模型)

+

基于 ArkTS 的分层架构

+
+
+
+

AppScope/

+

应用级全局资源和 Hvigor 构建脚本的统一管理入口。

+
+
+

view/ & pages/

+

ArkTS 构建的 UI 层,包含手动/智能双模式和调试面板的完整界面。

+
+
+

service/

+

封装 MQTT 客户端(MqttReceiverClient.ts),TCP Socket 直连实现双向通信,零第三方依赖。

+
+
+

viewmodel/

+

核心数据结构和状态模型,确保 UI 与数据的响应式绑定。

+
+
+
+ + +
+
+

MqttReceiverClient.ts — 从零手写 MQTT 客户端

+
+
+

为什么自己写?

+

+ HarmonyOS 端没用任何第三方 MQTT 库,完全从 TCP Socket 开始手搓报文。这样对整个通信过程有完整的掌控力,出问题了也好排查。 +

+
+
+
+

协议层

+
    +
  • 手动拼接 Fixed Header + Variable Header + Payload
  • +
  • 实现了 CONNECT / PUBLISH / SUBSCRIBE / PINGREQ 等核心报文
  • +
  • 60s KeepAlive 心跳保活
  • +
  • MQTT 5.0 over WSS 直连 EMQX 公网 Broker
  • +
+
+
+

可靠性保障

+
    +
  • 断线自动重连 + 指数退避
  • +
  • 单 TCP 连接多 Topic 订阅与路由分发
  • +
  • @StorageLink 状态管理与 ArkUI 解耦
  • +
  • GlobalLogBus 日志总线记录完整通信轨迹
  • +
+
+
+
+

状态与方法

+
+
+ 控制状态 +

集中管理风扇档位、水泵档位、补光灯亮度,@StorageLink 跨页面共享状态。

+
+
+ 参数传递 +

传感器数据和控制指令通过统一格式在 MQTT 层可靠传输。

+
+
+ 日志同步 +

GlobalLogBus 统一收集通信状态、操作记录和异常信息。

+
+
+ 生命周期 +

进页面建连接、退页面销毁线程释放资源,杜绝内存泄漏。

+
+
+
+
+ + +
+
+

UI 设计:HDS + ArkUI

+

不只是能用,还要好看

+
+
+

HDS 核心组件

+
+
+ HdsNav 导航栏 +

沉浸式光场顶部导航,毛玻璃模糊效果

+
+
+ PressShadow 引力动效 +

按钮按压弹性形变 + 光场扩散反馈

+
+
+ SpringMotion 弹簧动画 +

分步延迟进入,弹簧曲线入场体验流畅

+
+
+
+
+

视觉风格

+
+
+ 深色光场 +

流光背景贯穿全界面,深色模式下氛围感拉满

+
+
+ 双栏布局 +

平板自适应双栏,信息密度和视觉平衡兼顾

+
+
+
+
+
+

动效:引力场

+

页面切换时的引力场效果,元素间自然的吸引排斥动画。

+
+
+

动效:光场

+

流光背景+双栏深色全局光场,动态光影随交互流动变化。

+
+
+

动效:转场

+

淡入淡出+弹性动画,SpringMotion 弹簧曲线丝滑过渡。

+
+
+
+

响应式布局

+

ArkUI 响应式栅格系统,自动适配手机和平板两种设备形态:

+
+
+ 手机端 +

单栏纵向滚动,卡片堆叠展示

+
+
+ 平板端 +

双栏并列,充分利用宽屏空间

+
+
+
+
+ + +
+
+

Smart Shed Glass

+

智能手表形态 —— 沉浸式材质 + 气态动效

+
+
+
+

Glass 形态特性

+
    +
  • 沉浸式材质 — 界面融入表盘玻璃质感
  • +
  • 气态动效 — 轻盈飘逸的过渡动画
  • +
  • 引力转场 — 保持和主 App 一致的交互语言
  • +
  • 双边缘流光 — 表盘两侧动态装饰
  • +
+
+
+

HdsButtons 自定义组件

+

基于 HDS 规范自定义的按钮组件体系,统一 Glass 形态下所有交互元素的视觉表现和触摸反馈。支持多种尺寸和状态样式(默认/按压/禁用),小屏幕上也好用。

+
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/projects/bio.html b/projects/bio.html deleted file mode 100644 index 84d3587..0000000 --- a/projects/bio.html +++ /dev/null @@ -1,149 +0,0 @@ - - - - - - 生物学项目 | Ray Chen - - - - - - - - - - -
-
-
-

生物学项目

-

收录我生物学方向论文与实验记录,包括PCR项目、蛋白质猜想、碳同化综述、橙色平板实验,以及农杆菌转化法的网页化展示。

-
- -
-
-

PCR实验项目

-

在高中首届开创PCR实验,将高等生物实验带入高中生物课堂。 -通过预实验与模板量实验探索最适合课堂实验的试剂剂量。

-
-
-
-
-
- PCR凝胶电泳结果 -
-
凝胶电泳结果显示清晰条带,目的基因扩增成功。 -与标准样对比长度约600bp,符合实验预期
-
-
-
-
-
- -
-
-

实验设计方案

-

详细的PCR实验设计,包括引物设计、温度循环参数和反应体系优化。在高中生物课堂可以落地,供以后的实验参考。

- -
-
-
-
- -
-
-

最终实验报告

-

完整的实验记录、数据分析和结论,验证了实验设计的有效性。

- -
-
-
-
-
- -
-
-

论文书架

-

研究与思考的记录,包含已成篇论文和进行中的草稿。

-
- -
-
-
- C3植物光合作用论文 -
-
-
- 草稿 - 2024.6.8 -
-

卡尔文循环的分子生物学研究

-

本文从分子结构视角深度解构了C4植物碳同化的复杂生化历程。通过将暗反应中能量转换与物质代谢过程流程化与可视化,为理解自养生物如何高效转化无机碳提供了微观层面的精确模型,展现了生物化学过程中的逻辑之美。

- -
-
-
-
- 酿酒酵母橙色平板实验论文 -
-
-
- 草稿 - 2026.03.08 -
-

酵母菌实验中平板变橙原因的分析与验证

-

针对微生物培养中偶发的培养基异常变色现象,本文通过严密的对照实验成功溯源了环境污染因子。该项研究不仅解决了具体的实验技术难题,其核心意义在于建立了标准化的误差分析与实验室质量控制流程,强调了科研实践中严谨态度与程序规范的重要性。

- -
-
-
-
- -
-
-
- 农杆菌转化示意图 -
-
-
-

交互式开发探索生物学过程

-

将复杂的基因工程流程转化为直观的网页交互,让学习变得生动有趣。农杆菌转化法网页展示了如何用代码构建生物学教学工具。

- 进入模拟网页 -
-
-
-
- - - - - - - - diff --git a/projects/biology.html b/projects/biology.html index d30bbba..770910d 100644 --- a/projects/biology.html +++ b/projects/biology.html @@ -4,6 +4,33 @@ 生物学项目 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -79,8 +106,8 @@

论文书架

已成篇 2024.6.23
-

朊病毒蛋白致病机制与遗传特性研究

-

本研究系统探讨了朊病毒蛋白(PrP^Sc)的致病机制与遗传特性,重点分析了其通过构象转化诱导正常朊病毒蛋白(PrP^C)发生错误折叠的分子机制,并讨论了朊病毒在跨物种传播中的物种屏障效应及其对公共卫生的潜在影响。

+

关于蛋白质在极特殊极特殊生物中作为遗传物质的猜想

+

本文大胆挑战生物学"中心法则"的绝对权威,基于朊病毒的自我复制特性与逆转录机制,严谨探讨了蛋白质作为原始遗传载体的可能性。该研究意在拓宽生物进化与遗传本质的思维边界,为极端环境下生命形态的研究提供了极具前瞻性的假说支撑。

@@ -97,8 +124,8 @@

朊病毒蛋白致病机制与遗传特性研究

草稿 2024.6.8
-

关于蛋白质在极特殊极特殊生物中作为遗传物质的猜想

-

本文大胆挑战生物学“中心法则”的绝对权威,基于朊病毒的自我复制特性与逆转录机制,严谨探讨了蛋白质作为原始遗传载体的可能性。该研究意在拓宽生物进化与遗传本质的思维边界,为极端环境下生命形态的研究提供了极具前瞻性的假说支撑。

+

C3植物卡尔文循环分子生物学研究

+

本文深入分析了C3植物中的卡尔文循环这一核心碳固定途径,系统研究了碳同化的分子机制,包括Rubisco等关键酶的催化特性及其调控机制,以及ATP和NADPH参与的能量转换过程。该研究旨在加深对C3植物光合效率限制的理解,并通过生化途径探索提高作物产量的潜在方向。

diff --git a/projects/gene.html b/projects/gene.html index 832da9f..62bacee 100644 --- a/projects/gene.html +++ b/projects/gene.html @@ -5,7 +5,35 @@ + 基因工程:农杆菌转化法交互实验室 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/resources/bio/agrobacterium/favicon.ico b/projects/gene.ico similarity index 100% rename from static/resources/bio/agrobacterium/favicon.ico rename to projects/gene.ico diff --git a/projects/idv.html b/projects/idv.html index d20a0f6..d20388d 100644 --- a/projects/idv.html +++ b/projects/idv.html @@ -3,10 +3,36 @@ + 第五人格,启动! | Ray Chen - + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/static/resources/idv/favicon.ico b/projects/idv.ico similarity index 100% rename from static/resources/idv/favicon.ico rename to projects/idv.ico diff --git a/projects/ncut_papers.html b/projects/ncut_papers.html index bf75826..dec307a 100644 --- a/projects/ncut_papers.html +++ b/projects/ncut_papers.html @@ -4,6 +4,33 @@ 学校论文 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/signal.html b/projects/signal.html new file mode 100644 index 0000000..9f481cf --- /dev/null +++ b/projects/signal.html @@ -0,0 +1,138 @@ + + + + + + 微弱电信号测量 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+

微弱电信号测量

+

基于 Arduino 嵌入式开发的微弱电信号测量系统设计

+
+ +
+
+

摘要

+
+
+
+

本文围绕微弱电信号测量中灵敏度低、易受干扰的问题,设计了一套基于Arduino嵌入式开发的测量系统。系统利用悬丝结构与光杠杆原理实现物理放大,并结合信号调理电路与嵌入式处理完成数据采集与计算。通过归一化算法和多级降噪方法,提高了测量稳定性与抗干扰能力。文中对系统结构、硬件实现、软件算法、标定方法及误差来源与不确定度进行了分析和评估,并通过实验方案对系统性能进行验证。同时,从成本角度对系统进行了评估,说明其具有较好的经济性。最后讨论了系统的应用场景及存在的局限。结果表明,该系统能够实现对微弱电信号的稳定测量,并具备一定实用价值。

+

关键词:Arduino;微弱电信号;跨阻放大器;PSD传感器;不确定度评估

+ +
+
+ 论文文档 +
+
+
+ +
+
+ +
+

项目文件

+

项目相关设计文档与工程资源

+
+
+ +
+
+ + + + + + + diff --git a/projects/spm.html b/projects/spm.html index 91b5688..b908361 100644 --- a/projects/spm.html +++ b/projects/spm.html @@ -4,6 +4,33 @@ Sweet Potato Mod | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/xxh.html b/projects/xxh.html index f3ee586..5cdd9a4 100644 --- a/projects/xxh.html +++ b/projects/xxh.html @@ -4,6 +4,33 @@ XXH测试 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/xxh_test.html b/projects/xxh_test.html index 90bb9ee..756d426 100644 --- a/projects/xxh_test.html +++ b/projects/xxh_test.html @@ -4,6 +4,33 @@ XXH测试 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/.DS_Store b/static/.DS_Store index a0395fb..4a38f57 100644 Binary files a/static/.DS_Store and b/static/.DS_Store differ diff --git a/static/components/navbar.html b/static/components/navbar.html deleted file mode 100644 index f3053c3..0000000 --- a/static/components/navbar.html +++ /dev/null @@ -1,36 +0,0 @@ - - \ No newline at end of file diff --git a/static/css/dashboard.css b/static/css/dashboard.css deleted file mode 100644 index be49c79..0000000 --- a/static/css/dashboard.css +++ /dev/null @@ -1,1710 +0,0 @@ -.dashboard-page { - max-width: 1180px; - padding-top: 7rem; - position: relative; -} - -/* ==================== - 第一部分:Hero 区域(标题 + 图标 + 下载) - ==================== */ -.hero-section { - margin-bottom: 2rem; -} - -.hero-header { - display: flex; - align-items: flex-start; - gap: 2rem; - margin-bottom: 0.9rem; -} - -.app-icon-wrapper { - flex-shrink: 0; - width: 96px; - height: 96px; - border-radius: 22px; - overflow: hidden; - border: 2px solid rgba(56, 189, 248, 0.4); - box-shadow: 0 8px 32px rgba(2, 6, 23, 0.4), 0 0 24px rgba(56, 189, 248, 0.15); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - background: linear-gradient(135deg, rgba(15, 23, 42, 0.8), rgba(30, 41, 59, 0.6)); -} - -.app-icon-wrapper:hover { - box-shadow: 0 12px 40px rgba(2, 6, 23, 0.5); - border-color: rgba(148, 163, 184, 0.35); -} - -.app-icon { - width: 100%; - height: 100%; - object-fit: cover; - display: block; -} - -.hero-content { - flex: 1; - min-width: 0; -} - -.hero-title { - font-size: 2rem; - font-weight: 700; - color: #f8fafc; - margin-bottom: 0.5rem; - letter-spacing: -0.02em; - text-shadow: 0 0 30px rgba(255, 255, 255, 0.12); -} - -.hero-lead { - font-size: 0.95rem; - color: rgba(203, 213, 225, 0.9); - line-height: 1.6; - margin-bottom: 0.9rem; -} - -.hero-link { - color: #7dd3fc; - text-decoration: none; - font-weight: 600; - border-bottom: 1px dashed rgba(56, 189, 248, 0.5); - transition: all 0.3s ease; -} - -.hero-link:hover { - color: #bae6fd; - border-bottom-color: rgba(148, 163, 184, 0.5); -} - -.hero-tags-wrapper { - margin-bottom: 1.5rem; -} - -.hero-tags { - display: flex; - flex-wrap: wrap; - gap: 0.6rem; -} - -.hero-tag { - font-size: 0.78rem; - padding: 0.4rem 0.9rem; - border-radius: 999px; - border: 1px solid rgba(125, 211, 252, 0.45); - color: rgba(226, 232, 240, 0.95); - background: rgba(99, 102, 241, 0.15); - backdrop-filter: blur(10px); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - font-weight: 500; - letter-spacing: 0.02em; -} - -.hero-tag:hover { - border-color: rgba(148, 163, 184, 0.35); - background: rgba(99, 102, 241, 0.25); -} - -/* 下载区域样式 */ -.download-section { - display: flex; - flex-direction: column; - align-items: center; /* 水平居中 */ -} - -.qq-support { - margin-top: 1rem; - padding: 0.9rem 1.2rem; - border-radius: 12px; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.08), rgba(2, 132, 199, 0.05)); - border: 1px solid rgba(56, 189, 248, 0.2); - text-align: center; -} - -.qq-support .support-icon { - font-size: 1.6rem; - margin-bottom: 0.4rem; - display: block; -} - -.qq-support .support-content { - display: block; -} - -.qq-support .support-link { - display: inline-flex; - align-items: center; - gap: 0.5rem; - color: #7dd3fc; - text-decoration: none; - font-size: 0.88rem; - font-weight: 600; - padding: 0.5rem 1.1rem; - border-radius: 999px; - background: rgba(56, 189, 248, 0.12); - border: 1px solid rgba(56, 189, 248, 0.3); - transition: all 0.3s ease; -} - -.qq-support .support-link:hover { - color: #bae6fd; - background: rgba(56, 189, 248, 0.2); - border-color: rgba(148, 163, 184, 0.35); -} - -.qq-container { - background: linear-gradient(135deg, rgba(56, 189, 248, 0.1), rgba(2, 132, 199, 0.08)); - border: 1px solid rgba(56, 189, 248, 0.25); -} - -.qq-support-large { - display: flex; - align-items: center; - gap: 1.5rem; - padding: 0.5rem; -} - -.qq-support-large .support-icon { - font-size: 2.8rem; - flex-shrink: 0; -} - -.qq-support-large .support-content { - flex: 1; - text-align: left; -} - -.qq-support-large .support-content h3 { - color: #f8fafc; - font-size: 1.2rem; - margin-bottom: 0.4rem; - font-weight: 700; -} - -.qq-support-large .support-content p { - color: rgba(203, 213, 225, 0.85); - font-size: 0.9rem; - margin-bottom: 0.8rem; - line-height: 1.6; -} - -.qq-support-large .support-link { - display: inline-flex; - align-items: center; - gap: 0.6rem; - color: #f0f9ff; - text-decoration: none; - font-size: 0.95rem; - font-weight: 600; - padding: 0.65rem 1.4rem; - border-radius: 999px; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.25), rgba(2, 132, 199, 0.2)); - border: 1px solid rgba(56, 189, 248, 0.5); - transition: all 0.3s ease; - box-shadow: 0 4px 16px rgba(56, 189, 248, 0.15); -} - -.qq-support-large .support-link:hover { - color: #ffffff; - background: rgba(56, 189, 248, 0.35); - border-color: rgba(148, 163, 184, 0.35); -} - -.qq-support-card { - border-radius: 18px; - border: 1px solid rgba(56, 189, 248, 0.3); - background: transparent; - padding: 1.4rem 1.5rem; - backdrop-filter: none; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - display: flex; - align-items: center; - gap: 1.1rem; -} - -.qq-support-card:hover { - border-color: rgba(148, 163, 184, 0.35); - background: transparent; -} - -.qq-support-card .support-icon { - font-size: 2.2rem; - flex-shrink: 0; -} - -.qq-support-card .support-content { - flex: 1; - text-align: left; -} - -.qq-support-card .support-content h3 { - color: #f8fafc; - font-size: 1.05rem; - margin-bottom: 0.35rem; - font-weight: 700; -} - -.qq-support-card .support-content p { - color: rgba(203, 213, 225, 0.8); - font-size: 0.82rem; - margin-bottom: 0.7rem; - line-height: 1.5; -} - -.qq-support-card .support-link { - display: inline-flex; - align-items: center; - gap: 0.5rem; - color: #f0f9ff; - text-decoration: none; - font-size: 0.88rem; - font-weight: 600; - padding: 0.55rem 1.1rem; - border-radius: 999px; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.25), rgba(2, 132, 199, 0.18)); - border: 1px solid rgba(56, 189, 248, 0.45); - transition: all 0.3s ease; - box-shadow: 0 3px 12px rgba(56, 189, 248, 0.12); -} - -.qq-support-card .support-link:hover { - color: #ffffff; - background: rgba(56, 189, 248, 0.35); - border-color: rgba(148, 163, 184, 0.35); -} - -.platform-grid { - display: grid; - grid-template-columns: repeat(6, minmax(160px, 1fr)); - justify-content: center; - gap: 0.8rem; - padding: 0 0.2rem; -} - - -.platform-btn { - border: 1px solid rgba(148, 163, 184, 0.26); - background: transparent; - border-radius: 12px; - text-decoration: none; - color: #f8fafc; - padding: 1rem 0.8rem; - min-height: 110px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 0.7rem; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - backdrop-filter: none; - position: relative; - overflow: hidden; -} - -.platform-btn::after { - content: ''; - position: absolute; - inset: 0; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.1), transparent); - opacity: 0; - transition: opacity 0.4s ease; -} - -.platform-btn:hover::after { - opacity: 1; -} - -.platform-icon-wrap { - width: 50px; - height: 50px; - border-radius: 8px; - display: inline-flex; - align-items: center; - justify-content: center; - background: transparent; - border: none; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - z-index: 1; - flex-shrink: 0; -} - -.platform-icon-img { - width: 28px; - height: 28px; - display: block; - transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.platform-btn:hover .platform-icon-wrap { - border-color: transparent; - background: transparent; - box-shadow: none; -} - -.platform-btn:hover .platform-icon-img { - transform: scale(1.12); -} - -.platform-main { - font-size: 0.9rem; - font-weight: 600; - position: relative; - z-index: 1; - text-align: center; -} - -.platform-btn:hover { - border-color: rgba(148, 163, 184, 0.35); - background: transparent; -} - -.platform-primary { - border-color: rgba(251, 146, 60, 0.35); - background: linear-gradient(150deg, rgba(234, 88, 12, 0.08), rgba(15, 23, 42, 0.12)); - box-shadow: 0 0 12px rgba(251, 146, 60, 0.08); -} - -.platform-primary::before { - content: ''; - position: absolute; - inset: 0; - background: linear-gradient(135deg, rgba(251, 146, 60, 0.03), transparent); - pointer-events: none; -} - -.platform-primary .platform-icon-wrap { - border-color: rgba(251, 146, 60, 0.35); - background: linear-gradient(135deg, rgba(124, 45, 18, 0.3), rgba(234, 88, 12, 0.05)); - box-shadow: 0 0 8px rgba(251, 146, 60, 0.1); -} - -.platform-primary:hover { - border-color: rgba(251, 146, 60, 0.5); - background: linear-gradient(135deg, rgba(234, 88, 12, 0.12), rgba(15, 23, 42, 0.3)); - box-shadow: 0 12px 32px rgba(234, 88, 12, 0.15), 0 0 20px rgba(251, 146, 60, 0.12); -} - -.platform-primary:hover .platform-icon-wrap { - border-color: rgba(251, 146, 60, 0.6); - background: linear-gradient(135deg, rgba(124, 45, 18, 0.5), rgba(234, 88, 12, 0.15)); - box-shadow: 0 0 16px rgba(251, 146, 60, 0.25); -} - -.platform-primary:hover .platform-icon-img { - transform: scale(1.12); -} - -.platform-web { - border-color: rgba(56, 189, 248, 0.35); - background: linear-gradient(150deg, rgba(2, 132, 199, 0.08), rgba(15, 23, 42, 0.12)); - box-shadow: 0 0 12px rgba(56, 189, 248, 0.08); -} - -.platform-web::before { - content: ''; - position: absolute; - inset: 0; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.03), transparent); - pointer-events: none; -} - -.platform-web .platform-icon-wrap { - border-color: rgba(56, 189, 248, 0.35); - background: linear-gradient(135deg, rgba(15, 23, 42, 0.6), rgba(2, 132, 199, 0.08)); - box-shadow: 0 0 8px rgba(56, 189, 248, 0.1); -} - -.platform-web:hover { - border-color: rgba(56, 189, 248, 0.5); - background: linear-gradient(135deg, rgba(2, 132, 199, 0.12), rgba(15, 23, 42, 0.3)); - box-shadow: 0 12px 32px rgba(2, 132, 199, 0.15), 0 0 20px rgba(56, 189, 248, 0.12); -} - -.platform-web:hover .platform-icon-wrap { - border-color: rgba(56, 189, 248, 0.6); - background: linear-gradient(135deg, rgba(15, 23, 42, 0.7), rgba(2, 132, 199, 0.2)); - box-shadow: 0 0 16px rgba(56, 189, 248, 0.25); -} - -.platform-web:hover .platform-icon-img { - transform: scale(1.12); -} - -button.platform-btn { - font: inherit; - text-align: left; -} - -.platform-disabled, -.platform-disabled:hover { - cursor: not-allowed; - border-color: rgba(148, 163, 184, 0.18); - background: rgba(15, 23, 42, 0.16); - transform: none; - opacity: 0.58; -} - -.platform-disabled .platform-icon-wrap { - border-color: rgba(148, 163, 184, 0.2); - background: rgba(15, 23, 42, 0.3); -} - -.platform-disabled.platform-android { - border-color: rgba(74, 222, 128, 0.3); - background: linear-gradient(150deg, rgba(22, 163, 74, 0.1), rgba(15, 23, 42, 0.1)); -} - -.platform-disabled.platform-android .platform-icon-wrap { - border-color: rgba(74, 222, 128, 0.35); - background: linear-gradient(135deg, rgba(20, 83, 45, 0.3), rgba(22, 163, 74, 0.05)); - box-shadow: 0 0 10px rgba(74, 222, 128, 0.1); -} - -.platform-disabled.platform-ios { - border-color: rgba(168, 85, 247, 0.3); - background: linear-gradient(150deg, rgba(168, 85, 247, 0.1), rgba(15, 23, 42, 0.1)); -} - -.platform-disabled.platform-ios .platform-icon-wrap { - border-color: rgba(168, 85, 247, 0.35); - background: linear-gradient(135deg, rgba(88, 28, 135, 0.3), rgba(168, 85, 247, 0.05)); - box-shadow: 0 0 10px rgba(168, 85, 247, 0.1); -} - -/* ==================== - 第二、三部分:内容区域通用样式 - ==================== */ -.content-section { - margin-bottom: 2rem; -} - -.section-container { - padding: 1.8rem; - border-radius: 20px; - background: linear-gradient(155deg, rgba(15, 23, 42, 0.6), rgba(30, 41, 59, 0.25)); - backdrop-filter: blur(14px); - border: 1px solid rgba(148, 163, 184, 0.2); - box-shadow: 0 12px 40px rgba(2, 6, 23, 0.35); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.section-container:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.section-header { - margin-bottom: 1.5rem; -} - -.section-header h2 { - font-size: 1.5rem; - color: #f8fafc; - margin-bottom: 0.5rem; - font-weight: 700; - letter-spacing: -0.02em; - text-shadow: 0 0 30px rgba(255, 255, 255, 0.12); -} - -.section-header p { - color: rgba(226, 232, 240, 0.85); - font-size: 0.95rem; - line-height: 1.7; - max-width: 720px; -} - -/* ==================== - 访问数据与下载整合卡片 - ==================== */ -.access-metrics-card { - padding: 0; - background: transparent; - border: none; - box-shadow: none; - backdrop-filter: none; - display: flex; - flex-direction: column; - gap: 2rem; -} - -.metrics-section { - padding-bottom: 1rem; -} - -.metrics-grid-small { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1.2rem; -} - -.metric-card-small { - border-radius: 0; - border: none; - background: transparent; - padding: 0.8rem; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - text-align: center; -} - -.metric-card-small .metric-label { - font-size: 0.85rem; - color: rgba(186, 230, 253, 0.95); - margin-bottom: 0.5rem; - font-weight: 600; - letter-spacing: 0.02em; - display: flex; - align-items: center; - justify-content: center; - gap: 0.4rem; -} - -.metric-card-small .metric-label::before { - content: ''; - font-size: 0; -} - -.metric-card-small .metric-value { - font-size: 1.8rem; - font-weight: 700; - color: #f8fafc; - font-family: 'JetBrains Mono', monospace; - text-shadow: 0 0 20px rgba(56, 189, 248, 0.3); - line-height: 1.2; -} - -.metric-card-small .metric-field { - font-size: 0.75rem; - color: rgba(148, 163, 184, 0.5); - margin-top: 0.4rem; - font-family: 'JetBrains Mono', monospace; - letter-spacing: 0.05em; -} - -/* ==================== - 数据展示区域 - ==================== */ -.metrics-grid { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1.5rem; - padding: 1rem 0; -} - -.metric-card { - border-radius: 0; - border: none; - background: transparent; - padding: 1rem; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; - text-align: center; -} - -.metric-card:hover { - transform: translateY(-4px); -} - -.metric-label { - font-size: 0.9rem; - color: rgba(186, 230, 253, 0.95); - margin-bottom: 0.6rem; - font-weight: 600; - letter-spacing: 0.02em; - display: flex; - align-items: center; - justify-content: center; - gap: 0.5rem; -} - -.metric-label::before { - content: '📊'; - font-size: 0.8rem; -} - -.metric-value { - font-family: 'JetBrains Mono', monospace; - font-size: clamp(1.8rem, 3vw, 2.5rem); - color: #f0f9ff; - letter-spacing: 0.025em; - font-weight: 700; - line-height: 1.2; - text-shadow: 0 0 35px rgba(14, 165, 233, 0.5); - margin-bottom: 0.5rem; - background: linear-gradient(90deg, #7dd3fc, #38bdf8); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.metric-field { - margin-top: 0.6rem; - font-family: 'JetBrains Mono', monospace; - font-size: 0.75rem; - color: rgba(125, 211, 252, 0.9); - opacity: 0.9; - padding: 0.3rem 0.6rem; - background: rgba(15, 23, 42, 0.4); - border-radius: 6px; - display: inline-block; - border: 1px solid rgba(125, 211, 252, 0.2); -} - -.metrics-note { - margin-top: 1rem; - margin-bottom: 0; - color: rgba(148, 163, 184, 0.9); - font-size: 0.81rem; - text-align: center; - padding: 0.4rem 0; - background: transparent; - border: none; -} - -.metrics-note i { - color: rgba(56, 189, 248, 0.8); -} - -/* ==================== - 详细信息区域 - ==================== */ -.details-grid { - display: grid; - grid-template-columns: 1.2fr 0.8fr; - gap: 1.4rem; -} - -.details-main { - display: flex; - flex-direction: column; - gap: 1.2rem; -} - -.details-sidebar { - display: flex; - flex-direction: column; - gap: 1.2rem; -} - -.info-card { - border-radius: 18px; - border: 1px solid rgba(148, 163, 184, 0.22); - background: transparent; - padding: 1.6rem 1.7rem; - backdrop-filter: none; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; -} - -.info-card:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.info-card:hover::before { - opacity: 1; -} - -.roadmap-card::before { - background: linear-gradient(90deg, rgba(168, 85, 247, 0.2), rgba(168, 85, 247, 0.8), rgba(168, 85, 247, 0.2)); -} - -.roadmap-card:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.card-header { - display: flex; - align-items: center; - gap: 0.9rem; - margin-bottom: 1.1rem; -} - -.card-number { - font-size: 1.4rem; - font-weight: 700; - color: rgba(56, 189, 248, 0.8); - font-family: 'JetBrains Mono', monospace; - letter-spacing: 0.05em; -} - -.roadmap-card .card-number { - color: rgba(168, 85, 247, 0.8); -} - -.card-header h3 { - color: #f8fafc; - font-size: 1.15rem; - font-weight: 600; - margin: 0; -} - -.card-body { - color: rgba(203, 213, 225, 0.9); -} - -.card-body p { - color: rgba(203, 213, 225, 0.9); - line-height: 1.75; - font-size: 0.88rem; - margin-bottom: 0.85rem; -} - -.card-body p:last-child { - margin-bottom: 0; -} - -.card-body .detail-list { - margin: 0; - padding-left: 1.1rem; - color: rgba(203, 213, 225, 0.92); -} - -.card-body .detail-list li { - margin-bottom: 0.55rem; - line-height: 1.68; - font-size: 0.86rem; - position: relative; -} - -.card-body .detail-list li::marker { - color: rgba(56, 189, 248, 0.7); -} - -/* 侧边栏卡片 */ -.highlight-card { - border-radius: 18px; - border: 1px solid rgba(148, 163, 184, 0.22); - background: transparent; - padding: 1.6rem 1.7rem; - backdrop-filter: none; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.harmony-card { - border-color: rgba(251, 146, 60, 0.25); - background: transparent; - box-shadow: none; -} - -.harmony-card:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.harmony-card h3 { - color: #ffedd5; - text-shadow: 0 0 16px rgba(251, 146, 60, 0.25); -} - -.highlight-icon { - font-size: 2rem; - margin-bottom: 0.8rem; -} - -.highlight-card h3 { - color: #f8fafc; - font-size: 1.05rem; - font-weight: 600; - margin-bottom: 0.4rem; -} - -.highlight-summary { - color: rgba(148, 163, 184, 0.9); - font-size: 0.79rem; - margin-bottom: 0.9rem; - font-style: italic; -} - -.highlight-list { - margin: 0; - padding-left: 1.1rem; - color: rgba(203, 213, 225, 0.92); -} - -.highlight-list li { - margin-bottom: 0.55rem; - line-height: 1.68; - font-size: 0.86rem; - position: relative; -} - -.highlight-list li::marker { - color: rgba(251, 146, 60, 0.7); -} - -/* 注意事项卡片 */ -.note-card { - border-radius: 18px; - border: 1px solid rgba(251, 191, 36, 0.3); - background: linear-gradient(135deg, rgba(251, 191, 36, 0.1), rgba(15, 23, 42, 0.4)); - padding: 1.5rem 1.6rem; - backdrop-filter: blur(12px); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.note-card:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.note-icon { - font-size: 1.6rem; - margin-bottom: 0.7rem; -} - -.note-card h3 { - color: #f8fafc; - font-size: 1rem; - font-weight: 600; - margin-bottom: 0.7rem; -} - -.note-list { - margin: 0; - padding-left: 1.1rem; - color: rgba(203, 213, 225, 0.92); -} - -.note-list li { - margin-bottom: 0.55rem; - line-height: 1.68; - font-size: 0.86rem; -} - -/* 支持卡片 */ -.support-card { - display: flex; - align-items: center; - gap: 1.4rem; - padding: 1.4rem 1.6rem; - border-radius: 18px; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.18), rgba(2, 132, 199, 0.1)); - border: 1px solid rgba(56, 189, 248, 0.4); - box-shadow: 0 8px 28px rgba(56, 189, 248, 0.18); - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.support-card:hover { - transform: translateY(-4px); - box-shadow: 0 12px 36px rgba(56, 189, 248, 0.28), 0 0 24px rgba(56, 189, 248, 0.15); - border-color: rgba(56, 189, 248, 0.6); -} - -.support-icon { - font-size: 2.4rem; - flex-shrink: 0; -} - -.support-content h3 { - color: #f8fafc; - font-size: 1.08rem; - margin-bottom: 0.45rem; - font-weight: 600; -} - -.support-content p { - color: rgba(203, 213, 225, 0.88); - font-size: 0.87rem; - margin-bottom: 0.55rem; - line-height: 1.65; -} - -.support-link { - display: inline-block; - color: #7dd3fc; - text-decoration: none; - font-size: 0.9rem; - font-weight: 600; - padding: 0.4rem 0.8rem; - border-radius: 10px; - background: rgba(56, 189, 248, 0.15); - border: 1px solid rgba(56, 189, 248, 0.35); - transition: all 0.3s ease; -} - -.support-link:hover { - color: #bae6fd; - background: rgba(56, 189, 248, 0.25); - border-color: rgba(148, 163, 184, 0.35); -} - -/* ==================== - 响应式设计 - ==================== */ -@media (max-width: 1023px) { - .details-grid { - grid-template-columns: 1fr; - } - - .details-sidebar { - order: -1; - } - - .platform-grid { - grid-template-columns: repeat(4, minmax(160px, 1fr)); - } - - .metrics-grid { - grid-template-columns: 1fr; - } - - .metrics-grid-small { - grid-template-columns: 1fr; - } - - .platform-grid { - grid-template-columns: repeat(3, minmax(160px, 1fr)); - } - - .section-container { - padding: 1.4rem; - } - - .access-metrics-card { - padding: 0; - gap: 1.5rem; - } - - .hero-title { - font-size: var(--h2-size); - } - - .app-icon-wrapper { - width: 80px; - height: 80px; - } -} - -@media (max-width: 767px) { - .dashboard-page { - padding-top: 6.4rem; - } - - .platform-grid { - grid-template-columns: repeat(2, minmax(160px, 1fr)); - } - - .hero-header { - flex-direction: column; - text-align: center; - } - - .hero-tags { - justify-content: center; - } - - .section-header h2 { - font-size: var(--h3-size); - } - - .access-metrics-card { - padding: 0; - gap: 1.2rem; - } - - .metric-card-small .metric-value { - font-size: 1.5rem; - } -} - -/* ==================== - 技术架构板块 - ==================== */ -.tech-two-columns { - display: grid; - grid-template-columns: 1.1fr 1fr; - gap: 1.6rem; -} - -.tech-column { - display: flex; - flex-direction: column; - gap: 1.6rem; -} - -.tech-detail-block { - border-radius: 16px; - border: 1px solid rgba(148, 163, 184, 0.22); - background: transparent; - padding: 1.5rem 1.7rem; - backdrop-filter: none; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.tech-detail-block:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.tech-detail-block h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 0.6rem; - padding-bottom: 0.7rem; - border-bottom: 1px solid rgba(148, 163, 184, 0.2); -} - -.tech-detail-block h4 { - color: #7dd3fc; - font-size: 0.95rem; - font-weight: 600; - margin: 1.2rem 0 0.6rem 0; - padding-bottom: 0.5rem; - border-bottom: 1px dashed rgba(148, 163, 184, 0.15); -} - -.tech-summary { - color: rgba(203, 213, 225, 0.85); - font-size: 0.88rem; - line-height: 1.65; - margin-bottom: 1rem; - padding-left: 0.3rem; - border-left: 3px solid rgba(56, 189, 248, 0.5); - padding-top: 0.2rem; - padding-bottom: 0.2rem; -} - -.tech-subsection { - padding-left: 0.3rem; -} - -.tech-list { - margin: 0; - padding-left: 1.2rem; - color: rgba(203, 213, 225, 0.92); -} - -.tech-list li { - margin-bottom: 0.65rem; - line-height: 1.65; - font-size: 0.86rem; - font-family: 'JetBrains Mono', monospace; -} - -.tech-list li::marker { - color: rgba(56, 189, 248, 0.7); -} - -/* ==================== - 数据库特性板块 - ==================== */ -.database-features { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 1.2rem; -} - -.feature-card { - border-radius: 16px; - border: 1px solid rgba(148, 163, 184, 0.22); - background: transparent; - padding: 1.5rem; - backdrop-filter: none; - text-align: center; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.feature-card:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.feature-icon { - font-size: 2.4rem; - margin-bottom: 0.8rem; - display: block; -} - -.feature-card h4 { - color: #f8fafc; - font-size: 0.9rem; - font-weight: 600; - margin: 0; - line-height: 1.5; -} - -/* ==================== - 数据库接入板块 - ==================== */ -.intro-text { - color: rgba(203, 213, 225, 0.9); - font-size: 0.95rem; - line-height: 1.7; - max-width: 720px; - margin-top: 0.5rem; -} - -.integration-layout { - display: grid; - grid-template-columns: 2fr 5fr; - gap: 1.6rem; - margin-top: 1.5rem; -} - -.integration-left h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 0.6rem; -} - -.integration-intro { - color: rgba(203, 213, 225, 0.75); - font-size: 0.85rem; - line-height: 1.5; - margin-bottom: 1rem; -} - -.integration-cases-vertical { - display: flex; - flex-direction: column; - gap: 0.8rem; -} - -.case-item { - padding: 1rem 1.2rem; - border-radius: 12px; - background: transparent; - border: 1px solid rgba(148, 163, 184, 0.22); - text-decoration: none; - transition: all 0.3s ease; - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.8rem; -} - -.case-item:hover { - border-color: rgba(148, 163, 184, 0.35); - background: rgba(56, 189, 248, 0.05); -} - -.case-content { - flex: 1; - min-width: 0; -} - -.case-title { - color: #f8fafc; - font-size: 0.95rem; - font-weight: 600; - margin-bottom: 0.35rem; -} - -.case-subtitle { - color: rgba(203, 213, 225, 0.75); - font-size: 0.8rem; - line-height: 1.4; -} - -.case-link-icon { - flex-shrink: 0; - color: rgba(56, 189, 248, 0.6); - font-size: 0.9rem; - transition: all 0.3s ease; -} - -.case-item:hover .case-link-icon { - color: rgba(56, 189, 248, 0.8); - transform: none; -} - -.integration-right { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.api-buttons { - display: flex; - gap: 0.8rem; - flex-wrap: wrap; -} - -.api-section { - margin: 1rem 0; - padding: 1.5rem; - border-radius: 16px; - background: transparent; - border: 1px solid rgba(168, 85, 247, 0.2); -} - -.api-section h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 0.8rem; -} - -.api-section p { - color: rgba(203, 213, 225, 0.85); - font-size: 0.9rem; - line-height: 1.6; - margin-bottom: 1.2rem; -} - -.api-btn { - display: inline-block; - padding: 0.7rem 1.5rem; - border-radius: 12px; - background: linear-gradient(135deg, rgba(168, 85, 247, 0.25), rgba(139, 92, 246, 0.2)); - border: 1px solid rgba(168, 85, 247, 0.5); - color: #e9d5ff; - text-decoration: none; - font-weight: 600; - font-size: 0.95rem; - transition: all 0.3s ease; -} - -.api-btn:hover { - background: rgba(168, 85, 247, 0.35); - border-color: rgba(148, 163, 184, 0.35); -} - -.api-btn-secondary { - background: linear-gradient(135deg, rgba(56, 189, 248, 0.25), rgba(2, 132, 199, 0.2)); - border-color: rgba(56, 189, 248, 0.5); - color: #bae6fd; -} - -.api-btn-secondary:hover { - background: rgba(56, 189, 248, 0.35); - border-color: rgba(148, 163, 184, 0.35); -} - -.integration-warning { - margin: 1rem 0; - padding: 1.5rem; - border-radius: 16px; - background: linear-gradient(135deg, rgba(251, 191, 36, 0.08), rgba(245, 158, 11, 0.05)); - border: 1px solid rgba(251, 191, 36, 0.3); -} - -.integration-warning h3 { - color: #fef3c7; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 1rem; -} - -.integration-warning p { - color: rgba(254, 243, 199, 0.9); - font-size: 0.9rem; - line-height: 1.7; - margin-bottom: 0.7rem; -} - -.integration-warning p:last-child { - margin-bottom: 0; -} - -/* ==================== - 项目链接板块 - ==================== */ -.links-grid { - display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); - gap: 1.2rem; - max-width: 800px; - margin: 0 auto; -} - -.link-card { - border-radius: 16px; - border: 1px solid rgba(148, 163, 184, 0.22); - background: linear-gradient(135deg, rgba(15, 23, 42, 0.5), rgba(30, 41, 59, 0.25)); - padding: 1.6rem; - backdrop-filter: blur(12px); - text-align: center; - text-decoration: none; - color: #f8fafc; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.link-card:hover { - border-color: rgba(56, 189, 248, 0.5); - transform: translateY(-6px); - box-shadow: 0 16px 40px rgba(2, 6, 23, 0.4), 0 0 28px rgba(56, 189, 248, 0.12); -} - -.link-icon { - font-size: 2.6rem; - margin-bottom: 0.9rem; - display: block; -} - -.link-card h4 { - color: #f8fafc; - font-size: 0.95rem; - font-weight: 600; - margin: 0; -} - -/* ==================== - 团队与致谢板块 - ==================== */ -.team-content { - display: flex; - flex-direction: column; - gap: 2rem; -} - -.team-members { - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 1.4rem; -} - -.member-card { - border-radius: 16px; - border: 1px solid rgba(148, 163, 184, 0.22); - background: transparent; - padding: 1.6rem; - backdrop-filter: none; - display: flex; - align-items: center; - gap: 1rem; - transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); -} - -.member-card:hover { - border-color: rgba(148, 163, 184, 0.35); -} - -.member-avatar { - font-size: 2.8rem; - flex-shrink: 0; -} - -.member-info h4 { - color: #f8fafc; - font-size: 0.95rem; - font-weight: 600; - margin: 0; - line-height: 1.5; -} - -.license-section { - border-radius: 16px; - border: 1px solid rgba(168, 85, 247, 0.3); - background: transparent; - padding: 1.6rem 1.8rem; - backdrop-filter: none; -} - -.contact-section { - border-radius: 16px; - border: 1px solid rgba(74, 222, 128, 0.3); - background: transparent; - padding: 1.6rem 1.8rem; - backdrop-filter: none; -} - -.contact-section h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 1rem; -} - -.contact-list { - color: rgba(203, 213, 225, 0.85); - font-size: 0.95rem; - line-height: 1.8; -} - -.contact-list p { - margin: 0.5rem 0; -} - -.contact-list a { - color: rgba(74, 222, 128, 0.9); - text-decoration: none; - transition: all 0.3s ease; -} - -.contact-list a:hover { - color: rgba(74, 222, 128, 1); - text-decoration: underline; -} - -.license-section h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 1.2rem; - padding-bottom: 0.7rem; - border-bottom: 1px solid rgba(148, 163, 184, 0.2); -} - -.license-badge-link { - text-decoration: none; - display: inline-block; -} - -.license-badge-link:hover .license-badge { - border-color: rgba(148, 163, 184, 0.35); - transform: translateY(-2px); -} - -.license-badge { - display: inline-block; - padding: 0.5rem 1.2rem; - border-radius: 999px; - background: linear-gradient(135deg, rgba(168, 85, 247, 0.2), rgba(139, 92, 246, 0.15)); - border: 1px solid rgba(168, 85, 247, 0.4); - margin-bottom: 1rem; -} - -.license-name { - color: #e9d5ff; - font-size: 0.95rem; - font-weight: 700; - letter-spacing: 0.05em; -} - -.license-desc { - color: rgba(203, 213, 225, 0.85); - font-size: 0.9rem; - line-height: 1.7; - max-width: 640px; - margin: 0 auto; -} - -.acknowledgments-section { - border-radius: 16px; - border: 1px solid rgba(56, 189, 248, 0.3); - background: transparent; - padding: 1.6rem 1.8rem; - backdrop-filter: none; -} - -.acknowledgments-section h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 1.2rem; - padding-bottom: 0.7rem; - border-bottom: 1px solid rgba(148, 163, 184, 0.2); -} - -.acknowledgments-list { - margin: 0; - padding-left: 1.2rem; - color: rgba(203, 213, 225, 0.92); -} - -.acknowledgments-list li { - margin-bottom: 0.65rem; - line-height: 1.7; - font-size: 0.9rem; -} - -.acknowledgments-list li::marker { - color: rgba(56, 189, 248, 0.7); -} - -/* ==================== - 联系我们板块 - ==================== */ -.contact-grid { - display: grid; - grid-template-columns: 2fr 1fr; - gap: 1.6rem; - margin-top: 1.5rem; -} - -.contact-team { - border-radius: 16px; - border: 1px solid rgba(56, 189, 248, 0.3); - background: transparent; - padding: 1.6rem 1.8rem; - backdrop-filter: none; -} - -.contact-team h3 { - color: #f8fafc; - font-size: 1.1rem; - font-weight: 600; - margin-bottom: 1.2rem; - padding-bottom: 0.7rem; - border-bottom: 1px solid rgba(148, 163, 184, 0.2); -} - -.team-title-link { - color: #f8fafc; - text-decoration: none; - transition: all 0.3s ease; -} - -.team-title-link:hover { - color: #38bdf8; -} - -.team-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 1rem; -} - -.team-item { - padding: 1rem 1.2rem; - border-radius: 12px; - background: linear-gradient(135deg, rgba(56, 189, 248, 0.08), rgba(2, 132, 199, 0.05)); - border: 1px solid rgba(56, 189, 248, 0.2); - transition: all 0.3s ease; -} - -.team-item:hover { - border-color: rgba(148, 163, 184, 0.35); - background: rgba(56, 189, 248, 0.12); - transform: translateX(4px); -} - -.team-name { - color: #f8fafc; - font-size: 0.95rem; - font-weight: 600; - margin-bottom: 0.4rem; -} - -.team-contact { - color: rgba(125, 211, 252, 0.9); - font-size: 0.85rem; - font-family: 'JetBrains Mono', monospace; - margin-bottom: 0.4rem; -} - -.qq-link { - color: rgba(125, 211, 252, 0.9); - text-decoration: none; - display: inline-flex; - align-items: center; - gap: 0.4rem; - transition: all 0.3s ease; -} - -.qq-link:hover { - color: #7dd3fc; - text-decoration: underline; -} - -.qq-link i { - font-size: 0.75rem; -} - -.team-role { - color: rgba(203, 213, 225, 0.8); - font-size: 0.82rem; - line-height: 1.5; -} - -.contact-info { - display: flex; - flex-direction: column; - gap: 1.2rem; -} - -/* ==================== - 响应式调整 - 新增板块 - ==================== */ -@media (max-width: 1023px) { - .tech-two-columns { - grid-template-columns: 1fr; - } - - .integration-layout { - grid-template-columns: 1fr; - } - - .database-features { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .cases-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .links-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - } - - .team-members { - grid-template-columns: 1fr; - } - - .contact-grid { - grid-template-columns: 1fr; - } - - .contact-team { - order: -1; - } - - .team-grid { - grid-template-columns: 1fr; - } - - /* 修复移动端标题和图标布局 */ - .card-header { - flex-direction: row; - flex-wrap: wrap; - } - - .card-number { - font-size: 1.2rem; - } - - .card-header h3 { - font-size: var(--text-base); - } - - .note-icon, - .highlight-icon { - font-size: 1.5rem; - } - - .note-card h3, - .highlight-card h3 { - font-size: var(--text-sm); - } - - .section-container { - padding: 1.2rem; - } - - .info-card, - .highlight-card, - .note-card { - padding: 1.3rem 1.4rem; - } -} - -@media (max-width: 767px) { - .database-features { - grid-template-columns: 1fr; - } - - .cases-grid { - grid-template-columns: 1fr; - } - - .links-grid { - grid-template-columns: 1fr; - } -} - -/* ========================================= - Dashboard 滑动进入动画 - ========================================= */ -.dashboard-page .hero-section, -.dashboard-page .content-section { - opacity: 0; - transform: translateY(24px); - transition: opacity 0.5s ease-out, transform 0.5s ease-out; -} - -.dashboard-page .hero-section.reveal-in, -.dashboard-page .content-section.reveal-in { - opacity: 1; - transform: translateY(0); -} diff --git a/static/css/home.css b/static/css/index.css similarity index 86% rename from static/css/home.css rename to static/css/index.css index f55ab43..7db2cd6 100644 --- a/static/css/home.css +++ b/static/css/index.css @@ -123,8 +123,8 @@ .floating-elements { position: absolute; - top: -24px; - right: -24px; + top: -16px; + right: -16px; width: 110px; height: 110px; background: var(--secondary); @@ -460,6 +460,15 @@ a.skill-link { gap: 2rem; } +.projects-grid.projects-grid-main { + grid-template-columns: repeat(3, 1fr); +} + +.projects-grid.projects-grid-compact { + grid-template-columns: repeat(4, 1fr); + gap: 1.2rem; +} + .projects-group { margin-top: 3rem; } @@ -489,11 +498,6 @@ a.skill-link { line-height: 1.6; } -.projects-grid-compact { - grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); - gap: 1.2rem; -} - .project-card.project-card-text { min-height: 196px; display: flex; @@ -594,43 +598,107 @@ a.skill-link { } .project-image.harmony { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(23, 63, 130, 0.3)), url('../resources/main_page/dashboard.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(23, 63, 130, 0.15)), url('../resources/main_page/dashboard.png'); } .project-image.bio { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(16, 185, 129, 0.28)), url('../resources/main_page/bio.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(16, 185, 129, 0.12)), url('../resources/main_page/bio.png'); } .project-image.spm { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(245, 158, 11, 0.28)), url('../resources/main_page/spm.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(245, 158, 11, 0.12)), url('../resources/main_page/spm.png'); } .project-image.ohos { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(0, 122, 255, 0.28)), url('../resources/main_page/openharmony.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(0, 122, 255, 0.12)), url('../resources/main_page/openharmony.png'); } .project-image.dr { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(239, 68, 68, 0.28)), url('../resources/main_page/dr.png'); -} - -.project-image.dx { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(168, 85, 247, 0.28)), url('../resources/main_page/dx.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(239, 68, 68, 0.12)), url('../resources/main_page/dr.png'); } .project-image.signal { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(59, 130, 246, 0.28)), url('../resources/main_page/signal.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(59, 130, 246, 0.12)), url('../resources/main_page/signal.png'); } .project-image.piano { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(168, 85, 247, 0.28)), url('../resources/main_page/piano.png'); + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(168, 85, 247, 0.12)), url('../resources/main_page/piano.png'); } -.project-image.drawing { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(236, 72, 153, 0.28)), url('../resources/main_page/drawing.png'); +.project-image.books { + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(245, 158, 11, 0.12)), url('../resources/main_page/books.png'); } -.project-image.books { - background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.55), rgba(245, 158, 11, 0.28)), url('../resources/main_page/books.png'); +.project-image.smartshed { + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(52, 211, 153, 0.15), rgba(6, 182, 212, 0.1)), url('../resources/main_page/openharmony.png'); +} + +.project-image.rps { + background-image: linear-gradient(135deg, rgba(9, 18, 39, 0.25), rgba(245, 158, 11, 0.15), rgba(239, 68, 68, 0.1)), url('../resources/main_page/rps.png'); +} + +.life-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 2rem; +} + +.life-card { + position: relative; + display: flex; + flex-direction: column; + border-radius: var(--radius); + overflow: hidden; + text-decoration: none; + color: inherit; + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.05); + transition: var(--transition); +} + +.life-card:hover { + transform: translateY(-8px); + border-color: var(--primary); + box-shadow: 0 20px 48px rgba(99, 102, 241, 0.15), 0 8px 20px rgba(0, 0, 0, 0.25); +} + +.life-card-visual { + height: 220px; + position: relative; + overflow: hidden; + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +.life-card-visual::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(to top, rgba(11, 19, 37, 0.7) 0%, rgba(11, 19, 37, 0.25) 50%, transparent 100%); + z-index: 1; +} + +.piano-visual { + background-image: url('../resources/main_page/piano.png'); +} + +.books-visual { + background-image: url('../resources/main_page/books.png'); +} + +.life-card-body { + padding: 1.5rem; + flex: 1; + display: flex; + flex-direction: column; +} + +.life-card-title { + font-size: 1.25rem; + font-weight: 700; + margin-bottom: 0.5rem; + color: #fff; } .project-content { @@ -664,6 +732,9 @@ a.skill-link { color: rgba(255, 255, 255, 0.7); margin-bottom: 1rem; font-size: 0.95rem; + line-height: 1.6; + word-break: break-word; + overflow-wrap: break-word; } .project-tags { @@ -1305,6 +1376,34 @@ textarea.form-control { } } +@media (max-width: 1279px) { + .projects-grid.projects-grid-main { + grid-template-columns: repeat(3, 1fr); + gap: 1.5rem; + } + + .projects-grid.projects-grid-compact { + grid-template-columns: repeat(3, 1fr); + } + + .projects-grid-main .project-image { + height: 170px; + } + + .projects-grid-main .project-content { + padding: 1.2rem; + } + + .projects-grid-main .project-title { + font-size: 1.1rem; + } + + .projects-grid-main .project-description { + font-size: 0.88rem; + margin-bottom: 0.8rem; + } +} + @media (max-width: 1023px) { .hero { min-height: auto; @@ -1388,11 +1487,11 @@ textarea.form-control { } .floating-elements { - width: 50px; - height: 50px; - top: 6px; - right: 4px; - font-size: 1rem; + width: 60px; + height: 60px; + font-size: 1.2rem; + top: -14px; + right: -14px; } .section-title { @@ -1452,10 +1551,20 @@ textarea.form-control { background: rgba(13, 26, 47, 0.56); } - .projects-grid { + .projects-grid, + .projects-grid.projects-grid-main, + .projects-grid.projects-grid-compact { grid-template-columns: 1fr; } + .life-grid { + grid-template-columns: 1fr; + } + + .life-card-visual { + height: 180px; + } + .project-image { height: auto; aspect-ratio: 16 / 9; @@ -1540,6 +1649,18 @@ textarea.form-control { font-size: var(--text-xs); } + .floating-elements { + width: 50px; + height: 50px; + font-size: 1rem; + top: -10px; + right: -10px; + } + + .hero { + padding: 7.5rem 0 1.5rem; + } + .btn-group { flex-direction: column; width: 100%; @@ -1557,3 +1678,79 @@ textarea.form-control { min-height: 320px; } } + +/* ==================== + 超小屏幕适配(< 480px) + ==================== */ +@media (max-width: 480px) { + .hero { + padding: 7rem 0 1rem; + } + + .hero-text h1 { + font-size: clamp(1.8rem, 6vw, 2.4rem); + } + + .hero-content { + grid-template-columns: 1fr; + gap: 2rem; + text-align: center; + } + + .profile-img { + max-width: 140px; + margin: 0 auto; + } + + .floating-elements { + width: 40px; + height: 40px; + font-size: 0.9rem; + top: -6px; + right: -6px; + } + + .star-tooltip { + bottom: -44px; + font-size: 0.75rem; + padding: 0.4rem 0.8rem; + } + + .star-tooltip::before { + top: -5px; + width: 7px; + height: 7px; + } + + .section-title { + font-size: clamp(1.5rem, 5vw, 1.9rem); + } + + .project-card { + padding: 1rem; + } + + .project-description { + font-size: var(--text-xs); + line-height: 1.5; + } + + .project-tags { + flex-wrap: wrap; + gap: 0.35rem; + } + + .tag { + font-size: 0.7rem; + padding: 0.2rem 0.6rem; + } + + .gallery-track, + .gallery-slide img { + min-height: 240px; + } + + .contact-card { + padding: 1.2rem; + } +} diff --git a/static/css/rockpapersissors.css b/static/css/rockpapersissors.css new file mode 100644 index 0000000..96ab7fa --- /dev/null +++ b/static/css/rockpapersissors.css @@ -0,0 +1,273 @@ +/* RockPaperSissors 页面专用样式 */ +/* 2026 暑期 Python 课程项目 — 机器学习 & 深度学习 */ + +/* ===== 概览网格 ===== */ +.rps-hero-image { + margin-bottom: 3rem; + border-radius: var(--radius); + overflow: hidden; + border: 1px solid var(--glass-border); +} + +.rps-hero-image img { + width: 100%; + display: block; +} + +.rps-overview-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 1rem; + margin-bottom: 3rem; +} + +.rps-overview-card { + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--glass-border); + border-radius: var(--radius); + padding: 1.4rem; + text-align: left; + transition: var(--transition); +} + +.rps-overview-card:hover { + transform: translateY(-4px); + border-color: rgba(245, 158, 11, 0.4); + background: rgba(245, 158, 11, 0.06); +} + +.rps-overview-index { + font-size: 0.75rem; + font-weight: 700; + color: #f59e0b; + letter-spacing: 1px; + margin-bottom: 0.6rem; + display: block; +} + +.rps-overview-card h2 { + font-size: 1rem; + margin-bottom: 0.4rem; + color: #fff; +} + +.rps-overview-card p { + font-size: 0.85rem; + color: rgba(255, 255, 255, 0.6); + line-height: 1.55; +} + +/* ===== Panel ===== */ +.rps-panel { + margin-bottom: 3rem; +} + +.rps-sub-header { + display: flex; + align-items: center; + gap: 0.8rem; + margin-bottom: 1.5rem; +} + +.rps-sub-header .sub-number { + font-size: 0.85rem; + font-weight: 700; + color: #f59e0b; + background: rgba(245, 158, 11, 0.12); + padding: 0.2rem 0.6rem; + border-radius: 6px; + letter-spacing: 0.5px; +} + +.rps-sub-header h3 { + font-size: 1.15rem; + color: #fff; +} + +.rps-sub-header p { + color: rgba(255, 255, 255, 0.5); + font-size: 0.85rem; +} + +/* Grid */ +.rps-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; +} + +.rps-grid-2 { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1rem; +} + +.rps-card { + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--glass-border); + border-radius: var(--radius); + padding: 1.4rem; + transition: var(--transition); +} + +.rps-card:hover { + transform: translateY(-4px); + border-color: rgba(245, 158, 11, 0.4); +} + +.rps-card h3 { + font-size: 1rem; + color: #fff; + margin-bottom: 0.6rem; + display: flex; + align-items: center; + gap: 0.4rem; +} + +.rps-card h3 i { + color: #f59e0b; + font-size: 0.9rem; +} + +.rps-card p, .rps-card li { + font-size: 0.88rem; + color: rgba(255, 255, 255, 0.65); + line-height: 1.65; +} + +.rps-card ul, .rps-card ol { + padding-left: 1.2rem; + margin: 0.4rem 0; +} + +.rps-card li { + margin-bottom: 0.3rem; +} + +.rps-card code { + font-family: 'JetBrains Mono', monospace; + font-size: 0.82rem; + background: rgba(255, 255, 255, 0.08); + padding: 0.1rem 0.4rem; + border-radius: 4px; + color: #f59e0b; +} + +/* Metric rows */ +.rps-metric { + display: flex; + justify-content: space-between; + padding: 0.5rem 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.05); +} + +.rps-metric:last-child { + border-bottom: none; +} + +.rps-metric-name { + color: rgba(255, 255, 255, 0.6); + font-size: 0.85rem; +} + +.rps-metric-value { + color: #fff; + font-weight: 600; + font-size: 0.88rem; + font-family: 'JetBrains Mono', monospace; +} + +/* Tags */ +.rps-tags { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + margin-top: 0.5rem; +} + +.rps-tag { + font-size: 0.75rem; + padding: 0.2rem 0.6rem; + border-radius: 6px; + background: rgba(255, 255, 255, 0.06); + color: rgba(255, 255, 255, 0.6); + border: 1px solid rgba(255, 255, 255, 0.08); +} + +.rps-tag.py { + background: rgba(55, 136, 198, 0.12); + color: #3b88c6; + border-color: rgba(55, 136, 198, 0.2); +} + +.rps-tag.ml { + background: rgba(245, 158, 11, 0.12); + color: #f59e0b; + border-color: rgba(245, 158, 11, 0.2); +} + +.rps-tag.dl { + background: rgba(239, 68, 68, 0.12); + color: #ef4444; + border-color: rgba(239, 68, 68, 0.2); +} + +.rps-tag.cv { + background: rgba(139, 92, 246, 0.12); + color: #8b5cf6; + border-color: rgba(139, 92, 246, 0.2); +} + +.rps-tag.data { + background: rgba(16, 185, 129, 0.12); + color: #10b981; + border-color: rgba(16, 185, 129, 0.2); +} + +/* Full-width card */ +.rps-card-full { + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--glass-border); + border-radius: var(--radius); + padding: 1.4rem; + transition: var(--transition); + margin-top: 1rem; +} + +.rps-card-full:hover { + border-color: rgba(245, 158, 11, 0.35); +} + +.rps-card-full h3 { + font-size: 1rem; + color: #fff; + margin-bottom: 0.6rem; +} + +.rps-card-full p { + font-size: 0.88rem; + color: rgba(255, 255, 255, 0.65); + line-height: 1.65; +} + +/* Responsive */ +@media (max-width: 1023px) { + .rps-overview-grid { + grid-template-columns: repeat(2, 1fr); + } + .rps-grid { + grid-template-columns: repeat(2, 1fr); + } + .rps-grid-2 { + grid-template-columns: 1fr; + } +} + +@media (max-width: 767px) { + .rps-overview-grid { + grid-template-columns: 1fr; + } + .rps-grid { + grid-template-columns: 1fr; + } +} diff --git a/static/css/signal.css b/static/css/signal.css new file mode 100644 index 0000000..55a4899 --- /dev/null +++ b/static/css/signal.css @@ -0,0 +1,245 @@ +.signal-page { + max-width: 1180px; +} + +.signal-panel, +.signal-module { + border: 1px solid rgba(255, 255, 255, 0.12); + background: linear-gradient(155deg, rgba(15, 23, 42, 0.78), rgba(30, 41, 59, 0.52)); + border-radius: 22px; + padding: clamp(1.2rem, 2.4vw, 2rem); + box-shadow: 0 22px 40px rgba(2, 6, 23, 0.36); + margin-bottom: 1.2rem; +} + +.signal-hero { + border: none; + background: none; + border-radius: 0; + box-shadow: none; + padding: 0; + margin-bottom: 1.6rem; + position: relative; +} + +.signal-hero h1 { + margin: 0; + color: #fff; + font-size: clamp(2.2rem, 3.5vw, 3rem); + letter-spacing: -0.03em; + line-height: 1.15; + font-weight: 700; +} + +.signal-hero-desc { + color: rgba(255, 255, 255, 0.6); + margin-top: 1rem; + line-height: 1.8; + font-size: 1.05rem; + max-width: 680px; +} + +.signal-hero::after { + content: ''; + display: block; + width: 60px; + height: 3px; + margin-top: 2rem; + background: linear-gradient(90deg, var(--primary), var(--secondary)); + border-radius: 2px; +} + +.signal-hero-actions { + margin-top: 1rem; + display: flex; + gap: 0.72rem; + flex-wrap: wrap; +} + +.signal-panel-head h2 { + margin: 0; + color: #e2e8f0; + font-size: 1.35rem; +} + +.signal-abstract-grid { + display: grid; + grid-template-columns: 1fr 420px; + gap: 1.5rem; + margin-top: 0.9rem; +} + +.signal-abstract-text p { + color: rgba(226, 232, 240, 0.84); + line-height: 1.72; + margin: 0; +} + +.signal-abstract-text .signal-hero-actions { + margin-top: 1.2rem; +} + +.signal-hero-actions .button i { + margin-right: 0.5em; +} + +.signal-keywords { + margin-top: 0.8rem; + font-size: 0.88rem; + color: rgba(226, 232, 240, 0.6); +} + +.signal-keywords-label { + font-weight: 600; + color: rgba(226, 232, 240, 0.8); +} + +.signal-card { + border: 1px solid rgba(148, 163, 184, 0.26); + border-radius: 16px; + background: rgba(2, 6, 23, 0.45); + padding: 0.9rem; +} + +.signal-doc-image { + border-radius: 16px; + overflow: hidden; + border: 1px solid rgba(148, 163, 184, 0.26); + background: rgba(2, 6, 23, 0.45); +} + +.signal-doc-image img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +.signal-module { + border-color: rgba(148, 163, 184, 0.3); +} + +.signal-module-head { + display: flex; + gap: 0.82rem; + align-items: flex-start; + margin-bottom: 0.9rem; +} + +.signal-module-index { + width: 2.05rem; + height: 2.05rem; + border-radius: 999px; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.9rem; + color: #0f172a; + font-weight: 600; + background: #22d3ee; + flex-shrink: 0; +} + +.signal-module-head h2 { + margin: 0; + color: #e2e8f0; + font-size: 1.42rem; +} + +.signal-module-head p { + margin: 0.46rem 0 0 0; + color: rgba(226, 232, 240, 0.82); + line-height: 1.74; +} + +.signal-module-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0.75rem; +} + +.signal-module-grid > :nth-child(5):last-child, +.signal-module-grid > :nth-child(5):nth-last-child(2) { + grid-column: auto; +} + +.signal-file-card { + display: flex; + align-items: flex-start; + gap: 1rem; + text-decoration: none; + cursor: pointer; + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), + border-color 0.3s cubic-bezier(0.4, 0, 0.2, 1), + background 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.signal-file-card:hover { + transform: translateY(-4px); + border-color: rgba(99, 102, 241, 0.6); + background: rgba(99, 102, 241, 0.08); +} + +.signal-file-thumb { + width: 80px; + height: 60px; + border-radius: 10px; + overflow: hidden; + flex-shrink: 0; + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(2, 6, 23, 0.5); +} + +.signal-file-thumb img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} + +.signal-file-info { + flex: 1; + min-width: 0; +} + +.signal-file-info h3 { + margin: 0 0 0.3rem 0; + color: #dbeafe; + font-size: 1.04rem; +} + +.signal-file-ext { + display: inline-block; + font-family: 'JetBrains Mono', monospace; + font-size: 0.78rem; + color: rgba(255, 255, 255, 0.45); + margin-bottom: 0.4rem; +} + +.signal-file-info p { + color: rgba(226, 232, 240, 0.7); + font-size: 0.88rem; + line-height: 1.6; + margin: 0; +} + +@media (max-width: 1023px) { + .signal-abstract-grid { + grid-template-columns: 1fr; + } + + .signal-module-grid { + grid-template-columns: 1fr; + } + + .signal-hero-actions { + width: 100%; + } +} + +@media (max-width: 767px) { + .signal-file-thumb { + width: 64px; + height: 48px; + } +} diff --git a/static/css/smartshed.css b/static/css/smartshed.css new file mode 100644 index 0000000..11675a6 --- /dev/null +++ b/static/css/smartshed.css @@ -0,0 +1,368 @@ +/* SmartShed 页面专用样式 */ +/* 智慧大棚物联网控制系统 — 高信息密度版 */ + +/* ============================================================ + 层级体系(从大到小): + .ss-chapter-wrap → 章节外框容器(01~05) + .ss-panel:only-child > .ss-panel-head → 居中章节标题 + .ss-panel:not(:only-child) > .ss-panel-head → 左对齐子区段标题 + .ss-card h3 → 卡片内标题 + .ss-card p/li → 正文 + ============================================================ */ + +/* ===== 章节容器 ===== */ +.ss-chapter-wrap { + background: rgba(255, 255, 255, 0.015); + border: 1px solid rgba(255, 255, 255, 0.04); + border-radius: 14px; + padding: 1.4rem 1.5rem; + margin-bottom: 1.4rem; + position: relative; +} + +.ss-chapter-wrap::before { + content: ''; + position: absolute; + top: 0; left: 10%; right: 10%; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(52,211,153,0.12), transparent); +} + +.ss-chapter-wrap--last { margin-bottom: 2.2rem; } + +.ss-chapter-wrap > .ss-panel { margin-bottom: 1.4rem; } +.ss-chapter-wrap > .ss-panel:last-child { margin-bottom: 0; } + +/* ===== 章节大标题 —— 居中紧凑 ===== */ +.ss-panel:has(> .ss-panel-head:only-child) { margin-bottom: 0; } + +.ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head { + text-align: center; + padding: 0.25rem 0 0.5rem; +} +.ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head::after { + content: ''; + display: block; + width: 45px; height: 2px; + background: linear-gradient(90deg, transparent, rgba(52,211,153,0.22), transparent); + margin: 0.4rem auto 0; +} +.ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head h2 { + font-size: 1.28rem; font-weight: 700; letter-spacing: 0.4px; +} +.ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head p { + font-size: 0.82rem; color: rgba(255,255,255,0.38); +} + +/* ===== 子区段标题 —— 左对齐带左边框 ===== */ +.ss-panel:not(:has(> .ss-panel-head:only-child)) > .ss-panel-head { + margin-bottom: 0.85rem; + padding-left: 0.75rem; + border-left: 3px solid rgba(52,211,153,0.16); +} +.ss-panel:not(:has(> .ss-panel-head:only-child)) > .ss-panel-head h2 { + font-size: 1.08rem; font-weight: 600; +} + +/* ===== 面板基础 ===== */ +.ss-panel { margin-bottom: 1.6rem; } +.ss-panel-head { margin-bottom: 0.9rem; } +.ss-panel-head h2 { color: #fff; margin-bottom: 0.15rem; } +.ss-panel-head p { color: rgba(255,255,255,0.44); font-size: 0.84rem; } + +/* ===== Grid cards ===== */ +.ss-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0.7rem; +} + +.ss-card { + background: rgba(255, 255, 255, 0.026); + border: 1px solid var(--glass-border); + border-radius: var(--radius); + padding: 1rem 1.1rem; + transition: all 0.25s ease; + position: relative; + overflow: hidden; +} + +.ss-card::before { + content: ''; + position: absolute; top: 0; left: 0; right: 0; height: 1px; + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.06), transparent); + opacity: 0; transition: opacity 0.25s ease; +} + +.ss-card:hover { + transform: translateY(-2px); + border-color: rgba(52,211,153,0.2); + background: rgba(255,255,255,0.036); + box-shadow: 0 4px 18px rgba(0,0,0,0.15); +} +.ss-card:hover::before { opacity: 1; } + +.ss-card h3 { + font-size: 0.9rem; color: #fff; margin-bottom: 0.5rem; + display: flex; align-items: center; gap: 0.4rem; font-weight: 600; +} +.ss-card h3 i { color: #34d399; font-size: 0.82rem; width: 18px; text-align: center; flex-shrink: 0; } + +.ss-card p, +.ss-card li { + font-size: 0.81rem; color: rgba(255,255,255,0.56); line-height: 1.58; +} + +.ss-card ul, .ss-card ol { padding-left: 1.1rem; margin: 0.35rem 0; } +.ss-card li { margin-bottom: 0.22rem; } +.ss-card li::marker { color: rgba(52,211,153,0.32); } + +.ss-card code { + font-family: 'JetBrains Mono', monospace; font-size: 0.74rem; + background: rgba(255,255,255,0.06); padding: 0.1rem 0.35rem; + border-radius: 3px; color: #34d399; border: 1px solid rgba(52,211,153,0.07); +} + +/* ===== Arch 架构图 ===== */ +.ss-arch-flow { + display: flex; align-items: stretch; justify-content: center; + flex-wrap: wrap; padding: 1.3rem 0.5rem; +} +.ss-arch-flow > * + * { margin-left: 0.4rem; } + +.ss-arch-node { + flex: 1; min-width: 170px; max-width: 250px; + background: linear-gradient(145deg, rgba(255,255,255,0.032), rgba(255,255,255,0.01)); + border: 1px solid var(--glass-border); border-radius: var(--radius); + padding: 1.1rem 0.85rem; text-align: center; position: relative; +} +.ss-arch-node::after { + content: ''; position: absolute; bottom: -6px; left: 50%; transform: translateX(-50%); + width: 50%; height: 12px; + background: radial-gradient(ellipse, rgba(52,211,153,0.05), transparent); filter: blur(4px); +} +.ss-arch-node h4 { font-size: 0.76rem; color: #34d399; text-transform: uppercase; letter-spacing: 1.2px; margin-bottom: 0.5rem; font-weight: 700; } +.ss-arch-node p { font-size: 0.79rem; color: rgba(255,255,255,0.58); line-height: 1.48; } + +.ss-arch-arrow { + font-size: 1.1rem; color: rgba(52,211,153,0.22); + flex-shrink: 0; display: flex; align-items: center; padding: 0 0.35rem; top: -2px; position: relative; +} + +/* ===== Dataflow 数据流 ===== */ +.ss-flow-list { + display: flex; flex-direction: column; gap: 0; + position: relative; padding: 0.15rem 0; +} +.ss-flow-list::before { + content: ''; position: absolute; left: 12px; top: 0; bottom: 0; + width: 2px; opacity: 0.11; +} +.ss-flow-list:has(.ss-flow-item.up)::before { background: #34d399; } +.ss-flow-list:has(.ss-flow-item.down)::before { background: #f59e0b; } + +.ss-flow-item { + display: flex; align-items: flex-start; gap: 0.75rem; + padding: 0.78rem 0.9rem; + background: rgba(255,255,255,0.016); + border-radius: 9px; border-left: 3px solid; + margin-bottom: 0.38rem; position: relative; + transition: background 0.18s ease; +} +.ss-flow-item:hover { background: rgba(255,255,255,0.028); } +.ss-flow-item.up { border-color: rgba(52,211,153,0.28); } +.ss-flow-item.down { border-color: rgba(245,158,11,0.28); } + +.ss-flow-item::before { + content: ''; position: absolute; left: -6.5px; top: 1.12rem; + width: 9px; height: 9px; border-radius: 50%; border: 2px solid; + background: var(--glass-bg, #0a0a0a); z-index: 1; +} +.ss-flow-item.up::before { border-color: #34d399; box-shadow: 0 0 6px rgba(52,211,153,0.15); } +.ss-flow-item.down::before { border-color: #f59e0b; box-shadow: 0 0 6px rgba(245,158,11,0.15); } + +.ss-flow-icon { + width: 30px; height: 30px; border-radius: 8px; + display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 0.85rem; +} +.ss-flow-item.up .ss-flow-icon { background: rgba(52,211,153,0.10); color: #34d399; } +.ss-flow-item.down .ss-flow-icon { background: rgba(245,158,11,0.10); color: #f59e0b; } + +.ss-flow-text { flex: 1; min-width: 0; } +.ss-flow-text h4 { font-size: 0.86rem; color: #fff; margin-bottom: 0.18rem; font-weight: 600; } +.ss-flow-text p { font-size: 0.77rem; color: rgba(255,255,255,0.48); line-height: 1.46; } + +/* ===== Topic tags ===== */ +.ss-topic-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0.4rem; } +.ss-topic-tag { + font-family: 'JetBrains Mono', monospace; font-size: 0.74rem; + padding: 0.42rem 0.7rem; + background: rgba(255,255,255,0.022); border: 1px solid var(--glass-border); + border-radius: 7px; color: rgba(255,255,255,0.58); + transition: border-color 0.18s ease; +} +.ss-topic-tag:hover { border-color: rgba(52,211,153,0.24); } +.ss-topic-tag .topic-label { color: #34d399; font-weight: 500; margin-right: 0.3rem; } + +/* ===== Tags 标签 ===== */ +.ss-tags { display: flex; flex-wrap: wrap; gap: 0.28rem; margin-top: 0.4rem; } +.ss-tag { + font-size: 0.68rem; padding: 0.14rem 0.48rem; border-radius: 4px; + background: rgba(255,255,255,0.03); color: rgba(255,255,255,0.5); + border: 1px solid rgba(255,255,255,0.045); + transition: all 0.18s ease; font-weight: 500; +} +.ss-tag:hover { background: rgba(255,255,255,0.055); } +.ss-tag.hw { background: rgba(52,211,153,0.08); color: #34d399; border-color: rgba(52,211,153,0.14); } +.ss-tag.sw { background: rgba(6,182,212,0.08); color: #06b6d4; border-color: rgba(6,182,212,0.14); } +.ss-tag.proto { background: rgba(245,158,11,0.08); color: #f59e0b; border-color: rgba(245,158,11,0.14); } + +/* ===== 硬件连接列表(替代变形的 table)===== */ +.ss-hw-list { display: flex; flex-direction: column; gap: 0.3rem; margin-top: 0.7rem; } + +.ss-hw-item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.45rem 0.6rem; + background: rgba(255,255,255,0.02); + border-radius: 7px; + border-left: 2px solid rgba(52,211,153,0.15); + font-size: 0.78rem; + transition: background 0.15s ease; +} +.ss-hw-item:hover { background: rgba(255,255,255,0.04); } + +.ss-hw-name { + color: #fff; font-weight: 600; + min-width: 5rem; flex-shrink: 0; +} + +.ss-hw-desc { + color: rgba(255,255,255,0.48); + min-width: 5.5rem; flex-shrink: 0; +} + +.ss-hw-item code { + font-family: 'JetBrains Mono', monospace; font-size: 0.7rem; + background: rgba(52,211,153,0.08); color: #34d399; + padding: 0.1rem 0.35rem; border-radius: 3px; + border: 1px solid rgba(52,211,153,0.1); white-space: nowrap; +} + +/* ===== 表格 ===== */ +.ss-card table { border-radius: 6px; overflow: hidden; } +.ss-card table thead tr th { font-size: 0.73rem; letter-spacing: 0.2px; } +.ss-card table tbody tr { transition: background 0.12s ease; } +.ss-card table tbody tr:hover { background: rgba(255,255,255,0.018); } + +/* ===== 内联子卡片 hover ===== */ +.ss-card > div[style*="grid"] > div, +.ss-card > [style*="display:grid"] > div { + transition: transform 0.18s ease; border-radius: 7px; +} +.ss-card > div[style*="grid"] > div:hover, +.ss-card > [style*="display:grid"] > div:hover { transform: translateY(-1px); } + +/* ===== 结尾卡片 ===== */ +.ss-card[style*="text-align:center"] { + background: linear-gradient(145deg, rgba(52,211,153,0.03), rgba(6,182,212,0.02)); +} + +/* ============================================================ + 响应式断点 + ============================================================ */ + +/* 平板 / 笔记本 (1024~1279px) */ +@media (max-width: 1279px) { + .ss-chapter-wrap { padding: 1.2rem 1.2rem; } + .ss-grid { grid-template-columns: repeat(2, 1fr); } + .ss-arch-node { min-width: 155px; max-width: 220px; } +} + +/* 小平板 / 大屏手机 (768~1023px) */ +@media (max-width: 1023px) { + .ss-chapter-wrap { padding: 1.1rem 1rem; border-radius: 12px; } + .ss-chapter-wrap::before { left: 5%; right: 5%; } + + .ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head h2 { font-size: 1.15rem; } + .ss-panel:not(:has(> .ss-panel-head:only-child)) > .ss-panel-head h2 { font-size: 1.02rem; } + + .ss-grid { grid-template-columns: repeat(2, 1fr); gap: 0.6rem; } + .ss-card { padding: 0.88rem 1rem; } + + .ss-arch-flow { flex-direction: column; align-items: center; padding: 1rem 0.4rem; } + .ss-arch-node { max-width: 100%; width: 100%; min-width: unset; } + .ss-arch-arrow { transform: rotate(90deg); } + + .ss-topic-grid { grid-template-columns: 1fr; } + .ss-flow-list::before, .ss-flow-item::before { display: none; } + + /* 内联 grid 降为单列 */ + .ss-card > div[style*="grid-template-columns:repeat(3"] { grid-template-columns: 1fr !important; } + .ss-card > div[style*="grid-template-columns:repeat(2"] { grid-template-columns: 1fr !important; } +} + +/* 手机竖屏 (≤767px) */ +@media (max-width: 767px) { + .ss-chapter-wrap { + padding: 1rem 0.75rem; border-radius: 10px; + margin-bottom: 1.2rem; border-left: none; border-right: none; + } + .ss-chapter-wrap--last { margin-bottom: 1.6rem; } + .ss-chapter-wrap::before { display: none; } + + .ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head { padding: 0.2rem 0 0.4rem; } + .ss-panel:has(> .ss-panel-head:only-child) > .ss-panel-head h2 { font-size: 1.06rem; } + + .ss-panel:not(:has(> .ss-panel-head:only-child)) > .ss-panel-head { + padding-left: 0.6rem; border-left-width: 2px; + } + .ss-panel:not(:has(> .ss-panel-head:only-child)) > .ss-panel-head h2 { font-size: 0.98rem; } + + .ss-panel { margin-bottom: 1.3rem; } + .ss-chapter-wrap > .ss-panel { margin-bottom: 1.1rem; } + + .ss-grid { grid-template-columns: 1fr; gap: 0.55rem; } + .ss-card { padding: 0.85rem 0.95rem; } + .ss-card h3 { font-size: 0.87rem; } + + .ss-flow-item { padding: 0.68rem 0.72rem; gap: 0.6rem; margin-bottom: 0.38rem; border-radius: 8px; } + .ss-flow-icon { width: 27px; height: 27px; font-size: 0.78rem; } + .ss-flow-text h4 { font-size: 0.82rem; } + .ss-flow-text p { font-size: 0.73rem; } + + /* 硬件列表手机端:每行折两行 */ + .ss-hw-item { flex-wrap: wrap; gap: 0.3rem 0.5rem; padding: 0.5rem; } + .ss-hw-name { min-width: unset; } + .ss-hw-desc { min-width: unset; } + + /* 表格横向滚动,保持原样 */ + .ss-card table { + display: block; + overflow-x: auto; + white-space: nowrap; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: none; + scrollbar-width: none; + } + .ss-card table::-webkit-scrollbar { display: none; } +} + +/* 超小屏手机 (≤480px) */ +@media (max-width: 480px) { + .ss-chapter-wrap { padding: 0.85rem 0.6rem; } + .ss-card { padding: 0.75rem 0.85rem; } + .ss-card h3 { font-size: 0.84rem; } + .ss-card p, .ss-card li { font-size: 0.77rem; } + .ss-flow-item { padding: 0.6rem 0.62rem; gap: 0.5rem; } + .ss-flow-icon { width: 25px; height: 25px; font-size: 0.74rem; } +} + +/* 大屏优化 (≥1440px) */ +@media (min-width: 1440px) { + .ss-chapter-wrap { padding: 1.7rem 1.9rem; max-width: 1200px; margin-left: auto; margin-right: auto; } + .ss-grid { gap: 0.85rem; } + .ss-card { padding: 1.15rem 1.25rem; } + .ss-arch-node { max-width: 280px; } +} diff --git a/static/css/subpage.css b/static/css/subpage.css index 31e66b3..f5b9947 100644 --- a/static/css/subpage.css +++ b/static/css/subpage.css @@ -1,7 +1,7 @@ .page { max-width: 1100px; margin: 0 auto; - padding: 8rem clamp(1.2rem, 4vw, 2.5rem) 4rem; + padding: 9rem clamp(1.6rem, 4vw, 3.5rem) 5rem; flex: 1 0 auto; opacity: 0; transition: opacity 0.3s ease; @@ -201,6 +201,7 @@ display: inline-flex; justify-content: center; align-items: center; + gap: 0.4rem; text-decoration: none; border-radius: 10px; padding: 0.75rem 0.9rem; @@ -285,7 +286,7 @@ @media (max-width: 767px) { .page { - padding: 6rem clamp(1rem, 4vw, 1.5rem) 2rem; + padding: 7rem clamp(1.3rem, 4vw, 2rem) 3rem; } .button-row { @@ -909,3 +910,53 @@ font-size: var(--text-sm); } } + +/* ==================== + 超小屏幕适配(< 480px) + ==================== */ +@media (max-width: 480px) { + .page { + padding: 5.5rem clamp(1rem, 4vw, 1.6rem) 2rem; + } + + .hero-card h1 { + font-size: clamp(1.6rem, 5vw, 2rem); + } + + .hero-card p { + font-size: var(--text-sm); + } + + .card { + padding: 1rem; + } + + .card h2 { + font-size: var(--text-base); + } + + .card-image { + height: 120px; + } + + .button-large { + width: 100%; + justify-content: center; + font-size: var(--text-sm); + } + + .info-card, + .highlight-card, + .note-card, + .tech-detail-block { + padding: 1rem 1.1rem; + } + + .thesis-card h3 { + font-size: var(--text-base); + } + + .thesis-abstract { + font-size: var(--text-xs); + } +} diff --git a/static/js/common.js b/static/js/common.js index 11c9bc5..1d0a92d 100644 --- a/static/js/common.js +++ b/static/js/common.js @@ -19,7 +19,7 @@ function initParticles() { }, move: { enable: true, - speed: isMobile ? 0.8 : 1.2, + speed: isMobile ? 2.5 : 3.5, direction: 'none', random: true, straight: false, @@ -43,29 +43,9 @@ function initParticles() { }); } -function initParticlePointerFollow() { - var layer = document.getElementById('particles-js'); - if (!layer) return; - var targetX = 0, targetY = 0, currentX = 0, currentY = 0, maxOffset = 38; - function updateTarget(cx, cy) { - var mx = window.innerWidth / 2, my = window.innerHeight / 2; - targetX = ((cx - mx) / mx) * maxOffset; - targetY = ((cy - my) / my) * maxOffset; - } - function animate() { - currentX += (targetX - currentX) * 0.08; - currentY += (targetY - currentY) * 0.08; - layer.style.transform = 'translate3d(' + currentX + 'px,' + currentY + 'px,0)'; - requestAnimationFrame(animate); - } - window.addEventListener('pointermove', function(e) { updateTarget(e.clientX, e.clientY); }, { passive: true }); - window.addEventListener('touchmove', function(e) { var t = e.touches && e.touches[0]; if (t) updateTarget(t.clientX, t.clientY); }, { passive: true }); - window.addEventListener('pointerleave', function() { targetX = 0; targetY = 0; }); - window.addEventListener('touchend', function() { targetX = 0; targetY = 0; }, { passive: true }); - animate(); -} - function initParticleMagnetEffect() { + if (window.__particleMagnetActive) return; + window.__particleMagnetActive = true; var maxRetry = 30; var retry = 0; @@ -80,14 +60,16 @@ function initParticleMagnetEffect() { var canvasEl = instance.canvas.el; var pointer = { x: 0, y: 0, active: false }; var radius = 236; - var strength = 0.00126; - var damping = 0.988; - var maxSpeed = 4.25; + var strength = 0.0006; + var damping = 0.994; + var maxSpeed = 2.0; var sparseRadius = 96; var sparseThreshold = 1; var minParticles = 40; var magneticPower = 0; var frame = 0; + var lastTime = 0; + var TARGET_FRAME_TIME = 16.67; function getOpacityValue(p) { if (p && p.opacity && typeof p.opacity.value === 'number') return p.opacity.value; @@ -170,11 +152,15 @@ function initParticleMagnetEffect() { window.addEventListener('pointerleave', function() { pointer.active = false; }, { passive: true }); window.addEventListener('touchend', function() { pointer.active = false; }, { passive: true }); - function tick() { + function tick(timestamp) { + if (!lastTime) lastTime = timestamp; + var deltaTime = Math.min(Math.max((timestamp - lastTime) / TARGET_FRAME_TIME, 0.1), 3.0); + lastTime = timestamp; + frame += 1; magneticPower += pointer.active - ? (1 - magneticPower) * 0.14 - : (0 - magneticPower) * 0.012; + ? (1 - magneticPower) * 0.06 * deltaTime + : (0 - magneticPower) * 0.012 * deltaTime; if (magneticPower > 0.001 && particles.length) { for (var i = 0; i < particles.length; i += 1) { @@ -186,7 +172,7 @@ function initParticleMagnetEffect() { var dist = Math.sqrt(distSq); if (dist > radius) continue; var normalized = 1 - dist / radius; - var pull = normalized * normalized * strength * magneticPower; + var pull = normalized * normalized * strength * magneticPower * deltaTime; p.vx += dx * pull; p.vy += dy * pull; var speed = Math.sqrt(p.vx * p.vx + p.vy * p.vy); @@ -202,22 +188,23 @@ function initParticleMagnetEffect() { var pp = particles[j]; if (typeof pp.vx !== 'number') pp.vx = 0; if (typeof pp.vy !== 'number') pp.vy = 0; - pp.vx *= damping; - pp.vy *= damping; + var dampFactor = Math.pow(damping, deltaTime); + pp.vx *= dampFactor; + pp.vy *= dampFactor; if (pp.__generated && typeof pp.__ttl === 'number') { - pp.__ttl -= 1; + pp.__ttl -= 1 * deltaTime; if (pp.__ttl <= 0) pp.__fadeOut = true; } if (pp.__fadeIn) { - var next = getOpacityValue(pp) + 0.011; + var next = getOpacityValue(pp) + 0.011 * deltaTime; setOpacityValue(pp, next); if (next >= 0.5) pp.__fadeIn = false; } if (pp.__fadeOut) { - var nextVal = getOpacityValue(pp) - 0.004; + var nextVal = getOpacityValue(pp) - 0.004 * deltaTime; if (nextVal <= 0.008) { particles.splice(j, 1); continue; @@ -233,7 +220,7 @@ function initParticleMagnetEffect() { requestAnimationFrame(tick); } - tick(); + tick(0); return true; } @@ -299,8 +286,16 @@ function initMobileMenu() { overlay.addEventListener('click', closeMenu); - document.addEventListener('click', function() { - closeMenu(); + document.addEventListener('click', function(e) { + if (navLinks.classList.contains('mobile-open') && !navLinks.contains(e.target) && !mobileMenuBtn.contains(e.target)) { + closeMenu(); + } + }); + + window.addEventListener('resize', function() { + if (window.innerWidth > 900) { + closeMenu(); + } }); } @@ -420,7 +415,29 @@ function initSmoothScroll() { }); } -var locale = localStorage.getItem('rayawa_locale') || 'zh'; +function detectLocaleFromPath() { + var path = window.location.pathname; + if (path.indexOf('/fr/') === 0 || path === '/fr') return 'fr'; + if (path.indexOf('/en/') === 0 || path === '/en') return 'en'; + return null; +} + +function detectLocaleFromHTML() { + var htmlLang = document.documentElement.lang || ''; + if (htmlLang.startsWith('fr')) return 'fr'; + if (htmlLang.startsWith('en')) return 'en'; + if (htmlLang.startsWith('zh')) return 'zh'; + return null; +} + +var detectedLocale = detectLocaleFromPath(); +var htmlLocale = detectLocaleFromHTML(); +var pageLocale = detectedLocale || htmlLocale; +if (pageLocale) { + localStorage.setItem('rayawa_locale', pageLocale); +} +var storedLocale = localStorage.getItem('rayawa_locale'); +var locale = pageLocale || storedLocale || 'zh'; var TRANSITION_MS = 420; var REVEAL_ROW_TOLERANCE = 14; @@ -814,7 +831,6 @@ function initPageLeaveTransitions() { function initCommon() { initPageEntrance(); initParticles(); - initParticlePointerFollow(); initParticleMagnetEffect(); initNavbarScroll(); initMobileMenu(); @@ -825,10 +841,22 @@ function initCommon() { initPageLeaveTransitions(); } -if (!window.__HOME_JS) { +if (!window.__HOME_JS && !document.body.classList.contains('is-homepage')) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initCommon); } else { initCommon(); } +} else if (document.body.classList.contains('is-homepage')) { + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + initNavbarScroll(); + initMobileMenu(); + initFloatingTools(); + }); + } else { + initNavbarScroll(); + initMobileMenu(); + initFloatingTools(); + } } diff --git a/static/js/dashboard.js b/static/js/dashboard.js deleted file mode 100644 index 703621f..0000000 --- a/static/js/dashboard.js +++ /dev/null @@ -1,133 +0,0 @@ -(function() { - var metricsEl = document.getElementById('metricsGrid'); - if (!metricsEl) return; - - var PLATFORM_ICONS = { - web: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg0KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHJlY3Qgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiBvcGFjaXR5PSIwIj48L3JlY3Q+PGc+PHBhdGggZD0iTTEyIDEuMDFROS4wMiAxLjAxIDYuNDkgMi40OFEzLjk2IDMuOTYgMi40OCA2LjQ5UTEuMDEgOS4wMiAxLjAxIDEyUTEuMDEgMTQuOTggMi40OCAxNy41MVEzLjk2IDIwLjA0IDYuNDkgMjEuNTJROS4wMiAyMi45OSAxMiAyMi45OVExNC45OCAyMi45OSAxNy41MSAyMS41MlEyMC4wNCAyMC4wNCAyMS41MiAxNy41MVEyMi45OSAxNC45OCAyMi45OSAxMlEyMi45OSA5LjAyIDIxLjUyIDYuNDlRMjAuMDQgMy45NiAxNy41MSAyLjQ4UTE0Ljk4IDEuMDEgMTIgMS4wMVpNMTYuOTcgMTEuMjZRMTYuOSA5LjI2IDE2LjM0IDcuMzRRMTguMDIgNi44MiAxOS4zNyA2UTIwLjI2IDcuMSAyMC44IDguNDRRMjEuMzQgOS43NyAyMS40NiAxMS4yNkwxNi45NyAxMS4yNlpNOC41MiAxMS4yNlE4LjU5IDkuNDMgOS4xIDcuN1ExMC4zNyA3Ljk5IDExLjk5IDcuOTlRMTMuNjEgNy45OSAxNC45IDcuNzNRMTUuNDEgOS40MSAxNS40OCAxMS4yNkw4LjUyIDExLjI2Wk0xNS40OCAxMi43NFExNS4zOCAxNC41IDE0Ljg2IDE2LjI3UTEyIDE1LjcgOS4xNCAxNi4yN1E4LjYyIDE0LjUgOC41MiAxMi43NEwxNS40OCAxMi43NFpNMTUuODkgNS45M1ExNS4yNiA0LjI1IDE0LjMgMi43OFExNS40MyAzLjA3IDE2LjQ0IDMuNjFRMTcuNDUgNC4xNSAxOC4yOSA0LjlRMTcuMjEgNS41IDE1Ljg5IDUuOTNaTTEyLjMxIDIuNTJRMTMuNjEgNC4yIDE0LjQyIDYuMjlRMTMuMjcgNi41IDEyLjAxIDYuNVExMC43NSA2LjUgOS42IDYuMjZRMTAuMDEgNS4yNiAxMC41NCA0LjMyUTExLjA2IDMuMzggMTEuNzQgMi41MlExMS44OCAyLjUgMTIuMDIgMi41UTEyLjE3IDIuNSAxMi4zMSAyLjUyWk04LjE0IDUuOVE2Ljg5IDUuNTIgNS43MSA0Ljg3UTYuNTUgNC4xMyA3LjU3IDMuNlE4LjU5IDMuMDcgOS43IDIuNzhROC43MSA0LjMyIDguMTQgNS45Wk00LjY2IDUuOThRNi4xIDYuODIgNy42NiA3LjMyUTcuMSA5LjI5IDcuMDMgMTEuMjNMMi41NCAxMS4yM1EyLjY0IDkuNzcgMy4xOSA4LjQ0UTMuNzQgNy4xIDQuNjYgNS45OFpNNy4wMyAxMi43NFE3LjEgMTQuNTkgNy42OCAxNi42NlE2LjA3IDE3LjE2IDQuNjYgMThRMy43NCAxNi44NyAzLjE5IDE1LjU0UTIuNjQgMTQuMjEgMi41NCAxMi43NEw3LjAzIDEyLjc0Wk04LjE4IDE4LjA3UTguNzggMTkuNjggOS44MiAyMS4yNFE4LjY5IDIwLjk1IDcuNjQgMjAuNDFRNi42IDE5Ljg3IDUuNzEgMTkuMVE2Ljg2IDE4LjQ4IDguMTggMTguMDdaTTExLjg2IDIxLjQ4UTExLjI4IDIwLjc4IDEwLjggMjBRMTAuMzIgMTkuMjIgOS45NCAxOC4zOEw5LjY1IDE3LjcxUTEwLjk0IDE3LjQ3IDEyLjAyIDE3LjQ3UTEzLjEgMTcuNDcgMTQuMzUgMTcuNzFRMTQuMyAxNy44NiAxNC4wMiAxOC40OFExMy42MyAxOS4zIDEzLjE4IDIwLjA1UTEyLjcyIDIwLjgxIDEyLjE3IDIxLjQ4UTEyLjA3IDIxLjQ4IDEyLjAxIDIxLjQ4UTExLjk1IDIxLjQ4IDExLjg2IDIxLjQ4Wk0xNS44NCAxOC4wNVExNy4xNCAxOC40NiAxOC4yOSAxOS4xUTE3LjQyIDE5Ljg3IDE2LjM4IDIwLjQyUTE1LjM0IDIwLjk4IDE0LjIxIDIxLjI0UTE1LjIyIDE5LjY2IDE1Ljg0IDE4LjA1Wk0xOS4zNyAxOFExNy45IDE3LjE0IDE2LjMyIDE2LjYzUTE2LjkgMTQuNzYgMTYuOTcgMTIuNzRMMjEuNDggMTIuNzRRMjEuMzYgMTQuMjMgMjAuODIgMTUuNTZRMjAuMjggMTYuOSAxOS4zNyAxOFoiIGZpbGw9InJnYmEoMjU1LDI1NSwyNTUsMSkiPjwvcGF0aD48L2c+PC9zdmc+', - harmony: 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0MCcgaGVpZ2h0PSc0MCcgdmlld0JveD0nMCAwIDQwIDQwJz4gIDxnIGZpbGw9JyNGRkYnIGZpbGwtcnVsZT0nZXZlbm9kZCc+ICAgIDxwYXRoIGZpbGwtcnVsZT0nbm9uemVybycgZD0nTTAgMGg0MHY0MEgweicgb3BhY2l0eT0nMCcvPiAgICA8cGF0aCBkPSdNMTUuMiAyMy4yYy0uNC0uMi0uOC0uMy0xLjMtLjNzLS45LjEtMS4zLjNjLS40LjItLjcuNS0uOS45LS4yLjQtLjMuOC0uMyAxLjNzLjEuOS4zIDEuM2MuMi40LjUuNy45LjkuNC4yLjguMyAxLjMuM3MuOS0uMSAxLjMtLjNjLjQtLjIuNy0uNS45LS45LjItLjQuMy0uOC4zLTEuM3MtLjEtLjktLjMtMS4zYy0uMi0uNC0uNS0uNy0uOS0uOXpNMTEuNiA1QzggNSA1IDcuOSA1IDExLjZ2MTYuOEM1IDMyIDcuOSAzNSAxMS42IDM1aDE2LjhjMy42IDAgNi42LTIuOSA2LjYtNi42VjExLjZDMzUgOCAzMi4xIDUgMjguNCA1SDExLjZ6bS0uOSA1LjNoMS41djMuMmgzLjV2LTMuMmgxLjV2OGgtMS41di0zLjRoLTMuNXYzLjRoLTEuNXYtOHptNi4xIDIyaC01LjdWMzFoNS43djEuM3ptLjctNC44Yy0uNC42LS45IDEuMS0xLjUgMS41LS42LjQtMS4zLjUtMi4xLjVzLTEuNS0uMi0yLjEtLjVjLS42LS40LTEuMS0uOS0xLjUtMS41LS40LS42LS41LTEuMy0uNS0yLjFzLjItMS41LjUtMi4xYy40LS42LjktMS4xIDEuNS0xLjUuNi0uNCAxLjMtLjUgMi4xLS41czEuNS4yIDIuMS41Yy42LjQgMS4xLjkgMS41IDEuNS40LjYuNSAxLjMuNSAyLjFzLS4yIDEuNS0uNSAyLjF6bTEwLjYgMS4xYy0uMi40LS42LjYtMSAuOC0uNC4yLS45LjMtMS40LjMtLjUgMC0xLjMtLjEtMS45LS40LS41LS4zLS45LS42LTEuMS0xLjFWMjhoLjFsLjctLjQuMi0uMS4yLjMuNi42Yy4zLjIuNy4zIDEgLjMuMyAwIC43IDAgMS0uMy4yLS4yLjMtLjQuMy0uNyAwLS4zIDAtLjQtLjItLjUtLjItLjItLjQtLjMtLjgtLjRsLTEuMS0uM2MtMS4zLS40LTItMS4xLTItMi4zIDAtMS4yLjEtLjkuNC0xLjMuMi0uNC42LS42IDEtLjguNC0uMi45LS4zIDEuNC0uMy41IDAgMS4yLjEgMS43LjQuNC4yLjguNiAxIDF2LjNjLjEgMCAwIC4xIDAgLjFsLS45LjYtLjItLjNjLS4xLS4yLS4zLS40LS41LS41LS4zLS4yLS42LS4yLS45LS4yLS4zIDAtLjcgMC0uOS4zLS4yLjItLjMuNC0uMy43IDAgLjMgMCAuNC4yLjUuMi4yLjQuMy44LjRsMS4xLjNjMS4zLjQgMS45IDEuMSAxLjkgMi4zIDAgMS4yLS4xLjktLjMgMS4zbC0uMS0uNHptLS4yLTEwLjRWMTNsLTIgMy4yaC0uN2wtMi0zLjJ2NS4xaC0xLjR2LThoMS40bDIuNSA0IDIuNS00aDEuM3Y4aC0xLjRsLS4yLjF6Jy8+ICA8L2c+PC9zdmc+', - apple: 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHhtbG5zOnhsaW5rPSdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rJyB3aWR0aD0nNDAnIGhlaWdodD0nNDAnIHZpZXdCb3g9JzAgMCA0MCA0MCc+ICA8ZGVmcz4gICAgPHBhdGggaWQ9JzQ3ZjEzMjNjLTk5M2MtNGQ0NS1hYWIxLWJlYmIxMjA2YzJiYi1hJyBkPSdNLjAwMS41OTJoMjYuOTI2djI0LjAzOUguMDAxeicvPiAgPC9kZWZzPiAgPGcgZmlsbD0nbm9uZScgZmlsbC1ydWxlPSdldmVub2RkJz4gICAgPHBhdGggZD0nTTAgMGg0MHY0MEgweicvPiAgICA8ZyBvcGFjaXR5PScxJyB0cmFuc2Zvcm09J3RyYW5zbGF0ZSg2LjMxNiAyLjczNyknPiAgICAgIDxnIHRyYW5zZm9ybT0ndHJhbnNsYXRlKDAgNy4wNDUpJz4gICAgICAgIDxtYXNrIGlkPSc0N2YxMzIzYy05OTNjLTRkNDUtYWFiMS1iZWJiMTIwNmMyYmItYicgZmlsbD0nI2ZmZic+ICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0nIzQ3ZjEzMjNjLTk5M2MtNGQ0NS1hYWIxLWJlYmIxMjA2YzJiYi1hJy8+ICAgICAgICA8L21hc2s+ICAgICAgICA8cGF0aCBmaWxsPScjRkZGJyBkPSdNMjAuMDA1LjYwOGMtMi43MjItLjE5My01LjAzMSAxLjQ1Ni02LjMyIDEuNDU2LTEuMzA4IDAtMy4zMjQtMS40MTUtNS40NjEtMS4zNzYtMi44MDYuMDQtNS4zOTMgMS41NjQtNi44NCAzLjk3MkMtMS41MzEgOS41MDYuNjQgMTYuNjg3IDMuNDc5IDIwLjYyYzEuMzg5IDEuOTIyIDMuMDQ1IDQuMDg4IDUuMjIxIDQuMDA5IDIuMDk0LS4wOCAyLjg4Ny0xLjI5OCA1LjQxOC0xLjI5OCAyLjUzIDAgMy4yNDMgMS4yOTggNS40NTggMS4yNTkgMi4yNTQtLjA0IDMuNjgzLTEuOTYyIDUuMDYxLTMuODk0IDEuNTk2LTIuMjMgMi4yNTEtNC4zOSAyLjI5LTQuNTA1LS4wNS0uMDE4LTQuMzk0LTEuNjE0LTQuNDM3LTYuNDA4LS4wNC00LjAwOCAzLjQxNS01LjkzNSAzLjU3My02LjAyOEMyNC4xMDIuOTg5IDIxLjA3My42ODQgMjAuMDA1LjYwOCcgbWFzaz0ndXJsKCM0N2YxMzIzYy05OTNjLTRkNDUtYWFiMS1iZWJiMTIwNmMyYmItYiknLz4gICAgICA8L2c+ICAgICAgPHBhdGggZmlsbD0nI0ZGRicgZD0nTTE4LjMyNSA1LjA1N0MxOS40ODIgMy43MTggMjAuMjYgMS44NTQgMjAuMDQ1IDBjLTEuNjYzLjA2My0zLjY3NiAxLjA2Mi00Ljg3IDIuNC0xLjA3IDEuMTg1LTIuMDA4IDMuMDgzLTEuNzUzIDQuODk5IDEuODU1LjEzNyAzLjc0OC0uOTAyIDQuOTAzLTIuMjQyJy8+ICAgIDwvZz4gIDwvZz48L3N2Zz4=', - android: 'data:image/svg+xml;charset=utf-8;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHhtbG5zOnhsaW5rPSdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rJyB3aWR0aD0nNDAnIGhlaWdodD0nNDAnIHZpZXdCb3g9JzAgMCA0MCA0MCc+ICA8ZGVmcz4gICAgPHBhdGggaWQ9J2E2ODgxMDhmLTMwOWYtNGUxOC1hMGRjLWVkMDI2NzQxZmExMi1hJyBkPSdNMCAwaDMzLjY4NHYxOC45NDdIMHonLz4gIDwvZGVmcz4gIDxnIGZpbGw9J25vbmUnIGZpbGwtcnVsZT0nZXZlbm9kZCc+ICAgIDxwYXRoIGQ9J00wIDBoNDB2NDBIMHonLz4gICAgPGcgb3BhY2l0eT0nMScgdHJhbnNmb3JtPSd0cmFuc2xhdGUoMy4xNTggMTEuMTU4KSc+ICAgICAgPG1hc2sgaWQ9J2E2ODgxMDhmLTMwOWYtNGUxOC1hMGRjLWVkMDI2NzQxZmExMi1iJyBmaWxsPScjZmZmJz4gICAgICAgIDx1c2UgeGxpbms6aHJlZj0nI2E2ODgxMDhmLTMwOWYtNGUxOC1hMGRjLWVkMDI2NzQxZmExMi1hJy8+ICAgICAgPC9tYXNrPiAgICAgIDxwYXRoIGZpbGw9JyNGRkYnIGQ9J00yNC41OTQgMTQuMTU2YTEuNDAyIDEuNDAyIDAgMSAxLS4wMDMtMi44MDMgMS40MDIgMS40MDIgMCAwIDEgLjAwMyAyLjgwM20tMTUuNTA0IDBhMS40MDIgMS40MDIgMCAxIDEtLjAwMi0yLjgwMyAxLjQwMiAxLjQwMiAwIDAgMSAuMDAyIDIuODAzTTI1LjA5NyA1LjcyTDI3LjkuODc0YS41ODQuNTg0IDAgMCAwLTEuMDEtLjU4M0wyNC4wNSA1LjJjLTIuMTctLjk4OS00LjYwOC0xLjU0LTcuMjEtMS41NC0yLjYgMC01LjAzOC41NTItNy4yMDkgMS41NEw2Ljc5NC4yOTFhLjU4NC41ODQgMCAwIDAtMS4wMS41ODJsMi44MDMgNC44NDhDMy43NzQgOC4zMzUuNDgyIDEzLjIgMCAxOC45NDdoMzMuNjg0QzMzLjIwMiAxMy4yIDI5LjkxIDguMzM1IDI1LjA5NyA1LjcyMScgbWFzaz0ndXJsKCNhNjg4MTA4Zi0zMDlmLTRlMTgtYTBkYy1lZDAyNjc0MWZhMTItYiknLz4gICAgPC9nPiAgPC9nPjwvc3ZnPg==', - }; - - function applyPlatformIcons() { - var iconEls = document.querySelectorAll('[data-platform-icon]'); - iconEls.forEach(function(el) { - var key = el.getAttribute('data-platform-icon'); - var src = PLATFORM_ICONS[key]; - if (src) el.src = src; - }); - } - - applyPlatformIcons(); - - var API_BASE = 'http://ddns.shenjack.top:10003'; - - var mockData = { - totalViews: 89274129, - todayViews: 62396, - harmonyTotalViews: 935082, - }; - - var updateTime = '2026-04-17T11:18:11Z'; - - function updateTimestamp() { - var noteEl = document.querySelector('.metrics-note'); - if (noteEl) { - noteEl.innerHTML = noteEl.innerHTML.replace(/\{\{updateTime\}\}/g, updateTime); - } - } - updateTimestamp(); - - function fetchStatistics() { - return Promise.all([ - fetch(API_BASE + '/api/v0/statistics/today_access').then(function(res) { - console.log('today_access status:', res.status); - return res.json(); - }), - fetch(API_BASE + '/api/v0/statistics/top_rayawa_access').then(function(res) { - console.log('top_rayawa_access status:', res.status); - return res.json(); - }), - fetch(API_BASE + '/api/v0/statistics/total_access').then(function(res) { - console.log('total_access status:', res.status); - return res.json(); - }) - ]).then(function(results) { - console.log('API results:', results); - var data = { - todayViews: typeof results[0] === 'number' ? results[0] : results[0].count || results[0].value || 0, - harmonyTotalViews: typeof results[1] === 'number' ? results[1] : results[1].count || results[1].value || 0, - totalViews: typeof results[2] === 'number' ? results[2] : results[2].count || results[2].value || 0 - }; - console.log('Parsed data:', data); - // return data; - return mockData; ///api错误 - }).catch(function(error) { - console.error('API fetch error:', error); - return mockData; - }); - } - - var prefersReducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; - - function formatNumber(value) { - return new Intl.NumberFormat().format(Math.max(0, Math.floor(value))); - } - - function animateCounter(el, target, duration) { - if (!el) return; - if (prefersReducedMotion) { - el.textContent = formatNumber(target); - return; - } - - var start = 0; - var startTime = performance.now(); - - function frame(now) { - var progress = Math.min((now - startTime) / duration, 1); - var eased = 1 - Math.pow(1 - progress, 3); - var value = start + (target - start) * eased; - el.textContent = formatNumber(value); - if (progress < 1) { - requestAnimationFrame(frame); - } else { - el.textContent = formatNumber(target); - } - } - - requestAnimationFrame(frame); - } - - var items = Array.from(metricsEl.querySelectorAll('.metric-value')); - items.forEach(function(el) { - el.textContent = '0'; - }); - - var started = false; - function startCounters(data) { - if (started) return; - started = true; - items.forEach(function(el, index) { - var key = el.getAttribute('data-counter-key'); - var fallback = Number(el.getAttribute('data-counter-fallback')) || 0; - var target = (data && Object.prototype.hasOwnProperty.call(data, key)) ? data[key] : fallback; - el.setAttribute('data-counter-target', String(target)); - var duration = 1200 + index * 320; - animateCounter(el, target, duration); - }); - } - - fetchStatistics().then(function(data) { - var observer = new IntersectionObserver(function(entries) { - entries.forEach(function(entry) { - if (entry.isIntersecting) { - startCounters(data); - observer.disconnect(); - } - }); - }, { threshold: 0.26 }); - - observer.observe(metricsEl); - }); -})(); diff --git a/static/js/footer.js b/static/js/footer.js index e23a6b6..78d82ee 100644 --- a/static/js/footer.js +++ b/static/js/footer.js @@ -18,48 +18,54 @@ var FOOTER_TEXT = { zh: { - description: '记录开发、研究与生活。', + description: 'Ray汐 · 清霁Ray · Rayawa', thanksLink: '致谢', projects: '项目', life: '生活', - copy: '© 2024 Ray Chen. All Rights Reserved.', - projectHmdb: '鸿蒙应用看板', + copy: '© 2026 Ray Chen. All Rights Reserved.', + projectHmdb: '华为应用市场看板', projectBio: '生物学项目', + projectSignal: '微弱电信号测量', + projectSmartShed: '智慧大棚 SmartShed', + projectRps: '石头剪刀布检测', projectSpm: '烤地瓜模组', projectOhos: 'Hi3861 开发', - projectSignal: 'Signal', lifeGallery: '摄影与生活', lifePiano: '钢琴', lifeDrawing: '绘画', lifeBooks: '书单' }, en: { - description: 'Notes on development, research, and life.', + description: 'Ray汐 · 清霁Ray · Rayawa', thanksLink: 'Thanks', projects: 'Projects', life: 'Life', - copy: '© 2024 Ray Chen. All Rights Reserved.', - projectHmdb: 'HarmonyOS Dashboard', + copy: '© 2026 Ray Chen. All Rights Reserved.', + projectHmdb: 'Harmony Gallery', projectBio: 'Biology Projects', + projectSignal: 'Weak Signal Measurement', + projectSmartShed: 'SmartShed', + projectRps: 'Rock Paper Scissors Detection', projectSpm: 'Sweet Potato Mod', projectOhos: 'Hi3861 Development', - projectSignal: 'Signal', lifeGallery: 'Photography', lifePiano: 'Piano', lifeDrawing: 'Drawing', lifeBooks: 'Books' }, fr: { - description: 'Carnets de développement, de recherche et de vie.', + description: 'Ray汐 · 清霁Ray · Rayawa', thanksLink: 'Remerciements', projects: 'Projets', life: 'Vie', - copy: '© 2024 Ray Chen. Tous droits réservés.', - projectHmdb: 'Tableau de bord HarmonyOS', + copy: '© 2026 Ray Chen. Tous droits réservés.', + projectHmdb: 'Gallery Huawei', projectBio: 'Projets de biologie', + projectSignal: 'Mesure de signaux faibles', + projectSmartShed: 'SmartShed', + projectRps: 'Détection Pierre-Papier-Ciseaux', projectSpm: 'Mod Patate douce', projectOhos: 'Développement Hi3861', - projectSignal: 'Signal', lifeGallery: 'Photographie', lifePiano: 'Piano', lifeDrawing: 'Dessin', @@ -96,17 +102,18 @@ '@media(max-width:768px){.footer-content{align-items:flex-start;gap:.8rem}.footer-social-link{width:44px;height:44px}.copyright{gap:.2rem}}'; var projectLinks = [ - { href: prefix + langPrefix + 'dashboard.html', text: t.projectHmdb }, + { href: 'https://dashboard.rayawa.top', text: t.projectHmdb }, { href: prefix + langPrefix + 'projects/biology.html', text: t.projectBio }, + { href: prefix + langPrefix + 'projects/signal.html', text: t.projectSignal }, + { href: prefix + langPrefix + 'projects/SmartShed.html', text: t.projectSmartShed }, + { href: prefix + langPrefix + 'projects/RockPaperSissors.html', text: t.projectRps }, { href: prefix + langPrefix + 'projects/spm.html', text: t.projectSpm }, - { href: prefix + langPrefix + 'projects/Hi3861.html', text: t.projectOhos }, - { href: prefix + langPrefix + 'projects/signal.html', text: t.projectSignal } + { href: prefix + langPrefix + 'projects/Hi3861.html', text: t.projectOhos } ]; var lifeLinks = [ { href: prefix + langPrefix + 'index.html#gallery', text: t.lifeGallery }, { href: prefix + 'life/piano.html', text: t.lifePiano }, - { href: prefix + 'life/drawing.html', text: t.lifeDrawing }, { href: prefix + 'life/books.html', text: t.lifeBooks } ]; diff --git a/static/js/home.js b/static/js/index.js similarity index 71% rename from static/js/home.js rename to static/js/index.js index d536ca5..af02ebc 100644 --- a/static/js/home.js +++ b/static/js/index.js @@ -228,41 +228,6 @@ function initLanguageSwitcher() { }); } -function initNavbarScroll() { - const navbar = document.getElementById('navbar'); - if (!navbar) return; - window.addEventListener('scroll', () => { - navbar.classList.toggle('scrolled', window.scrollY > 50); - }, { passive: true }); - navbar.classList.toggle('scrolled', window.scrollY > 50); -} - -function initSmoothScroll() { - document.querySelectorAll('a[href^="#"]').forEach((anchor) => { - anchor.addEventListener('click', (e) => { - const targetId = anchor.getAttribute('href'); - if (!targetId || targetId === '#') return; - e.preventDefault(); - const targetElement = document.querySelector(targetId); - if (!targetElement) return; - targetElement.scrollIntoView({ behavior: 'smooth' }); - }); - }); - - function scrollToHash() { - const hash = window.location.hash; - if (!hash || hash === '#') return; - const target = document.querySelector(hash); - if (!target) return; - window.setTimeout(() => { - target.scrollIntoView({ behavior: 'smooth' }); - }, 300); - } - - window.addEventListener('loadingScreenDone', scrollToHash); - window.setTimeout(scrollToHash, 3000); -} - function initContactForm() { const form = document.getElementById('contactForm'); if (!form) return; @@ -344,66 +309,6 @@ function initContactForm() { }); } -function initMobileMenu() { - const mobileMenuBtn = document.getElementById('mobileMenuBtn'); - const navLinks = document.querySelector('.nav-links'); - if (!mobileMenuBtn || !navLinks) return; - - let overlay = document.querySelector('.mobile-overlay'); - if (!overlay) { - overlay = document.createElement('div'); - overlay.className = 'mobile-overlay'; - document.body.appendChild(overlay); - } - - function closeMenu() { - navLinks.classList.remove('mobile-open'); - mobileMenuBtn.setAttribute('aria-expanded', 'false'); - overlay.classList.remove('is-visible'); - } - - function openMenu() { - navLinks.classList.add('mobile-open'); - mobileMenuBtn.setAttribute('aria-expanded', 'true'); - overlay.classList.add('is-visible'); - } - - mobileMenuBtn.addEventListener('click', (e) => { - e.stopPropagation(); - if (navLinks.classList.contains('mobile-open')) { - closeMenu(); - } else { - openMenu(); - } - }); - - navLinks.addEventListener('click', (e) => { - e.stopPropagation(); - }); - - navLinks.querySelectorAll('a').forEach((link) => { - link.addEventListener('click', () => { - if (window.innerWidth <= 900) { - closeMenu(); - } - }); - }); - - overlay.addEventListener('click', closeMenu); - - document.addEventListener('click', (e) => { - if (navLinks.classList.contains('mobile-open') && !navLinks.contains(e.target) && !mobileMenuBtn.contains(e.target)) { - closeMenu(); - } - }); - - window.addEventListener('resize', () => { - if (window.innerWidth > 900) { - closeMenu(); - } - }); -} - function initGalleryCarousel() { const carousel = document.getElementById('galleryCarousel'); if (!carousel) return; @@ -421,12 +326,13 @@ function initGalleryCarousel() { let timer = null; let autoStarted = false; + const dotLabelTpl = t.dotLabel || '第 {n} 张'; const dots = slides.map((_, idx) => { const dot = document.createElement('button'); dot.type = 'button'; dot.className = 'gallery-dot' + (idx === 0 ? ' active' : ''); dot.dataset.index = String(idx + 1); - dot.setAttribute('aria-label', t.dotLabel.replace('{n}', String(idx + 1))); + dot.setAttribute('aria-label', dotLabelTpl.replace('{n}', String(idx + 1))); dot.addEventListener('click', () => { goTo(idx); restart(); @@ -436,9 +342,10 @@ function initGalleryCarousel() { }); galleryA11yUpdater = () => { + const dotLabelTpl2 = t.dotLabel || '第 {n} 张'; dots.forEach((dot) => { const idx = dot.dataset.index || '1'; - dot.setAttribute('aria-label', t.dotLabel.replace('{n}', idx)); + dot.setAttribute('aria-label', dotLabelTpl2.replace('{n}', idx)); }); prevBtn.setAttribute('aria-label', locale === 'zh' ? '上一张' : locale === 'fr' ? 'Precedent' : 'Previous'); nextBtn.setAttribute('aria-label', locale === 'zh' ? '下一张' : locale === 'fr' ? 'Suivant' : 'Next'); @@ -740,8 +647,8 @@ function initParticlePointerFollow() { } function animate() { - currentX += (targetX - currentX) * 0.08; - currentY += (targetY - currentY) * 0.08; + currentX += (targetX - currentX) * 0.03; + currentY += (targetY - currentY) * 0.03; layer.style.transform = `translate3d(${currentX}px, ${currentY}px, 0)`; window.requestAnimationFrame(animate); } @@ -769,207 +676,6 @@ function initParticlePointerFollow() { animate(); } -function initParticleMagnetEffect() { - const maxRetry = 30; - let retry = 0; - - function boot() { - if (!window.pJSDom || !window.pJSDom.length) return false; - const instance = window.pJSDom[0] && window.pJSDom[0].pJS; - if (!instance || !instance.particles || !instance.particles.array || !instance.canvas || !instance.canvas.el) { - return false; - } - - const particles = instance.particles.array; - const canvasEl = instance.canvas.el; - const pointer = { x: 0, y: 0, active: false }; - const radius = 236; - const strength = 0.00126; - const damping = 0.988; - const maxSpeed = 4.25; - const sparseRadius = 96; - const sparseThreshold = 1; - const minParticles = 58; - let magneticPower = 0; - let frame = 0; - - function getOpacityValue(particle) { - if (particle && particle.opacity && typeof particle.opacity.value === 'number') return particle.opacity.value; - if (particle && typeof particle.opacity === 'number') return particle.opacity; - return 0.5; - } - - function setOpacityValue(particle, value) { - const next = Math.max(0, Math.min(1, value)); - if (particle && particle.opacity && typeof particle.opacity.value === 'number') { - particle.opacity.value = next; - return; - } - if (particle) particle.opacity = next; - } - - function spawnParticleAt(x, y) { - if (!instance.fn || !instance.fn.modes || typeof instance.fn.modes.pushParticles !== 'function') return; - instance.fn.modes.pushParticles(1, { pos_x: x, pos_y: y }); - - const p = particles[particles.length - 1]; - if (!p) return; - p.__generated = true; - p.__fadeIn = true; - p.__ttl = 520 + Math.floor(Math.random() * 520); - p.__fadeOut = false; - p.vx = (Math.random() - 0.5) * 0.8; - p.vy = (Math.random() - 0.5) * 0.8; - setOpacityValue(p, 0.04); - } - - function countParticlesNear(x, y, r) { - let count = 0; - const rSq = r * r; - for (let i = 0; i < particles.length; i += 1) { - const p = particles[i]; - const dx = p.x - x; - const dy = p.y - y; - if (dx * dx + dy * dy <= rSq) count += 1; - } - return count; - } - - function maintainSparseRegions() { - const width = instance.canvas.w || canvasEl.width || window.innerWidth; - const height = instance.canvas.h || canvasEl.height || window.innerHeight; - for (let i = 0; i < 2; i += 1) { - const x = Math.random() * width; - const y = Math.random() * height; - if (countParticlesNear(x, y, sparseRadius) <= sparseThreshold) { - spawnParticleAt(x, y); - } - } - - if (particles.length > minParticles && Math.random() < 0.1) { - const idx = Math.floor(Math.random() * particles.length); - const p = particles[idx]; - if (p && !p.__fadeOut && !p.__fadeIn) { - p.__fadeOut = true; - } - } - } - - function setPointer(clientX, clientY) { - const rect = canvasEl.getBoundingClientRect(); - if (rect.width <= 0 || rect.height <= 0) return; - if (clientX < rect.left || clientX > rect.right || clientY < rect.top || clientY > rect.bottom) { - pointer.active = false; - return; - } - - const pxWidth = instance.canvas.w || canvasEl.width || rect.width; - const pxHeight = instance.canvas.h || canvasEl.height || rect.height; - const scaleX = pxWidth / rect.width; - const scaleY = pxHeight / rect.height; - pointer.x = (clientX - rect.left) * scaleX; - pointer.y = (clientY - rect.top) * scaleY; - pointer.active = true; - } - - window.addEventListener('pointermove', (e) => { - setPointer(e.clientX, e.clientY); - }, { passive: true }); - - window.addEventListener('touchmove', (e) => { - const touch = e.touches && e.touches[0]; - if (!touch) return; - setPointer(touch.clientX, touch.clientY); - }, { passive: true }); - - window.addEventListener('pointerleave', () => { - pointer.active = false; - }, { passive: true }); - - window.addEventListener('touchend', () => { - pointer.active = false; - }, { passive: true }); - - function tick() { - frame += 1; - magneticPower += pointer.active - ? (1 - magneticPower) * 0.14 - : (0 - magneticPower) * 0.012; - - if (magneticPower > 0.001 && particles.length) { - for (let i = 0; i < particles.length; i += 1) { - const p = particles[i]; - const dx = pointer.x - p.x; - const dy = pointer.y - p.y; - const distSq = dx * dx + dy * dy; - if (distSq <= 1) continue; - - const dist = Math.sqrt(distSq); - if (dist > radius) continue; - - const normalized = 1 - dist / radius; - const pull = normalized * normalized * strength * magneticPower; - p.vx += dx * pull; - p.vy += dy * pull; - - const speed = Math.sqrt(p.vx * p.vx + p.vy * p.vy); - if (speed > maxSpeed) { - const scale = maxSpeed / speed; - p.vx *= scale; - p.vy *= scale; - } - } - } - - for (let i = particles.length - 1; i >= 0; i -= 1) { - const p = particles[i]; - if (typeof p.vx !== 'number') p.vx = 0; - if (typeof p.vy !== 'number') p.vy = 0; - p.vx *= damping; - p.vy *= damping; - - if (p.__generated && typeof p.__ttl === 'number') { - p.__ttl -= 1; - if (p.__ttl <= 0) p.__fadeOut = true; - } - - if (p.__fadeIn) { - const next = getOpacityValue(p) + 0.011; - setOpacityValue(p, next); - if (next >= 0.5) p.__fadeIn = false; - } - - if (p.__fadeOut) { - const next = getOpacityValue(p) - 0.004; - if (next <= 0.008) { - particles.splice(i, 1); - continue; - } - setOpacityValue(p, next); - } - } - - if (frame % 12 === 0) { - maintainSparseRegions(); - } - - window.requestAnimationFrame(tick); - } - - tick(); - return true; - } - - if (boot()) return; - - const timer = window.setInterval(() => { - retry += 1; - if (boot() || retry >= maxRetry) { - window.clearInterval(timer); - } - }, 120); -} - function initHeroStarInteraction() { const star = document.getElementById('heroStar'); if (!star) return; @@ -1085,16 +791,13 @@ initLanguageSwitcher(); setLocale(locale, { persist: false }); hydrateRevealItems(); initParticles(); -initNavbarScroll(); -initSmoothScroll(); initContactForm(); -initMobileMenu(); initGalleryCarousel(); initSectionReveal(); initPageLeaveTransitions(); requestAnimationFrame(() => { initParticlePointerFollow(); - initParticleMagnetEffect(); + if (typeof initParticleMagnetEffect === 'function') initParticleMagnetEffect(); }); initHeroStarInteraction(); initAwardLinks(); diff --git a/static/js/navbar.js b/static/js/navbar.js index dc66099..10662cf 100644 --- a/static/js/navbar.js +++ b/static/js/navbar.js @@ -16,9 +16,9 @@ var langPrefix = langDir ? langDir + '/' : ''; var NAV_TEXT = { - zh: { home: '首页', about: '关于我', projects: '项目', gallery: '摄影与生活', contact: '联系' }, - en: { home: 'Home', about: 'About Me', projects: 'Projects', gallery: 'Photography', contact: 'Contact' }, - fr: { home: 'Accueil', about: 'À propos de moi', projects: 'Projets', gallery: 'Photographie', contact: 'Contact' } + zh: { home: '首页', about: '关于我', projects: '项目', gallery: '摄影与生活', contact: '联系我' }, + en: { home: 'Home', about: 'About Me', projects: 'Projects', gallery: 'Gallery & Life', contact: 'Contact Me' }, + fr: { home: 'Accueil', about: 'À propos de moi', projects: 'Projets', gallery: 'Gallery & Vie', contact: 'Contact moi' } }; var texts = NAV_TEXT[langDir] || NAV_TEXT.zh; @@ -54,9 +54,9 @@ }).join('') + '' + '
' + - '中文' + - 'EN' + - 'FR' + + '中文中文' + + 'EnglishEN' + + 'FrançaisFR' + '
' + '' + '' + diff --git a/static/resources/.DS_Store b/static/resources/.DS_Store index d32d8bf..6a5389d 100644 Binary files a/static/resources/.DS_Store and b/static/resources/.DS_Store differ diff --git a/static/resources/bio/.DS_Store b/static/resources/bio/.DS_Store index eb7a8f9..abc6a9d 100644 Binary files a/static/resources/bio/.DS_Store and b/static/resources/bio/.DS_Store differ diff --git a/static/resources/bio/agrobacterium/README.md b/static/resources/bio/agrobacterium/README.md deleted file mode 100644 index e3ec39b..0000000 --- a/static/resources/bio/agrobacterium/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# 农杆菌转化法交互实验室 -### Ray Chen@2026. All rights reserved. -基于HTML5+JS+CSS开发的交互网页,旨在通过数字化手段直观展示农杆菌介导的植物基因转化过程。 - ---- - -### 📂 文件结构 - -项目采用模块化设计,将表现层、逻辑层与数据层分离,方便维护与扩展: - -* **`index.html`**:项目主入口,定义模拟器的 UI 结构。 -* **`style.css`**:定义网页视觉样式、布局以及实验动画效果。 -* **`script.js`**:核心逻辑脚本,负责交互控制、实验流程管理及动画触发。 -* **`favicon.ico`**:站点图标。 - ---- - -### 🚀 使用方法 - -本项目为纯前端实现,简单两步即可运行: - -1. **下载源码**:将本项目的所有文件下载并存放在同一个文件夹中。推荐使用zip下载后解压。 -2. **本地运行**:在文件夹中找到 **`index.html`**,双击使用浏览器(推荐 Chrome, Edge 或 Safari)打开即可开始交互实验。 - ---- - -### 💡 开发说明 - -* **国际化支持**:通过修改 `content.json` 中的字段,可以轻松实现多语言切换,无需改动 `index.html` 中的 HTML 标签。 -* **交互逻辑**:实验严格遵循农杆菌转化的生物学规律(如 Ti 质粒构建、侵染、T-DNA 整合等),并通过 `script.js` 确保步骤的逻辑正确性。 -* **轻量化**:不依赖任何第三方重量级框架,加载速度快,适合作为教学辅助工具。 diff --git a/static/resources/bio/agrobacterium/agrobacterium.html b/static/resources/bio/agrobacterium/agrobacterium.html deleted file mode 100644 index d640b9c..0000000 --- a/static/resources/bio/agrobacterium/agrobacterium.html +++ /dev/null @@ -1,347 +0,0 @@ - - - - - - - - 基因工程:农杆菌转化法交互实验室 - - - - - - - -
- -
- - - - - - - - - - -
- -
-
-
- -
- -
- -
- 探究用时 - 00:00 -
-
- -
- -
-
-
-
-

苏云金芽孢杆菌 (Bt)

-

目的基因供体

-
-
- - - -
- - - - -
- -
-
- -
-
-

土壤农杆菌

-

运载体来源

-
-
- - - -
- - - - -
- -
-
-
- -
- - - - - - - - - - - - - - -
提示消息
-
- -
-
请跟随引导思考并完成利用"农杆菌转化法"将抗虫基因导入棉花细胞的流程
- -
-
-
- - - - - - - - \ No newline at end of file diff --git a/static/resources/bio/agrobacterium/script.js b/static/resources/bio/agrobacterium/script.js deleted file mode 100644 index fca8e58..0000000 --- a/static/resources/bio/agrobacterium/script.js +++ /dev/null @@ -1,451 +0,0 @@ -let currentStep = 1; -let s2SelectedTools = new Set(); -let s2SelectedComps = new Set(); -let timeElapsed = 0; -let timerId = null; -let isTimerRunning = true; - -let state = { - 1: { bt: false, ti: false }, - 2: { inserted: false, validated: false, dragErrors: 0, selectErrors: 0 }, - 3: { agroConverted: false, plantInfected: false, dragErrors: 0 }, - 4: { done: false } -}; - -function showToast(text) { - const toast = document.getElementById('toast-msg'); - toast.innerText = text; - toast.style.opacity = "1"; - setTimeout(() => toast.style.opacity = "0", 3000); -} - -let typingTimer = null; -function typeWriter(text, speed = 20) { - const textBox = document.getElementById('hint-text'); - const icon = document.getElementById('hint-svg'); - if (!textBox || !icon) return; - - clearTimeout(typingTimer); - textBox.innerHTML = ""; - - icon.classList.add('gemini-loading'); - - let i = 0; - function typing() { - if (i < text.length) { - textBox.innerHTML += text.charAt(i); - i++; - typingTimer = setTimeout(typing, speed); - } else { - icon.classList.remove('gemini-loading'); - } - } - typing(); -} - -function clearHint() { - const textBox = document.getElementById('hint-text'); - const icon = document.getElementById('hint-svg'); - clearTimeout(typingTimer); - textBox.innerHTML = ""; - icon.classList.remove('spin'); -} - -window.onload = () => { - // 启动计时器 - timerId = setInterval(() => { - if (!isTimerRunning) return; - timeElapsed++; - const m = Math.floor(timeElapsed / 60); - const s = timeElapsed % 60; - document.getElementById('display-time').innerText = `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; - }, 1000); - - // 初始页面引导 - typeWriter("欢迎来到构建转基因抗虫棉实验。第一步:我们需要从相关细菌内获取基因和载体,请点击细胞进行获取。"); -}; - -function stopTimer() { - isTimerRunning = false; - clearInterval(timerId); -} - -/* --- STAGE 1 --- */ -function extractBt() { - if (state[1].bt) return; - const res = document.getElementById('bt-result'); - res.classList.remove('hidden'); - res.classList.add('extract-bt-anim'); - state[1].bt = true; - - typeWriter("已成功获取 Bt 抗虫基因,即将通过 PCR 技术完成扩增..."); - - setTimeout(() => { - typeWriter("Bt 基因扩增成功!"); - checkS1(); - }, 2000); -} - -function extractTi() { - if (state[1].ti) return; - const res = document.getElementById('ti-result'); - res.classList.remove('hidden'); - res.classList.add('extract-ti-anim'); - state[1].ti = true; - - typeWriter("已成功获取 Ti 质粒,即将通过 PCR 技术完成扩增..."); - - setTimeout(() => { - typeWriter("Ti 质粒扩增成功!"); - checkS1(); - }, 2000); -} - -function checkS1() { - if (state[1].bt && state[1].ti) { - setTimeout(() => { - typeWriter("两种 PCR 扩增完成,点击“下一步”开始构建重组质粒!"); - }, 2000); - document.getElementById('submit-btn').disabled = false; - } -} - - -/* --- STAGE 2 --- */ - - -function allowDrop(ev) { - ev.preventDefault(); -} - -function onS2DragStart(ev) { - ev.dataTransfer.setData("type", "bt-gene"); - typeWriter("正在移动Bt基因,请将其精准拖入Ti质粒的T-DNA区域(橙色部分)。"); -} - -function handleS2Insertion(ev) { - ev.preventDefault(); - const dataType = ev.dataTransfer.getData("type"); - if (dataType === "bt-gene") { - state[2].inserted = true; - const btGene = document.getElementById('bt-green-gene'); - if (btGene) btGene.classList.add('invisible'); - - const tdnaCore = document.getElementById('tdna-core'); - if (!tdnaCore) return; - - const svgns = "http://www.w3.org/2000/svg"; - const svgElement = tdnaCore.ownerSVGElement; - - if (document.getElementById('bt-inserted-segment')) return; - - const originalDashArray = tdnaCore.getAttribute('stroke-dasharray').split(' '); - const originalSolidLength = parseFloat(originalDashArray[0]); - const originalDashOffset = parseFloat(tdnaCore.getAttribute('stroke-dashoffset')); - - const greenPercent = 0.4; - const greenSolidLength = originalSolidLength * greenPercent; - const greenDashOffset = originalDashOffset - (originalSolidLength - greenSolidLength) / 2; - - const btSegment = document.createElementNS(svgns, "circle"); - btSegment.setAttribute("cx", tdnaCore.getAttribute("cx")); - btSegment.setAttribute("cy", tdnaCore.getAttribute("cy")); - btSegment.setAttribute("r", tdnaCore.getAttribute("r")); - btSegment.setAttribute("fill", "none"); - btSegment.setAttribute("stroke", "#22c55e"); - btSegment.setAttribute("stroke-width", "20"); - btSegment.setAttribute("stroke-dasharray", `${greenSolidLength} ${originalSolidLength * 5}`); - btSegment.setAttribute("stroke-dashoffset", greenDashOffset.toString()); - btSegment.setAttribute("id", "bt-inserted-segment"); - btSegment.classList.add('animate-pulse'); - - svgElement.appendChild(btSegment); - - const guide = document.getElementById('s2-guide'); - if (guide) { - guide.classList.remove('hidden', 'text-red-600'); - guide.classList.add('text-green-600', 'font-bold'); - typeWriter("完美!Bt基因已成功插入T-DNA。现在请向下滚动,选择完成重组质粒构建所需的酶。"); - } - - setTimeout(() => { - if (typeof initS2Components === 'function') { - initS2Components(); - } - const phase2 = document.getElementById('s2-phase-2'); - if (phase2) { - phase2.classList.remove('hidden'); - phase2.scrollIntoView({ behavior: 'smooth' }); - } - }, 1000); - } -} - -function handleS2WrongDrop(ev) { - ev.preventDefault(); - const dataType = ev.dataTransfer.getData("type"); - if (dataType === "bt-gene") { - state[2].dragErrors++; - const guide = document.getElementById('s2-guide'); - guide.classList.remove('hidden', 'text-green-600'); - guide.classList.add('text-red-600', 'font-bold', 'animate-bounce'); - typeWriter("位置错误!Bt基因必须插入到T-DNA片段中,才能在之后转移至植物基因组。"); - setTimeout(() => guide.classList.remove('animate-bounce'), 500); - } -} - -function initS2Components() { const comps = ["启动子", "终止子", "标记基因", "复制原点", "内含子", "起始密码子"]; const container = document.getElementById('comp-container'); container.innerHTML = ''; comps.forEach(c => { const btn = document.createElement('button'); btn.className = "component-btn"; btn.innerText = c; btn.onclick = () => { if (s2SelectedComps.has(c)) { s2SelectedComps.delete(c); btn.classList.remove('selected'); } else { s2SelectedComps.add(c); btn.classList.add('selected'); } }; container.appendChild(btn); }); } - -function checkFinalS2() { - const required = ["启动子", "终止子", "标记基因", "复制原点"]; - const missing = required.filter(x => !s2SelectedComps.has(x)); - const extra = Array.from(s2SelectedComps).filter(x => !required.includes(x)); - - const guide = document.getElementById('s2-guide'); - guide.classList.remove('hidden'); - - if (missing.length === 0 && extra.length === 0) { - typeWriter("工具选择完全正确!重组Ti质粒构建完成。现在可以进入转化阶段。"); - - state[2].validated = true; - const submitBtn = document.getElementById('submit-btn'); - if (submitBtn) submitBtn.disabled = false; - - } else if (missing.length > 0) { - state[2].selectErrors++; - typeWriter(`还差一点!你似乎漏掉了关键的工具:${missing.join('、')}。请重新检查。`); - - state[2].validated = false; - } else if (extra.length > 0) { - state[2].selectErrors++; - typeWriter(`工具选多了!${extra.join('、')}在这个过程中是不需要的,请取消勾选。`); - state[2].validated = false; - } -} - -/* --- STAGE 3 --- */ -function onS3Drag(ev) { - ev.dataTransfer.setData("type", "full-plasmid"); -} - -function onS3Drop(ev, target) { - ev.preventDefault(); - const type = ev.dataTransfer.getData("type"); - - // 错误处理:直接选植物 - if (target === 'plant') { - state[3].dragErrors++; - typeWriter("❌ 操作失败!重组Ti质粒无法直接进入植物细胞。必须先通过农杆菌进行转化。"); - // 视觉抖动提示 - document.getElementById('target-plant').classList.add('animate-shake'); - setTimeout(() => document.getElementById('target-plant').classList.remove('animate-shake'), 500); - return; - } - - // 正确处理:选择农杆菌 - if (target === 'agro') { - document.getElementById('source-plasmid-container').classList.add('invisible'); - document.getElementById('agro-plasmid-inner').classList.remove('hidden'); - document.getElementById('target-agro').classList.replace('border-dashed', 'border-solid'); - document.getElementById('target-agro').classList.add('bg-emerald-100'); - - typeWriter("✅ 成功!重组Ti质粒已进入农杆菌。现在利用农杆菌的侵染特性,将基因送入植物细胞。"); - - setTimeout(() => { - document.getElementById('btn-infect').classList.remove('hidden'); - }, 800); - } -} - -function startInfection() { - document.getElementById('btn-infect').classList.add('hidden'); - const tdna = document.getElementById('flying-tdna'); - const agroInner = document.getElementById('agro-plasmid-inner'); - - agroInner.classList.add('animate-pulse'); - typeWriter("农杆菌正在感应植物信号... 注意!只有 T-DNA(橙色部分)会脱离质粒进入植物。"); - - setTimeout(() => { - tdna.classList.remove('hidden'); - - tdna.animate([ - { left: '-120px', opacity: 1, transform: 'scale(1.2)' }, - { left: '40px', opacity: 1, transform: 'scale(0.8)' } - ], { - duration: 2000, - easing: 'ease-in-out', - fill: 'forwards' - }).onfinish = () => { - // 4. 最终状态:橙色整合进染色体 - tdna.style.display = 'none'; - const chr = document.getElementById('chromosome'); - - chr.classList.replace('bg-slate-200', 'bg-orange-500'); - chr.classList.add('shadow-[0_0_10px_#f59e0b]'); - - typeWriter("✨ 转化完成!我们已获得含有重组Ti质粒的农杆菌!接下来将会发生什么?"); - document.getElementById('submit-btn').disabled = false; - }; - }, 1000); -}; - - -/* --- STAGE 4 --- */ -function runChecks() { - const c1 = document.getElementById('check-1'); - const c2 = document.getElementById('check-2'); - c1.innerHTML = ` -

分子水平检测

-
-

PCR技术 (DNA检测)

-

检测中...

-
-
-

抗原-抗体杂交 (蛋白质检测)

-

检测中...

-
- `; - typeWriter("正在进行分子水平检测,通过PCR确认基因存在,通过抗体检测确认杀虫蛋白已表达..."); - - setTimeout(() => { - document.getElementById('pcr-status').innerText = "检测结果:阳性 (基因已整合)"; - document.getElementById('pcr-status').classList.replace('text-blue-500', 'text-green-600'); - }, 1200); - - setTimeout(() => { - document.getElementById('wb-status').innerText = "检测结果:阳性 (蛋白已表达)"; - document.getElementById('wb-status').classList.replace('text-blue-500', 'text-green-600'); - c1.classList.add('done'); - typeWriter("分子检测通过!最后进行个体水平的抗虫鉴定:将棉铃虫放入培养瓶。"); - }, 2000); - - setTimeout(() => { - c2.innerHTML = ` -

抗性鉴定 (棉铃虫接种)

-
-
-

对照组

-
🍃
-
🐛
-

接种中...

-
-
-

实验组(Bt)

-
🌿
-
🐛
-

接种中...

-
-
- `; - c2.classList.add('done'); - const wormNormal = document.getElementById('worm-normal'); - const wormGM = document.getElementById('worm-gm'); - - let step = 0; - const interval = setInterval(() => { - step += 3; - const wiggle = Math.sin(step / 5) * 3; - wormNormal.style.transform = `translateY(-${step}px) translateX(${wiggle}px)`; - wormGM.style.transform = `translateY(-${step}px) translateX(${wiggle}px)`; - }, 100); - - setTimeout(() => { - clearInterval(interval); - document.getElementById('normal-status').innerText = "叶片被大量啃食"; - document.getElementById('normal-status').classList.add('text-red-500'); - wormGM.innerText = "💀"; - document.getElementById('gm-status').innerText = "幼虫死亡,叶片完好"; - document.getElementById('gm-status').classList.add('text-green-600'); - typeWriter("实验成功!抗虫棉表现出显著的抗性。你可以点击提交查看成绩了。"); - }, 2000); - - setTimeout(() => { - state[4].done = true; - stopTimer(); - document.getElementById('submit-btn').disabled = false; - document.getElementById('submit-btn').innerText = "提交实验报告"; - }, 2800); - }, 3200); -} - -function nextStage() { - if (currentStep === 1) jumpTo(2); - else if (currentStep === 2) jumpTo(3); - else if (currentStep === 3) jumpTo(4); - else if (currentStep === 4) document.getElementById('quiz-modal').classList.remove('hidden'); -} - -function jumpTo(n) { - clearHint(); - currentStep = n; - document.querySelectorAll('.stage-content').forEach(s => s.classList.add('hidden')); - document.getElementById('stage-' + n).classList.remove('hidden'); - document.querySelectorAll('.flow-step').forEach(s => s.classList.remove('active')); - document.getElementById('nav-' + n).classList.add('active'); - document.getElementById('submit-btn').disabled = true; - - // 阶段切换引导 - if (n === 1) typeWriter("第一步:提取目的基因与质粒。点击细菌内部的遗传物质进行提取。"); - if (n === 2) typeWriter("第二步:构建基因表达载体。请将Bt基因拖入Ti质粒的橙色T-DNA区段,并选出构建所需的酶。"); - if (n === 3) typeWriter("第三步:我们需要将重组Ti质粒导入受体细胞。请选择下一步最合适的受体细胞。请以拖拽的方式将抗虫基因导入植物细胞!"); - if (n === 4) { - typeWriter("第四步:组织培养与筛选。棉花细胞正在通过脱分化形成愈伤组织,随后再分化成完整植株..."); - const leaf = document.getElementById('p4-leaf'); - const callus = document.getElementById('p4-callus'); - const plantlet = document.getElementById('p4-plantlet'); - const status = document.getElementById('p4-status'); - - leaf.style.opacity = "1"; - status.innerText = "正在脱分化..."; - setTimeout(() => { - leaf.classList.add('hidden'); - callus.classList.remove('hidden'); - status.innerText = "愈伤组织形成中..."; - }, 1200); - setTimeout(() => { - callus.style.transform = "scale(1.2)"; - status.innerText = "正在再分化..."; - }, 2200); - setTimeout(() => { - callus.classList.add('hidden'); - plantlet.classList.remove('hidden'); - plantlet.style.transform = "scale(0.7)"; - status.innerText = "获得再生植株"; - }, 3200); - setTimeout(() => { - document.getElementById('p4-overlay').classList.add('hidden'); - document.getElementById('p4-start-test').classList.remove('hidden'); - typeWriter("植株已再生。现在点击“开始鉴定”按钮,验证转基因是否成功。"); - }, 4200); - } -} - -function handleQuiz(btn, correct) { - if (correct) { - btn.classList.add('bg-green-100', 'border-green-500', 'text-green-700'); - typeWriter("回答正确!T-DNA具有可转移并整合到受体细胞染色体DNA上的特性。"); - } else { - btn.classList.add('bg-red-100', 'border-red-500', 'text-red-700'); - typeWriter("回答错误。请回想一下,农杆菌转化法中真正进入植物细胞核的是哪一部分?"); - } -} - -function finishAll() { - document.getElementById('quiz-modal').classList.add('hidden'); - document.getElementById('final-modal').classList.remove('hidden'); - - // 获取计时 - const finalTime = document.getElementById('display-time').innerText; - - // 渲染最终得分报告 - const statsHtml = ` -
-

⏱️ 实验总用时:${finalTime}

-

❌ 载体构建拖拽错误:${state[2].dragErrors}

-

📝 载体组件选择错误:${state[2].selectErrors}

-

🔄 转化路径操作错误:${state[3].dragErrors}

-
- `; - - document.getElementById('time-stats').innerHTML = statsHtml; -} \ No newline at end of file diff --git a/static/resources/bio/agrobacterium/style.css b/static/resources/bio/agrobacterium/style.css deleted file mode 100644 index 5c2d54d..0000000 --- a/static/resources/bio/agrobacterium/style.css +++ /dev/null @@ -1,287 +0,0 @@ -/* style.css (优化版) */ -@import url('https://cdn.tailwindcss.com'); - -/* -------- 动画和关键帧保持原样 -------- */ -.bt-inserted { - animation: scaleUp 0.5s ease forwards; -} - -#hint-svg { - transform-origin: center; - transition: transform 0.3s ease-out, opacity 0.3s ease-out; -} - -@keyframes gemini-thinking { - 0% { - transform: rotate(0deg) scale(1); - opacity: 0.8; - } - - 50% { - transform: rotate(180deg) scale(1.15); - opacity: 1; - } - - 100% { - transform: rotate(360deg) scale(1); - opacity: 0.8; - } -} - -.gemini-loading { - animation: gemini-thinking 1.5s linear infinite; -} - -@keyframes scaleUp { - 0% { - transform: scale(0); - opacity: 0; - } - - 100% { - transform: scale(1); - opacity: 1; - } -} - -@keyframes extract-bt { - 0% { - transform: translate(0, 0); - opacity: 1; - } - - 100% { - transform: translate(140px, -200px) scale(1.5); - } -} - -@keyframes extract-ti { - 0% { - transform: translate(0, 0); - opacity: 1; - } - - 100% { - transform: translate(-140px, -200px) scale(1.5); - } -} - -.extract-bt-anim { - animation: extract-bt 1s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -.extract-ti-anim { - animation: extract-ti 1s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275); -} - -/* -------- 流程导航优化 -------- */ -.flow-step { - flex: 1; - text-align: center; - padding: 12px 5px; - border-bottom: 4px solid #e2e8f0; - transition: all 0.3s; - font-size: 0.75rem; - color: #94a3b8; - cursor: pointer; - background-clip: padding-box; -} - -.flow-step.active { - border-bottom-color: #3b82f6; - color: #1e40af; - font-weight: bold; - background: #eff6ff; -} - -.flow-step.completed { - border-bottom-color: #10b981; - color: #065f46; -} - -/* -------- 细菌和植物细胞 -------- */ -.bacteria { - width: 100px; - height: 160px; - border-radius: 50px; - position: relative; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - cursor: pointer; - transition: transform 0.3s ease, box-shadow 0.3s ease; - border-width: 4px; - background-color: white; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); -} - -.bacteria:hover { - transform: scale(1.05); -} - -.plant-cell { - width: 140px; - height: 140px; - border: 4px solid #a8a29e; - background: #fafaf9; - border-radius: 20px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - position: relative; - transition: transform 0.3s ease, box-shadow 0.3s ease; - box-shadow: 0 1px 5px rgba(0, 0, 0, 0.06); -} - -.plasmid-in-cell { - position: absolute; - bottom: 12px; - left: 50%; - transform: translateX(-50%); - pointer-events: none; -} - -/* 核酸缠绕效果保持原样 */ -.nucleoid-tangle { - position: absolute; - top: 30px; - width: 60px; - height: 60px; - opacity: 0.4; - pointer-events: none; -} - -/* -------- 工具和组件按钮优化 -------- */ -.tool-btn { - padding: 4px 10px; - border: 1px solid #cbd5e1; - border-radius: 6px; - font-size: 11px; - background: white; - transition: all 0.2s ease; -} - -.tool-btn.selected { - background: #1e293b; - color: white; -} - -.component-btn { - padding: 6px 14px; - border: 2px solid #e2e8f0; - border-radius: 999px; - font-size: 12px; - cursor: pointer; - background: white; - transition: all 0.2s ease; -} - -.component-btn.selected { - border-color: #3b82f6; - background: #3b82f6; - color: white; -} - -/* -------- 引导框优化 -------- */ -.guide-box { - background: #f8fafc; - border-left: 4px solid #3b82f6; - padding: 14px; - margin-top: 10px; - border-radius: 0 8px 8px 0; - font-size: 13px; - line-height: 1.4; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); -} - -/* -------- 培养物和检测 -------- */ -.callus { - width: 80px; - height: 60px; - background: #fde68a; - border-radius: 40% 60% 70% 30% / 40% 50% 60% 50%; - animation: blob 3s infinite alternate; -} - -.check-item { - padding: 10px; - border-radius: 8px; - margin-bottom: 8px; - background: #f8fafc; - border-left: 4px solid #cbd5e1; - opacity: 0.4; - transition: all 0.3s ease; -} - -.check-item.done { - opacity: 1; - border-left-color: #10b981; - background: #f0fdf4; -} - -/* -------- 模态框和提示 -------- */ -.modal-overlay { - position: absolute; - inset: 0; - background: rgba(0, 0, 0, 0.7); - display: flex; - align-items: center; - justify-content: center; - z-index: 100; - backdrop-filter: blur(4px); -} - -.toast { - position: fixed; - bottom: 80px; - left: 50%; - transform: translateX(-50%); - background: #1e293b; - color: white; - padding: 12px 20px; - border-radius: 12px; - font-size: 13px; - opacity: 0; - transition: opacity 0.3s ease; - z-index: 200; -} - -.guide-modal { - background: white; - padding: 24px; - border-radius: 20px; - max-width: 400px; - width: 90%; - border: 2px solid #3b82f6; - box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); -} - -/* -------- 响应式优化 -------- */ -@media (max-width: 768px) { - .stage-content { - padding: 1rem; - } - - #ti-plasmid-container { - transform: scale(0.8); - } - - .bacteria { - transform: scale(0.9); - } - - .flow-step { - font-size: 0.65rem; - padding: 0.25rem 0.5rem; - } -} - -/* -------- Footer 优化 -------- */ -footer { - padding-bottom: calc(1rem + env(safe-area-inset-bottom)); - background: rgba(248, 250, 252, 0.95); - backdrop-filter: blur(8px); - border-top: 1px solid #e5e7eb; -} \ No newline at end of file diff --git a/static/resources/bio/pcr.jpg b/static/resources/bio/pcr.jpg index d349258..021d7b9 100755 Binary files a/static/resources/bio/pcr.jpg and b/static/resources/bio/pcr.jpg differ diff --git a/static/resources/bio/saccharomyces.jpg b/static/resources/bio/saccharomyces.jpg index 3189d82..3ade49b 100644 Binary files a/static/resources/bio/saccharomyces.jpg and b/static/resources/bio/saccharomyces.jpg differ diff --git a/static/resources/dashboard/.DS_Store b/static/resources/dashboard/.DS_Store index a550751..3195098 100644 Binary files a/static/resources/dashboard/.DS_Store and b/static/resources/dashboard/.DS_Store differ diff --git a/static/resources/idv/CNAME b/static/resources/idv/CNAME deleted file mode 100644 index b86de7f..0000000 --- a/static/resources/idv/CNAME +++ /dev/null @@ -1 +0,0 @@ -idv.rayawa.top \ No newline at end of file diff --git a/static/resources/idv/idv.html b/static/resources/idv/idv.html deleted file mode 100644 index 9686227..0000000 --- a/static/resources/idv/idv.html +++ /dev/null @@ -1,1147 +0,0 @@ - - - - - - 第五人格,启动! - - - - - - - - - - - -
- -
-

第五人格,启动!

-

本赛季目标:从四阶V到六阶V (1250积分)

-
- - -
- - -
-

- 计算结果 -

- -
- -
-
- -
-

剩余天数

-

70

-
- - -
-
- -
-

日均所需积分

-

14

-
- - -
-
- -
-

当前积分

-

0

-
- - -
-
- -
-

目标积分

-

1250

-
-
- - -
-
-
- 积分进度 - (当前积分/目标积分) -
-
- 0/1000 - 0% -
-
-
-
-
-
- 0 - 目标积分 (1250) -
-
-
- - -
-
-

- 当前段位进度 -

-
- 四阶V -
当前积分: 0
-
-
- - -
- -
- - -
- - -
- -
-
- 4V -
- - - - - -
-
- 四阶V - 0-100 -
- - -
-
- 4IV -
- - - - - -
-
- 四阶IV - 101-200 -
- - -
-
- 4III -
- - - - - -
-
- 四阶III - 201-300 -
- - -
-
- 4II -
- - - - - -
-
- 四阶II - 301-400 -
- - -
-
- 4I -
- - - - - -
-
- 四阶I - 401-500 -
- - -
-
- 5V -
- - - - - -
-
- 五阶V - 501-650 -
- - -
-
- 5IV -
- - - - - -
-
- 五阶IV - 651-800 -
- - -
-
- 5III -
- - - - - -
-
- 五阶III - 801-950 -
- - -
-
- 5II -
- - - - - -
-
- 五阶II - 951-1100 -
- - -
-
- 5I -
- - - - - -
-
- 五阶I - 1101-1250 -
- - -
-
- 6V -
- - - - - -
-
- 六阶V - 目标 -
-
-
- - -
-

每个段位需要100积分,每20积分点亮一颗星星 (共5星)

-

当前进度: 0% (0/100)

-
-
- - -
- -
-

- 积分调整 -

- - -
-
-
-

- 当前积分 -

-

手动调整当前积分

-
-
-
0
-
积分
-
-
-
- - -
-
- -
- - - - -
-
- - - - - -
- - -
-
-
- - -
-
-

- 调整历史记录 -

-
- 共 0 条记录 -
-
- -
- -
- -

暂无调整记录

-

调整积分后,记录将显示在这里

-
-
-
-
- - -
- -
- -
- - - - -
-
- - -
- -
- - - - -
-
- - -
- -
- - - - -
-
-
- - -
- -
-
- - - -
- - - - - - - - diff --git a/static/resources/main_page/.DS_Store b/static/resources/main_page/.DS_Store index 54dca02..fd312f7 100644 Binary files a/static/resources/main_page/.DS_Store and b/static/resources/main_page/.DS_Store differ diff --git a/static/resources/main_page/books.png b/static/resources/main_page/books.png index 7fae353..182ae81 100644 Binary files a/static/resources/main_page/books.png and b/static/resources/main_page/books.png differ diff --git a/static/resources/main_page/drawing.png b/static/resources/main_page/drawing.png deleted file mode 100644 index 7fae353..0000000 Binary files a/static/resources/main_page/drawing.png and /dev/null differ diff --git a/static/resources/main_page/rps.png b/static/resources/main_page/rps.png new file mode 100644 index 0000000..485fd50 Binary files /dev/null and b/static/resources/main_page/rps.png differ diff --git a/static/resources/main_page/signal.png b/static/resources/main_page/signal.png index f4638ec..3dad742 100644 Binary files a/static/resources/main_page/signal.png and b/static/resources/main_page/signal.png differ diff --git a/static/resources/bio/agrobacterium/.DS_Store b/static/resources/openharmony/.DS_Store similarity index 90% rename from static/resources/bio/agrobacterium/.DS_Store rename to static/resources/openharmony/.DS_Store index ce4b310..daf24a3 100644 Binary files a/static/resources/bio/agrobacterium/.DS_Store and b/static/resources/openharmony/.DS_Store differ diff --git a/static/resources/openharmony/smartshed.pdf b/static/resources/openharmony/smartshed.pdf new file mode 100644 index 0000000..f893cfb Binary files /dev/null and b/static/resources/openharmony/smartshed.pdf differ diff --git a/static/resources/openharmony/smartshed.pptx b/static/resources/openharmony/smartshed.pptx new file mode 100644 index 0000000..efaea36 Binary files /dev/null and b/static/resources/openharmony/smartshed.pptx differ diff --git a/static/resources/papers/.gitkeep b/static/resources/papers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/static/resources/rps/.DS_Store b/static/resources/rps/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/static/resources/rps/.DS_Store differ diff --git a/static/resources/rps/rps.gif b/static/resources/rps/rps.gif new file mode 100644 index 0000000..e578e56 Binary files /dev/null and b/static/resources/rps/rps.gif differ diff --git a/static/resources/idv/.DS_Store b/static/resources/signal/.DS_Store similarity index 79% rename from static/resources/idv/.DS_Store rename to static/resources/signal/.DS_Store index a275636..2fc8c62 100644 Binary files a/static/resources/idv/.DS_Store and b/static/resources/signal/.DS_Store differ diff --git a/static/resources/signal/circuit.fzz b/static/resources/signal/circuit.fzz new file mode 100644 index 0000000..6d2fb97 Binary files /dev/null and b/static/resources/signal/circuit.fzz differ diff --git a/static/resources/signal/circuit.png b/static/resources/signal/circuit.png new file mode 100644 index 0000000..fe86fca Binary files /dev/null and b/static/resources/signal/circuit.png differ diff --git a/static/resources/signal/code.png b/static/resources/signal/code.png new file mode 100644 index 0000000..94464b9 Binary files /dev/null and b/static/resources/signal/code.png differ diff --git a/static/resources/signal/doc.pdf b/static/resources/signal/doc.pdf new file mode 100644 index 0000000..f3cdc87 Binary files /dev/null and b/static/resources/signal/doc.pdf differ diff --git a/static/resources/signal/doc.png b/static/resources/signal/doc.png new file mode 100644 index 0000000..3dad742 Binary files /dev/null and b/static/resources/signal/doc.png differ diff --git a/static/resources/signal/expenditure.png b/static/resources/signal/expenditure.png new file mode 100644 index 0000000..430f7fe Binary files /dev/null and b/static/resources/signal/expenditure.png differ diff --git a/static/resources/signal/expenditure.xlsx b/static/resources/signal/expenditure.xlsx new file mode 100644 index 0000000..a037a69 Binary files /dev/null and b/static/resources/signal/expenditure.xlsx differ diff --git a/static/resources/signal/filter.cpp b/static/resources/signal/filter.cpp new file mode 100644 index 0000000..50f1420 --- /dev/null +++ b/static/resources/signal/filter.cpp @@ -0,0 +1,56 @@ +#include +using namespace std; +float getFilteredValue(int sampleCount, int trimCount) { + int samples[sampleCount]; + // 数据采集 + for (int i = 0; i < sampleCount; i++) { + samples[i] = ads.readADC_SingleEnded(0); + delay(1); + } + // 数据排序 + for (int i = 0; i < sampleCount - 1; i++) { + for (int j = 0; j < sampleCount - i - 1; j++) { + if (samples[j] > samples[j + 1]) { + int temp = samples[j]; + samples[j] = samples[j + 1]; + samples[j + 1] = temp; + } + } + } + // 中值滤波 + int median = samples[sampleCount / 2]; // 求出中值 + long long sum_temp = 0; + for (int i = trimCount; i < sampleCount - trimCount; i++) { + sum_temp += samples[i]; + } + float mean_temp = (float)sum_temp / (sampleCount - 2 * trimCount); + + float variance = 0; + for (int i = trimCount; i < sampleCount - trimCount; i++) { + float diff = samples[i] - mean_temp; + variance += diff * diff; + } + variance /= (sampleCount - 2 * trimCount - 1); + float stddev = sqrt(variance); + // 将超出中值±3倍标准差的异常值替换为中值 + for (int i = 0; i < sampleCount; i++) { + if (fabs(samples[i] - median) > 3 * stddev) { + samples[i] = median; + } + } + // 截尾平均 + long long sum = 0; + int effectiveCount = sampleCount - 2 * trimCount; + for (int i = trimCount; i < sampleCount - trimCount; i++) { + sum += samples[i]; + } + float averageRaw = (float)sum / effectiveCount; + // 转换电压 + const float ADC_TO_VOLTAGE = 0.000125F; // 根据量程改变 + return averageRaw * ADC_TO_VOLTAGE; +} +int main() +{ + + return 0; +} \ No newline at end of file diff --git a/static/resources/signal/loop.cpp b/static/resources/signal/loop.cpp new file mode 100644 index 0000000..786055f --- /dev/null +++ b/static/resources/signal/loop.cpp @@ -0,0 +1,27 @@ +#includetream> +using namespace std; +void loop() { + //获取PSD两端模拟电压原始值 + int adc0 = ads.readADC_SingleEnded(0); + int adc1 = ads.readADC_SingleEnded(1); + //转换为实际电平值 + float V1 = adc0 * 0.0000625; // 对应ADS1115 62.5uV精度 + float V2 = adc1 * 0.0000625; + // 计算归一化算子,消除光源强度波动 + if ((V1 + V2) != 0) { + float P = (V2 - V1) / (V2 + V1); + // 物理映射转换 + float x = (L / 2.0) * P; + float I = (k * x) / (2.0 * D * N * B * S); + float U = I * Z; + //输出结果显示 + Serial.print("Voltage(uV):"); Serial.print(I * 1e9); + Serial.print("Current(nA):"); Serial.print(U * 1e6); + } + delay(10); +} +int main() +{ + + return 0; +} \ No newline at end of file diff --git a/static/resources/signal/structure.SLDPRT b/static/resources/signal/structure.SLDPRT new file mode 100644 index 0000000..b4b5d6e Binary files /dev/null and b/static/resources/signal/structure.SLDPRT differ diff --git a/static/resources/signal/structure.SLDPRT.png b/static/resources/signal/structure.SLDPRT.png new file mode 100644 index 0000000..9892cda Binary files /dev/null and b/static/resources/signal/structure.SLDPRT.png differ diff --git a/static/resources/signal/tex.png b/static/resources/signal/tex.png new file mode 100644 index 0000000..33f7844 Binary files /dev/null and b/static/resources/signal/tex.png differ diff --git a/static/resources/signal/tex.tex b/static/resources/signal/tex.tex new file mode 100644 index 0000000..8396490 --- /dev/null +++ b/static/resources/signal/tex.tex @@ -0,0 +1,53 @@ +\documentclass[tikz,border=10pt]{standalone} +\usepackage{amsmath} +\usetikzlibrary{shapes.geometric, arrows.meta, shadings} + +\begin{document} +\begin{tikzpicture}[>=Stealth, thick] + + \draw [line width=1.2pt] (-4.5, 0.5) rectangle (-3.5, 4.5); + \node at (-4.0, 2.5) {\textbf{N}}; + + \draw [line width=1.2pt] (4.5, 0.5) rectangle (3.5, 4.5); + \node at (4.0, 2.5) {\textbf{S}}; + + \foreach \y in {0.8, 1.4, ..., 3.8, 4.3} { + \draw [->, blue!40, line width=0.8pt] (3.4, \y) -- (-3.4, \y); + } + \node [blue] at (2, 4.1) {$\vec{B}$}; + + % --- 3. Extra Thick Support Frame (支架 4pt) --- + \draw [line width=4pt, color=gray!60] (-2.8,-1.2) -- (-2.8,6) -- (2.8,6) -- (2.8,-1.2); + \node at (0,6.4) {\textbf{Support Frame}}; + + % --- 4. Suspension Wire (贯穿细线) --- + % 延长至横向配重的顶部 (y=0.2) + \draw [line width=0.6pt] (0,6) -- (0,0.2); + \fill [black] (0,6) circle (0.1); + \node [right] at (0.15,5.5) {\small Suspension Wire}; + + % --- 5. Enlarged Rectangular Coil Frame (Aspect Ratio 55:43) --- + % 宽度 2.8, 高度 2.19 (y: 3.5 down to 1.31) + \draw [line width=1.5pt] (-1.4, 1.31) rectangle (1.4, 3.5); + \node at (-0.9, 3.2) {\small Coil}; + + % --- 6. Optical Mirror (Glass/Glint Effects) --- + \begin{scope} + \clip (0,3.5) circle (0.5); + \shade [inner color=cyan!5, outer color=cyan!25] (0,3.5) circle (0.5); + \end{scope} + \draw [line width=1pt] (0,3.5) circle (0.5); + + % 高光效果 + \draw [white, line width=1.5pt, opacity=0.8] (0.15, 3.85) arc (60:30:0.5); + \draw [white, line width=0.8pt, opacity=0.6] (-0.2, 3.2) -- (0.05, 3.4); + \node [left] at (-0.3, 4) {\small Mirror}; + + % --- 7. Rotated Counterweight (横向长方形配重) --- + % 旋转90度后,宽度设为 0.6,高度设为 0.4 + % 顶部连接在 y=0.2,底部到 y=-0.2 + \draw [fill=black!95] (-0.3, -0.2) rectangle (0.3, 0.2); + \node [below] at (0, -0.2) {\small Weight}; + +\end{tikzpicture} +\end{document} \ No newline at end of file diff --git a/thanks.html b/thanks.html index a870460..0c10e0a 100644 --- a/thanks.html +++ b/thanks.html @@ -4,6 +4,33 @@ 致谢 | Ray Chen + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -43,7 +70,7 @@

老师

同学

-
义乌学社hjz、jdh、ljy、lzq、whn、wth、wyx、yyzy、zrq、zxy(按姓名字母顺序排序)
我的好朋友AndyGao、bzy、秀秀、ywx、lxr、wjy、ydx、lmd、lyc
9B208xxh、rjp、ldy、ddk
+
义乌学社hjz、jdh、ljy、lzq、whn、wth、wyx、yyzy、zrq、zxy(按姓名字母顺序排序)
我的好朋友AndyGao、bzy、秀秀、ywx、lxr、wjy、ydx、lmd、lyc、zhy
9B208xxh、rjp、ldy、ddk