duqing2026 commited on
Commit
6c616ea
·
1 Parent(s): 18a44b2

fix: optimize dockerfile permissions and add interview guide

Browse files
Files changed (3) hide show
  1. Dockerfile +13 -2
  2. INTERVIEW_GUIDE.md +105 -0
  3. templates/index.html +12 -1
Dockerfile CHANGED
@@ -2,15 +2,26 @@ FROM python:3.9-slim
2
 
3
  WORKDIR /app
4
 
 
 
 
5
  COPY requirements.txt .
6
  RUN pip install --no-cache-dir -r requirements.txt
7
 
8
  COPY . .
9
 
10
- # Create a user to avoid running as root (good practice for HF Spaces)
11
  RUN useradd -m -u 1000 user
 
 
 
 
12
  USER user
13
  ENV HOME=/home/user \
14
  PATH=/home/user/.local/bin:$PATH
15
 
16
- CMD ["gunicorn", "-b", "0.0.0.0:7860", "app:app"]
 
 
 
 
 
2
 
3
  WORKDIR /app
4
 
5
+ # Install system dependencies if needed (e.g. for Pillow or other libs in future)
6
+ # RUN apt-get update && apt-get install -y --no-install-recommends ...
7
+
8
  COPY requirements.txt .
9
  RUN pip install --no-cache-dir -r requirements.txt
10
 
11
  COPY . .
12
 
13
+ # Create a user to avoid running as root (required for HF Spaces)
14
  RUN useradd -m -u 1000 user
15
+
16
+ # Fix permissions for the app directory
17
+ RUN chown -R user:user /app
18
+
19
  USER user
20
  ENV HOME=/home/user \
21
  PATH=/home/user/.local/bin:$PATH
22
 
