@pixel-normal-edit/mcp 2.0.10 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/clear-firebase.js +37 -0
  2. package/core/command-bus.js +6 -3
  3. package/core/server.js +98 -3
  4. package/domains/art-tree/README.md +134 -0
  5. package/domains/art-tree/REORGANIZATION_PLAN.md +168 -0
  6. package/domains/art-tree/REORGANIZATION_SUMMARY.md +260 -0
  7. package/domains/art-tree/index.js +58 -58
  8. package/domains/art-tree/lessons/3d/box-properties.js +38 -0
  9. package/domains/art-tree/lessons/3d/cone-properties.js +31 -0
  10. package/domains/art-tree/lessons/3d/cylinder-properties.js +29 -0
  11. package/domains/art-tree/lessons/3d/sphere-properties.js +25 -0
  12. package/domains/art-tree/lessons/advanced/angles.js +30 -0
  13. package/domains/art-tree/lessons/advanced/distances.js +26 -0
  14. package/domains/art-tree/lessons/advanced/shape-ratios.js +25 -0
  15. package/domains/art-tree/lessons/advanced/shape-relationships.js +28 -0
  16. package/domains/art-tree/lessons/advanced/symmetry-and-axis.js +26 -0
  17. package/domains/art-tree/{analysis_lessons.js → lessons/analysis/object-analysis.js} +5 -16
  18. package/domains/art-tree/lessons/basic/circles.js +26 -0
  19. package/domains/art-tree/lessons/basic/composition.js +34 -0
  20. package/domains/art-tree/lessons/basic/curves.js +31 -0
  21. package/domains/art-tree/lessons/basic/ellipses.js +26 -0
  22. package/domains/art-tree/lessons/basic/freehand.js +19 -0
  23. package/domains/art-tree/lessons/basic/index.js +36 -0
  24. package/domains/art-tree/lessons/basic/lines.js +38 -0
  25. package/domains/art-tree/lessons/basic/parallel-and-intersecting.js +22 -0
  26. package/domains/art-tree/lessons/basic/polygons.js +25 -0
  27. package/domains/art-tree/lessons/basic/proportions-and-angles.js +20 -0
  28. package/domains/art-tree/lessons/basic/spiral.js +21 -0
  29. package/domains/art-tree/lessons/basic/squares.js +28 -0
  30. package/domains/art-tree/lessons/basic/strokes.js +23 -0
  31. package/domains/art-tree/lessons/basic/triangles.js +30 -0
  32. package/domains/art-tree/lessons/cross-sections/bottle-sections.js +26 -0
  33. package/domains/art-tree/lessons/cross-sections/glass-sections.js +24 -0
  34. package/domains/art-tree/lessons/cross-sections/head-sections.js +17 -0
  35. package/domains/art-tree/lessons/curves/curve-properties.js +50 -0
  36. package/domains/art-tree/lessons/curves/curve-topology.js +45 -0
  37. package/domains/art-tree/lessons/curves/curve-types.js +44 -0
  38. package/domains/art-tree/lessons/ellipses/coaxial-ellipses.js +29 -0
  39. package/domains/art-tree/lessons/ellipses/ellipse-anatomy.js +26 -0
  40. package/domains/art-tree/lessons/ellipses/ellipse-orientations.js +28 -0
  41. package/domains/art-tree/lessons/ellipses/ellipse-proportions.js +27 -0
  42. package/domains/art-tree/lessons/hidden/hidden-box.js +20 -0
  43. package/domains/art-tree/lessons/hidden/hidden-cup.js +19 -0
  44. package/domains/art-tree/lessons/hidden/hidden-head.js +18 -0
  45. package/domains/art-tree/lessons/index.js +42 -0
  46. package/domains/art-tree/{layer_lessons.js → lessons/layers/layer-step.js} +5 -16
  47. package/domains/art-tree/lessons/lighting/contact-shadow.js +33 -0
  48. package/domains/art-tree/lessons/lighting/light-direction.js +30 -0
  49. package/domains/art-tree/lessons/lighting/light-zones.js +30 -0
  50. package/domains/art-tree/lessons/materials/material-glass.js +21 -0
  51. package/domains/art-tree/lessons/materials/material-shiny.js +26 -0
  52. package/domains/art-tree/lessons/materials/material-texture.js +26 -0
  53. package/domains/art-tree/lessons/perspective/1point-perspective.js +30 -0
  54. package/domains/art-tree/lessons/perspective/2point-perspective.js +30 -0
  55. package/domains/art-tree/lessons/perspective/3point-perspective.js +45 -0
  56. package/domains/art-tree/lessons/perspective/foreshortening.js +38 -0
  57. package/domains/art-tree/lessons/sky/sun-shapes.js +25 -0
  58. package/domains/art-tree/lessons/sky/sunset-colors.js +27 -0
  59. package/domains/art-tree/lessons/sky/sunset-sky.js +32 -0
  60. package/domains/art-tree/{structure_lessons.js → lessons/structure/axis-orientation.js} +3 -53
  61. package/domains/art-tree/lessons/structure/complex-structure.js +21 -0
  62. package/domains/art-tree/lessons/structure/x-yzaxes.js +28 -0
  63. package/domains/art-tree/lessons/surfaces/chair-analysis.js +17 -0
  64. package/domains/art-tree/lessons/surfaces/cup-analysis.js +18 -0
  65. package/domains/art-tree/lessons/surfaces/edge-types.js +40 -0
  66. package/domains/art-tree/lessons/surfaces/surface-types.js +42 -0
  67. package/domains/art-tree/lessons/transforms/bend.js +27 -0
  68. package/domains/art-tree/{transform_lessons_2.js → lessons/transforms/combine.js} +3 -54
  69. package/domains/art-tree/lessons/transforms/cut.js +25 -0
  70. package/domains/art-tree/lessons/transforms/hollow.js +24 -0
  71. package/domains/art-tree/lessons/transforms/rotate.js +16 -0
  72. package/domains/art-tree/lessons/transforms/squash.js +31 -0
  73. package/domains/art-tree/lessons/transforms/stretch.js +31 -0
  74. package/domains/art-tree/lessons/transforms/taper-swell.js +33 -0
  75. package/domains/art-tree/{vocab_lessons.js → lessons/vocab/vocab-house.js} +5 -16
  76. package/domains/art-tree/lib/tool-register.js +104 -0
  77. package/domains/art-tree/lib/validators.js +78 -0
  78. package/domains/art-tree/shapes/grid.js +37 -0
  79. package/domains/art-tree/shapes/polyline.js +26 -0
  80. package/domains/art-tree/{3d_tools.js → tools/3d.js} +2 -2
  81. package/domains/art-tree/{advanced_tools.js → tools/advanced.js} +2 -2
  82. package/domains/art-tree/{analysis_tools.js → tools/analysis.js} +2 -2
  83. package/domains/art-tree/{tools.js → tools/basic.js} +3 -3
  84. package/domains/art-tree/{cross_section_tools.js → tools/cross-sections.js} +2 -2
  85. package/domains/art-tree/{curve_tools.js → tools/curves.js} +2 -2
  86. package/domains/art-tree/{ellipse_tools.js → tools/ellipses.js} +2 -2
  87. package/domains/art-tree/{hidden_tools.js → tools/hidden.js} +2 -2
  88. package/domains/art-tree/tools/index.js +53 -0
  89. package/domains/art-tree/{layer_tools.js → tools/layers.js} +2 -2
  90. package/domains/art-tree/{light_tools.js → tools/lighting.js} +2 -2
  91. package/domains/art-tree/{material_tools.js → tools/materials.js} +2 -2
  92. package/domains/art-tree/{perspective_tools.js → tools/perspective.js} +2 -2
  93. package/domains/art-tree/{sky_tools.js → tools/sky.js} +2 -2
  94. package/domains/art-tree/{structure_tools.js → tools/structure.js} +2 -2
  95. package/domains/art-tree/{surface_tools.js → tools/surfaces.js} +2 -2
  96. package/domains/art-tree/{transform_tools.js → tools/transforms.js} +3 -3
  97. package/domains/art-tree/{vocab_tools.js → tools/vocab.js} +2 -2
  98. package/package.json +1 -1
  99. package/rules/README.md +358 -285
  100. package/rules/index.js +9 -9
  101. package/rules/prerequisites.js +121 -64
  102. package/rules/rules.js +76 -35
  103. package/rules/workflow.js +270 -56
  104. package/tools/canvas-tools.js +2 -2
  105. package/tools/drawing-tools.js +23 -12
  106. package/tools/workspace-tools.js +5 -4
  107. package/domains/art-tree/3d_lessons.js +0 -114
  108. package/domains/art-tree/advanced_lessons.js +0 -124
  109. package/domains/art-tree/cross_section_lessons.js +0 -65
  110. package/domains/art-tree/curve_lessons.js +0 -138
  111. package/domains/art-tree/ellipse_lessons.js +0 -105
  112. package/domains/art-tree/hidden_lessons.js +0 -55
  113. package/domains/art-tree/lessons.js +0 -305
  114. package/domains/art-tree/light_lessons.js +0 -92
  115. package/domains/art-tree/material_lessons.js +0 -71
  116. package/domains/art-tree/perspective_lessons.js +0 -138
  117. package/domains/art-tree/sky_lessons_1.js +0 -82
  118. package/domains/art-tree/surface_lessons.js +0 -112
  119. package/domains/art-tree/transform_lessons_1.js +0 -108
  120. /package/domains/art-tree/{3d_shapes.js → shapes/3d.js} +0 -0
  121. /package/domains/art-tree/{advanced_shapes.js → shapes/advanced.js} +0 -0
  122. /package/domains/art-tree/{analysis_shapes.js → shapes/analysis.js} +0 -0
  123. /package/domains/art-tree/{shapes.js → shapes/basic.js} +0 -0
  124. /package/domains/art-tree/{cross_section_shapes.js → shapes/cross-sections.js} +0 -0
  125. /package/domains/art-tree/{curve_shapes.js → shapes/curves.js} +0 -0
  126. /package/domains/art-tree/{ellipse_shapes.js → shapes/ellipses.js} +0 -0
  127. /package/domains/art-tree/{hidden_shapes.js → shapes/hidden.js} +0 -0
  128. /package/domains/art-tree/{layer_shapes.js → shapes/layers.js} +0 -0
  129. /package/domains/art-tree/{light_shapes.js → shapes/lighting.js} +0 -0
  130. /package/domains/art-tree/{material_shapes.js → shapes/materials.js} +0 -0
  131. /package/domains/art-tree/{perspective_shapes.js → shapes/perspective.js} +0 -0
  132. /package/domains/art-tree/{sky_shapes_1.js → shapes/sky.js} +0 -0
  133. /package/domains/art-tree/{structure_shapes.js → shapes/structure.js} +0 -0
  134. /package/domains/art-tree/{surface_shapes.js → shapes/surfaces.js} +0 -0
  135. /package/domains/art-tree/{transform_shapes.js → shapes/transforms.js} +0 -0
  136. /package/domains/art-tree/{vocab_shapes.js → shapes/vocab.js} +0 -0
