@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.
- package/clear-firebase.js +37 -0
- package/core/command-bus.js +6 -3
- package/core/server.js +98 -3
- 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/README.md +358 -285
- package/rules/index.js +9 -9
- package/rules/prerequisites.js +121 -64
- package/rules/rules.js +76 -35
- package/rules/workflow.js +270 -56
- 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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from ellipse_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Ellipse Orientations (Horizontal, Vertical, Tilted)
|
|
8
|
+
*/
|
|
9
|
+
function lessonEllipseOrientations(canvasSize = 32, color = '#2196f3') {
|
|
10
|
+
const commands = [];
|
|
11
|
+
const midY = Math.floor(canvasSize / 2);
|
|
12
|
+
const qX = Math.floor(canvasSize / 4);
|
|
13
|
+
const rLong = Math.floor(canvasSize * 0.2);
|
|
14
|
+
const rShort = Math.floor(canvasSize * 0.1);
|
|
15
|
+
|
|
16
|
+
// Horizontal (Left)
|
|
17
|
+
commands.push(shapes.drawEllipse(qX, midY, rLong, rShort, color, false));
|
|
18
|
+
|
|
19
|
+
// Vertical (Middle)
|
|
20
|
+
commands.push(shapes.drawEllipse(qX * 2, midY, rShort, rLong, '#e91e63', false));
|
|
21
|
+
|
|
22
|
+
// Tilted (Right) - 45 degrees
|
|
23
|
+
commands.push(...ellipseShapes.drawRotatedEllipse(qX * 3, midY, rLong, rShort, Math.PI / 4, '#4caf50'));
|
|
24
|
+
|
|
25
|
+
return commands;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { lessonEllipseOrientations };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from ellipse_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Ellipse Proportions (Wide vs Narrow)
|
|
8
|
+
*/
|
|
9
|
+
function lessonEllipseProportions(canvasSize = 32, color = '#ff9800') {
|
|
10
|
+
const commands = [];
|
|
11
|
+
const midY = Math.floor(canvasSize / 2);
|
|
12
|
+
const qX = Math.floor(canvasSize / 4);
|
|
13
|
+
const rx = Math.floor(canvasSize * 0.2);
|
|
14
|
+
|
|
15
|
+
// Wide Ellipse (Closer to a circle)
|
|
16
|
+
commands.push(shapes.drawEllipse(qX, midY, rx, Math.floor(rx * 0.8), color, false));
|
|
17
|
+
|
|
18
|
+
// Medium Ellipse
|
|
19
|
+
commands.push(shapes.drawEllipse(qX * 2, midY, rx, Math.floor(rx * 0.4), '#9c27b0', false));
|
|
20
|
+
|
|
21
|
+
// Narrow Ellipse (Almost a line)
|
|
22
|
+
commands.push(shapes.drawEllipse(qX * 3, midY, rx, Math.floor(rx * 0.1), '#f44336', false));
|
|
23
|
+
|
|
24
|
+
return commands;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { lessonEllipseProportions };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from hidden_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Hidden Box (6-sided box)
|
|
8
|
+
* You see 3 faces, but you must understand all 6.
|
|
9
|
+
*/
|
|
10
|
+
function lessonHiddenBox(canvasSize = 32, visibleColor = '#2196f3', hiddenColor = '#e0e0e0') {
|
|
11
|
+
const cx = Math.floor(canvasSize / 2);
|
|
12
|
+
const cy = Math.floor(canvasSize / 2);
|
|
13
|
+
const w = Math.floor(canvasSize * 0.4);
|
|
14
|
+
const h = Math.floor(canvasSize * 0.4);
|
|
15
|
+
const d = Math.floor(canvasSize * 0.4);
|
|
16
|
+
|
|
17
|
+
return hiddenShapes.drawXRayBox(cx, cy, w, h, d, visibleColor, hiddenColor);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = { lessonHiddenBox };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from hidden_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Hidden Cup (Cup and inner bottom)
|
|
8
|
+
* You don't see the full inside bottom, but must understand how the wall goes down.
|
|
9
|
+
*/
|
|
10
|
+
function lessonHiddenCup(canvasSize = 32, visibleColor = '#4caf50', hiddenColor = '#e0e0e0') {
|
|
11
|
+
const cx = Math.floor(canvasSize / 2);
|
|
12
|
+
const cy = Math.floor(canvasSize / 2);
|
|
13
|
+
const r = Math.floor(canvasSize * 0.25);
|
|
14
|
+
const h = Math.floor(canvasSize * 0.5);
|
|
15
|
+
|
|
16
|
+
return hiddenShapes.drawXRayCup(cx, cy, r, h, visibleColor, hiddenColor);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { lessonHiddenCup };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from hidden_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Hidden Head (Human head and skull)
|
|
8
|
+
* You don't see the whole skull, but must understand the structure behind it.
|
|
9
|
+
*/
|
|
10
|
+
function lessonHiddenHead(canvasSize = 32, visibleColor = '#ff5722', hiddenColor = '#e0e0e0') {
|
|
11
|
+
const cx = Math.floor(canvasSize / 2);
|
|
12
|
+
const cy = Math.floor(canvasSize * 0.4);
|
|
13
|
+
const r = Math.floor(canvasSize * 0.25);
|
|
14
|
+
|
|
15
|
+
return hiddenShapes.drawXRayHead(cx, cy, r, visibleColor, hiddenColor);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { lessonHiddenHead };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* lessons/index.js — Art Tree: Lessons Index
|
|
4
|
+
*
|
|
5
|
+
* Exports all lesson functions and catalog getters organized by category.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const basic = require('./basic');
|
|
9
|
+
const advanced = require('./advanced');
|
|
10
|
+
const curves = require('./curves');
|
|
11
|
+
const ellipses = require('./ellipses');
|
|
12
|
+
const forms3d = require('./3d');
|
|
13
|
+
const structure = require('./structure');
|
|
14
|
+
const crossSections = require('./cross-sections');
|
|
15
|
+
const transforms = require('./transforms');
|
|
16
|
+
const surfaces = require('./surfaces');
|
|
17
|
+
const perspective = require('./perspective');
|
|
18
|
+
const hidden = require('./hidden');
|
|
19
|
+
const lighting = require('./lighting');
|
|
20
|
+
const materials = require('./materials');
|
|
21
|
+
const analysis = require('./analysis');
|
|
22
|
+
const layers = require('./layers');
|
|
23
|
+
const sky = require('./sky');
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
...basic,
|
|
27
|
+
...advanced,
|
|
28
|
+
...curves,
|
|
29
|
+
...ellipses,
|
|
30
|
+
...forms3d,
|
|
31
|
+
...structure,
|
|
32
|
+
...crossSections,
|
|
33
|
+
...transforms,
|
|
34
|
+
...surfaces,
|
|
35
|
+
...perspective,
|
|
36
|
+
...hidden,
|
|
37
|
+
...lighting,
|
|
38
|
+
...materials,
|
|
39
|
+
...analysis,
|
|
40
|
+
...layers,
|
|
41
|
+
...sky,
|
|
42
|
+
};
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from layer_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Lesson: Layer Structure (Tư duy Layer)
|
|
@@ -15,18 +18,4 @@ function lessonLayerStep(canvasSize = 32, layerIndex = 1) {
|
|
|
15
18
|
return layerShapes.drawLayeredCup(cx, cy, canvasSize, validLayer);
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
return [
|
|
20
|
-
{
|
|
21
|
-
id: 'layer_step',
|
|
22
|
-
name: '7-Layer Painting Structure',
|
|
23
|
-
description: 'View the contents of a specific layer of a Cup (1=Ref, 2=Sketch, 3=Construction, 4=Lineart, 5=Color, 6=Shadow, 7=Light)',
|
|
24
|
-
fn: lessonLayerStep
|
|
25
|
-
}
|
|
26
|
-
];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
module.exports = {
|
|
30
|
-
lessonLayerStep,
|
|
31
|
-
getLayerLessonCatalog
|
|
32
|
-
};
|
|
21
|
+
module.exports = { lessonLayerStep };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from light_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Contact Shadow (Point of contact shadow)
|
|
8
|
+
* The darkest area where an object touches the ground.
|
|
9
|
+
*/
|
|
10
|
+
function lessonContactShadow(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx = Math.floor(canvasSize / 2);
|
|
13
|
+
const cy = Math.floor(canvasSize / 2);
|
|
14
|
+
const r = Math.floor(canvasSize * 0.3);
|
|
15
|
+
|
|
16
|
+
// Ground line
|
|
17
|
+
commands.push(shapes.drawLine(0, cy + r, canvasSize, cy + r, '#9e9e9e'));
|
|
18
|
+
|
|
19
|
+
// Sphere outline
|
|
20
|
+
commands.push(shapes.drawCircle(cx, cy, r, '#bdbdbd', false));
|
|
21
|
+
|
|
22
|
+
// Cast shadow (faint)
|
|
23
|
+
commands.push(shapes.drawEllipse(cx + Math.floor(r*0.5), cy + r, Math.floor(r*1.2), Math.floor(r*0.2), '#757575', true));
|
|
24
|
+
|
|
25
|
+
// CONTACT SHADOW (Pitch black, right at the touching point)
|
|
26
|
+
// Draw a very small, very dark ellipse directly under the center
|
|
27
|
+
commands.push(shapes.drawEllipse(cx, cy + r, Math.floor(r * 0.4), 2, '#000000', true));
|
|
28
|
+
commands.push(shapes.drawEllipse(cx, cy + r, Math.floor(r * 0.2), 1, '#000000', true));
|
|
29
|
+
|
|
30
|
+
return commands;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = { lessonContactShadow };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from light_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Light Direction & Intensity (Light direction and plane values)
|
|
8
|
+
* Shows a box with planes facing/turning away from light.
|
|
9
|
+
*/
|
|
10
|
+
function lessonLightDirection(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx = Math.floor(canvasSize / 2);
|
|
13
|
+
const cy = Math.floor(canvasSize / 2);
|
|
14
|
+
const w = Math.floor(canvasSize * 0.25);
|
|
15
|
+
const h = Math.floor(canvasSize * 0.25);
|
|
16
|
+
|
|
17
|
+
// Light from top-left
|
|
18
|
+
const lightAngle = -Math.PI * 0.8;
|
|
19
|
+
|
|
20
|
+
const lx = cx - Math.floor(canvasSize * 0.35);
|
|
21
|
+
const ly = cy - Math.floor(canvasSize * 0.35);
|
|
22
|
+
commands.push(...lightShapes.drawLightSource(lx, ly, Math.floor(canvasSize * 0.05)));
|
|
23
|
+
|
|
24
|
+
// Draw shaded box
|
|
25
|
+
commands.push(...lightShapes.drawShadedBox(cx, cy, w, h, lightAngle));
|
|
26
|
+
|
|
27
|
+
return commands;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { lessonLightDirection };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from light_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: 6 Zones of Light (Sphere)
|
|
8
|
+
* Highlight, Light, Halftone, Core shadow, Reflected light, Cast shadow.
|
|
9
|
+
*/
|
|
10
|
+
function lessonLightZones(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx = Math.floor(canvasSize / 2);
|
|
13
|
+
const cy = Math.floor(canvasSize / 2);
|
|
14
|
+
const r = Math.floor(canvasSize * 0.25);
|
|
15
|
+
|
|
16
|
+
// Light from top-left (approx -45 degrees or -135 degrees mathematically)
|
|
17
|
+
const lightAngle = -Math.PI * 0.75;
|
|
18
|
+
|
|
19
|
+
// Draw light source
|
|
20
|
+
const lx = cx + Math.floor(r * 2 * Math.cos(lightAngle));
|
|
21
|
+
const ly = cy + Math.floor(r * 2 * Math.sin(lightAngle));
|
|
22
|
+
commands.push(...lightShapes.drawLightSource(lx, ly, Math.floor(canvasSize * 0.05)));
|
|
23
|
+
|
|
24
|
+
// Draw shaded sphere
|
|
25
|
+
commands.push(...lightShapes.drawShadedSphere(cx, cy, r, lightAngle));
|
|
26
|
+
|
|
27
|
+
return commands;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { lessonLightZones };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from material_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Transparent (Glass)
|
|
8
|
+
* Demonstrates Fresnel effect, sharp reflections, and light transmission.
|
|
9
|
+
*/
|
|
10
|
+
function lessonMaterialGlass(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx = Math.floor(canvasSize / 2);
|
|
13
|
+
const cy = Math.floor(canvasSize / 2);
|
|
14
|
+
const r = Math.floor(canvasSize * 0.35);
|
|
15
|
+
|
|
16
|
+
commands.push(...materialShapes.drawGlassSphere(cx, cy, r));
|
|
17
|
+
|
|
18
|
+
return commands;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = { lessonMaterialGlass };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from material_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Shiny vs Matte (Metal vs Plastic/Rubber)
|
|
8
|
+
* Compares high contrast sharp highlights vs low contrast diffused highlights.
|
|
9
|
+
*/
|
|
10
|
+
function lessonMaterialShiny(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx1 = Math.floor(canvasSize * 0.3);
|
|
13
|
+
const cx2 = Math.floor(canvasSize * 0.7);
|
|
14
|
+
const cy = Math.floor(canvasSize / 2);
|
|
15
|
+
const r = Math.floor(canvasSize * 0.2);
|
|
16
|
+
|
|
17
|
+
// 1. Metal Sphere (Left)
|
|
18
|
+
commands.push(...materialShapes.drawMetalSphere(cx1, cy, r));
|
|
19
|
+
|
|
20
|
+
// 2. Matte/Plastic Sphere (Right)
|
|
21
|
+
commands.push(...materialShapes.drawMatteSphere(cx2, cy, r, '#e65100'));
|
|
22
|
+
|
|
23
|
+
return commands;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = { lessonMaterialShiny };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from material_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Texture (Wood vs Stone)
|
|
8
|
+
* Compares organic lines vs rough cracks.
|
|
9
|
+
*/
|
|
10
|
+
function lessonMaterialTexture(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx1 = Math.floor(canvasSize * 0.3);
|
|
13
|
+
const cx2 = Math.floor(canvasSize * 0.7);
|
|
14
|
+
const cy = Math.floor(canvasSize / 2);
|
|
15
|
+
const r = Math.floor(canvasSize * 0.2);
|
|
16
|
+
|
|
17
|
+
// 1. Wood Sphere (Left)
|
|
18
|
+
commands.push(...materialShapes.drawTexturedSphere(cx1, cy, r, 'wood'));
|
|
19
|
+
|
|
20
|
+
// 2. Stone Sphere (Right)
|
|
21
|
+
commands.push(...materialShapes.drawTexturedSphere(cx2, cy, r, 'stone'));
|
|
22
|
+
|
|
23
|
+
return commands;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = { lessonMaterialTexture };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from perspective_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: 1-Point Perspective
|
|
8
|
+
*/
|
|
9
|
+
function lesson1PointPerspective(canvasSize = 32, color = '#2196f3') {
|
|
10
|
+
const commands = [];
|
|
11
|
+
const horizonY = Math.floor(canvasSize * 0.4);
|
|
12
|
+
const vpX = Math.floor(canvasSize * 0.5);
|
|
13
|
+
const vpY = horizonY;
|
|
14
|
+
|
|
15
|
+
// Horizon & VP
|
|
16
|
+
commands.push(...perspShapes.drawHorizon(canvasSize, horizonY));
|
|
17
|
+
commands.push(...perspShapes.drawVP(vpX, vpY));
|
|
18
|
+
|
|
19
|
+
// Box below horizon (seeing top face)
|
|
20
|
+
const w = Math.floor(canvasSize * 0.2);
|
|
21
|
+
const h = Math.floor(canvasSize * 0.15);
|
|
22
|
+
commands.push(...perspShapes.draw1PointBox(vpX, vpY, Math.floor(canvasSize * 0.2), horizonY + Math.floor(canvasSize * 0.2), w, h, 0.4, color));
|
|
23
|
+
|
|
24
|
+
// Box above horizon (seeing bottom face)
|
|
25
|
+
commands.push(...perspShapes.draw1PointBox(vpX, vpY, Math.floor(canvasSize * 0.6), horizonY - Math.floor(canvasSize * 0.3), w, h, 0.4, '#e91e63'));
|
|
26
|
+
|
|
27
|
+
return commands;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { lesson1PointPerspective };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from perspective_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: 2-Point Perspective
|
|
8
|
+
*/
|
|
9
|
+
function lesson2PointPerspective(canvasSize = 32, color = '#4caf50') {
|
|
10
|
+
const commands = [];
|
|
11
|
+
const horizonY = Math.floor(canvasSize * 0.5);
|
|
12
|
+
const vp1X = Math.floor(canvasSize * 0.1);
|
|
13
|
+
const vp2X = Math.floor(canvasSize * 0.9);
|
|
14
|
+
|
|
15
|
+
// Horizon & VPs
|
|
16
|
+
commands.push(...perspShapes.drawHorizon(canvasSize, horizonY));
|
|
17
|
+
commands.push(...perspShapes.drawVP(vp1X, horizonY));
|
|
18
|
+
commands.push(...perspShapes.drawVP(vp2X, horizonY));
|
|
19
|
+
|
|
20
|
+
// 2-Point Box straddling the horizon
|
|
21
|
+
const startX = Math.floor(canvasSize * 0.4);
|
|
22
|
+
const startY = Math.floor(canvasSize * 0.3);
|
|
23
|
+
const h = Math.floor(canvasSize * 0.4);
|
|
24
|
+
|
|
25
|
+
commands.push(...perspShapes.draw2PointBox(vp1X, horizonY, vp2X, horizonY, startX, startY, h, 0.3, 0.4, color));
|
|
26
|
+
|
|
27
|
+
return commands;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { lesson2PointPerspective };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from perspective_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: 3-Point Perspective (Bird's eye view)
|
|
8
|
+
*/
|
|
9
|
+
function lesson3PointPerspective(canvasSize = 32, color = '#ff9800') {
|
|
10
|
+
const commands = [];
|
|
11
|
+
const horizonY = Math.floor(canvasSize * 0.2);
|
|
12
|
+
const vp1X = Math.floor(canvasSize * 0.1);
|
|
13
|
+
const vp2X = Math.floor(canvasSize * 0.9);
|
|
14
|
+
const vp3X = Math.floor(canvasSize * 0.5);
|
|
15
|
+
const vp3Y = Math.floor(canvasSize * 1.5); // VP3 far below (Bird's eye)
|
|
16
|
+
|
|
17
|
+
// Horizon & VPs
|
|
18
|
+
commands.push(...perspShapes.drawHorizon(canvasSize, horizonY));
|
|
19
|
+
commands.push(...perspShapes.drawVP(vp1X, horizonY));
|
|
20
|
+
commands.push(...perspShapes.drawVP(vp2X, horizonY));
|
|
21
|
+
// VP3 is usually off-canvas, but we draw a line to it to show direction
|
|
22
|
+
|
|
23
|
+
// We approximate a 3-point box by drawing converging vertical lines to VP3
|
|
24
|
+
const topY = Math.floor(canvasSize * 0.4);
|
|
25
|
+
const h = Math.floor(canvasSize * 0.4);
|
|
26
|
+
|
|
27
|
+
// Center edge converging to VP3
|
|
28
|
+
commands.push(shapes.drawLine(vp3X, topY, vp3X, topY+h, color)); // simplified
|
|
29
|
+
commands.push(shapes.drawLine(vp3X, topY+h, vp3X, vp3Y, '#e0e0e0')); // Guide to VP3
|
|
30
|
+
|
|
31
|
+
// Left and Right top edges to VP1, VP2
|
|
32
|
+
commands.push(shapes.drawLine(vp3X, topY, vp1X, horizonY, '#e0e0e0'));
|
|
33
|
+
commands.push(shapes.drawLine(vp3X, topY, vp2X, horizonY, '#e0e0e0'));
|
|
34
|
+
|
|
35
|
+
// Draw the rest of the box structure to simulate 3-point
|
|
36
|
+
const lX = vp3X - Math.floor(canvasSize * 0.15);
|
|
37
|
+
const rX = vp3X + Math.floor(canvasSize * 0.2);
|
|
38
|
+
// Vertical edges also converge to VP3 slightly (foreshortening)
|
|
39
|
+
commands.push(shapes.drawLine(lX, topY + Math.floor(canvasSize * 0.1), lX + 2, topY + h, color));
|
|
40
|
+
commands.push(shapes.drawLine(rX, topY + Math.floor(canvasSize * 0.15), rX - 3, topY + h - 5, color));
|
|
41
|
+
|
|
42
|
+
return commands;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
module.exports = { lesson3PointPerspective };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from perspective_lessons.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson: Foreshortening (Depth foreshortening)
|
|
8
|
+
* Drawing a cylinder pointing directly at the viewer
|
|
9
|
+
*/
|
|
10
|
+
function lessonForeshortening(canvasSize = 32, color = '#9c27b0') {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const cx = Math.floor(canvasSize / 2);
|
|
13
|
+
const cy = Math.floor(canvasSize / 2);
|
|
14
|
+
|
|
15
|
+
// Draw overlapping circles getting larger (coming towards viewer)
|
|
16
|
+
const numCircles = 5;
|
|
17
|
+
const maxR = Math.floor(canvasSize * 0.4);
|
|
18
|
+
const minR = Math.floor(canvasSize * 0.15);
|
|
19
|
+
|
|
20
|
+
for(let i=0; i<numCircles; i++) {
|
|
21
|
+
const t = i / (numCircles - 1); // 0 to 1
|
|
22
|
+
// Radius grows exponentially to simulate perspective
|
|
23
|
+
const r = minR + (maxR - minR) * (t * t);
|
|
24
|
+
// Y position shifts slightly to show overlap
|
|
25
|
+
const y = cy - Math.floor(canvasSize * 0.2) + Math.floor(canvasSize * 0.4 * t);
|
|
26
|
+
|
|
27
|
+
// Draw the circle
|
|
28
|
+
commands.push(shapes.drawCircle(cx, y, Math.floor(r), color, false));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Draw bounding lines converging
|
|
32
|
+
commands.push(shapes.drawLine(cx - minR, cy - Math.floor(canvasSize * 0.2), cx - maxR, cy + Math.floor(canvasSize * 0.2), '#bdbdbd'));
|
|
33
|
+
commands.push(shapes.drawLine(cx + minR, cy - Math.floor(canvasSize * 0.2), cx + maxR, cy + Math.floor(canvasSize * 0.2), '#bdbdbd'));
|
|
34
|
+
|
|
35
|
+
return commands;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { lessonForeshortening };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from sky_lessons_1.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson 1: Sun Shapes (Hình dạng mặt trời)
|
|
8
|
+
* Compares Basic, Soft, and Rays
|
|
9
|
+
*/
|
|
10
|
+
function lessonSunShapes(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
const y = Math.floor(canvasSize / 2);
|
|
13
|
+
const r = Math.floor(canvasSize * 0.15);
|
|
14
|
+
|
|
15
|
+
// Left: Basic
|
|
16
|
+
commands.push(...skyShapes1.drawSunBasic(Math.floor(canvasSize * 0.2), y, r));
|
|
17
|
+
// Center: Soft
|
|
18
|
+
commands.push(...skyShapes1.drawSunSoft(Math.floor(canvasSize * 0.5), y, r));
|
|
19
|
+
// Right: Rays
|
|
20
|
+
commands.push(...skyShapes1.drawSunRays(Math.floor(canvasSize * 0.8), y, r));
|
|
21
|
+
|
|
22
|
+
return commands;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = { lessonSunShapes };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from sky_lessons_1.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson 2: Sunset Colors (Màu sắc buổi chiều)
|
|
8
|
+
* Shows the progression of colors from blue to yellow
|
|
9
|
+
*/
|
|
10
|
+
function lessonSunsetColors(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
|
|
13
|
+
// The classic sunset gradient: Blue -> Purple -> Pink -> Orange -> Yellow (top to bottom)
|
|
14
|
+
const sunsetPalette = [
|
|
15
|
+
'#3f51b5', // Blue
|
|
16
|
+
'#9c27b0', // Purple
|
|
17
|
+
'#e91e63', // Pink
|
|
18
|
+
'#ff9800', // Orange
|
|
19
|
+
'#ffeb3b' // Yellow
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
commands.push(...skyShapes1.drawSkyGradient(0, 0, canvasSize, canvasSize, sunsetPalette));
|
|
23
|
+
|
|
24
|
+
return commands;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = { lessonSunsetColors };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-extracted from sky_lessons_1.js
|
|
3
|
+
*/
|
|
4
|
+
const shapes = require('../../shapes');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Lesson 3: Sunset Sky (Bầu trời hoàng hôn)
|
|
8
|
+
* Combines the gradient sky with a soft sun setting at the bottom
|
|
9
|
+
*/
|
|
10
|
+
function lessonSunsetSky(canvasSize = 32) {
|
|
11
|
+
const commands = [];
|
|
12
|
+
|
|
13
|
+
// 1. Draw the Sky
|
|
14
|
+
const sunsetPalette = [
|
|
15
|
+
'#1a237e', // Dark Blue
|
|
16
|
+
'#512da8', // Deep Purple
|
|
17
|
+
'#c2185b', // Magenta
|
|
18
|
+
'#ff5722', // Deep Orange
|
|
19
|
+
'#ffb300' // Amber
|
|
20
|
+
];
|
|
21
|
+
commands.push(...skyShapes1.drawSkyGradient(0, 0, canvasSize, canvasSize, sunsetPalette));
|
|
22
|
+
|
|
23
|
+
// 2. Draw the Sun (Soft glowing sun near the bottom)
|
|
24
|
+
const cx = Math.floor(canvasSize / 2);
|
|
25
|
+
const cy = Math.floor(canvasSize * 0.8);
|
|
26
|
+
const r = Math.floor(canvasSize * 0.15);
|
|
27
|
+
commands.push(...skyShapes1.drawSunSoft(cx, cy, r));
|
|
28
|
+
|
|
29
|
+
return commands;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { lessonSunsetSky };
|
|
@@ -1,44 +1,7 @@
|
|
|
1
|
-
const shapes = require('./shapes');
|
|
2
|
-
const structureShapes = require('./structure_shapes');
|
|
3
|
-
const shapes3d = require('./3d_shapes');
|
|
4
|
-
const ellipseShapes = require('./ellipse_shapes');
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Lesson: XYZ Axes (Vertical, Horizontal, Depth)
|
|
8
|
-
*/
|
|
9
|
-
function lessonXYZAxes(canvasSize = 32, color = '#2196f3') {
|
|
10
|
-
const commands = [];
|
|
11
|
-
const cx = Math.floor(canvasSize / 2);
|
|
12
|
-
const cy = Math.floor(canvasSize / 2);
|
|
13
|
-
const length = Math.floor(canvasSize * 0.4);
|
|
14
|
-
|
|
15
|
-
// Draw the axes
|
|
16
|
-
commands.push(...structureShapes.drawXYZAxes(cx, cy, length));
|
|
17
|
-
|
|
18
|
-
// Draw a simple box aligned with these axes to show how objects follow them
|
|
19
|
-
const w = Math.floor(length * 0.5);
|
|
20
|
-
const h = Math.floor(length * 0.5);
|
|
21
|
-
const d = Math.floor(length * 0.5);
|
|
22
|
-
// Using a lighter color for the reference box
|
|
23
|
-
commands.push(...shapes3d.drawWireframeBox(cx + Math.floor(w/2), cy - Math.floor(h/2), w, h, d, '#e0e0e0'));
|
|
24
|
-
|
|
25
|
-
return commands;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
1
|
/**
|
|
29
|
-
*
|
|
2
|
+
* Auto-extracted from structure_lessons.js
|
|
30
3
|
*/
|
|
31
|
-
|
|
32
|
-
const commands = [];
|
|
33
|
-
const cx = Math.floor(canvasSize / 2);
|
|
34
|
-
const cy = Math.floor(canvasSize / 2);
|
|
35
|
-
const totalHeight = Math.floor(canvasSize * 0.8);
|
|
36
|
-
|
|
37
|
-
// Draw bottle structure showing cross-sections and central axis
|
|
38
|
-
commands.push(...structureShapes.drawBottleAnatomy(cx, cy, totalHeight, color));
|
|
39
|
-
|
|
40
|
-
return commands;
|
|
41
|
-
}
|
|
4
|
+
const shapes = require('../../shapes');
|
|
42
5
|
|
|
43
6
|
/**
|
|
44
7
|
* Lesson: Axis Orientation (Object pointing along different axes)
|
|
@@ -86,17 +49,4 @@ function lessonAxisOrientation(canvasSize = 32, color = '#00bcd4') {
|
|
|
86
49
|
return commands;
|
|
87
50
|
}
|
|
88
51
|
|
|
89
|
-
|
|
90
|
-
return [
|
|
91
|
-
{ id: 'structure_xyz', name: 'XYZ Axes', description: 'Understanding 3D space directions (Vertical, Horizontal, Depth)', fn: lessonXYZAxes },
|
|
92
|
-
{ id: 'structure_bottle', name: 'Complex Structure (Bottle)', description: 'Analyzing an object using a central axis and multiple cross-sections', fn: lessonComplexStructure },
|
|
93
|
-
{ id: 'structure_orientation', name: 'Axis Orientation', description: 'Identifying which axis an object is oriented along', fn: lessonAxisOrientation },
|
|
94
|
-
];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
module.exports = {
|
|
98
|
-
lessonXYZAxes,
|
|
99
|
-
lessonComplexStructure,
|
|
100
|
-
lessonAxisOrientation,
|
|
101
|
-
getStructureLessonCatalog
|
|
102
|
-
};
|
|
52
|
+
module.exports = { lessonAxisOrientation };
|