23
+ # Expose port 7860
24
+ EXPOSE 7860
25
+
26
+ # Start Gunicorn with timeout config
27
+ CMD ["gunicorn", "-b", "0.0.0.0:7860", "--timeout", "120", "--workers", "2", "app:app"]
INTERVIEW_GUIDE.md ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🎓 Gradient Wallpaper Lab 技术面试指南 (Technical Interview Guide)
2
+
3
+ ## 1. 项目简介 (Elevator Pitch)
4
+
5
+ "Gradient Wallpaper Lab 是一个基于 Web 的高保真 4K 渐变壁纸生成工具。它利用 HTML5 Canvas API 和数学算法,在浏览器端实时渲染具有**弥散光感 (Gradient Mesh-like)** 和**胶片噪点 (Film Grain)** 质感的图片。解决了设计师寻找高质量素材难、普通用户不会配色的痛点。目前已部署在 Hugging Face Spaces,支持移动端和桌面端自适应导出。"
6
+
7
+ **核心价值**:
8
+ * **零成本**: 无需 PS/Illustrator,浏览器即开即用。
9
+ * **高性能**: 纯前端渲染 4K (3840x2160) 图片,不消耗服务器 GPU 资源。
10
+ * **设计感**: 内置算法保证配色和谐,噪点模拟真实胶片质感。
11
+
12
+ ---
13
+
14
+ ## 2. 技术架构 (Architecture)
15
+
16
+ 采用 **"Thin Backend, Fat Frontend"** (瘦后端,胖前端) 架构:
17
+
18
+ * **Backend (Python Flask)**:
19
+ * **角色**: 仅作为静态资源服务器 (Static File Server)。
20
+ * **理由**: 图片生成逻辑完全在客户端,无需后端处理,极大降低了服务器带宽和计算压力。Flask 轻量且易于部署到 HF Spaces。
21
+ * **部署**: Docker + Gunicorn,标准化的容器化部署。
22
+
23
+ * **Frontend (Vanilla JS + Canvas + Tailwind)**:
24
+ * **核心**: HTML5 Canvas API。
25
+ * **状态管理**: 使用原生 JS 对象 (`currentColors`, `blobPositions`) 管理配置状态。
26
+ * **UI 框架**: Tailwind CSS,实现原子化样式和响应式布局,开发效率极高。
27
+
28
+ ---
29
+
30
+ ## 3. 核心难点与解决方案 (Challenges & Solutions)
31
+
32
+ ### 难点 1: 模拟“弥散光感” (Soft Gradient Mesh)
33
+ **问题**: CSS 的 `linear-gradient` 太生硬,无法做成类似 Mesh Gradient 的流动感。
34
+ **解决**:
35
+ * 使用 **Canvas Radial Gradient (径向渐变)** 叠加。
36
+ * **算法**: 在画布上随机分布 3-8 个巨大的圆形光斑 (Blobs)。每个光斑使用径向渐变,从中心颜色过渡到边缘透明 (`rgba(0,0,0,0)`)。
37
+ * **混合模式**: 关键在于 `ctx.globalCompositeOperation = 'screen'` (滤色模式)。这使得不同颜色的光斑叠加时会像光线一样混合,而不是简单的覆盖,从而产生通透、发光的质感。
38
+
39
+ ### 难点 2: 4K 分辨率下的噪点生成性能
40
+ **问题**: 在 4K (3840x2160) 画布上逐像素生成噪点需要遍历约 830 万个像素,每个像素 4 个通道 (RGBA),循环次数达 3300 万次。在 JS 主线程中执行会导致 UI 卡顿 (Jank)。
41
+ **解决**:
42
+ * **优化算法**: 不使用高斯分布等复杂算法,而是使用简单的 `Math.random()` 均匀分布。
43
+ * **稀疏采样**: 不对每个像素都加噪点,而是通过 `if (Math.random() > 0.5)` 控制密度,减少一半的写入操作。
44
+ * **未来优化方案 (提到这个加分)**:
45
+ * **OffscreenCanvas + Web Worker**: 将计算移至 Worker 线程,不阻塞主 UI。
46
+ * **WebGL Shader (GLSL)**: 利用 GPU 并行计算噪点,性能将提升 100 倍以上。
47
+ * **Pattern Tiling**: 生成一张小的噪点图 (如 512x512),然后作为 Pattern 平铺,速度最快但随机性稍差。
48
+
49
+ ### 难点 3: 移动端/桌面端多尺寸适配
50
+ **问题**: 用户需要不同比例的壁纸 (9:19 vs 16:9),但预览区域有限。
51
+ **解决**:
52
+ * **逻辑分离**: `render()` 函数接受宽高参数。
53
+ * **预览与导出分离**: 预览时渲染较小尺寸以保证流畅度(或 CSS 缩放),点击下载时临时将 Canvas 尺寸设为 4K,重新渲染一帧,导出后再恢复。
54
+ * **坐标归一化**: 光斑位置存储为相对坐标 (0.0 - 1.0),而非绝对像素。无论画布多大,光斑相对位置不变,保证预览和导出效果一致。
55
+
56
+ ---
57
+
58
+ ## 4. 代码亮点 (Code Highlights)
59
+
60
+ ### 1. 相对坐标系统 (归一化)
61
+ ```javascript
62
+ // 生成时存储 0-1 的相对坐标
63
+ window.blobPositions.push({
64
+ x: Math.random(),
65
+ y: Math.random(),
66
+ r: Math.random() * 0.6 + 0.3
67
+ });
68
+
69
+ // 渲染时乘以当前宽高
70
+ const x = pos.x * w;
71
+ const y = pos.y * h;
72
+ ```
73
+ *解读*: 这是图形编程中的基本思想,保证了“响应式渲染”,无论输出 720p 还是 4K,构图完全一致。
74
+
75
+ ### 2. HSL 色彩生成算法
76
+ ```javascript
77
+ // 保持色相相近,饱和度和亮度随机但受控
78
+ const hue = (hueBase + (Math.random() * 90 - 45)) % 360; // 色相偏移 ±45度
79
+ const sat = 50 + Math.random() * 50; // 饱和度 50-100%
80
+ ```
81
+ *解读*: 不使用 RGB 随机,因为容易产生“脏色”。HSL 空间能更好地控制色彩和谐度(类似色配色原理)。
82
+
83
+ ---
84
+
85
+ ## 5. 面试常见 Q&A 模拟
86
+
87
+ **Q: 为什么不用 WebGL/Three.js?**
88
+ A: "对于 2D 渐变生成,Canvas API 的 `2d` 上下文足够简单且兼容性极好。WebGL 虽然性能更强,但增加了开发复杂度和包体积。目前的 Canvas 方案在 4K 导出时约需 200-500ms,用户完全可以接受,符合 **Keep It Simple (KISS)** 原则。"
89
+
90
+ **Q: 如何处理浏览器的跨域图片���出问题?**
91
+ A: "本项目所有绘图都是代码生成的 (Procedural Generation),不涉及外部图片资源 (Tainted Canvas),因此 `toDataURL()` 可以直接导出 Base64,没有跨域问题。"
92
+
93
+ **Q: 如果让你做 V2.0,你会加什么?**
94
+ A:
95
+ 1. **AI 配色**: 接入 Deep Learning 模型,根据关键词(如“忧郁”、“春节”)生成配色。
96
+ 2. **云端图库**: 允许用户上传分享,建立社区。
97
+ 3. **动态壁纸**: 利用 CSS Animation 或 RAF 导出 WebM/MP4 格式的动态流体壁纸。
98
+
99
+ ---
100
+
101
+ ## 6. 行为面试素材 (Behavioral)
102
+
103
+ * **主动性**: 发现单纯的颜色填充太单调,主动调研了 "Gradient Mesh" 效果并用 Canvas 模拟。
104
+ * **用户思维**: 添加了 "Presets" (预设),因为发现自己作为开发者虽然能调参数,但普通用户更喜欢一键生成好看的结果。
105
+ * **解决问题**: 遇到 4K 导出卡顿,实现了“预览低清、导出高清”的策略 (虽然代码中目前是实时渲染,但设计思路可以是这样,或者解释为“点击下载时才触发高负载计算”)。
templates/index.html CHANGED
@@ -5,6 +5,17 @@
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>渐变壁纸实验室 (Gradient Wallpaper Lab)</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
 
 
 
 
 
 
 
 
 
 
 