@@ -1,305 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * lessons.js — Art Tree: Basic Shapes Lessons
4
- *
5
- * Layer: Lesson API (built on top of Shape API)
6
- *
7
- * Provides structured lessons that guide learners through
8
- * drawing basic geometric shapes step by step.
9
- * Each lesson returns a sequence of command payloads.
10
- */
11
- const shapes = require('./shapes');
12
-
13
- /**
14
- * Lesson 1: Lines — Introduction to drawing straight lines.
15
- * Teaches horizontal, vertical, and diagonal lines.
16
- * @param {number} canvasSize - Canvas dimension (assumes square)
17
- * @param {string} color - Primary color for the lesson
18
- * @returns {Array<Object>} Array of command payloads
19
- */
20
- function lessonLines(canvasSize = 32, color = '#ff0000') {
21
- const mid = Math.floor(canvasSize / 2);
22
- const margin = Math.floor(canvasSize * 0.15);
23
- return [
24
- // Horizontal line
25
- shapes.drawLine(margin, mid, canvasSize - margin, mid, color),
26
- // Vertical line
27
- shapes.drawLine(mid, margin, mid, canvasSize - margin, '#0000ff'),
28
- // Diagonal (top-left to bottom-right)
29
- shapes.drawLine(margin, margin, canvasSize - margin, canvasSize - margin, '#00aa00'),
30
- // Diagonal (top-right to bottom-left)
31
- shapes.drawLine(canvasSize - margin, margin, margin, canvasSize - margin, '#ff8800'),
32
- ];
33
- }
34
-
35
- /**
36
- * Lesson 2: Squares & Rectangles — Understanding right angles and proportions.
37
- * @param {number} canvasSize - Canvas dimension
38
- * @param {string} color - Primary color
39
- * @returns {Array<Object>} Array of command payloads
40
- */
41
- function lessonSquares(canvasSize = 32, color = '#1565c0') {
42
- const margin = Math.floor(canvasSize * 0.1);
43
- const small = Math.floor(canvasSize * 0.2);
44
- const large = Math.floor(canvasSize * 0.35);
45
- return [
46
- // Small square (outline)
47
- shapes.drawSquare(margin, margin, small, color, false),
48
- // Large square (filled)
49
- shapes.drawSquare(canvasSize - margin - large, margin, large, '#ff7043', true),
50
- // Rectangle (horizontal)
51
- shapes.drawRectangle(margin, canvasSize - margin - small, large + small, small, '#4caf50', false),
52
- // Rectangle (vertical, filled)
53
- shapes.drawRectangle(canvasSize - margin - small, canvasSize - margin - large, small, large, '#9c27b0', true),
54
- ];
55
- }
56
-
57
- /**
58
- * Lesson 3: Circles — Learning curves and symmetry.
59
- * @param {number} canvasSize - Canvas dimension
60
- * @param {string} color - Primary color
61
- * @returns {Array<Object>} Array of command payloads
62
- */
63
- function lessonCircles(canvasSize = 32, color = '#e91e63') {
64
- const mid = Math.floor(canvasSize / 2);
65
- const r1 = Math.floor(canvasSize * 0.15);
66
- const r2 = Math.floor(canvasSize * 0.3);
67
- return [
68
- // Small circle (outline)
69
- shapes.drawCircle(mid, mid, r1, color, false),
70
- // Large circle (filled)
71
- shapes.drawCircle(mid, mid, r2, '#2196f3', true),
72
- // Small filled circle offset
73
- shapes.drawCircle(mid + r1, mid - r1, Math.floor(r1 / 2), '#ff9800', true),
74
- ];
75
- }
76
-
77
- /**
78
- * Lesson 4: Ellipses — Understanding oval shapes and proportions.
79
- * @param {number} canvasSize - Canvas dimension
80
- * @param {string} color - Primary color
81
- * @returns {Array<Object>} Array of command payloads
82
- */
83
- function lessonEllipses(canvasSize = 32, color = '#9c27b0') {
84
- const mid = Math.floor(canvasSize / 2);
85
- const rx = Math.floor(canvasSize * 0.3);
86
- const ry = Math.floor(canvasSize * 0.15);
87
- return [
88
- // Horizontal ellipse (outline)
89
- shapes.drawEllipse(mid, mid, rx, ry, color, false),
90
- // Vertical ellipse (filled)
91
- shapes.drawEllipse(mid, mid, ry, rx, '#4caf50', true),
92
- // Small circle-like ellipse
93
- shapes.drawEllipse(mid + rx, mid - ry, Math.floor(rx / 3), Math.floor(ry / 2), '#ff5722', true),
94
- ];
95
- }
96
-
97
- /**
98
- * Lesson 5: Triangles — Three-point shapes and stability.
99
- * @param {number} canvasSize - Canvas dimension
100
- * @param {string} color - Primary color
101
- * @returns {Array<Object>} Array of command payloads
102
- */
103
- function lessonTriangles(canvasSize = 32, color = '#ff5722') {
104
- const mid = Math.floor(canvasSize / 2);
105
- const size = Math.floor(canvasSize * 0.4);
106
- const margin = Math.floor(canvasSize * 0.1);
107
- return [
108
- // Equilateral triangle (outline)
109
- shapes.drawEquilateralTriangle(mid, mid, size, color, false),
110
- // Right triangle (filled)
111
- shapes.drawTriangle([
112
- { x: margin, y: canvasSize - margin },
113
- { x: margin, y: margin },
114
- { x: Math.floor(canvasSize * 0.35), y: canvasSize - margin },
115
- ], '#3f51b5', true),
116
- // Inverted triangle
117
- shapes.drawEquilateralTriangle(mid, mid, Math.floor(size * 0.6), '#009688', true),
118
- ];
119
- }
120
-
121
- /**
122
- * Lesson 6: Polygons — Multi-sided shapes.
123
- * @param {number} canvasSize - Canvas dimension
124
- * @param {string} color - Primary color
125
- * @returns {Array<Object>} Array of command payloads
126
- */
127
- function lessonPolygons(canvasSize = 32, color = '#607d8b') {
128
- const mid = Math.floor(canvasSize / 2);
129
- const r = Math.floor(canvasSize * 0.35);
130
- return [
131
- // Pentagon
132
- shapes.drawRegularPolygon(mid, mid, 5, r, '#4caf50', false),
133
- // Hexagon (filled)
134
- shapes.drawRegularPolygon(mid, mid, 6, Math.floor(r * 0.7), '#ff9800', true),
135
- // Octagon
136
- shapes.drawRegularPolygon(mid, mid, 8, Math.floor(r * 0.5), '#9c27b0', false),
137
- ];
138
- }
139
-
140
- /**
141
- * Lesson 7: Composition — Combining basic shapes to create simple objects.
142
- * @param {number} canvasSize - Canvas dimension
143
- * @returns {Array<Object>} Array of command payloads
144
- */
145
- function lessonComposition(canvasSize = 32) {
146
- const mid = Math.floor(canvasSize / 2);
147
- const q1 = Math.floor(canvasSize * 0.25);
148
- const q3 = Math.floor(canvasSize * 0.75);
149
- const small = Math.floor(canvasSize * 0.1);
150
- return [
151
- // House: square body
152
- shapes.drawSquare(q1, mid, q3 - q1, '#8d6e63', true),
153
- // House: triangle roof
154
- shapes.drawTriangle([
155
- { x: q1 - 1, y: mid },
156
- { x: mid, y: q1 },
157
- { x: q3 + 1, y: mid },
158
- ], '#d32f2f', true),
159
- // Sun: circle
160
- shapes.drawCircle(canvasSize - small - 2, small + 2, small, '#ffc107', true),
161
- // Tree: rectangle trunk
162
- shapes.drawRectangle(q1 + small, canvasSize - small - 2, Math.floor(small / 2), small, '#5d4037', true),
163
- // Tree: circle top
164
- shapes.drawCircle(q1 + Math.floor(small / 4), canvasSize - small - 4, Math.floor(small / 2), '#388e3c', true),
165
- ];
166
- }
167
-
168
- /**
169
- * Lesson 8: Freehand — Practice freehand drawing with simulated hand tremor.
170
- */
171
- function lessonFreehand(canvasSize = 32, color = '#795548') {
172
- const margin = Math.floor(canvasSize * 0.1);
173
- const points = [];
174
- let y = Math.floor(canvasSize / 2);
175
- for (let x = margin; x < canvasSize - margin; x += 2) {
176
- points.push({ x, y: y + Math.floor(Math.random() * 3) - 1 });
177
- }
178
- return shapes.drawPolyline(points, color);
179
- }
180
-
181
- /**
182
- * Lesson 9: Proportions and Angles — Practice maintaining proportions and angles.
183
- */
184
- function lessonProportionsAndAngles(canvasSize = 32, color = '#3f51b5') {
185
- const mid = Math.floor(canvasSize / 2);
186
- const size1 = Math.floor(canvasSize * 0.4);
187
- const size2 = Math.floor(size1 / 2);
188
- return [
189
- shapes.drawSquare(mid - Math.floor(size1/2), mid - Math.floor(size1/2), size1, color, false),
190
- shapes.drawSquare(mid - Math.floor(size2/2), mid - Math.floor(size2/2), size2, '#e91e63', false),
191
- shapes.drawLine(mid, mid, mid + size1, mid - size1, '#009688')
192
- ];
193
- }
194
-
195
- /**
196
- * Lesson 10: Curves — C-curves and S-curves.
197
- */
198
- function lessonCurves(canvasSize = 32, color = '#9c27b0') {
199
- const commands = [];
200
- const mid = Math.floor(canvasSize / 2);
201
- const r = Math.floor(canvasSize * 0.15);
202
- // C curve
203
- const cPoints = [];
204
- for (let i = -Math.PI/2; i <= Math.PI/2; i += 0.2) {
205
- cPoints.push({ x: Math.round(mid - r - r * Math.cos(i)), y: Math.round(mid / 2 + r * Math.sin(i)) });
206
- }
207
- commands.push(...shapes.drawPolyline(cPoints, color));
208
- // S curve
209
- const sPoints = [];
210
- for (let i = -Math.PI/2; i <= Math.PI*1.5; i += 0.2) {
211
- const isTop = i < Math.PI/2;
212
- const cy = isTop ? (mid + Math.floor(canvasSize*0.1)) : (mid + Math.floor(canvasSize*0.1) + r*2);
213
- const signX = isTop ? -1 : 1;
214
- sPoints.push({ x: Math.round(mid + r + signX * r * Math.cos(i)), y: Math.round(cy + r * Math.sin(i)) });
215
- }
216
- commands.push(...shapes.drawPolyline(sPoints, '#e91e63'));
217
- return commands;
218
- }
219
-
220
- /**
221
- * Lesson 11: Spiral — Drawing spiral curves.
222
- */
223
- function lessonSpiral(canvasSize = 32, color = '#ff9800') {
224
- const mid = Math.floor(canvasSize / 2);
225
- const points = [];
226
- const maxRadius = Math.floor(canvasSize * 0.4);
227
- const loops = 3;
228
- for (let angle = 0; angle < Math.PI * 2 * loops; angle += 0.3) {
229
- const r = (angle / (Math.PI * 2 * loops)) * maxRadius;
230
- points.push({ x: Math.round(mid + r * Math.cos(angle)), y: Math.round(mid + r * Math.sin(angle)) });
231
- }
232
- return shapes.drawPolyline(points, color);
233
- }
234
-
235
- /**
236
- * Lesson 12: Strokes — Long strokes, short strokes, thick and thin lines.
237
- */
238
- function lessonStrokes(canvasSize = 32, color = '#2196f3') {
239
- const margin = Math.floor(canvasSize * 0.1);
240
- const y1 = Math.floor(canvasSize * 0.3);
241
- const y2 = Math.floor(canvasSize * 0.5);
242
- const y3 = Math.floor(canvasSize * 0.7);
243
- return [
244
- shapes.drawLine(margin, y1, canvasSize - margin, y1, color),
245
- shapes.drawLine(margin, y2, Math.floor(canvasSize / 2), y2, '#4caf50'),
246
- shapes.drawLine(margin, y3, canvasSize - margin, y3, '#f44336'),
247
- shapes.drawLine(margin, y3 + 1, canvasSize - margin, y3 + 1, '#f44336'),
248
- shapes.drawLine(margin, y3 + 2, canvasSize - margin, y3 + 2, '#f44336'),
249
- ];
250
- }
251
-
252
- /**
253
- * Lesson 13: Parallel & Intersecting Lines — Drawing parallel and intersecting lines.
254
- */
255
- function lessonParallelAndIntersecting(canvasSize = 32, color = '#00bcd4') {
256
- const margin = Math.floor(canvasSize * 0.1);
257
- const mid = Math.floor(canvasSize / 2);
258
- const offset = 4;
259
- return [
260
- shapes.drawLine(margin, margin, canvasSize - margin, margin, color),
261
- shapes.drawLine(margin, margin + offset, canvasSize - margin, margin + offset, color),
262
- shapes.drawLine(margin, margin + offset * 2, canvasSize - margin, margin + offset * 2, color),
263
- shapes.drawLine(mid - offset*2, mid, mid + offset*2, canvasSize - margin, '#ff5722'),
264
- shapes.drawLine(mid + offset*2, mid, mid - offset*2, canvasSize - margin, '#ff5722')
265
- ];
266
- }
267
-
268
- /**
269
- * Get all available lessons with metadata.
270
- * @returns {Array<{id: string, name: string, description: string, fn: Function}>}
271
- */
272
- function getLessonCatalog() {
273
- return [
274
- { id: 'lines', name: 'Lines', description: 'Draw horizontal, vertical and diagonal lines', fn: lessonLines },
275
- { id: 'squares', name: 'Squares & Rectangles', description: 'Understand right angles and proportions', fn: lessonSquares },
276
- { id: 'circles', name: 'Circles', description: 'Learn curves and symmetry', fn: lessonCircles },
277
- { id: 'ellipses', name: 'Ellipses', description: 'Understand oval shapes and proportions', fn: lessonEllipses },
278
- { id: 'triangles', name: 'Triangles', description: 'Three-point shapes and stability', fn: lessonTriangles },
279
- { id: 'polygons', name: 'Polygons', description: 'Multi-sided shapes', fn: lessonPolygons },
280
- { id: 'composition', name: 'Composition', description: 'Combine basic shapes to create simple objects', fn: lessonComposition },
281
- { id: 'freehand', name: 'Freehand Drawing', description: 'Practice freehand drawing without rulers', fn: lessonFreehand },
282
- { id: 'proportions', name: 'Proportions & Angles', description: 'Practice maintaining proportions and angles', fn: lessonProportionsAndAngles },
283
- { id: 'curves', name: 'Curves', description: 'C-curves and S-curves', fn: lessonCurves },
284
- { id: 'spiral', name: 'Spiral', description: 'Drawing spiral curves', fn: lessonSpiral },
285
- { id: 'strokes', name: 'Stroke Types', description: 'Long strokes, short strokes, thick and thin lines', fn: lessonStrokes },
286
- { id: 'parallel_intersecting', name: 'Parallel & Intersecting', description: 'Draw parallel and intersecting lines', fn: lessonParallelAndIntersecting },
287
- ];
288
- }
289
-
290
- module.exports = {
291
- lessonLines,
292
- lessonSquares,
293
- lessonCircles,
294
- lessonEllipses,
295
- lessonTriangles,
296
- lessonPolygons,
297
- lessonComposition,
298
- lessonFreehand,
299
- lessonProportionsAndAngles,
300
- lessonCurves,
301
- lessonSpiral,
302
- lessonStrokes,
303
- lessonParallelAndIntersecting,
304
- getLessonCatalog,
305
- };
@@ -1,92 +0,0 @@
1
- const shapes = require('./shapes');
2
- const lightShapes = require('./light_shapes');
3
-
4
- /**
5
- * Lesson: 6 Zones of Light (Sphere)
6
- * Highlight, Light, Halftone, Core shadow, Reflected light, Cast shadow.
7
- */
8
- function lessonLightZones(canvasSize = 32) {
9
- const commands = [];
10
- const cx = Math.floor(canvasSize / 2);
11
- const cy = Math.floor(canvasSize / 2);
12
- const r = Math.floor(canvasSize * 0.25);
13
-
14
- // Light from top-left (approx -45 degrees or -135 degrees mathematically)
15
- const lightAngle = -Math.PI * 0.75;
16
-
17
- // Draw light source
18
- const lx = cx + Math.floor(r * 2 * Math.cos(lightAngle));
19
- const ly = cy + Math.floor(r * 2 * Math.sin(lightAngle));
20
- commands.push(...lightShapes.drawLightSource(lx, ly, Math.floor(canvasSize * 0.05)));
21
-
22
- // Draw shaded sphere
23
- commands.push(...lightShapes.drawShadedSphere(cx, cy, r, lightAngle));
24
-
25
- return commands;
26
- }
27
-
28
- /**
29
- * Lesson: Light Direction & Intensity (Light direction and plane values)
30
- * Shows a box with planes facing/turning away from light.
31
- */
32
- function lessonLightDirection(canvasSize = 32) {
33
- const commands = [];
34
- const cx = Math.floor(canvasSize / 2);
35
- const cy = Math.floor(canvasSize / 2);
36
- const w = Math.floor(canvasSize * 0.25);
37
- const h = Math.floor(canvasSize * 0.25);
38
-
39
- // Light from top-left
40
- const lightAngle = -Math.PI * 0.8;
41
-
42
- const lx = cx - Math.floor(canvasSize * 0.35);
43
- const ly = cy - Math.floor(canvasSize * 0.35);
44
- commands.push(...lightShapes.drawLightSource(lx, ly, Math.floor(canvasSize * 0.05)));
45
-
46
- // Draw shaded box
47
- commands.push(...lightShapes.drawShadedBox(cx, cy, w, h, lightAngle));
48
-
49
- return commands;
50
- }
51
-
52
- /**
53
- * Lesson: Contact Shadow (Point of contact shadow)
54
- * The darkest area where an object touches the ground.
55
- */
56
- function lessonContactShadow(canvasSize = 32) {
57
- const commands = [];
58
- const cx = Math.floor(canvasSize / 2);
59
- const cy = Math.floor(canvasSize / 2);
60
- const r = Math.floor(canvasSize * 0.3);
61
-
62
- // Ground line
63
- commands.push(shapes.drawLine(0, cy + r, canvasSize, cy + r, '#9e9e9e'));
64
-
65
- // Sphere outline
66
- commands.push(shapes.drawCircle(cx, cy, r, '#bdbdbd', false));
67
-
68
- // Cast shadow (faint)
69
- commands.push(shapes.drawEllipse(cx + Math.floor(r*0.5), cy + r, Math.floor(r*1.2), Math.floor(r*0.2), '#757575', true));
70
-
71
- // CONTACT SHADOW (Pitch black, right at the touching point)
72
- // Draw a very small, very dark ellipse directly under the center
73
- commands.push(shapes.drawEllipse(cx, cy + r, Math.floor(r * 0.4), 2, '#000000', true));
74
- commands.push(shapes.drawEllipse(cx, cy + r, Math.floor(r * 0.2), 1, '#000000', true));
75
-
76
- return commands;
77
- }
78
-
79
- function getLightLessonCatalog() {
80
- return [
81
- { id: 'light_zones', name: '6 Zones of Light', description: 'Highlight to Cast shadow on a sphere', fn: lessonLightZones },
82
- { id: 'light_dir', name: 'Light Direction', description: 'Planes facing vs turning away from light', fn: lessonLightDirection },
83
- { id: 'light_contact', name: 'Contact Shadow', description: 'The darkest point where object touches ground', fn: lessonContactShadow },
84
- ];
85
- }
86
-
87
- module.exports = {
88
- lessonLightZones,
89
- lessonLightDirection,
90
- lessonContactShadow,
91
- getLightLessonCatalog
92
- };
@@ -1,71 +0,0 @@
1
- const materialShapes = require('./material_shapes');
2
-
3
- /**
4
- * Lesson: Shiny vs Matte (Metal vs Plastic/Rubber)
5
- * Compares high contrast sharp highlights vs low contrast diffused highlights.
6
- */
7
- function lessonMaterialShiny(canvasSize = 32) {
8
- const commands = [];
9
- const cx1 = Math.floor(canvasSize * 0.3);
10
- const cx2 = Math.floor(canvasSize * 0.7);
11
- const cy = Math.floor(canvasSize / 2);
12
- const r = Math.floor(canvasSize * 0.2);
13
-
14
- // 1. Metal Sphere (Left)
15
- commands.push(...materialShapes.drawMetalSphere(cx1, cy, r));
16
-
17
- // 2. Matte/Plastic Sphere (Right)
18
- commands.push(...materialShapes.drawMatteSphere(cx2, cy, r, '#e65100'));
19
-
20
- return commands;
21
- }
22
-
23
- /**
24
- * Lesson: Transparent (Glass)
25
- * Demonstrates Fresnel effect, sharp reflections, and light transmission.
26
- */
27
- function lessonMaterialGlass(canvasSize = 32) {
28
- const commands = [];
29
- const cx = Math.floor(canvasSize / 2);
30
- const cy = Math.floor(canvasSize / 2);
31
- const r = Math.floor(canvasSize * 0.35);
32
-
33
- commands.push(...materialShapes.drawGlassSphere(cx, cy, r));
34
-
35
- return commands;
36
- }
37
-
38
- /**
39
- * Lesson: Texture (Wood vs Stone)
40
- * Compares organic lines vs rough cracks.
41
- */
42
- function lessonMaterialTexture(canvasSize = 32) {
43
- const commands = [];
44
- const cx1 = Math.floor(canvasSize * 0.3);
45
- const cx2 = Math.floor(canvasSize * 0.7);
46
- const cy = Math.floor(canvasSize / 2);
47
- const r = Math.floor(canvasSize * 0.2);
48
-
49
- // 1. Wood Sphere (Left)
50
- commands.push(...materialShapes.drawTexturedSphere(cx1, cy, r, 'wood'));
51
-
52
- // 2. Stone Sphere (Right)
53
- commands.push(...materialShapes.drawTexturedSphere(cx2, cy, r, 'stone'));
54
-
55
- return commands;
56
- }
57
-
58
- function getMaterialLessonCatalog() {
59
- return [
60
- { id: 'material_shiny', name: 'Metal vs Matte', description: 'Sharp highlights (Metal) vs Soft highlights (Plastic)', fn: lessonMaterialShiny },
61
- { id: 'material_glass', name: 'Glass & Transparency', description: 'Fresnel effect and transmitted light', fn: lessonMaterialGlass },
62
- { id: 'material_texture', name: 'Texture: Wood vs Stone', description: 'Grain lines vs cracks on a 3D form', fn: lessonMaterialTexture },
63
- ];
64
- }
65
-
66
- module.exports = {
67
- lessonMaterialShiny,
68
- lessonMaterialGlass,
69
- lessonMaterialTexture,
70
- getMaterialLessonCatalog
71
- };
@@ -1,138 +0,0 @@
1
- const shapes = require('./shapes');
2
- const perspShapes = require('./perspective_shapes');
3
-
4
- /**
5
- * Lesson: 1-Point Perspective
6
- */
7
- function lesson1PointPerspective(canvasSize = 32, color = '#2196f3') {
8
- const commands = [];
9
- const horizonY = Math.floor(canvasSize * 0.4);
10
- const vpX = Math.floor(canvasSize * 0.5);
11
- const vpY = horizonY;
12
-
13
- // Horizon & VP
14
- commands.push(...perspShapes.drawHorizon(canvasSize, horizonY));
15
- commands.push(...perspShapes.drawVP(vpX, vpY));
16
-
17
- // Box below horizon (seeing top face)
18
- const w = Math.floor(canvasSize * 0.2);
19
- const h = Math.floor(canvasSize * 0.15);
20
- commands.push(...perspShapes.draw1PointBox(vpX, vpY, Math.floor(canvasSize * 0.2), horizonY + Math.floor(canvasSize * 0.2), w, h, 0.4, color));
21
-
22
- // Box above horizon (seeing bottom face)
23
- commands.push(...perspShapes.draw1PointBox(vpX, vpY, Math.floor(canvasSize * 0.6), horizonY - Math.floor(canvasSize * 0.3), w, h, 0.4, '#e91e63'));
24
-
25
- return commands;
26
- }
27
-
28
- /**
29
- * Lesson: 2-Point Perspective
30
- */
31
- function lesson2PointPerspective(canvasSize = 32, color = '#4caf50') {
32
- const commands = [];
33
- const horizonY = Math.floor(canvasSize * 0.5);
34
- const vp1X = Math.floor(canvasSize * 0.1);
35
- const vp2X = Math.floor(canvasSize * 0.9);
36
-
37
- // Horizon & VPs
38
- commands.push(...perspShapes.drawHorizon(canvasSize, horizonY));
39
- commands.push(...perspShapes.drawVP(vp1X, horizonY));
40
- commands.push(...perspShapes.drawVP(vp2X, horizonY));
41
-
42
- // 2-Point Box straddling the horizon
43
- const startX = Math.floor(canvasSize * 0.4);
44
- const startY = Math.floor(canvasSize * 0.3);
45
- const h = Math.floor(canvasSize * 0.4);
46
-
47
- commands.push(...perspShapes.draw2PointBox(vp1X, horizonY, vp2X, horizonY, startX, startY, h, 0.3, 0.4, color));
48
-
49
- return commands;
50
- }
51
-
52
- /**
53
- * Lesson: 3-Point Perspective (Bird's eye view)
54
- */
55
- function lesson3PointPerspective(canvasSize = 32, color = '#ff9800') {
56
- const commands = [];
57
- const horizonY = Math.floor(canvasSize * 0.2);
58
- const vp1X = Math.floor(canvasSize * 0.1);
59
- const vp2X = Math.floor(canvasSize * 0.9);
60
- const vp3X = Math.floor(canvasSize * 0.5);
61
- const vp3Y = Math.floor(canvasSize * 1.5); // VP3 far below (Bird's eye)
62
-
63
- // Horizon & VPs
64
- commands.push(...perspShapes.drawHorizon(canvasSize, horizonY));
65
- commands.push(...perspShapes.drawVP(vp1X, horizonY));
66
- commands.push(...perspShapes.drawVP(vp2X, horizonY));
67
- // VP3 is usually off-canvas, but we draw a line to it to show direction
68
-
69
- // We approximate a 3-point box by drawing converging vertical lines to VP3
70
- const topY = Math.floor(canvasSize * 0.4);
71
- const h = Math.floor(canvasSize * 0.4);
72
-
73
- // Center edge converging to VP3
74
- commands.push(shapes.drawLine(vp3X, topY, vp3X, topY+h, color)); // simplified
75
- commands.push(shapes.drawLine(vp3X, topY+h, vp3X, vp3Y, '#e0e0e0')); // Guide to VP3
76
-
77
- // Left and Right top edges to VP1, VP2
78
- commands.push(shapes.drawLine(vp3X, topY, vp1X, horizonY, '#e0e0e0'));
79
- commands.push(shapes.drawLine(vp3X, topY, vp2X, horizonY, '#e0e0e0'));
80
-
81
- // Draw the rest of the box structure to simulate 3-point
82
- const lX = vp3X - Math.floor(canvasSize * 0.15);
83
- const rX = vp3X + Math.floor(canvasSize * 0.2);
84
- // Vertical edges also converge to VP3 slightly (foreshortening)
85
- commands.push(shapes.drawLine(lX, topY + Math.floor(canvasSize * 0.1), lX + 2, topY + h, color));
86
- commands.push(shapes.drawLine(rX, topY + Math.floor(canvasSize * 0.15), rX - 3, topY + h - 5, color));
87
-
88
- return commands;
89
- }
90
-
91
- /**
92
- * Lesson: Foreshortening (Depth foreshortening)
93
- * Drawing a cylinder pointing directly at the viewer
94
- */
95
- function lessonForeshortening(canvasSize = 32, color = '#9c27b0') {
96
- const commands = [];
97
- const cx = Math.floor(canvasSize / 2);
98
- const cy = Math.floor(canvasSize / 2);
99
-
100
- // Draw overlapping circles getting larger (coming towards viewer)
101
- const numCircles = 5;
102
- const maxR = Math.floor(canvasSize * 0.4);
103
- const minR = Math.floor(canvasSize * 0.15);
104
-
105
- for(let i=0; i<numCircles; i++) {
106
- const t = i / (numCircles - 1); // 0 to 1
107
- // Radius grows exponentially to simulate perspective
108
- const r = minR + (maxR - minR) * (t * t);
109
- // Y position shifts slightly to show overlap
110
- const y = cy - Math.floor(canvasSize * 0.2) + Math.floor(canvasSize * 0.4 * t);
111
-
112
- // Draw the circle
113
- commands.push(shapes.drawCircle(cx, y, Math.floor(r), color, false));
114
- }
115
-
116
- // Draw bounding lines converging
117
- commands.push(shapes.drawLine(cx - minR, cy - Math.floor(canvasSize * 0.2), cx - maxR, cy + Math.floor(canvasSize * 0.2), '#bdbdbd'));
118
- commands.push(shapes.drawLine(cx + minR, cy - Math.floor(canvasSize * 0.2), cx + maxR, cy + Math.floor(canvasSize * 0.2), '#bdbdbd'));
119
-
120
- return commands;
121
- }
122
-
123
- function getPerspectiveLessonCatalog() {
124
- return [
125
- { id: 'persp_1point', name: '1-Point Perspective', description: 'Horizon, 1 VP, Front vs Receding planes', fn: lesson1PointPerspective },
126
- { id: 'persp_2point', name: '2-Point Perspective', description: 'Horizon, 2 VPs, Edges facing viewer', fn: lesson2PointPerspective },
127
- { id: 'persp_3point', name: '3-Point Perspective', description: '3 VPs (Bird\'s eye view)', fn: lesson3PointPerspective },
128
- { id: 'persp_foreshorten', name: 'Foreshortening', description: 'Cylinder pointing at viewer', fn: lessonForeshortening },
129
- ];
130
- }
131
-
132
- module.exports = {
133
- lesson1PointPerspective,
134
- lesson2PointPerspective,
135
- lesson3PointPerspective,
136
- lessonForeshortening,
137
- getPerspectiveLessonCatalog
138
- };
@@ -1,82 +0,0 @@
1
- const skyShapes1 = require('./sky_shapes_1');
2
-
3
- /**
4
- * Lesson 1: Sun Shapes (Hình dạng mặt trời)
5
- * Compares Basic, Soft, and Rays
6
- */
7
- function lessonSunShapes(canvasSize = 32) {
8
- const commands = [];
9
- const y = Math.floor(canvasSize / 2);
10
- const r = Math.floor(canvasSize * 0.15);
11
-
12
- // Left: Basic
13
- commands.push(...skyShapes1.drawSunBasic(Math.floor(canvasSize * 0.2), y, r));
14
- // Center: Soft
15
- commands.push(...skyShapes1.drawSunSoft(Math.floor(canvasSize * 0.5), y, r));
16
- // Right: Rays
17
- commands.push(...skyShapes1.drawSunRays(Math.floor(canvasSize * 0.8), y, r));
18
-
19
- return commands;
20
- }
21
-
22
- /**
23
- * Lesson 2: Sunset Colors (Màu sắc buổi chiều)
24
- * Shows the progression of colors from blue to yellow
25
- */
26
- function lessonSunsetColors(canvasSize = 32) {
27
- const commands = [];
28
-
29
- // The classic sunset gradient: Blue -> Purple -> Pink -> Orange -> Yellow (top to bottom)
30
- const sunsetPalette = [
31
- '#3f51b5', // Blue
32
- '#9c27b0', // Purple
33
- '#e91e63', // Pink
34
- '#ff9800', // Orange
35
- '#ffeb3b' // Yellow
36
- ];
37
-
38
- commands.push(...skyShapes1.drawSkyGradient(0, 0, canvasSize, canvasSize, sunsetPalette));
39
-
40
- return commands;
41
- }
42
-
43
- /**
44
- * Lesson 3: Sunset Sky (Bầu trời hoàng hôn)
45
- * Combines the gradient sky with a soft sun setting at the bottom
46
- */
47
- function lessonSunsetSky(canvasSize = 32) {
48
- const commands = [];
49
-
50
- // 1. Draw the Sky
51
- const sunsetPalette = [
52
- '#1a237e', // Dark Blue
53
- '#512da8', // Deep Purple
54
- '#c2185b', // Magenta
55
- '#ff5722', // Deep Orange
56
- '#ffb300' // Amber
57
- ];
58
- commands.push(...skyShapes1.drawSkyGradient(0, 0, canvasSize, canvasSize, sunsetPalette));
59
-
60
- // 2. Draw the Sun (Soft glowing sun near the bottom)
61
- const cx = Math.floor(canvasSize / 2);
62
- const cy = Math.floor(canvasSize * 0.8);
63
- const r = Math.floor(canvasSize * 0.15);
64
- commands.push(...skyShapes1.drawSunSoft(cx, cy, r));
65
-
66
- return commands;
67
- }
68
-
69
- function getSkyLesson1Catalog() {
70
- return [
71
- { id: 'sky_sun_shapes', name: 'Sun Shapes', description: 'Basic vs Soft vs Rays', fn: lessonSunShapes },
72
- { id: 'sky_sunset_colors', name: 'Sunset Colors', description: 'Gradient bands from Blue to Yellow', fn: lessonSunsetColors },
73
- { id: 'sky_sunset_sky', name: 'Sunset Sky', description: 'Combining gradient sky with a soft sun', fn: lessonSunsetSky },
74
- ];
75
- }
76
-
77
- module.exports = {
78
- lessonSunShapes,
79
- lessonSunsetColors,
80
- lessonSunsetSky,
81
- getSkyLesson1Catalog
82
- };