@pixel-normal-edit/mcp 2.1.0 → 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.
- package/clear-firebase.js +37 -0
- package/domains/art-tree/README.md +134 -0
- package/domains/art-tree/REORGANIZATION_PLAN.md +168 -0
- package/domains/art-tree/REORGANIZATION_SUMMARY.md +260 -0
- package/domains/art-tree/index.js +58 -58
- package/domains/art-tree/lessons/3d/box-properties.js +38 -0
- package/domains/art-tree/lessons/3d/cone-properties.js +31 -0
- package/domains/art-tree/lessons/3d/cylinder-properties.js +29 -0
- package/domains/art-tree/lessons/3d/sphere-properties.js +25 -0
- package/domains/art-tree/lessons/advanced/angles.js +30 -0
- package/domains/art-tree/lessons/advanced/distances.js +26 -0
- package/domains/art-tree/lessons/advanced/shape-ratios.js +25 -0
- package/domains/art-tree/lessons/advanced/shape-relationships.js +28 -0
- package/domains/art-tree/lessons/advanced/symmetry-and-axis.js +26 -0
- package/domains/art-tree/{analysis_lessons.js → lessons/analysis/object-analysis.js} +5 -16
- package/domains/art-tree/lessons/basic/circles.js +26 -0
- package/domains/art-tree/lessons/basic/composition.js +34 -0
- package/domains/art-tree/lessons/basic/curves.js +31 -0
- package/domains/art-tree/lessons/basic/ellipses.js +26 -0
- package/domains/art-tree/lessons/basic/freehand.js +19 -0
- package/domains/art-tree/lessons/basic/index.js +36 -0
- package/domains/art-tree/lessons/basic/lines.js +38 -0
- package/domains/art-tree/lessons/basic/parallel-and-intersecting.js +22 -0
- package/domains/art-tree/lessons/basic/polygons.js +25 -0
- package/domains/art-tree/lessons/basic/proportions-and-angles.js +20 -0
- package/domains/art-tree/lessons/basic/spiral.js +21 -0
- package/domains/art-tree/lessons/basic/squares.js +28 -0
- package/domains/art-tree/lessons/basic/strokes.js +23 -0
- package/domains/art-tree/lessons/basic/triangles.js +30 -0
- package/domains/art-tree/lessons/cross-sections/bottle-sections.js +26 -0
- package/domains/art-tree/lessons/cross-sections/glass-sections.js +24 -0
- package/domains/art-tree/lessons/cross-sections/head-sections.js +17 -0
- package/domains/art-tree/lessons/curves/curve-properties.js +50 -0
- package/domains/art-tree/lessons/curves/curve-topology.js +45 -0
- package/domains/art-tree/lessons/curves/curve-types.js +44 -0
- package/domains/art-tree/lessons/ellipses/coaxial-ellipses.js +29 -0
- package/domains/art-tree/lessons/ellipses/ellipse-anatomy.js +26 -0
- package/domains/art-tree/lessons/ellipses/ellipse-orientations.js +28 -0
- package/domains/art-tree/lessons/ellipses/ellipse-proportions.js +27 -0
- package/domains/art-tree/lessons/hidden/hidden-box.js +20 -0
- package/domains/art-tree/lessons/hidden/hidden-cup.js +19 -0
- package/domains/art-tree/lessons/hidden/hidden-head.js +18 -0
- package/domains/art-tree/lessons/index.js +42 -0
- package/domains/art-tree/{layer_lessons.js → lessons/layers/layer-step.js} +5 -16
- package/domains/art-tree/lessons/lighting/contact-shadow.js +33 -0
- package/domains/art-tree/lessons/lighting/light-direction.js +30 -0
- package/domains/art-tree/lessons/lighting/light-zones.js +30 -0
- package/domains/art-tree/lessons/materials/material-glass.js +21 -0
- package/domains/art-tree/lessons/materials/material-shiny.js +26 -0
- package/domains/art-tree/lessons/materials/material-texture.js +26 -0
- package/domains/art-tree/lessons/perspective/1point-perspective.js +30 -0
- package/domains/art-tree/lessons/perspective/2point-perspective.js +30 -0
- package/domains/art-tree/lessons/perspective/3point-perspective.js +45 -0
- package/domains/art-tree/lessons/perspective/foreshortening.js +38 -0
- package/domains/art-tree/lessons/sky/sun-shapes.js +25 -0
- package/domains/art-tree/lessons/sky/sunset-colors.js +27 -0
- package/domains/art-tree/lessons/sky/sunset-sky.js +32 -0
- package/domains/art-tree/{structure_lessons.js → lessons/structure/axis-orientation.js} +3 -53
- package/domains/art-tree/lessons/structure/complex-structure.js +21 -0
- package/domains/art-tree/lessons/structure/x-yzaxes.js +28 -0
- package/domains/art-tree/lessons/surfaces/chair-analysis.js +17 -0
- package/domains/art-tree/lessons/surfaces/cup-analysis.js +18 -0
- package/domains/art-tree/lessons/surfaces/edge-types.js +40 -0
- package/domains/art-tree/lessons/surfaces/surface-types.js +42 -0
- package/domains/art-tree/lessons/transforms/bend.js +27 -0
- package/domains/art-tree/{transform_lessons_2.js → lessons/transforms/combine.js} +3 -54
- package/domains/art-tree/lessons/transforms/cut.js +25 -0
- package/domains/art-tree/lessons/transforms/hollow.js +24 -0
- package/domains/art-tree/lessons/transforms/rotate.js +16 -0
- package/domains/art-tree/lessons/transforms/squash.js +31 -0
- package/domains/art-tree/lessons/transforms/stretch.js +31 -0
- package/domains/art-tree/lessons/transforms/taper-swell.js +33 -0
- package/domains/art-tree/{vocab_lessons.js → lessons/vocab/vocab-house.js} +5 -16
- package/domains/art-tree/lib/tool-register.js +104 -0
- package/domains/art-tree/lib/validators.js +78 -0
- package/domains/art-tree/shapes/grid.js +37 -0
- package/domains/art-tree/shapes/polyline.js +26 -0
- package/domains/art-tree/{3d_tools.js → tools/3d.js} +2 -2
- package/domains/art-tree/{advanced_tools.js → tools/advanced.js} +2 -2
- package/domains/art-tree/{analysis_tools.js → tools/analysis.js} +2 -2
- package/domains/art-tree/{tools.js → tools/basic.js} +3 -3
- package/domains/art-tree/{cross_section_tools.js → tools/cross-sections.js} +2 -2
- package/domains/art-tree/{curve_tools.js → tools/curves.js} +2 -2
- package/domains/art-tree/{ellipse_tools.js → tools/ellipses.js} +2 -2
- package/domains/art-tree/{hidden_tools.js → tools/hidden.js} +2 -2
- package/domains/art-tree/tools/index.js +53 -0
- package/domains/art-tree/{layer_tools.js → tools/layers.js} +2 -2
- package/domains/art-tree/{light_tools.js → tools/lighting.js} +2 -2
- package/domains/art-tree/{material_tools.js → tools/materials.js} +2 -2
- package/domains/art-tree/{perspective_tools.js → tools/perspective.js} +2 -2
- package/domains/art-tree/{sky_tools.js → tools/sky.js} +2 -2
- package/domains/art-tree/{structure_tools.js → tools/structure.js} +2 -2
- package/domains/art-tree/{surface_tools.js → tools/surfaces.js} +2 -2
- package/domains/art-tree/{transform_tools.js → tools/transforms.js} +3 -3
- package/domains/art-tree/{vocab_tools.js → tools/vocab.js} +2 -2
- package/package.json +1 -1
- package/rules/prerequisites.js +30 -30
- package/rules/rules.js +1 -1
- package/rules/workflow.js +28 -20
- package/tools/canvas-tools.js +2 -2
- package/tools/drawing-tools.js +23 -12
- package/tools/workspace-tools.js +5 -4
- package/domains/art-tree/3d_lessons.js +0 -114
- package/domains/art-tree/advanced_lessons.js +0 -124
- package/domains/art-tree/cross_section_lessons.js +0 -65
- package/domains/art-tree/curve_lessons.js +0 -138
- package/domains/art-tree/ellipse_lessons.js +0 -105
- package/domains/art-tree/hidden_lessons.js +0 -55
- package/domains/art-tree/lessons.js +0 -305
- package/domains/art-tree/light_lessons.js +0 -92
- package/domains/art-tree/material_lessons.js +0 -71
- package/domains/art-tree/perspective_lessons.js +0 -138
- package/domains/art-tree/sky_lessons_1.js +0 -82
- package/domains/art-tree/surface_lessons.js +0 -112
- package/domains/art-tree/transform_lessons_1.js +0 -108
- /package/domains/art-tree/{3d_shapes.js → shapes/3d.js} +0 -0
- /package/domains/art-tree/{advanced_shapes.js → shapes/advanced.js} +0 -0
- /package/domains/art-tree/{analysis_shapes.js → shapes/analysis.js} +0 -0
- /package/domains/art-tree/{shapes.js → shapes/basic.js} +0 -0
- /package/domains/art-tree/{cross_section_shapes.js → shapes/cross-sections.js} +0 -0
- /package/domains/art-tree/{curve_shapes.js → shapes/curves.js} +0 -0
- /package/domains/art-tree/{ellipse_shapes.js → shapes/ellipses.js} +0 -0
- /package/domains/art-tree/{hidden_shapes.js → shapes/hidden.js} +0 -0
- /package/domains/art-tree/{layer_shapes.js → shapes/layers.js} +0 -0
- /package/domains/art-tree/{light_shapes.js → shapes/lighting.js} +0 -0
- /package/domains/art-tree/{material_shapes.js → shapes/materials.js} +0 -0
- /package/domains/art-tree/{perspective_shapes.js → shapes/perspective.js} +0 -0
- /package/domains/art-tree/{sky_shapes_1.js → shapes/sky.js} +0 -0
- /package/domains/art-tree/{structure_shapes.js → shapes/structure.js} +0 -0
- /package/domains/art-tree/{surface_shapes.js → shapes/surfaces.js} +0 -0
- /package/domains/art-tree/{transform_shapes.js → shapes/transforms.js} +0 -0
- /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
|
-
};
|