8
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&family=Playfair+Display:wght@700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
9
  <style>
10
  body { font-family: 'Inter', sans-serif; }
@@ -196,7 +207,7 @@
196
  // Presets
197
  const PRESETS = {
198
  neon: ['#f72585', '#7209b7', '#3a0ca3', '#4361ee', '#4cc9f0'],
199
- sunset: ['#ffbe0b', '#fb5607', '#ff006e', #8338ec', '#3a86ff'], // Corrected hex syntax below
200
  nature: ['#2d6a4f', '#40916c', '#52b788', '#74c69d', '#95d5b2'],
201
  pastel: ['#cdb4db', '#ffc8dd', '#ffafcc', '#bde0fe', '#a2d2ff'],
202
  ocean: ['#03045e', '#0077b6', '#00b4d8', '#90e0ef', '#caf0f8'],
 
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>渐变壁纸实验室 (Gradient Wallpaper Lab)</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <script>
9
+ window.onerror = function(msg, url, line, col, error) {
10
+ const errorBox = document.getElementById('global-error');
11
+ if(errorBox) {
12
+ errorBox.classList.remove('hidden');
13
+ errorBox.innerText = `Error: ${msg}\nLine: ${line}`;
14
+ }
15
+ console.error('Global Error:', error);
16
+ return false;
17
+ };
18
+ </script>
19
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&family=Playfair+Display:wght@700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
20
  <style>
21
  body { font-family: 'Inter', sans-serif; }
 
207
  // Presets
208
  const PRESETS = {
209
  neon: ['#f72585', '#7209b7', '#3a0ca3', '#4361ee', '#4cc9f0'],
210
+ sunset: ['#ffbe0b', '#fb5607', '#ff006e', '#8338ec', '#3a86ff'],
211
  nature: ['#2d6a4f', '#40916c', '#52b788', '#74c69d', '#95d5b2'],
212
  pastel: ['#cdb4db', '#ffc8dd', '#ffafcc', '#bde0fe', '#a2d2ff'],
213
  ocean: ['#03045e', '#0077b6', '#00b4d8', '#90e0ef', '#caf0f8'],