From 7ce085bf29c130b53e05cda3e1aebedfa2d34a22 Mon Sep 17 00:00:00 2001 From: Stalgia Grigg Date: Thu, 29 Feb 2024 10:19:47 -0800 Subject: [PATCH] Initial content push --- .../en/00_Structure/01_Coordinates.js | 32 +++ .../en/00_Structure/01_Coordinates.mdx | 13 + .../en/00_Structure/02_Width_and_Height.js | 15 ++ .../en/00_Structure/02_Width_and_Height.mdx | 13 + .../en/00_Structure/03_Setup_and_Draw.js | 23 ++ .../en/00_Structure/03_Setup_and_Draw.mdx | 11 + .../examples/en/00_Structure/04_No_Loop.js | 26 ++ .../examples/en/00_Structure/04_No_Loop.mdx | 8 + .../examples/en/00_Structure/05_Loop.js | 27 ++ .../examples/en/00_Structure/05_Loop.mdx | 12 + .../examples/en/00_Structure/06_Redraw.js | 29 +++ .../examples/en/00_Structure/06_Redraw.mdx | 10 + .../examples/en/00_Structure/07_Functions.js | 23 ++ .../examples/en/00_Structure/07_Functions.mdx | 11 + .../examples/en/00_Structure/08_Recursion.js | 28 +++ .../examples/en/00_Structure/08_Recursion.mdx | 14 ++ .../en/00_Structure/09_Create_Graphics.js | 24 ++ .../en/00_Structure/09_Create_Graphics.mdx | 11 + .../en/01_Form/00_Points_and_Lines.js | 31 +++ .../en/01_Form/00_Points_and_Lines.mdx | 9 + .../en/01_Form/01_Shape_Primitives.js | 25 ++ .../en/01_Form/01_Shape_Primitives.mdx | 13 + .../examples/en/01_Form/02_Pie_Chart.js | 30 +++ .../examples/en/01_Form/02_Pie_Chart.mdx | 10 + .../examples/en/01_Form/03_Regular_Polygon.js | 37 +++ .../en/01_Form/03_Regular_Polygon.mdx | 12 + src/content/examples/en/01_Form/04_Star.js | 41 ++++ src/content/examples/en/01_Form/04_Star.mdx | 11 + .../examples/en/01_Form/05_Triangle_Strip.js | 33 +++ .../examples/en/01_Form/05_Triangle_Strip.mdx | 12 + src/content/examples/en/01_Form/06_Bezier.js | 22 ++ src/content/examples/en/01_Form/06_Bezier.mdx | 13 + .../examples/en/01_Form/07_3D_Primitives.js | 24 ++ .../examples/en/01_Form/07_3D_Primitives.mdx | 11 + .../01_Form/08_Trig_Wheels_and_Pie_Chart.js | 75 ++++++ .../01_Form/08_Trig_Wheels_and_Pie_Chart.mdx | 3 + .../examples/en/02_Data/00_Variables.js | 33 +++ .../examples/en/02_Data/00_Variables.mdx | 8 + .../examples/en/02_Data/01_True_and_False.js | 24 ++ .../examples/en/02_Data/01_True_and_False.mdx | 13 + .../examples/en/02_Data/03_Variable_Scope.js | 39 +++ .../examples/en/02_Data/03_Variable_Scope.mdx | 13 + src/content/examples/en/02_Data/04_Numbers.js | 24 ++ .../examples/en/02_Data/04_Numbers.mdx | 13 + src/content/examples/en/03_Arrays/00_Array.js | 35 +++ .../examples/en/03_Arrays/00_Array.mdx | 15 ++ .../examples/en/03_Arrays/01_Array_2d.js | 32 +++ .../examples/en/03_Arrays/01_Array_2d.mdx | 12 + .../examples/en/03_Arrays/02_Array_Objects.js | 68 +++++ .../en/03_Arrays/02_Array_Objects.mdx | 9 + .../en/03_Arrays/03_Walk_Over_2dArray.js | 73 ++++++ .../en/03_Arrays/03_Walk_Over_2dArray.mdx | 3 + .../examples/en/04_Control/00_Iteration.js | 38 +++ .../examples/en/04_Control/00_Iteration.mdx | 9 + .../en/04_Control/01_Embedded_Iteration.js | 18 ++ .../en/04_Control/01_Embedded_Iteration.mdx | 9 + .../en/04_Control/02_Conditionals_1.js | 17 ++ .../en/04_Control/02_Conditionals_1.mdx | 13 + .../en/04_Control/03_Conditionals_2.js | 22 ++ .../en/04_Control/03_Conditionals_2.mdx | 12 + .../en/04_Control/04_Logical_Operators.js | 37 +++ .../en/04_Control/04_Logical_Operators.mdx | 11 + .../en/05_Image/00_Load_and_Display_Image.js | 14 ++ .../en/05_Image/00_Load_and_Display_Image.mdx | 13 + .../en/05_Image/01_Background_Image.js | 23 ++ .../en/05_Image/01_Background_Image.mdx | 14 ++ .../examples/en/05_Image/02_Transparency.js | 17 ++ .../examples/en/05_Image/02_Transparency.mdx | 15 ++ .../examples/en/05_Image/03_Alpha_Mask.js | 20 ++ .../examples/en/05_Image/03_Alpha_Mask.mdx | 15 ++ .../examples/en/05_Image/04_Create_Image.js | 21 ++ .../examples/en/05_Image/04_Create_Image.mdx | 10 + .../examples/en/05_Image/05_Pointillism.js | 26 ++ .../examples/en/05_Image/05_Pointillism.mdx | 15 ++ src/content/examples/en/05_Image/06_Blur.mdx | 106 ++++++++ .../examples/en/05_Image/07_EdgeDetection.mdx | 109 ++++++++ .../examples/en/05_Image/08_Brightness.mdx | 78 ++++++ .../examples/en/05_Image/09_Convolution.js | 86 +++++++ .../examples/en/05_Image/09_Convolution.mdx | 12 + .../examples/en/05_Image/10_Copy_Method.js | 16 ++ .../examples/en/05_Image/10_Copy_Method.mdx | 9 + .../en/06_Image_Processing/00_ Pixel_Array.js | 38 +++ .../06_Image_Processing/00_ Pixel_Array.mdx | 9 + .../en/06_Image_Processing/01_ Histogram.js | 43 ++++ .../en/06_Image_Processing/01_ Histogram.mdx | 10 + src/content/examples/en/07_Color/00_Hue.js | 21 ++ src/content/examples/en/07_Color/00_Hue.mdx | 9 + .../examples/en/07_Color/01_Saturation.js | 21 ++ .../examples/en/07_Color/01_Saturation.mdx | 11 + .../examples/en/07_Color/02_Brightness.js | 21 ++ .../examples/en/07_Color/02_Brightness.mdx | 10 + .../examples/en/07_Color/03_Color_Wheel.js | 32 +++ .../examples/en/07_Color/03_Color_Wheel.mdx | 10 + .../en/07_Color/04_Color_Variables.js | 36 +++ .../en/07_Color/04_Color_Variables.mdx | 12 + .../examples/en/07_Color/05_Relativity.js | 29 +++ .../examples/en/07_Color/05_Relativity.mdx | 12 + .../en/07_Color/06_Linear_Gradient.js | 48 ++++ .../en/07_Color/06_Linear_Gradient.mdx | 13 + .../en/07_Color/07_Radial_Gradient.js | 29 +++ .../en/07_Color/07_Radial_Gradient.mdx | 11 + .../examples/en/07_Color/08_Lerp_Color.js | 32 +++ .../examples/en/07_Color/08_Lerp_Color.mdx | 10 + .../en/08_Math/00_incrementdecrement.js | 38 +++ .../en/08_Math/00_incrementdecrement.mdx | 10 + .../en/08_Math/01_operatorprecedence.js | 43 ++++ .../en/08_Math/01_operatorprecedence.mdx | 17 ++ .../examples/en/08_Math/02_distance1d.js | 61 +++++ .../examples/en/08_Math/02_distance1d.mdx | 11 + .../examples/en/08_Math/03_distance2d.js | 20 ++ .../examples/en/08_Math/03_distance2d.mdx | 11 + src/content/examples/en/08_Math/04_sine.js | 24 ++ src/content/examples/en/08_Math/04_sine.mdx | 7 + .../examples/en/08_Math/05_sincosine.js | 37 +++ .../examples/en/08_Math/05_sincosine.mdx | 12 + .../examples/en/08_Math/06_sinewave.js | 44 ++++ .../examples/en/08_Math/06_sinewave.mdx | 8 + .../examples/en/08_Math/07_additivewave.js | 66 +++++ .../examples/en/08_Math/07_additivewave.mdx | 10 + .../en/08_Math/08_polartocartesian.js | 39 +++ .../en/08_Math/08_polartocartesian.mdx | 9 + .../examples/en/08_Math/09_arctangent.mdx | 57 +++++ .../examples/en/08_Math/10_Interpolate.js | 26 ++ .../examples/en/08_Math/10_Interpolate.mdx | 11 + .../examples/en/08_Math/11_doubleRandom.js | 18 ++ .../examples/en/08_Math/11_doubleRandom.mdx | 11 + src/content/examples/en/08_Math/12_random.js | 15 ++ src/content/examples/en/08_Math/12_random.mdx | 8 + src/content/examples/en/08_Math/13_noise1D.js | 28 +++ .../examples/en/08_Math/13_noise1D.mdx | 7 + .../examples/en/08_Math/14_noisewave.js | 38 +++ .../examples/en/08_Math/14_noisewave.mdx | 8 + src/content/examples/en/08_Math/15_Noise2D.js | 45 ++++ .../examples/en/08_Math/15_Noise2D.mdx | 7 + src/content/examples/en/08_Math/16_Noise3D.js | 44 ++++ .../examples/en/08_Math/16_Noise3D.mdx | 7 + .../examples/en/08_Math/17_Randomchords.js | 30 +++ .../examples/en/08_Math/17_Randomchords.mdx | 11 + .../examples/en/08_Math/18_randomGaussian.mdx | 41 ++++ src/content/examples/en/08_Math/19_Map.js | 15 ++ src/content/examples/en/08_Math/19_Map.mdx | 13 + .../en/08_Math/20_Graphing2DEquations.js | 48 ++++ .../en/08_Math/20_Graphing2DEquations.mdx | 9 + .../en/08_Math/21_parametricEquation.js | 38 +++ .../en/08_Math/21_parametricEquation.mdx | 10 + .../en/08_Math/22_trigonometryAndParticles.js | 60 +++++ .../08_Math/22_trigonometryAndParticles.mdx | 8 + .../examples/en/09_Simulate/00_Forces.js | 137 +++++++++++ .../examples/en/09_Simulate/00_Forces.mdx | 11 + .../en/09_Simulate/01_ParticleSystem.js | 65 +++++ .../en/09_Simulate/01_ParticleSystem.mdx | 8 + .../examples/en/09_Simulate/02_Flocking.js | 222 +++++++++++++++++ .../examples/en/09_Simulate/02_Flocking.mdx | 11 + .../examples/en/09_Simulate/03_WolframCA.js | 69 ++++++ .../examples/en/09_Simulate/03_WolframCA.mdx | 10 + .../examples/en/09_Simulate/04_GameOfLife.js | 92 +++++++ .../examples/en/09_Simulate/04_GameOfLife.mdx | 10 + .../05_MultipleParticleSystems.mdx | 152 ++++++++++++ .../examples/en/09_Simulate/06_Spirograph.mdx | 91 +++++++ .../examples/en/09_Simulate/07_LSystems.mdx | 122 +++++++++ .../examples/en/09_Simulate/08_Spring.js | 88 +++++++ .../examples/en/09_Simulate/08_Spring.mdx | 12 + .../examples/en/09_Simulate/09_Springs.mdx | 161 ++++++++++++ .../examples/en/09_Simulate/10_SoftBody.mdx | 120 +++++++++ .../en/09_Simulate/11_SmokeParticleSystem.js | 176 +++++++++++++ .../en/09_Simulate/11_SmokeParticleSystem.mdx | 3 + .../en/09_Simulate/12_BrownianMotion.js | 42 ++++ .../en/09_Simulate/12_BrownianMotion.mdx | 8 + .../examples/en/09_Simulate/13_Chain.mdx | 69 ++++++ .../09_Simulate/14_SnowflakeParticleSystem.js | 58 +++++ .../14_SnowflakeParticleSystem.mdx | 9 + .../en/09_Simulate/15_penrose_tiles.js | 121 +++++++++ .../en/09_Simulate/15_penrose_tiles.mdx | 9 + .../en/09_Simulate/16_Recursive_Tree.js | 49 ++++ .../en/09_Simulate/16_Recursive_Tree.mdx | 14 ++ .../examples/en/09_Simulate/17_Mandelbrot.js | 82 +++++++ .../examples/en/09_Simulate/17_Mandelbrot.mdx | 10 + .../examples/en/09_Simulate/18_Koch.js | 137 +++++++++++ .../examples/en/09_Simulate/18_Koch.mdx | 11 + .../examples/en/09_Simulate/19_Bubblesort.js | 61 +++++ .../examples/en/09_Simulate/19_Bubblesort.mdx | 12 + .../en/09_Simulate/20_SteepingFeet.js | 73 ++++++ .../en/09_Simulate/20_SteepingFeet.mdx | 15 ++ .../examples/en/09_Simulate/21_Particle.js | 63 +++++ .../examples/en/09_Simulate/21_Particle.mdx | 12 + .../examples/en/09_Simulate/22_Quicksort.mdx | 137 +++++++++++ .../examples/en/10_Interaction/10_Tickle.js | 44 ++++ .../examples/en/10_Interaction/10_Tickle.mdx | 10 + .../examples/en/10_Interaction/20_Follow1.js | 32 +++ .../examples/en/10_Interaction/20_Follow1.mdx | 10 + .../examples/en/10_Interaction/21_Follow2.js | 33 +++ .../examples/en/10_Interaction/21_Follow2.mdx | 11 + .../examples/en/10_Interaction/22_Follow3.js | 41 ++++ .../examples/en/10_Interaction/22_Follow3.mdx | 9 + .../examples/en/10_Interaction/23_snake.js | 166 +++++++++++++ .../examples/en/10_Interaction/23_snake.mdx | 3 + .../en/10_Interaction/24_Wavemaker.js | 32 +++ .../en/10_Interaction/24_Wavemaker.mdx | 11 + .../examples/en/10_Interaction/25_reach1.js | 52 ++++ .../examples/en/10_Interaction/25_reach1.mdx | 12 + .../examples/en/10_Interaction/26_reach2.js | 60 +++++ .../examples/en/10_Interaction/26_reach2.mdx | 10 + .../examples/en/10_Interaction/27_reach3.js | 76 ++++++ .../examples/en/10_Interaction/27_reach3.mdx | 11 + .../en/10_Interaction/28_ArduinoSensor.js | 20 ++ .../en/10_Interaction/28_ArduinoSensor.mdx | 20 ++ .../en/10_Interaction/29_kaleidoscope.js | 69 ++++++ .../en/10_Interaction/29_kaleidoscope.mdx | 9 + .../examples/en/11_Objects/01_Objects.js | 34 +++ .../examples/en/11_Objects/01_Objects.mdx | 11 + .../en/11_Objects/02_Multiple_Objects.js | 46 ++++ .../en/11_Objects/02_Multiple_Objects.mdx | 10 + .../en/11_Objects/03_Objects_Array.js | 38 +++ .../en/11_Objects/03_Objects_Array.mdx | 11 + .../03_Objects_Optional_Arguments.js | 60 +++++ .../03_Objects_Optional_Arguments.mdx | 11 + .../examples/en/12_Lights/02_Directional.js | 20 ++ .../examples/en/12_Lights/02_Directional.mdx | 13 + .../examples/en/12_Lights/05_Mixture.js | 40 +++ .../examples/en/12_Lights/05_Mixture.mdx | 10 + .../13_Motion/01_non_orthogonal_reflection.js | 106 ++++++++ .../01_non_orthogonal_reflection.mdx | 10 + .../examples/en/13_Motion/02_Linear_Motion.js | 18 ++ .../en/13_Motion/02_Linear_Motion.mdx | 11 + .../examples/en/13_Motion/03_Bounce.js | 40 +++ .../examples/en/13_Motion/03_Bounce.mdx | 9 + .../en/13_Motion/04_Bouncy_Bubbles.js | 91 +++++++ .../en/13_Motion/04_Bouncy_Bubbles.mdx | 9 + src/content/examples/en/13_Motion/05_Morph.js | 89 +++++++ .../examples/en/13_Motion/05_Morph.mdx | 9 + .../en/13_Motion/06_Moving_On_Curves.js | 42 ++++ .../en/13_Motion/06_Moving_On_Curves.mdx | 10 + .../en/13_Motion/07_Circle_Collision.mdx | 156 ++++++++++++ .../en/15_Instance_Mode/01_Instantiating.js | 31 +++ .../en/15_Instance_Mode/01_Instantiating.mdx | 8 + .../examples/en/16_Dom/03_Input_Button.js | 35 +++ .../examples/en/16_Dom/03_Input_Button.mdx | 11 + src/content/examples/en/16_Dom/04_Slider.js | 27 ++ src/content/examples/en/16_Dom/04_Slider.mdx | 11 + .../examples/en/16_Dom/07_Modify_DOM.js | 49 ++++ .../examples/en/16_Dom/07_Modify_DOM.mdx | 8 + src/content/examples/en/16_Dom/08_Video.js | 24 ++ src/content/examples/en/16_Dom/08_Video.mdx | 8 + .../examples/en/16_Dom/09_Video_Canvas.js | 22 ++ .../examples/en/16_Dom/09_Video_Canvas.mdx | 11 + .../examples/en/16_Dom/10_Video_Pixels.js | 26 ++ .../examples/en/16_Dom/10_Video_Pixels.mdx | 12 + src/content/examples/en/16_Dom/11_Capture.js | 15 ++ src/content/examples/en/16_Dom/11_Capture.mdx | 10 + src/content/examples/en/16_Dom/12_Drop.js | 30 +++ src/content/examples/en/16_Dom/12_Drop.mdx | 9 + .../en/17_Drawing/00_Continuous_Lines.js | 12 + .../en/17_Drawing/00_Continuous_Lines.mdx | 9 + .../examples/en/17_Drawing/01_Pattern.js | 23 ++ .../examples/en/17_Drawing/01_Pattern.mdx | 11 + .../examples/en/17_Drawing/02_Pulses.js | 25 ++ .../examples/en/17_Drawing/02_Pulses.mdx | 14 ++ .../examples/en/18_Transform/00_Translate.js | 34 +++ .../examples/en/18_Transform/00_Translate.mdx | 12 + .../examples/en/18_Transform/01_Scale.js | 38 +++ .../examples/en/18_Transform/01_Scale.mdx | 12 + .../examples/en/18_Transform/02_Rotate.js | 32 +++ .../examples/en/18_Transform/02_Rotate.mdx | 15 ++ .../examples/en/18_Transform/03_Arm.js | 41 ++++ .../examples/en/18_Transform/03_Arm.mdx | 15 ++ .../examples/en/19_Typography/00_Letters.js | 58 +++++ .../examples/en/19_Typography/00_Letters.mdx | 12 + .../examples/en/19_Typography/01_Words.js | 54 ++++ .../examples/en/19_Typography/01_Words.mdx | 12 + .../en/19_Typography/02_Text_Rotation.mdx | 78 ++++++ .../examples/en/20_3D/00_geometries.js | 70 ++++++ .../examples/en/20_3D/00_geometries.mdx | 9 + .../examples/en/20_3D/01_sine_cosine_in_3D.js | 25 ++ .../en/20_3D/01_sine_cosine_in_3D.mdx | 7 + .../examples/en/20_3D/02_multiple_lights.js | 36 +++ .../examples/en/20_3D/02_multiple_lights.mdx | 10 + src/content/examples/en/20_3D/03_materials.js | 60 +++++ .../examples/en/20_3D/03_materials.mdx | 11 + src/content/examples/en/20_3D/04_textures.js | 37 +++ src/content/examples/en/20_3D/04_textures.mdx | 9 + .../examples/en/20_3D/05_ray_casting.mdx | 112 +++++++++ .../examples/en/20_3D/07_orbit_control.js | 35 +++ .../examples/en/20_3D/07_orbit_control.mdx | 10 + .../examples/en/20_3D/08_basic_shader.mdx | 37 +++ .../en/20_3D/09_shader_as_a_texture.mdx | 78 ++++++ .../en/20_3D/10_passing_shader_uniforms.mdx | 49 ++++ .../en/20_3D/11_shader_using_webcam.mdx | 47 ++++ .../examples/en/20_3D/12_framebuffer_blur.js | 101 ++++++++ .../examples/en/20_3D/12_framebuffer_blur.mdx | 10 + .../examples/en/20_3D/12_simple_feedback.js | 49 ++++ .../examples/en/20_3D/12_simple_feedback.mdx | 10 + src/content/examples/en/21_Input/00_Clock.js | 57 +++++ src/content/examples/en/21_Input/00_Clock.mdx | 9 + .../examples/en/21_Input/01_Constrain.js | 32 +++ .../examples/en/21_Input/01_Constrain.mdx | 10 + src/content/examples/en/21_Input/02_Easing.js | 22 ++ .../examples/en/21_Input/02_Easing.mdx | 14 ++ .../examples/en/21_Input/03_Keyboard.js | 32 +++ .../examples/en/21_Input/03_Keyboard.mdx | 12 + .../examples/en/21_Input/04_Milliseconds.mdx | 41 ++++ .../examples/en/21_Input/05_Mouse1D.js | 19 ++ .../examples/en/21_Input/05_Mouse1D.mdx | 13 + .../examples/en/21_Input/06_Mouse2D.js | 16 ++ .../examples/en/21_Input/06_Mouse2D.mdx | 11 + .../en/21_Input/07_Mouse_Functions.js | 63 +++++ .../en/21_Input/07_Mouse_Functions.mdx | 9 + .../examples/en/21_Input/08_Mouse_Signals.js | 46 ++++ .../examples/en/21_Input/08_Mouse_Signals.mdx | 13 + .../examples/en/21_Input/09_MouseIsPressed.js | 16 ++ .../en/21_Input/09_MouseIsPressed.mdx | 10 + .../examples/en/21_Input/10_Rollover.mdx | 94 +++++++ .../examples/en/21_Input/11_Storing_Input.js | 30 +++ .../examples/en/21_Input/11_Storing_Input.mdx | 14 ++ .../22_Advanced_Data/00_Load_Saved_JSON.mdx | 130 ++++++++++ .../22_Advanced_Data/01_Load_Saved_Table.mdx | 136 ++++++++++ .../en/33_Sound/00_Load_and_Play_Sound.mdx | 39 +++ .../examples/en/33_Sound/01_Preload_Sound.mdx | 53 ++++ .../examples/en/33_Sound/02_soundFormats.js | 31 +++ .../examples/en/33_Sound/02_soundFormats.mdx | 29 +++ .../examples/en/33_Sound/03_Play_Mode.js | 32 +++ .../examples/en/33_Sound/03_Play_Mode.mdx | 13 + .../examples/en/33_Sound/04_Pan_SoundFile.js | 26 ++ .../examples/en/33_Sound/04_Pan_SoundFile.mdx | 14 ++ .../examples/en/33_Sound/05_Sound_Effect.js | 63 +++++ .../examples/en/33_Sound/05_Sound_Effect.mdx | 10 + .../en/33_Sound/06_Manipulate_Sound.js | 39 +++ .../en/33_Sound/06_Manipulate_Sound.mdx | 16 ++ .../en/33_Sound/07_Amplitude_Analysis.mdx | 76 ++++++ .../examples/en/33_Sound/08_Noise_Envelope.js | 38 +++ .../en/33_Sound/08_Noise_Envelope.mdx | 22 ++ .../examples/en/33_Sound/09_Note_Envelope.js | 46 ++++ .../examples/en/33_Sound/09_Note_Envelope.mdx | 19 ++ .../en/33_Sound/10_Oscillator_Waveform.js | 33 +++ .../en/33_Sound/10_Oscillator_Waveform.mdx | 14 ++ .../examples/en/33_Sound/11_Live_Input.js | 26 ++ .../examples/en/33_Sound/11_Live_Input.mdx | 16 ++ .../examples/en/33_Sound/12_FFT_Spectrum.js | 24 ++ .../examples/en/33_Sound/12_FFT_Spectrum.mdx | 12 + .../examples/en/33_Sound/13_Mic_Threshold.js | 42 ++++ .../examples/en/33_Sound/13_Mic_Threshold.mdx | 14 ++ .../examples/en/33_Sound/14_Filter_LowPass.js | 52 ++++ .../en/33_Sound/14_Filter_LowPass.mdx | 16 ++ .../en/33_Sound/15_Filter_BandPass.js | 41 ++++ .../en/33_Sound/15_Filter_BandPass.mdx | 16 ++ src/content/examples/en/33_Sound/16_Delay.js | 45 ++++ src/content/examples/en/33_Sound/16_Delay.mdx | 17 ++ src/content/examples/en/33_Sound/17_Reverb.js | 28 +++ .../examples/en/33_Sound/17_Reverb.mdx | 12 + .../en/33_Sound/18_Convolution_Reverb.mdx | 110 +++++++++ .../examples/en/33_Sound/19_Record_Save.js | 48 ++++ .../examples/en/33_Sound/19_Record_Save.mdx | 18 ++ .../en/33_Sound/21_FreqModulation.mdx | 232 ++++++++++++++++++ .../en/33_Sound/22_AmplitudeModulation.mdx | 106 ++++++++ .../35_Mobile/00_Acceleration_Ball_Bounce.js | 55 +++++ .../35_Mobile/00_Acceleration_Ball_Bounce.mdx | 6 + .../examples/en/35_Mobile/01_Simple_Draw.js | 12 + .../examples/en/35_Mobile/01_Simple_Draw.mdx | 6 + .../en/35_Mobile/02_Acceleration_Color.js | 21 ++ .../en/35_Mobile/02_Acceleration_Color.mdx | 6 + .../en/35_Mobile/03_Shake_Ball_Bounce.js | 110 +++++++++ .../en/35_Mobile/03_Shake_Ball_Bounce.mdx | 7 + .../examples/en/35_Mobile/04_Tilted_3D_Box.js | 12 + .../en/35_Mobile/04_Tilted_3D_Box.mdx | 6 + .../examples/en/90_Hello_P5/01_shapes.js | 25 ++ .../examples/en/90_Hello_P5/01_shapes.mdx | 9 + .../en/90_Hello_P5/02_interactivity.js | 33 +++ .../en/90_Hello_P5/02_interactivity.mdx | 9 + .../en/90_Hello_P5/03_interactivity.js | 22 ++ .../en/90_Hello_P5/03_interactivity.mdx | 9 + .../examples/en/90_Hello_P5/04_animate.js | 30 +++ .../examples/en/90_Hello_P5/04_animate.mdx | 9 + .../examples/en/90_Hello_P5/04_flocking.mdx | 198 +++++++++++++++ .../examples/en/90_Hello_P5/05_weather.js | 67 +++++ .../examples/en/90_Hello_P5/05_weather.mdx | 11 + .../examples/en/90_Hello_P5/06_drawing.js | 129 ++++++++++ .../examples/en/90_Hello_P5/06_drawing.mdx | 10 + .../examples/en/90_Hello_P5/07_song.js | 112 +++++++++ .../examples/en/90_Hello_P5/07_song.mdx | 13 + src/scripts/builders/reference.ts | 4 +- src/scripts/parsers/reference.ts | 12 +- src/scripts/utils.ts | 27 ++ 381 files changed, 12670 insertions(+), 8 deletions(-) create mode 100644 src/content/examples/en/00_Structure/01_Coordinates.js create mode 100644 src/content/examples/en/00_Structure/01_Coordinates.mdx create mode 100644 src/content/examples/en/00_Structure/02_Width_and_Height.js create mode 100644 src/content/examples/en/00_Structure/02_Width_and_Height.mdx create mode 100644 src/content/examples/en/00_Structure/03_Setup_and_Draw.js create mode 100644 src/content/examples/en/00_Structure/03_Setup_and_Draw.mdx create mode 100644 src/content/examples/en/00_Structure/04_No_Loop.js create mode 100644 src/content/examples/en/00_Structure/04_No_Loop.mdx create mode 100644 src/content/examples/en/00_Structure/05_Loop.js create mode 100644 src/content/examples/en/00_Structure/05_Loop.mdx create mode 100644 src/content/examples/en/00_Structure/06_Redraw.js create mode 100644 src/content/examples/en/00_Structure/06_Redraw.mdx create mode 100644 src/content/examples/en/00_Structure/07_Functions.js create mode 100644 src/content/examples/en/00_Structure/07_Functions.mdx create mode 100644 src/content/examples/en/00_Structure/08_Recursion.js create mode 100644 src/content/examples/en/00_Structure/08_Recursion.mdx create mode 100644 src/content/examples/en/00_Structure/09_Create_Graphics.js create mode 100644 src/content/examples/en/00_Structure/09_Create_Graphics.mdx create mode 100644 src/content/examples/en/01_Form/00_Points_and_Lines.js create mode 100644 src/content/examples/en/01_Form/00_Points_and_Lines.mdx create mode 100644 src/content/examples/en/01_Form/01_Shape_Primitives.js create mode 100644 src/content/examples/en/01_Form/01_Shape_Primitives.mdx create mode 100644 src/content/examples/en/01_Form/02_Pie_Chart.js create mode 100644 src/content/examples/en/01_Form/02_Pie_Chart.mdx create mode 100644 src/content/examples/en/01_Form/03_Regular_Polygon.js create mode 100644 src/content/examples/en/01_Form/03_Regular_Polygon.mdx create mode 100644 src/content/examples/en/01_Form/04_Star.js create mode 100644 src/content/examples/en/01_Form/04_Star.mdx create mode 100644 src/content/examples/en/01_Form/05_Triangle_Strip.js create mode 100644 src/content/examples/en/01_Form/05_Triangle_Strip.mdx create mode 100644 src/content/examples/en/01_Form/06_Bezier.js create mode 100644 src/content/examples/en/01_Form/06_Bezier.mdx create mode 100644 src/content/examples/en/01_Form/07_3D_Primitives.js create mode 100644 src/content/examples/en/01_Form/07_3D_Primitives.mdx create mode 100644 src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js create mode 100644 src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.mdx create mode 100644 src/content/examples/en/02_Data/00_Variables.js create mode 100644 src/content/examples/en/02_Data/00_Variables.mdx create mode 100644 src/content/examples/en/02_Data/01_True_and_False.js create mode 100644 src/content/examples/en/02_Data/01_True_and_False.mdx create mode 100644 src/content/examples/en/02_Data/03_Variable_Scope.js create mode 100644 src/content/examples/en/02_Data/03_Variable_Scope.mdx create mode 100644 src/content/examples/en/02_Data/04_Numbers.js create mode 100644 src/content/examples/en/02_Data/04_Numbers.mdx create mode 100644 src/content/examples/en/03_Arrays/00_Array.js create mode 100644 src/content/examples/en/03_Arrays/00_Array.mdx create mode 100644 src/content/examples/en/03_Arrays/01_Array_2d.js create mode 100644 src/content/examples/en/03_Arrays/01_Array_2d.mdx create mode 100644 src/content/examples/en/03_Arrays/02_Array_Objects.js create mode 100644 src/content/examples/en/03_Arrays/02_Array_Objects.mdx create mode 100644 src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.js create mode 100644 src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.mdx create mode 100644 src/content/examples/en/04_Control/00_Iteration.js create mode 100644 src/content/examples/en/04_Control/00_Iteration.mdx create mode 100644 src/content/examples/en/04_Control/01_Embedded_Iteration.js create mode 100644 src/content/examples/en/04_Control/01_Embedded_Iteration.mdx create mode 100644 src/content/examples/en/04_Control/02_Conditionals_1.js create mode 100644 src/content/examples/en/04_Control/02_Conditionals_1.mdx create mode 100644 src/content/examples/en/04_Control/03_Conditionals_2.js create mode 100644 src/content/examples/en/04_Control/03_Conditionals_2.mdx create mode 100644 src/content/examples/en/04_Control/04_Logical_Operators.js create mode 100644 src/content/examples/en/04_Control/04_Logical_Operators.mdx create mode 100644 src/content/examples/en/05_Image/00_Load_and_Display_Image.js create mode 100644 src/content/examples/en/05_Image/00_Load_and_Display_Image.mdx create mode 100644 src/content/examples/en/05_Image/01_Background_Image.js create mode 100644 src/content/examples/en/05_Image/01_Background_Image.mdx create mode 100644 src/content/examples/en/05_Image/02_Transparency.js create mode 100644 src/content/examples/en/05_Image/02_Transparency.mdx create mode 100644 src/content/examples/en/05_Image/03_Alpha_Mask.js create mode 100644 src/content/examples/en/05_Image/03_Alpha_Mask.mdx create mode 100644 src/content/examples/en/05_Image/04_Create_Image.js create mode 100644 src/content/examples/en/05_Image/04_Create_Image.mdx create mode 100644 src/content/examples/en/05_Image/05_Pointillism.js create mode 100644 src/content/examples/en/05_Image/05_Pointillism.mdx create mode 100644 src/content/examples/en/05_Image/06_Blur.mdx create mode 100644 src/content/examples/en/05_Image/07_EdgeDetection.mdx create mode 100644 src/content/examples/en/05_Image/08_Brightness.mdx create mode 100644 src/content/examples/en/05_Image/09_Convolution.js create mode 100644 src/content/examples/en/05_Image/09_Convolution.mdx create mode 100644 src/content/examples/en/05_Image/10_Copy_Method.js create mode 100644 src/content/examples/en/05_Image/10_Copy_Method.mdx create mode 100644 src/content/examples/en/06_Image_Processing/00_ Pixel_Array.js create mode 100644 src/content/examples/en/06_Image_Processing/00_ Pixel_Array.mdx create mode 100644 src/content/examples/en/06_Image_Processing/01_ Histogram.js create mode 100644 src/content/examples/en/06_Image_Processing/01_ Histogram.mdx create mode 100644 src/content/examples/en/07_Color/00_Hue.js create mode 100644 src/content/examples/en/07_Color/00_Hue.mdx create mode 100644 src/content/examples/en/07_Color/01_Saturation.js create mode 100644 src/content/examples/en/07_Color/01_Saturation.mdx create mode 100644 src/content/examples/en/07_Color/02_Brightness.js create mode 100644 src/content/examples/en/07_Color/02_Brightness.mdx create mode 100644 src/content/examples/en/07_Color/03_Color_Wheel.js create mode 100644 src/content/examples/en/07_Color/03_Color_Wheel.mdx create mode 100644 src/content/examples/en/07_Color/04_Color_Variables.js create mode 100644 src/content/examples/en/07_Color/04_Color_Variables.mdx create mode 100644 src/content/examples/en/07_Color/05_Relativity.js create mode 100644 src/content/examples/en/07_Color/05_Relativity.mdx create mode 100644 src/content/examples/en/07_Color/06_Linear_Gradient.js create mode 100644 src/content/examples/en/07_Color/06_Linear_Gradient.mdx create mode 100644 src/content/examples/en/07_Color/07_Radial_Gradient.js create mode 100644 src/content/examples/en/07_Color/07_Radial_Gradient.mdx create mode 100644 src/content/examples/en/07_Color/08_Lerp_Color.js create mode 100644 src/content/examples/en/07_Color/08_Lerp_Color.mdx create mode 100644 src/content/examples/en/08_Math/00_incrementdecrement.js create mode 100644 src/content/examples/en/08_Math/00_incrementdecrement.mdx create mode 100644 src/content/examples/en/08_Math/01_operatorprecedence.js create mode 100644 src/content/examples/en/08_Math/01_operatorprecedence.mdx create mode 100644 src/content/examples/en/08_Math/02_distance1d.js create mode 100644 src/content/examples/en/08_Math/02_distance1d.mdx create mode 100644 src/content/examples/en/08_Math/03_distance2d.js create mode 100644 src/content/examples/en/08_Math/03_distance2d.mdx create mode 100644 src/content/examples/en/08_Math/04_sine.js create mode 100644 src/content/examples/en/08_Math/04_sine.mdx create mode 100644 src/content/examples/en/08_Math/05_sincosine.js create mode 100644 src/content/examples/en/08_Math/05_sincosine.mdx create mode 100644 src/content/examples/en/08_Math/06_sinewave.js create mode 100644 src/content/examples/en/08_Math/06_sinewave.mdx create mode 100644 src/content/examples/en/08_Math/07_additivewave.js create mode 100644 src/content/examples/en/08_Math/07_additivewave.mdx create mode 100644 src/content/examples/en/08_Math/08_polartocartesian.js create mode 100644 src/content/examples/en/08_Math/08_polartocartesian.mdx create mode 100644 src/content/examples/en/08_Math/09_arctangent.mdx create mode 100644 src/content/examples/en/08_Math/10_Interpolate.js create mode 100644 src/content/examples/en/08_Math/10_Interpolate.mdx create mode 100644 src/content/examples/en/08_Math/11_doubleRandom.js create mode 100644 src/content/examples/en/08_Math/11_doubleRandom.mdx create mode 100644 src/content/examples/en/08_Math/12_random.js create mode 100644 src/content/examples/en/08_Math/12_random.mdx create mode 100644 src/content/examples/en/08_Math/13_noise1D.js create mode 100644 src/content/examples/en/08_Math/13_noise1D.mdx create mode 100644 src/content/examples/en/08_Math/14_noisewave.js create mode 100644 src/content/examples/en/08_Math/14_noisewave.mdx create mode 100644 src/content/examples/en/08_Math/15_Noise2D.js create mode 100644 src/content/examples/en/08_Math/15_Noise2D.mdx create mode 100644 src/content/examples/en/08_Math/16_Noise3D.js create mode 100644 src/content/examples/en/08_Math/16_Noise3D.mdx create mode 100644 src/content/examples/en/08_Math/17_Randomchords.js create mode 100644 src/content/examples/en/08_Math/17_Randomchords.mdx create mode 100644 src/content/examples/en/08_Math/18_randomGaussian.mdx create mode 100644 src/content/examples/en/08_Math/19_Map.js create mode 100644 src/content/examples/en/08_Math/19_Map.mdx create mode 100644 src/content/examples/en/08_Math/20_Graphing2DEquations.js create mode 100644 src/content/examples/en/08_Math/20_Graphing2DEquations.mdx create mode 100644 src/content/examples/en/08_Math/21_parametricEquation.js create mode 100644 src/content/examples/en/08_Math/21_parametricEquation.mdx create mode 100644 src/content/examples/en/08_Math/22_trigonometryAndParticles.js create mode 100644 src/content/examples/en/08_Math/22_trigonometryAndParticles.mdx create mode 100644 src/content/examples/en/09_Simulate/00_Forces.js create mode 100644 src/content/examples/en/09_Simulate/00_Forces.mdx create mode 100644 src/content/examples/en/09_Simulate/01_ParticleSystem.js create mode 100644 src/content/examples/en/09_Simulate/01_ParticleSystem.mdx create mode 100644 src/content/examples/en/09_Simulate/02_Flocking.js create mode 100644 src/content/examples/en/09_Simulate/02_Flocking.mdx create mode 100644 src/content/examples/en/09_Simulate/03_WolframCA.js create mode 100644 src/content/examples/en/09_Simulate/03_WolframCA.mdx create mode 100644 src/content/examples/en/09_Simulate/04_GameOfLife.js create mode 100644 src/content/examples/en/09_Simulate/04_GameOfLife.mdx create mode 100644 src/content/examples/en/09_Simulate/05_MultipleParticleSystems.mdx create mode 100644 src/content/examples/en/09_Simulate/06_Spirograph.mdx create mode 100644 src/content/examples/en/09_Simulate/07_LSystems.mdx create mode 100644 src/content/examples/en/09_Simulate/08_Spring.js create mode 100644 src/content/examples/en/09_Simulate/08_Spring.mdx create mode 100644 src/content/examples/en/09_Simulate/09_Springs.mdx create mode 100644 src/content/examples/en/09_Simulate/10_SoftBody.mdx create mode 100644 src/content/examples/en/09_Simulate/11_SmokeParticleSystem.js create mode 100644 src/content/examples/en/09_Simulate/11_SmokeParticleSystem.mdx create mode 100644 src/content/examples/en/09_Simulate/12_BrownianMotion.js create mode 100644 src/content/examples/en/09_Simulate/12_BrownianMotion.mdx create mode 100644 src/content/examples/en/09_Simulate/13_Chain.mdx create mode 100644 src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.js create mode 100644 src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.mdx create mode 100644 src/content/examples/en/09_Simulate/15_penrose_tiles.js create mode 100644 src/content/examples/en/09_Simulate/15_penrose_tiles.mdx create mode 100644 src/content/examples/en/09_Simulate/16_Recursive_Tree.js create mode 100644 src/content/examples/en/09_Simulate/16_Recursive_Tree.mdx create mode 100644 src/content/examples/en/09_Simulate/17_Mandelbrot.js create mode 100644 src/content/examples/en/09_Simulate/17_Mandelbrot.mdx create mode 100644 src/content/examples/en/09_Simulate/18_Koch.js create mode 100644 src/content/examples/en/09_Simulate/18_Koch.mdx create mode 100644 src/content/examples/en/09_Simulate/19_Bubblesort.js create mode 100644 src/content/examples/en/09_Simulate/19_Bubblesort.mdx create mode 100644 src/content/examples/en/09_Simulate/20_SteepingFeet.js create mode 100644 src/content/examples/en/09_Simulate/20_SteepingFeet.mdx create mode 100644 src/content/examples/en/09_Simulate/21_Particle.js create mode 100644 src/content/examples/en/09_Simulate/21_Particle.mdx create mode 100644 src/content/examples/en/09_Simulate/22_Quicksort.mdx create mode 100644 src/content/examples/en/10_Interaction/10_Tickle.js create mode 100644 src/content/examples/en/10_Interaction/10_Tickle.mdx create mode 100644 src/content/examples/en/10_Interaction/20_Follow1.js create mode 100644 src/content/examples/en/10_Interaction/20_Follow1.mdx create mode 100644 src/content/examples/en/10_Interaction/21_Follow2.js create mode 100644 src/content/examples/en/10_Interaction/21_Follow2.mdx create mode 100644 src/content/examples/en/10_Interaction/22_Follow3.js create mode 100644 src/content/examples/en/10_Interaction/22_Follow3.mdx create mode 100644 src/content/examples/en/10_Interaction/23_snake.js create mode 100644 src/content/examples/en/10_Interaction/23_snake.mdx create mode 100644 src/content/examples/en/10_Interaction/24_Wavemaker.js create mode 100644 src/content/examples/en/10_Interaction/24_Wavemaker.mdx create mode 100644 src/content/examples/en/10_Interaction/25_reach1.js create mode 100644 src/content/examples/en/10_Interaction/25_reach1.mdx create mode 100644 src/content/examples/en/10_Interaction/26_reach2.js create mode 100644 src/content/examples/en/10_Interaction/26_reach2.mdx create mode 100644 src/content/examples/en/10_Interaction/27_reach3.js create mode 100644 src/content/examples/en/10_Interaction/27_reach3.mdx create mode 100644 src/content/examples/en/10_Interaction/28_ArduinoSensor.js create mode 100644 src/content/examples/en/10_Interaction/28_ArduinoSensor.mdx create mode 100644 src/content/examples/en/10_Interaction/29_kaleidoscope.js create mode 100644 src/content/examples/en/10_Interaction/29_kaleidoscope.mdx create mode 100644 src/content/examples/en/11_Objects/01_Objects.js create mode 100644 src/content/examples/en/11_Objects/01_Objects.mdx create mode 100644 src/content/examples/en/11_Objects/02_Multiple_Objects.js create mode 100644 src/content/examples/en/11_Objects/02_Multiple_Objects.mdx create mode 100644 src/content/examples/en/11_Objects/03_Objects_Array.js create mode 100644 src/content/examples/en/11_Objects/03_Objects_Array.mdx create mode 100644 src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.js create mode 100644 src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.mdx create mode 100644 src/content/examples/en/12_Lights/02_Directional.js create mode 100644 src/content/examples/en/12_Lights/02_Directional.mdx create mode 100644 src/content/examples/en/12_Lights/05_Mixture.js create mode 100644 src/content/examples/en/12_Lights/05_Mixture.mdx create mode 100644 src/content/examples/en/13_Motion/01_non_orthogonal_reflection.js create mode 100644 src/content/examples/en/13_Motion/01_non_orthogonal_reflection.mdx create mode 100644 src/content/examples/en/13_Motion/02_Linear_Motion.js create mode 100644 src/content/examples/en/13_Motion/02_Linear_Motion.mdx create mode 100644 src/content/examples/en/13_Motion/03_Bounce.js create mode 100644 src/content/examples/en/13_Motion/03_Bounce.mdx create mode 100644 src/content/examples/en/13_Motion/04_Bouncy_Bubbles.js create mode 100644 src/content/examples/en/13_Motion/04_Bouncy_Bubbles.mdx create mode 100644 src/content/examples/en/13_Motion/05_Morph.js create mode 100644 src/content/examples/en/13_Motion/05_Morph.mdx create mode 100644 src/content/examples/en/13_Motion/06_Moving_On_Curves.js create mode 100644 src/content/examples/en/13_Motion/06_Moving_On_Curves.mdx create mode 100644 src/content/examples/en/13_Motion/07_Circle_Collision.mdx create mode 100644 src/content/examples/en/15_Instance_Mode/01_Instantiating.js create mode 100644 src/content/examples/en/15_Instance_Mode/01_Instantiating.mdx create mode 100644 src/content/examples/en/16_Dom/03_Input_Button.js create mode 100644 src/content/examples/en/16_Dom/03_Input_Button.mdx create mode 100644 src/content/examples/en/16_Dom/04_Slider.js create mode 100644 src/content/examples/en/16_Dom/04_Slider.mdx create mode 100644 src/content/examples/en/16_Dom/07_Modify_DOM.js create mode 100644 src/content/examples/en/16_Dom/07_Modify_DOM.mdx create mode 100644 src/content/examples/en/16_Dom/08_Video.js create mode 100644 src/content/examples/en/16_Dom/08_Video.mdx create mode 100644 src/content/examples/en/16_Dom/09_Video_Canvas.js create mode 100644 src/content/examples/en/16_Dom/09_Video_Canvas.mdx create mode 100644 src/content/examples/en/16_Dom/10_Video_Pixels.js create mode 100644 src/content/examples/en/16_Dom/10_Video_Pixels.mdx create mode 100644 src/content/examples/en/16_Dom/11_Capture.js create mode 100644 src/content/examples/en/16_Dom/11_Capture.mdx create mode 100644 src/content/examples/en/16_Dom/12_Drop.js create mode 100644 src/content/examples/en/16_Dom/12_Drop.mdx create mode 100644 src/content/examples/en/17_Drawing/00_Continuous_Lines.js create mode 100644 src/content/examples/en/17_Drawing/00_Continuous_Lines.mdx create mode 100644 src/content/examples/en/17_Drawing/01_Pattern.js create mode 100644 src/content/examples/en/17_Drawing/01_Pattern.mdx create mode 100644 src/content/examples/en/17_Drawing/02_Pulses.js create mode 100644 src/content/examples/en/17_Drawing/02_Pulses.mdx create mode 100644 src/content/examples/en/18_Transform/00_Translate.js create mode 100644 src/content/examples/en/18_Transform/00_Translate.mdx create mode 100644 src/content/examples/en/18_Transform/01_Scale.js create mode 100644 src/content/examples/en/18_Transform/01_Scale.mdx create mode 100644 src/content/examples/en/18_Transform/02_Rotate.js create mode 100644 src/content/examples/en/18_Transform/02_Rotate.mdx create mode 100644 src/content/examples/en/18_Transform/03_Arm.js create mode 100644 src/content/examples/en/18_Transform/03_Arm.mdx create mode 100644 src/content/examples/en/19_Typography/00_Letters.js create mode 100644 src/content/examples/en/19_Typography/00_Letters.mdx create mode 100644 src/content/examples/en/19_Typography/01_Words.js create mode 100644 src/content/examples/en/19_Typography/01_Words.mdx create mode 100644 src/content/examples/en/19_Typography/02_Text_Rotation.mdx create mode 100644 src/content/examples/en/20_3D/00_geometries.js create mode 100644 src/content/examples/en/20_3D/00_geometries.mdx create mode 100644 src/content/examples/en/20_3D/01_sine_cosine_in_3D.js create mode 100644 src/content/examples/en/20_3D/01_sine_cosine_in_3D.mdx create mode 100644 src/content/examples/en/20_3D/02_multiple_lights.js create mode 100644 src/content/examples/en/20_3D/02_multiple_lights.mdx create mode 100644 src/content/examples/en/20_3D/03_materials.js create mode 100644 src/content/examples/en/20_3D/03_materials.mdx create mode 100644 src/content/examples/en/20_3D/04_textures.js create mode 100644 src/content/examples/en/20_3D/04_textures.mdx create mode 100644 src/content/examples/en/20_3D/05_ray_casting.mdx create mode 100644 src/content/examples/en/20_3D/07_orbit_control.js create mode 100644 src/content/examples/en/20_3D/07_orbit_control.mdx create mode 100644 src/content/examples/en/20_3D/08_basic_shader.mdx create mode 100644 src/content/examples/en/20_3D/09_shader_as_a_texture.mdx create mode 100644 src/content/examples/en/20_3D/10_passing_shader_uniforms.mdx create mode 100644 src/content/examples/en/20_3D/11_shader_using_webcam.mdx create mode 100644 src/content/examples/en/20_3D/12_framebuffer_blur.js create mode 100644 src/content/examples/en/20_3D/12_framebuffer_blur.mdx create mode 100644 src/content/examples/en/20_3D/12_simple_feedback.js create mode 100644 src/content/examples/en/20_3D/12_simple_feedback.mdx create mode 100644 src/content/examples/en/21_Input/00_Clock.js create mode 100644 src/content/examples/en/21_Input/00_Clock.mdx create mode 100644 src/content/examples/en/21_Input/01_Constrain.js create mode 100644 src/content/examples/en/21_Input/01_Constrain.mdx create mode 100644 src/content/examples/en/21_Input/02_Easing.js create mode 100644 src/content/examples/en/21_Input/02_Easing.mdx create mode 100644 src/content/examples/en/21_Input/03_Keyboard.js create mode 100644 src/content/examples/en/21_Input/03_Keyboard.mdx create mode 100644 src/content/examples/en/21_Input/04_Milliseconds.mdx create mode 100644 src/content/examples/en/21_Input/05_Mouse1D.js create mode 100644 src/content/examples/en/21_Input/05_Mouse1D.mdx create mode 100644 src/content/examples/en/21_Input/06_Mouse2D.js create mode 100644 src/content/examples/en/21_Input/06_Mouse2D.mdx create mode 100644 src/content/examples/en/21_Input/07_Mouse_Functions.js create mode 100644 src/content/examples/en/21_Input/07_Mouse_Functions.mdx create mode 100644 src/content/examples/en/21_Input/08_Mouse_Signals.js create mode 100644 src/content/examples/en/21_Input/08_Mouse_Signals.mdx create mode 100644 src/content/examples/en/21_Input/09_MouseIsPressed.js create mode 100644 src/content/examples/en/21_Input/09_MouseIsPressed.mdx create mode 100644 src/content/examples/en/21_Input/10_Rollover.mdx create mode 100644 src/content/examples/en/21_Input/11_Storing_Input.js create mode 100644 src/content/examples/en/21_Input/11_Storing_Input.mdx create mode 100644 src/content/examples/en/22_Advanced_Data/00_Load_Saved_JSON.mdx create mode 100644 src/content/examples/en/22_Advanced_Data/01_Load_Saved_Table.mdx create mode 100644 src/content/examples/en/33_Sound/00_Load_and_Play_Sound.mdx create mode 100644 src/content/examples/en/33_Sound/01_Preload_Sound.mdx create mode 100644 src/content/examples/en/33_Sound/02_soundFormats.js create mode 100644 src/content/examples/en/33_Sound/02_soundFormats.mdx create mode 100644 src/content/examples/en/33_Sound/03_Play_Mode.js create mode 100644 src/content/examples/en/33_Sound/03_Play_Mode.mdx create mode 100644 src/content/examples/en/33_Sound/04_Pan_SoundFile.js create mode 100644 src/content/examples/en/33_Sound/04_Pan_SoundFile.mdx create mode 100644 src/content/examples/en/33_Sound/05_Sound_Effect.js create mode 100644 src/content/examples/en/33_Sound/05_Sound_Effect.mdx create mode 100644 src/content/examples/en/33_Sound/06_Manipulate_Sound.js create mode 100644 src/content/examples/en/33_Sound/06_Manipulate_Sound.mdx create mode 100644 src/content/examples/en/33_Sound/07_Amplitude_Analysis.mdx create mode 100644 src/content/examples/en/33_Sound/08_Noise_Envelope.js create mode 100644 src/content/examples/en/33_Sound/08_Noise_Envelope.mdx create mode 100644 src/content/examples/en/33_Sound/09_Note_Envelope.js create mode 100644 src/content/examples/en/33_Sound/09_Note_Envelope.mdx create mode 100644 src/content/examples/en/33_Sound/10_Oscillator_Waveform.js create mode 100644 src/content/examples/en/33_Sound/10_Oscillator_Waveform.mdx create mode 100644 src/content/examples/en/33_Sound/11_Live_Input.js create mode 100644 src/content/examples/en/33_Sound/11_Live_Input.mdx create mode 100644 src/content/examples/en/33_Sound/12_FFT_Spectrum.js create mode 100644 src/content/examples/en/33_Sound/12_FFT_Spectrum.mdx create mode 100644 src/content/examples/en/33_Sound/13_Mic_Threshold.js create mode 100644 src/content/examples/en/33_Sound/13_Mic_Threshold.mdx create mode 100644 src/content/examples/en/33_Sound/14_Filter_LowPass.js create mode 100644 src/content/examples/en/33_Sound/14_Filter_LowPass.mdx create mode 100644 src/content/examples/en/33_Sound/15_Filter_BandPass.js create mode 100644 src/content/examples/en/33_Sound/15_Filter_BandPass.mdx create mode 100644 src/content/examples/en/33_Sound/16_Delay.js create mode 100644 src/content/examples/en/33_Sound/16_Delay.mdx create mode 100644 src/content/examples/en/33_Sound/17_Reverb.js create mode 100644 src/content/examples/en/33_Sound/17_Reverb.mdx create mode 100644 src/content/examples/en/33_Sound/18_Convolution_Reverb.mdx create mode 100644 src/content/examples/en/33_Sound/19_Record_Save.js create mode 100644 src/content/examples/en/33_Sound/19_Record_Save.mdx create mode 100644 src/content/examples/en/33_Sound/21_FreqModulation.mdx create mode 100644 src/content/examples/en/33_Sound/22_AmplitudeModulation.mdx create mode 100644 src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js create mode 100644 src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.mdx create mode 100644 src/content/examples/en/35_Mobile/01_Simple_Draw.js create mode 100644 src/content/examples/en/35_Mobile/01_Simple_Draw.mdx create mode 100644 src/content/examples/en/35_Mobile/02_Acceleration_Color.js create mode 100644 src/content/examples/en/35_Mobile/02_Acceleration_Color.mdx create mode 100644 src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.js create mode 100644 src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.mdx create mode 100644 src/content/examples/en/35_Mobile/04_Tilted_3D_Box.js create mode 100644 src/content/examples/en/35_Mobile/04_Tilted_3D_Box.mdx create mode 100644 src/content/examples/en/90_Hello_P5/01_shapes.js create mode 100644 src/content/examples/en/90_Hello_P5/01_shapes.mdx create mode 100644 src/content/examples/en/90_Hello_P5/02_interactivity.js create mode 100644 src/content/examples/en/90_Hello_P5/02_interactivity.mdx create mode 100644 src/content/examples/en/90_Hello_P5/03_interactivity.js create mode 100644 src/content/examples/en/90_Hello_P5/03_interactivity.mdx create mode 100644 src/content/examples/en/90_Hello_P5/04_animate.js create mode 100644 src/content/examples/en/90_Hello_P5/04_animate.mdx create mode 100644 src/content/examples/en/90_Hello_P5/04_flocking.mdx create mode 100644 src/content/examples/en/90_Hello_P5/05_weather.js create mode 100644 src/content/examples/en/90_Hello_P5/05_weather.mdx create mode 100644 src/content/examples/en/90_Hello_P5/06_drawing.js create mode 100644 src/content/examples/en/90_Hello_P5/06_drawing.mdx create mode 100644 src/content/examples/en/90_Hello_P5/07_song.js create mode 100644 src/content/examples/en/90_Hello_P5/07_song.mdx diff --git a/src/content/examples/en/00_Structure/01_Coordinates.js b/src/content/examples/en/00_Structure/01_Coordinates.js new file mode 100644 index 0000000000..2fc3e05afa --- /dev/null +++ b/src/content/examples/en/00_Structure/01_Coordinates.js @@ -0,0 +1,32 @@ + +function setup() { + // Sets the screen to be 720 pixels wide and 400 pixels high + createCanvas(720, 400); +} + +function draw() { + // Set the background to black and turn off the fill color + background(0); + noFill(); + + // The two parameters of the point() method each specify + // coordinates. + // The first parameter is the x-coordinate and the second is the Y + stroke(255); + point(width * 0.5, height * 0.5); + point(width * 0.5, height * 0.25); + + // Coordinates are used for drawing all shapes, not just points. + // Parameters for different functions are used for different + // purposes. For example, the first two parameters to line() + // specify the coordinates of the first endpoint and the second + // two parameters specify the second endpoint + stroke(0, 153, 255); + line(0, height * 0.33, width, height * 0.33); + + // By default, the first two parameters to rect() are the + // coordinates of the upper-left corner and the second pair + // is the width and height + stroke(255, 153, 0); + rect(width * 0.25, height * 0.1, width * 0.5, height * 0.8); +} diff --git a/src/content/examples/en/00_Structure/01_Coordinates.mdx b/src/content/examples/en/00_Structure/01_Coordinates.mdx new file mode 100644 index 0000000000..2dff0b6f56 --- /dev/null +++ b/src/content/examples/en/00_Structure/01_Coordinates.mdx @@ -0,0 +1,13 @@ +--- +title: Coordinates +arialabel: >- + Black background with a orange outline of a square in the middle and a blue + line across at the top ⅓ point of the square +--- + + +All shapes drawn to the screen have a position that is +specified as a coordinate. All coordinates are measured as the distance from +the origin in units of pixels. The origin \[0, 0] is the coordinate in the +upper left of the window and the coordinate in the lower right is \[width-1, +height-1]. diff --git a/src/content/examples/en/00_Structure/02_Width_and_Height.js b/src/content/examples/en/00_Structure/02_Width_and_Height.js new file mode 100644 index 0000000000..94d6c6d965 --- /dev/null +++ b/src/content/examples/en/00_Structure/02_Width_and_Height.js @@ -0,0 +1,15 @@ + +function setup() { + createCanvas(720, 400); +} + +function draw() { + background(127); + noStroke(); + for (let i = 0; i < height; i += 20) { + fill(129, 206, 15); + rect(0, i, width, 10); + fill(255); + rect(i, 0, 10, height); + } +} diff --git a/src/content/examples/en/00_Structure/02_Width_and_Height.mdx b/src/content/examples/en/00_Structure/02_Width_and_Height.mdx new file mode 100644 index 0000000000..836c6eef9c --- /dev/null +++ b/src/content/examples/en/00_Structure/02_Width_and_Height.mdx @@ -0,0 +1,13 @@ +--- +title: Width and Height +arialabel: >- + Pattern of grey and green horizontal lines. The left half also has white + vertical lines. The left half is broken up into two triangular shapes, one + which is predominately green stripes, and one which is white with the white + stripes +--- + + +The 'width' and 'height' variables contain the +width and height of the display window as defined in the createCanvas() +function. diff --git a/src/content/examples/en/00_Structure/03_Setup_and_Draw.js b/src/content/examples/en/00_Structure/03_Setup_and_Draw.js new file mode 100644 index 0000000000..cc2cc59ac9 --- /dev/null +++ b/src/content/examples/en/00_Structure/03_Setup_and_Draw.js @@ -0,0 +1,23 @@ + +let y = 100; + +// The statements in the setup() function +// execute once when the program begins +function setup() { + // createCanvas must be the first statement + createCanvas(720, 400); + stroke(255); // Set line drawing color to white + frameRate(30); +} +// The statements in draw() are executed until the +// program is stopped. Each statement is executed in +// sequence and after the last line is read, the first +// line is executed again. +function draw() { + background(0); // Set the background to black + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/src/content/examples/en/00_Structure/03_Setup_and_Draw.mdx b/src/content/examples/en/00_Structure/03_Setup_and_Draw.mdx new file mode 100644 index 0000000000..1bc101d6d2 --- /dev/null +++ b/src/content/examples/en/00_Structure/03_Setup_and_Draw.mdx @@ -0,0 +1,11 @@ +--- +title: Setup and Draw +arialabel: >- + Animated horizontal white line on a black background that moves from the + bottom to the top of the screen +--- + + +The code inside the draw() function runs continuously from top +to bottom until the program is stopped. The +code in setup() is run once when the program starts. diff --git a/src/content/examples/en/00_Structure/04_No_Loop.js b/src/content/examples/en/00_Structure/04_No_Loop.js new file mode 100644 index 0000000000..a7ffcedc2e --- /dev/null +++ b/src/content/examples/en/00_Structure/04_No_Loop.js @@ -0,0 +1,26 @@ + +let y; + +// The statements in the setup() function +// execute once when the program begins +function setup() { + // createCanvas should be the first statement + createCanvas(720, 400); + stroke(255); // Set line drawing color to white + noLoop(); + + y = height * 0.5; +} + +// The statements in draw() are executed until the +// program is stopped. Each statement is executed in +// sequence and after the last line is read, the first +// line is executed again. +function draw() { + background(0); // Set the background to black + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/src/content/examples/en/00_Structure/04_No_Loop.mdx b/src/content/examples/en/00_Structure/04_No_Loop.mdx new file mode 100644 index 0000000000..90514efadb --- /dev/null +++ b/src/content/examples/en/00_Structure/04_No_Loop.mdx @@ -0,0 +1,8 @@ +--- +title: No Loop +arialabel: Horizontal white line across the middle of a black background +--- + + +The noLoop() function causes draw() to only execute once. +Without calling noLoop(), the code inside draw() is run continually. diff --git a/src/content/examples/en/00_Structure/05_Loop.js b/src/content/examples/en/00_Structure/05_Loop.js new file mode 100644 index 0000000000..113c61f698 --- /dev/null +++ b/src/content/examples/en/00_Structure/05_Loop.js @@ -0,0 +1,27 @@ + +let y = 0; + +// The statements in the setup() function +// execute once when the program begins +function setup() { + createCanvas(720, 400); // Size must be the first statement + stroke(255); // Set line drawing color to white + frameRate(30); + noLoop(); +} +// The statements in draw() are executed until the +// program is stopped. Each statement is executed in +// sequence and after the last line is read, the first +// line is executed again. +function draw() { + background(0); // Set the background to black + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} + +function mousePressed(){ + loop(); +} diff --git a/src/content/examples/en/00_Structure/05_Loop.mdx b/src/content/examples/en/00_Structure/05_Loop.mdx new file mode 100644 index 0000000000..ba129c0ab4 --- /dev/null +++ b/src/content/examples/en/00_Structure/05_Loop.mdx @@ -0,0 +1,12 @@ +--- +title: Loop +arialabel: >- + Horizontal white line on a black background that moves from the bottom to the + top of the screen parallel to the x-axis +--- + + +If noLoop() is run in setup(), the code in draw() +is only run once. In this example, click the mouse +to run the loop() function to cause the draw() the +run continuously. diff --git a/src/content/examples/en/00_Structure/06_Redraw.js b/src/content/examples/en/00_Structure/06_Redraw.js new file mode 100644 index 0000000000..ea0feeac0a --- /dev/null +++ b/src/content/examples/en/00_Structure/06_Redraw.js @@ -0,0 +1,29 @@ + + +let y; + +// The statements in the setup() function +// execute once when the program begins +function setup() { + createCanvas(720, 400); + stroke(255); + noLoop(); + y = height * 0.5; +} + +// The statements in draw() are executed until the +// program is stopped. Each statement is executed in +// sequence and after the last line is read, the first +// line is executed again. +function draw() { + background(0); + y = y - 4; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} + +function mousePressed() { + redraw(); +} diff --git a/src/content/examples/en/00_Structure/06_Redraw.mdx b/src/content/examples/en/00_Structure/06_Redraw.mdx new file mode 100644 index 0000000000..5d54b6a739 --- /dev/null +++ b/src/content/examples/en/00_Structure/06_Redraw.mdx @@ -0,0 +1,10 @@ +--- +title: Redraw +arialabel: >- + Horizontal white line across a black background that moves higher on the + screen with each mouse click +--- + + +The redraw() function makes draw() execute once. In this example, +draw() is executed once every time the mouse is clicked. diff --git a/src/content/examples/en/00_Structure/07_Functions.js b/src/content/examples/en/00_Structure/07_Functions.js new file mode 100644 index 0000000000..845202b081 --- /dev/null +++ b/src/content/examples/en/00_Structure/07_Functions.js @@ -0,0 +1,23 @@ + + +function setup() { + createCanvas(720, 400); + background(51); + noStroke(); + noLoop(); +} + +function draw() { + drawTarget(width * 0.25, height * 0.4, 200, 4); + drawTarget(width * 0.5, height * 0.5, 300, 10); + drawTarget(width * 0.75, height * 0.3, 120, 6); +} + +function drawTarget(xloc, yloc, size, num) { + const grayvalues = 255 / num; + const steps = size / num; + for (let i = 0; i < num; i++) { + fill(i * grayvalues); + ellipse(xloc, yloc, size - i * steps, size - i * steps); + } +} diff --git a/src/content/examples/en/00_Structure/07_Functions.mdx b/src/content/examples/en/00_Structure/07_Functions.mdx new file mode 100644 index 0000000000..af74d2e726 --- /dev/null +++ b/src/content/examples/en/00_Structure/07_Functions.mdx @@ -0,0 +1,11 @@ +--- +title: Functions +arialabel: >- + Three targets are created in the shape of black circles. There is a gradient + from white to black from the center of the circle to the outer edge. +--- + + +The drawTarget() function makes it easy to draw many distinct +targets. Each call to drawTarget() specifies the position, size, and number of +rings for each target. diff --git a/src/content/examples/en/00_Structure/08_Recursion.js b/src/content/examples/en/00_Structure/08_Recursion.js new file mode 100644 index 0000000000..e1d06016d8 --- /dev/null +++ b/src/content/examples/en/00_Structure/08_Recursion.js @@ -0,0 +1,28 @@ + + +function setup() { + createCanvas(720, 560); + noStroke(); + noLoop(); +} + +function draw() { + drawCircle(width / 2, 280, 6); +} + +function drawCircle(x, radius, level) { + // 'level' is the variable that terminates the recursion once it reaches + // a certain value (here, 1). If a terminating condition is not + // specified, a recursive function keeps calling itself again and again + // until it runs out of stack space - not a favourable outcome! + const tt = (126 * level) / 4.0; + fill(tt); + ellipse(x, height / 2, radius * 2, radius * 2); + if (level > 1) { + // 'level' decreases by 1 at every step and thus makes the terminating condition + // attainable + level = level - 1; + drawCircle(x - radius / 2, radius / 2, level); + drawCircle(x + radius / 2, radius / 2, level); + } +} diff --git a/src/content/examples/en/00_Structure/08_Recursion.mdx b/src/content/examples/en/00_Structure/08_Recursion.mdx new file mode 100644 index 0000000000..98b53d357e --- /dev/null +++ b/src/content/examples/en/00_Structure/08_Recursion.mdx @@ -0,0 +1,14 @@ +--- +title: Recursion +arialabel: >- + Grey circle with two grey circles across its middle. Each of these two grey + circles have more grey circles across its middle. This pattern continues until + no more can be drawn within them. +--- + + +A demonstration of recursion, which means functions call themselves. +A recursive function must have a terminating condition, without which it will +go into an infinite loop. Notice how the drawCircle() function calls itself +at the end of its block. It continues to do this until the variable "level" is +equal to 1. diff --git a/src/content/examples/en/00_Structure/09_Create_Graphics.js b/src/content/examples/en/00_Structure/09_Create_Graphics.js new file mode 100644 index 0000000000..e6a9ade240 --- /dev/null +++ b/src/content/examples/en/00_Structure/09_Create_Graphics.js @@ -0,0 +1,24 @@ + + +let pg; + +function setup() { + createCanvas(710, 400); + pg = createGraphics(400, 250); +} + +function draw() { + fill(0, 12); + rect(0, 0, width, height); + fill(255); + noStroke(); + ellipse(mouseX, mouseY, 60, 60); + + pg.background(51); + pg.noFill(); + pg.stroke(255); + pg.ellipse(mouseX - 150, mouseY - 75, 60, 60); + + //Draw the offscreen buffer to the screen with image() + image(pg, 150, 75); +} diff --git a/src/content/examples/en/00_Structure/09_Create_Graphics.mdx b/src/content/examples/en/00_Structure/09_Create_Graphics.mdx new file mode 100644 index 0000000000..73e14a7cf0 --- /dev/null +++ b/src/content/examples/en/00_Structure/09_Create_Graphics.mdx @@ -0,0 +1,11 @@ +--- +title: Create Graphics +arialabel: >- + Black background with a very dark grey rectangle in the middle. The user’s + mouse draws in white but not on the center rectangle. +--- + + +Creates and returns a new p5.Renderer object. Use this +class if you need to draw into an off-screen graphics buffer. The two parameters +define the width and height in pixels. diff --git a/src/content/examples/en/01_Form/00_Points_and_Lines.js b/src/content/examples/en/01_Form/00_Points_and_Lines.js new file mode 100644 index 0000000000..8c0c371436 --- /dev/null +++ b/src/content/examples/en/01_Form/00_Points_and_Lines.js @@ -0,0 +1,31 @@ + +function setup() { + let d = 70; + let p1 = d; + let p2 = p1 + d; + let p3 = p2 + d; + let p4 = p3 + d; + + // Sets the screen to be 720 pixels wide and 400 pixels high + createCanvas(720, 400); + background(0); + noSmooth(); + + translate(140, 0); + + // Draw gray box + stroke(153); + line(p3, p3, p2, p3); + line(p2, p3, p2, p2); + line(p2, p2, p3, p2); + line(p3, p2, p3, p3); + + // Draw white points + stroke(255); + point(p1, p1); + point(p1, p3); + point(p2, p4); + point(p3, p1); + point(p4, p2); + point(p4, p4); +} diff --git a/src/content/examples/en/01_Form/00_Points_and_Lines.mdx b/src/content/examples/en/01_Form/00_Points_and_Lines.mdx new file mode 100644 index 0000000000..cb68eae8fb --- /dev/null +++ b/src/content/examples/en/01_Form/00_Points_and_Lines.mdx @@ -0,0 +1,9 @@ +--- +title: Points and Lines +arialabel: White outline of a square on a black background +--- + + +Points and lines can be used to draw basic geometry. +Change the value of the variable 'd' to scale the form. The four +variables set the positions based on the value of 'd'. diff --git a/src/content/examples/en/01_Form/01_Shape_Primitives.js b/src/content/examples/en/01_Form/01_Shape_Primitives.js new file mode 100644 index 0000000000..37b7deca7c --- /dev/null +++ b/src/content/examples/en/01_Form/01_Shape_Primitives.js @@ -0,0 +1,25 @@ + +function setup() { + // Sets the screen to be 720 pixels wide and 400 pixels high + createCanvas(720, 400); + background(0); + noStroke(); + + fill(204); + triangle(18, 18, 18, 360, 81, 360); + + fill(102); + rect(81, 81, 63, 63); + + fill(204); + quad(189, 18, 216, 18, 216, 360, 144, 360); + + fill(255); + ellipse(252, 144, 72, 72); + + fill(204); + triangle(288, 18, 351, 360, 288, 360); + + fill(255); + arc(479, 300, 280, 280, PI, TWO_PI); +} diff --git a/src/content/examples/en/01_Form/01_Shape_Primitives.mdx b/src/content/examples/en/01_Form/01_Shape_Primitives.mdx new file mode 100644 index 0000000000..5d887bf612 --- /dev/null +++ b/src/content/examples/en/01_Form/01_Shape_Primitives.mdx @@ -0,0 +1,13 @@ +--- +title: Shape Primitives +arialabel: >- + From left to right: a grey triangle, a darker grey square, a light grey + trapezoid, a white circle, a light grey triangle, and a white half circle, on + a black background +--- + + +The basic shape primitive functions are triangle(), +rect(), quad(), ellipse(), and arc(). Squares are made with rect() +and circles are made with ellipse(). Each of these functions requires +a number of parameters to determine the shape's position and size. diff --git a/src/content/examples/en/01_Form/02_Pie_Chart.js b/src/content/examples/en/01_Form/02_Pie_Chart.js new file mode 100644 index 0000000000..68aab1811d --- /dev/null +++ b/src/content/examples/en/01_Form/02_Pie_Chart.js @@ -0,0 +1,30 @@ + +let angles = [30, 10, 45, 35, 60, 38, 75, 67]; + +function setup() { + createCanvas(720, 400); + noStroke(); + noLoop(); // Run once and stop +} + +function draw() { + background(100); + pieChart(300, angles); +} + +function pieChart(diameter, data) { + let lastAngle = 0; + for (let i = 0; i < data.length; i++) { + let gray = map(i, 0, data.length, 0, 255); + fill(gray); + arc( + width / 2, + height / 2, + diameter, + diameter, + lastAngle, + lastAngle + radians(angles[i]) + ); + lastAngle += radians(angles[i]); + } +} diff --git a/src/content/examples/en/01_Form/02_Pie_Chart.mdx b/src/content/examples/en/01_Form/02_Pie_Chart.mdx new file mode 100644 index 0000000000..b04dc83736 --- /dev/null +++ b/src/content/examples/en/01_Form/02_Pie_Chart.mdx @@ -0,0 +1,10 @@ +--- +title: Pie Chart +arialabel: >- + Pie chart on a grey background with the different slices of the pie chart in + various shades of grey +--- + + +Uses the arc() function to generate a pie chart from the data +stored in an array. diff --git a/src/content/examples/en/01_Form/03_Regular_Polygon.js b/src/content/examples/en/01_Form/03_Regular_Polygon.js new file mode 100644 index 0000000000..48611b6825 --- /dev/null +++ b/src/content/examples/en/01_Form/03_Regular_Polygon.js @@ -0,0 +1,37 @@ + +function setup() { + createCanvas(720, 400); +} + +function draw() { + background(102); + + push(); + translate(width * 0.2, height * 0.5); + rotate(frameCount / 200.0); + polygon(0, 0, 82, 3); + pop(); + + push(); + translate(width * 0.5, height * 0.5); + rotate(frameCount / 50.0); + polygon(0, 0, 80, 20); + pop(); + + push(); + translate(width * 0.8, height * 0.5); + rotate(frameCount / -100.0); + polygon(0, 0, 70, 7); + pop(); +} + +function polygon(x, y, radius, npoints) { + let angle = TWO_PI / npoints; + beginShape(); + for (let a = 0; a < TWO_PI; a += angle) { + let sx = x + cos(a) * radius; + let sy = y + sin(a) * radius; + vertex(sx, sy); + } + endShape(CLOSE); +} diff --git a/src/content/examples/en/01_Form/03_Regular_Polygon.mdx b/src/content/examples/en/01_Form/03_Regular_Polygon.mdx new file mode 100644 index 0000000000..04d4b04d00 --- /dev/null +++ b/src/content/examples/en/01_Form/03_Regular_Polygon.mdx @@ -0,0 +1,12 @@ +--- +title: Regular Polygon +arialabel: >- + Three white shapes with black outlines on a grey background rotating. From + left to right, a triangle, icosagon, and a heptagon +--- + + +What is your favorite? Pentagon? Hexagon? Heptagon? No? +What about the icosagon? The polygon() function created for this example is +capable of drawing any regular polygon. Try placing different numbers into +the polygon() function calls within draw() to explore. diff --git a/src/content/examples/en/01_Form/04_Star.js b/src/content/examples/en/01_Form/04_Star.js new file mode 100644 index 0000000000..912384efeb --- /dev/null +++ b/src/content/examples/en/01_Form/04_Star.js @@ -0,0 +1,41 @@ + +function setup() { + createCanvas(720, 400); +} + +function draw() { + background(102); + + push(); + translate(width * 0.2, height * 0.5); + rotate(frameCount / 200.0); + star(0, 0, 5, 70, 3); + pop(); + + push(); + translate(width * 0.5, height * 0.5); + rotate(frameCount / 50.0); + star(0, 0, 80, 100, 40); + pop(); + + push(); + translate(width * 0.8, height * 0.5); + rotate(frameCount / -100.0); + star(0, 0, 30, 70, 5); + pop(); +} + +function star(x, y, radius1, radius2, npoints) { + let angle = TWO_PI / npoints; + let halfAngle = angle / 2.0; + beginShape(); + for (let a = 0; a < TWO_PI; a += angle) { + let sx = x + cos(a) * radius2; + let sy = y + sin(a) * radius2; + vertex(sx, sy); + sx = x + cos(a + halfAngle) * radius1; + sy = y + sin(a + halfAngle) * radius1; + vertex(sx, sy); + } + endShape(CLOSE); +} diff --git a/src/content/examples/en/01_Form/04_Star.mdx b/src/content/examples/en/01_Form/04_Star.mdx new file mode 100644 index 0000000000..588de819e8 --- /dev/null +++ b/src/content/examples/en/01_Form/04_Star.mdx @@ -0,0 +1,11 @@ +--- +title: Star +arialabel: >- + Grey background with three white shapes rotating with black outlines. From + left to right, a 3-pointed star, a 40-pointed shape, and a 5-pointed star +--- + + +The star() function created for this example is capable of +drawing a wide range of different forms. Try placing different numbers +into the star() function calls within draw() to explore. diff --git a/src/content/examples/en/01_Form/05_Triangle_Strip.js b/src/content/examples/en/01_Form/05_Triangle_Strip.js new file mode 100644 index 0000000000..186c28c71a --- /dev/null +++ b/src/content/examples/en/01_Form/05_Triangle_Strip.js @@ -0,0 +1,33 @@ + +let x; +let y; +let outsideRadius = 150; +let insideRadius = 100; + +function setup() { + createCanvas(720, 400); + background(204); + x = width / 2; + y = height / 2; +} + +function draw() { + background(204); + + let numPoints = int(map(mouseX, 0, width, 6, 60)); + let angle = 0; + let angleStep = 180.0 / numPoints; + + beginShape(TRIANGLE_STRIP); + for (let i = 0; i <= numPoints; i++) { + let px = x + cos(radians(angle)) * outsideRadius; + let py = y + sin(radians(angle)) * outsideRadius; + angle += angleStep; + vertex(px, py); + px = x + cos(radians(angle)) * insideRadius; + py = y + sin(radians(angle)) * insideRadius; + vertex(px, py); + angle += angleStep; + } + endShape(); +} diff --git a/src/content/examples/en/01_Form/05_Triangle_Strip.mdx b/src/content/examples/en/01_Form/05_Triangle_Strip.mdx new file mode 100644 index 0000000000..dc1eb711a9 --- /dev/null +++ b/src/content/examples/en/01_Form/05_Triangle_Strip.mdx @@ -0,0 +1,12 @@ +--- +title: Triangle Strip +arialabel: >- + A ring of white triangles form a heptagon on the grey background. When a user + drags their mouse from left to right, the number of triangles increase and + create a smoother, circular ring +--- + + +Example by Ira Greenberg. Generate a closed ring using the +vertex() function and beginShape(TRIANGLE\_STRIP) mode. The outsideRadius +and insideRadius variables control ring's radii respectively. diff --git a/src/content/examples/en/01_Form/06_Bezier.js b/src/content/examples/en/01_Form/06_Bezier.js new file mode 100644 index 0000000000..785e1f27c0 --- /dev/null +++ b/src/content/examples/en/01_Form/06_Bezier.js @@ -0,0 +1,22 @@ + +function setup() { + createCanvas(720, 400); + stroke(255); + noFill(); +} + +function draw() { + background(0); + for (let i = 0; i < 200; i += 20) { + bezier( + mouseX - i / 2.0, + 40 + i, + 410, + 20, + 440, + 300, + 240 - i / 16.0, + 300 + i / 8.0 + ); + } +} diff --git a/src/content/examples/en/01_Form/06_Bezier.mdx b/src/content/examples/en/01_Form/06_Bezier.mdx new file mode 100644 index 0000000000..ee5247dd65 --- /dev/null +++ b/src/content/examples/en/01_Form/06_Bezier.mdx @@ -0,0 +1,13 @@ +--- +title: Bezier +arialabel: >- + 10 lines in a bezier curve formation. The bottom of the curve does not move + but as the user’s mouse moves, the top of the curve follows the left and right + movement +--- + + +The first two parameters for the bezier() function specify the +first point in the curve and the last two parameters specify the last point. +The middle parameters set the control points that define the shape of the +curve. diff --git a/src/content/examples/en/01_Form/07_3D_Primitives.js b/src/content/examples/en/01_Form/07_3D_Primitives.js new file mode 100644 index 0000000000..1000ca9c13 --- /dev/null +++ b/src/content/examples/en/01_Form/07_3D_Primitives.js @@ -0,0 +1,24 @@ + +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(100); + + noStroke(); + fill(50); + push(); + translate(-275, 175); + rotateY(1.25); + rotateX(-0.9); + box(100); + pop(); + + noFill(); + stroke(255); + push(); + translate(500, height * 0.35, -200); + sphere(300); + pop(); +} diff --git a/src/content/examples/en/01_Form/07_3D_Primitives.mdx b/src/content/examples/en/01_Form/07_3D_Primitives.mdx new file mode 100644 index 0000000000..74f5d5fe37 --- /dev/null +++ b/src/content/examples/en/01_Form/07_3D_Primitives.mdx @@ -0,0 +1,11 @@ +--- +title: 3D Primitives +arialabel: >- + Grey background with a dark grey cube in the bottom left corner and a white + outlined sphere in the bottom right corner +--- + + +Placing mathematically 3D objects in synthetic space. +The box() and sphere() functions take at least one parameter to specify their +size. These shapes are positioned using the translate() function. diff --git a/src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js b/src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js new file mode 100644 index 0000000000..7895fedc02 --- /dev/null +++ b/src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js @@ -0,0 +1,75 @@ + + +function setup() { + createCanvas(400, 400); + colorMode(HSB); + angleMode(DEGREES); + + //vars for color wheel center point + let x = width / 2; + let y = height / 2 + 100; + colorWheel(x, y, 100); //slide 11 + + noStroke(); + pieChartPop(200, 100); //slide 12 +} + +//**** slide 12 pie chart trig demo +function pieChartPop(x, y) { + let [total, child, young, adult, senior, elder] = [577, 103, 69, + 122, 170, 113 + ]; + let startValue = 0; + let range = 0; + + //child slice + range = child / total; + drawSlice("blue", x, y, 200, startValue, startValue + range); + startValue += range; + //young slice + range = young / total; + drawSlice("orange", x, y, 200, startValue, startValue + range); + startValue += range; + //adult slice + range = adult / total; + drawSlice("green", x, y, 200, startValue, startValue + range); + startValue += range; + //senior slice + range = senior / total; + drawSlice("tan", x, y, 200, startValue, startValue + range); + startValue += range; + //elder slice + range = elder / total; + drawSlice("pink", x, y, 200, startValue, startValue + range); + startValue += range; + +} + +/** + * drawSlice - draw colored arc based on angle percentages. slide 13 + * Adjust angles so that 0% starts at top (actually -90). + * @param {color} fColor - fill color + * @param {number} x - center x + * @param {number} y - center y + * @param {number} d - diameter + * @param {float} percent1 - starting percentage + * @param {float} percent2 - ending percentage + */ +function drawSlice(fColor, x, y, d, percent1, percent2) { + fill(fColor); + arc(x, y, d, d, -90 + percent1 * 360, -90 + percent2 * 360); +} + +//**** slide 11 trig demo +function colorWheel(x, y, rad) { + strokeWeight(10); + strokeCap(SQUARE); + + //Iterate 360 degrees of lines, +10deg per turn + for (let a = 0; a < 360; a += 10) { + stroke(a, 150, 200); //hue based on a + //radius is 100, angle is a degrees + line(x, y, x + rad * cos(a), + y + rad * sin(a)); + } +} diff --git a/src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.mdx b/src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.mdx new file mode 100644 index 0000000000..04ec6a7d33 --- /dev/null +++ b/src/content/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.mdx @@ -0,0 +1,3 @@ + + +undefined diff --git a/src/content/examples/en/02_Data/00_Variables.js b/src/content/examples/en/02_Data/00_Variables.js new file mode 100644 index 0000000000..c6d4ce01fb --- /dev/null +++ b/src/content/examples/en/02_Data/00_Variables.js @@ -0,0 +1,33 @@ + +function setup() { + createCanvas(720, 400); + background(0); + stroke(153); + strokeWeight(4); + strokeCap(SQUARE); + + let a = 50; + let b = 120; + let c = 180; + + line(a, b, a + c, b); + line(a, b + 10, a + c, b + 10); + line(a, b + 20, a + c, b + 20); + line(a, b + 30, a + c, b + 30); + + a = a + c; + b = height - b; + + line(a, b, a + c, b); + line(a, b + 10, a + c, b + 10); + line(a, b + 20, a + c, b + 20); + line(a, b + 30, a + c, b + 30); + + a = a + c; + b = height - b; + + line(a, b, a + c, b); + line(a, b + 10, a + c, b + 10); + line(a, b + 20, a + c, b + 20); + line(a, b + 30, a + c, b + 30); +} diff --git a/src/content/examples/en/02_Data/00_Variables.mdx b/src/content/examples/en/02_Data/00_Variables.mdx new file mode 100644 index 0000000000..460bb45db6 --- /dev/null +++ b/src/content/examples/en/02_Data/00_Variables.mdx @@ -0,0 +1,8 @@ +--- +title: Variables +arialabel: Black background with three sets of grey lines that form rectangles. +--- + + +Variables are used for storing values. In this example, change +the values of variables to affect the composition. diff --git a/src/content/examples/en/02_Data/01_True_and_False.js b/src/content/examples/en/02_Data/01_True_and_False.js new file mode 100644 index 0000000000..1aae36b4d8 --- /dev/null +++ b/src/content/examples/en/02_Data/01_True_and_False.js @@ -0,0 +1,24 @@ + +function setup() { + createCanvas(720, 400); + background(0); + stroke(255); + + let b = false; + let d = 20; + let middle = width / 2; + + for (let i = d; i <= width; i += d) { + b = i < middle; + + if (b === true) { + // Vertical line + line(i, d, i, height - d); + } + + if (b === false) { + // Horizontal line + line(middle, i - middle + d, width - d, i - middle + d); + } + } +} diff --git a/src/content/examples/en/02_Data/01_True_and_False.mdx b/src/content/examples/en/02_Data/01_True_and_False.mdx new file mode 100644 index 0000000000..73ab26fb88 --- /dev/null +++ b/src/content/examples/en/02_Data/01_True_and_False.mdx @@ -0,0 +1,13 @@ +--- +title: True and False +arialabel: >- + Black background with vertical white lines on the left half and horizontal + white lines on the right half +--- + + +A Boolean variable has only two possible values: true or false. +It is common to use Booleans with control statements to determine the flow +of a program. In this example, when the boolean value "b" is true, vertical +lines are drawn and when the boolean value "b" is false, horizontal +lines are drawn. diff --git a/src/content/examples/en/02_Data/03_Variable_Scope.js b/src/content/examples/en/02_Data/03_Variable_Scope.js new file mode 100644 index 0000000000..88ad50bd41 --- /dev/null +++ b/src/content/examples/en/02_Data/03_Variable_Scope.js @@ -0,0 +1,39 @@ + +let a = 80; // Create a global variable "a" + +function setup() { + createCanvas(720, 400); + background(0); + stroke(255); + noLoop(); +} + +function draw() { + // Draw a line using the global variable "a" + line(a, 0, a, height); + + // Use a local variable a in for loop + for (let a = 120; a < 200; a += 3) { + line(a, 0, a, height); + } + + // Make a call to the custom function drawAnotherLine() + drawAnotherLine(); + + // Make a call to the custom function drawYetAnotherLine() + drawYetAnotherLine(); +} + +function drawAnotherLine() { + // Create a new variable "a" local to this function + let a = 320; + // Draw a line using the local variable "a" + line(a, 0, a, height); +} + +function drawYetAnotherLine() { + // Because no new local variable "a" is set, + // this line draws using the original global + // variable "a" which is set to the value 20. + line(a + 3, 0, a + 3, height); +} diff --git a/src/content/examples/en/02_Data/03_Variable_Scope.mdx b/src/content/examples/en/02_Data/03_Variable_Scope.mdx new file mode 100644 index 0000000000..9fc06436ce --- /dev/null +++ b/src/content/examples/en/02_Data/03_Variable_Scope.mdx @@ -0,0 +1,13 @@ +--- +title: Variable Scope +arialabel: Black background with vertical white lines condensed on the left side +--- + + +Variables have a global or function "scope". For example, +variables declared within either the setup() or draw() functions may be +only used in these functions. Global variables, variables declared outside +of setup() and draw(), may be used anywhere within the program. If a function +variable is declared with the same name as a global variable, the program +will use the function variable to make its calculations within the current +scope. diff --git a/src/content/examples/en/02_Data/04_Numbers.js b/src/content/examples/en/02_Data/04_Numbers.js new file mode 100644 index 0000000000..f7b2c05ce6 --- /dev/null +++ b/src/content/examples/en/02_Data/04_Numbers.js @@ -0,0 +1,24 @@ + +let a = 0; // Create a global variable "a" of type Number +let b = 0; // Create a global variable "b" of type Number + +function setup() { + createCanvas(720, 400); + stroke(255); +} + +function draw() { + background(0); + + a = a + 1; // Increment a with an integer + b = b + 0.2; //Increment b with a float + line(a, 0, a, height / 2); + line(b, height / 2, b, height); + + if (a > width) { + a = 0; + } + if (b > width) { + b = 0; + } +} diff --git a/src/content/examples/en/02_Data/04_Numbers.mdx b/src/content/examples/en/02_Data/04_Numbers.mdx new file mode 100644 index 0000000000..804b2ddf83 --- /dev/null +++ b/src/content/examples/en/02_Data/04_Numbers.mdx @@ -0,0 +1,13 @@ +--- +title: Numbers +arialabel: >- + A black background with one white vertical line on the top half and one on the + bottom. Both lines move from the left to the right of the screen with the top + vertical line moving faster than the bottom. +--- + + +Numbers can be written with or without decimals. An integer +(more commonly called an int) is a number without a decimal point. A float +is a floating-point number, which means it is a number that has a decimal +place. diff --git a/src/content/examples/en/03_Arrays/00_Array.js b/src/content/examples/en/03_Arrays/00_Array.js new file mode 100644 index 0000000000..6d881e5784 --- /dev/null +++ b/src/content/examples/en/03_Arrays/00_Array.js @@ -0,0 +1,35 @@ + +let coswave = []; + +function setup() { + createCanvas(720, 360); + for (let i = 0; i < width; i++) { + let amount = map(i, 0, width, 0, PI); + coswave[i] = abs(cos(amount)); + } + background(255); + noLoop(); +} + +function draw() { + let y1 = 0; + let y2 = height / 3; + for (let i = 0; i < width; i += 3) { + stroke(coswave[i] * 255); + line(i, y1, i, y2); + } + + y1 = y2; + y2 = y1 + y1; + for (let i = 0; i < width; i += 3) { + stroke((coswave[i] * 255) / 4); + line(i, y1, i, y2); + } + + y1 = y2; + y2 = height; + for (let i = 0; i < width; i += 3) { + stroke(255 - coswave[i] * 255); + line(i, y1, i, y2); + } +} diff --git a/src/content/examples/en/03_Arrays/00_Array.mdx b/src/content/examples/en/03_Arrays/00_Array.mdx new file mode 100644 index 0000000000..80e90ac826 --- /dev/null +++ b/src/content/examples/en/03_Arrays/00_Array.mdx @@ -0,0 +1,15 @@ +--- +title: Array +arialabel: >- + Vertical lines are graphed across a white background to visualize the values + of a cosine curve +--- + + +An array is a list of data. Each piece of data in an array +is identified by an index number representing its position in +the array. Arrays are zero based, which means that the first +element in the array is \[0], the second element is \[1], and so on. +In this example, an array named "coswave" is created and +filled with the cosine values. This data is displayed three +separate ways on the screen. diff --git a/src/content/examples/en/03_Arrays/01_Array_2d.js b/src/content/examples/en/03_Arrays/01_Array_2d.js new file mode 100644 index 0000000000..1fb5091b7e --- /dev/null +++ b/src/content/examples/en/03_Arrays/01_Array_2d.js @@ -0,0 +1,32 @@ + +let distances = []; +let maxDistance; +let spacer; + +function setup() { + createCanvas(720, 360); + maxDistance = dist(width / 2, height / 2, width, height); + for (let x = 0; x < width; x++) { + distances[x] = []; // create nested array + for (let y = 0; y < height; y++) { + let distance = dist(width / 2, height / 2, x, y); + distances[x][y] = (distance / maxDistance) * 255; + } + } + spacer = 10; + noLoop(); // Run once and stop +} + +function draw() { + background(0); + // This embedded loop skips over values in the arrays based on + // the spacer variable, so there are more values in the array + // than are drawn here. Change the value of the spacer variable + // to change the density of the points + for (let x = 0; x < width; x += spacer) { + for (let y = 0; y < height; y += spacer) { + stroke(distances[x][y]); + point(x + spacer / 2, y + spacer / 2); + } + } +} diff --git a/src/content/examples/en/03_Arrays/01_Array_2d.mdx b/src/content/examples/en/03_Arrays/01_Array_2d.mdx new file mode 100644 index 0000000000..eef42282ee --- /dev/null +++ b/src/content/examples/en/03_Arrays/01_Array_2d.mdx @@ -0,0 +1,12 @@ +--- +title: Array 2D +arialabel: >- + A grid of dots drawn on a black background. Dots closer to the center are + darker in color and dots further away from the center are whiter in color +--- + + +Demonstrates the syntax for creating a two-dimensional (2D) +array. Values in a 2D array are accessed through two index values. +2D arrays are useful for storing images. In this example, each dot +is colored in relation to its distance from the center of the image. diff --git a/src/content/examples/en/03_Arrays/02_Array_Objects.js b/src/content/examples/en/03_Arrays/02_Array_Objects.js new file mode 100644 index 0000000000..f65ecdc55c --- /dev/null +++ b/src/content/examples/en/03_Arrays/02_Array_Objects.js @@ -0,0 +1,68 @@ + + +class Module { + constructor(xOff, yOff, x, y, speed, unit) { + this.xOff = xOff; + this.yOff = yOff; + this.x = x; + this.y = y; + this.speed = speed; + this.unit = unit; + this.xDir = 1; + this.yDir = 1; + } + + // Custom method for updating the variables + update() { + this.x = this.x + this.speed * this.xDir; + if (this.x >= this.unit || this.x <= 0) { + this.xDir *= -1; + this.x = this.x + 1 * this.xDir; + this.y = this.y + 1 * this.yDir; + } + if (this.y >= this.unit || this.y <= 0) { + this.yDir *= -1; + this.y = this.y + 1 * this.yDir; + } + } + + // Custom method for drawing the object + draw() { + fill(255); + ellipse(this.xOff + this.x, this.yOff + this.y, 6, 6); + } +} + +let unit = 40; +let count; +let mods = []; + +function setup() { + createCanvas(720, 360); + noStroke(); + let wideCount = width / unit; + let highCount = height / unit; + count = wideCount * highCount; + + let index = 0; + for (let y = 0; y < highCount; y++) { + for (let x = 0; x < wideCount; x++) { + mods[index++] = new Module( + x * unit, + y * unit, + unit / 2, + unit / 2, + random(0.05, 0.8), + unit + ); + } + } +} + +function draw() { + background(0); + for (let i = 0; i < count; i++) { + mods[i].update(); + mods[i].draw(); + } +} diff --git a/src/content/examples/en/03_Arrays/02_Array_Objects.mdx b/src/content/examples/en/03_Arrays/02_Array_Objects.mdx new file mode 100644 index 0000000000..cecc671a90 --- /dev/null +++ b/src/content/examples/en/03_Arrays/02_Array_Objects.mdx @@ -0,0 +1,9 @@ +--- +title: Array Objects +arialabel: >- + Small white circles all over a black background that move side to side and + sometimes collide and bounce off of each other +--- + + +Demonstrates the syntax for creating an array of custom objects. diff --git a/src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.js b/src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.js new file mode 100644 index 0000000000..195c15b938 --- /dev/null +++ b/src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.js @@ -0,0 +1,73 @@ + + + +//"use strict"; //catch some common coding errors + + +/** + * setup : + */ +function setup() { + createCanvas(400, 600); + //create 2D array, slide 4 + let friendArray = [ + ["Nona", "mac & cheese", "orange", "Eid al-fitr"], + ["Marylin", "ice cream", "blue", "Halloween"], + ["Rashaad", "garbage plates", "turquoise", "Christmas"], + ["Ava", "sushi", "pink", "New Years"] + ]; + friendArray.push(["Xavier", "Louisiana creole", "red", "their birthday"]); + + //walking 2D array, slide 6 + let y = 20; // Start row based on text size of 20 + for (let f = 0; f < friendArray.length; f++) { // outer array + let x = 10; // Start item in this row + for (let t = 0; t < friendArray[f].length; t++) { //inner + text(friendArray[f][t], x, y); + x += textWidth(friendArray[f][t]) + 20; //place next item + } + y += 28; // place next row + } + + //walking 2D array, variation on slide 6 + //with embedded arithmetic for y + // + for (let f = 0; f < friendArray.length; f++) { // outer array + let x = 10; // Start item in this row + for (let t = 0; t < friendArray[f].length; t++) { //inner + //y is v-padding + LCV * v-spacing + text(friendArray[f][t], x, 200 + f * 28); + x += textWidth(friendArray[f][t]) + 20; //place next item + } + } + + //walking 2D array, slide 7 + //need to use x and y variables to manage canvas placement + y = 400; + for (let friend of friendArray) { + let x = 10; // Start item in this row + console.log("x and y", x, y); + console.log("friend:", friend); + for (let item of friend) { + console.log("item & x:", item, x); + text(item, x, y); + x += textWidth(item) + 20; //place next item + } + y += 28; // place next row + } + + //slide 9, creating 2D array: schools of fish ages + console.log("\n *** Fish ages in 2D ***"); + const schools = []; + //4 schools of fish + for (let t = 0; t < 4; t++) { + schools[t] = []; //initialize this school + console.log("schools[t]?", t, schools[t]); + + // Add 10 randomized ages to the array + for (let a = 0; a < 10; a++) { + schools[t].push(round(random(1, 5))); + } + } + console.log(schools); + } diff --git a/src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.mdx b/src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.mdx new file mode 100644 index 0000000000..04ec6a7d33 --- /dev/null +++ b/src/content/examples/en/03_Arrays/03_Walk_Over_2dArray.mdx @@ -0,0 +1,3 @@ + + +undefined diff --git a/src/content/examples/en/04_Control/00_Iteration.js b/src/content/examples/en/04_Control/00_Iteration.js new file mode 100644 index 0000000000..3f2143997a --- /dev/null +++ b/src/content/examples/en/04_Control/00_Iteration.js @@ -0,0 +1,38 @@ + +let y; +let num = 14; + +function setup() { + createCanvas(720, 360); + background(102); + noStroke(); + + // Draw white bars + fill(255); + y = 60; + for (let i = 0; i < num / 3; i++) { + rect(50, y, 475, 10); + y += 20; + } + + // Gray bars + fill(51); + y = 40; + for (let i = 0; i < num; i++) { + rect(405, y, 30, 10); + y += 20; + } + y = 50; + for (let i = 0; i < num; i++) { + rect(425, y, 30, 10); + y += 20; + } + + // Thin lines + y = 45; + fill(0); + for (let i = 0; i < num - 1; i++) { + rect(120, y, 40, 1); + y += 20; + } +} diff --git a/src/content/examples/en/04_Control/00_Iteration.mdx b/src/content/examples/en/04_Control/00_Iteration.mdx new file mode 100644 index 0000000000..4a9cd82d2f --- /dev/null +++ b/src/content/examples/en/04_Control/00_Iteration.mdx @@ -0,0 +1,9 @@ +--- +title: Iteration +arialabel: >- + White bars on the top half of the screen intersect with thin lines on the left + and dark grey bars on the right +--- + + +Iteration with a "for" structure to construct repetitive forms. diff --git a/src/content/examples/en/04_Control/01_Embedded_Iteration.js b/src/content/examples/en/04_Control/01_Embedded_Iteration.js new file mode 100644 index 0000000000..37f7b691f0 --- /dev/null +++ b/src/content/examples/en/04_Control/01_Embedded_Iteration.js @@ -0,0 +1,18 @@ + +function setup() { + createCanvas(720, 360); + background(0); + noStroke(); + + let gridSize = 35; + + for (let x = gridSize; x <= width - gridSize; x += gridSize) { + for (let y = gridSize; y <= height - gridSize; y += gridSize) { + noStroke(); + fill(255); + rect(x - 1, y - 1, 3, 3); + stroke(255, 50); + line(x, y, width / 2, height / 2); + } + } +} diff --git a/src/content/examples/en/04_Control/01_Embedded_Iteration.mdx b/src/content/examples/en/04_Control/01_Embedded_Iteration.mdx new file mode 100644 index 0000000000..bb92bbfc70 --- /dev/null +++ b/src/content/examples/en/04_Control/01_Embedded_Iteration.mdx @@ -0,0 +1,9 @@ +--- +title: Embedded Iteration +arialabel: >- + Rays emerge from the center of the screen to the edges. There is also a square + grid of white circles over the window +--- + + +Embedding "for" structures allows repetition in two dimensions. diff --git a/src/content/examples/en/04_Control/02_Conditionals_1.js b/src/content/examples/en/04_Control/02_Conditionals_1.js new file mode 100644 index 0000000000..5fef4a68bb --- /dev/null +++ b/src/content/examples/en/04_Control/02_Conditionals_1.js @@ -0,0 +1,17 @@ + +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 10; i < width; i += 10) { + // If 'i' divides by 20 with no remainder draw the first line + // else draw the second line + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + } else { + stroke(153); + line(i, 20, i, 180); + } + } +} diff --git a/src/content/examples/en/04_Control/02_Conditionals_1.mdx b/src/content/examples/en/04_Control/02_Conditionals_1.mdx new file mode 100644 index 0000000000..c4207574ad --- /dev/null +++ b/src/content/examples/en/04_Control/02_Conditionals_1.mdx @@ -0,0 +1,13 @@ +--- +title: Conditionals 1 +arialabel: Pattern of alternating long and short lines +--- + + +Conditions are like questions. +They allow a program to decide to take one action if +the answer to a question is true or to do another action +if the answer to the question is false. +The questions asked within a program are always logical +or relational statements. For example, if the variable 'i' is +equal to zero then draw a line. diff --git a/src/content/examples/en/04_Control/03_Conditionals_2.js b/src/content/examples/en/04_Control/03_Conditionals_2.js new file mode 100644 index 0000000000..812857edf7 --- /dev/null +++ b/src/content/examples/en/04_Control/03_Conditionals_2.js @@ -0,0 +1,22 @@ + +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 2; i < width - 2; i += 4) { + // If 'i' divides by 20 with no remainder + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + // If 'i' divides by 10 with no remainder + } else if (i % 10 === 0) { + stroke(153); + line(i, 20, i, 180); + // If neither of the above two conditions are met + // then draw this line + } else { + stroke(102); + line(i, height / 2, i, height - 20); + } + } +} diff --git a/src/content/examples/en/04_Control/03_Conditionals_2.mdx b/src/content/examples/en/04_Control/03_Conditionals_2.mdx new file mode 100644 index 0000000000..707e20b854 --- /dev/null +++ b/src/content/examples/en/04_Control/03_Conditionals_2.mdx @@ -0,0 +1,12 @@ +--- +title: Conditionals 2 +arialabel: >- + The top half of the window has spaced out vertical lines. The bottom half of + the window has more condensed vertical lines +--- + + +We extend the language of conditionals from the previous +example by adding the keyword "else". This allows conditionals +to ask two or more sequential questions, each with a different +action. diff --git a/src/content/examples/en/04_Control/04_Logical_Operators.js b/src/content/examples/en/04_Control/04_Logical_Operators.js new file mode 100644 index 0000000000..57c31b088d --- /dev/null +++ b/src/content/examples/en/04_Control/04_Logical_Operators.js @@ -0,0 +1,37 @@ + +let test = false; + +function setup() { + createCanvas(720, 360); + background(126); + + for (let i = 5; i <= height; i += 5) { + // Logical AND + stroke(0); + if (i > 35 && i < 100) { + line(width / 4, i, width / 2, i); + test = false; + } + + // Logical OR + stroke(76); + if (i <= 35 || i >= 100) { + line(width / 2, i, width, i); + test = true; + } + + // Testing if a boolean value is "true" + // The expression "if(test)" is equivalent to "if(test == true)" + if (test) { + stroke(0); + point(width / 3, i); + } + + // Testing if a boolean value is "false" + // The expression "if(!test)" is equivalent to "if(test == false)" + if (!test) { + stroke(255); + point(width / 4, i); + } + } +} diff --git a/src/content/examples/en/04_Control/04_Logical_Operators.mdx b/src/content/examples/en/04_Control/04_Logical_Operators.mdx new file mode 100644 index 0000000000..a6948ead21 --- /dev/null +++ b/src/content/examples/en/04_Control/04_Logical_Operators.mdx @@ -0,0 +1,11 @@ +--- +title: Logical Operators +arialabel: >- + Horizontal black lines across half of a grey background. Part of these lines + are shifted left and there are vertical lines of dots above and below this +--- + + +The logical operators for AND (&&) and OR (||) are used to +combine simple relational statements into more complex expressions. +The NOT (!) operator is used to negate a boolean statement. diff --git a/src/content/examples/en/05_Image/00_Load_and_Display_Image.js b/src/content/examples/en/05_Image/00_Load_and_Display_Image.js new file mode 100644 index 0000000000..82c64ec587 --- /dev/null +++ b/src/content/examples/en/05_Image/00_Load_and_Display_Image.js @@ -0,0 +1,14 @@ + +let img; // Declare variable 'img'. + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // Load the image +} + +function draw() { + // Displays the image at its actual size at point (0,0) + image(img, 0, 0); + // Displays the image at point (0, height/2) at half size + image(img, 0, height / 2, img.width / 2, img.height / 2); +} diff --git a/src/content/examples/en/05_Image/00_Load_and_Display_Image.mdx b/src/content/examples/en/05_Image/00_Load_and_Display_Image.mdx new file mode 100644 index 0000000000..75b69eda3e --- /dev/null +++ b/src/content/examples/en/05_Image/00_Load_and_Display_Image.mdx @@ -0,0 +1,13 @@ +--- +title: Load and Display Image +arialabel: >- + An astronaut on a planet with the same image in a smaller size in the bottom + left quarter +--- + + +Images can be loaded and displayed to the screen at their +actual size or any other size. +

To run this example locally, you will need an +image file, and a running +local server.

diff --git a/src/content/examples/en/05_Image/01_Background_Image.js b/src/content/examples/en/05_Image/01_Background_Image.js new file mode 100644 index 0000000000..21b8fee0e8 --- /dev/null +++ b/src/content/examples/en/05_Image/01_Background_Image.js @@ -0,0 +1,23 @@ + +let bg; +let y = 0; + +function setup() { + // The background image must be the same size as the parameters + // into the createCanvas() method. In this program, the size of + // the image is 720x400 pixels. + bg = loadImage('assets/moonwalk.jpg'); + createCanvas(720, 400); +} + +function draw() { + background(bg); + + stroke(226, 204, 0); + line(0, y, width, y); + + y++; + if (y > height) { + y = 0; + } +} diff --git a/src/content/examples/en/05_Image/01_Background_Image.mdx b/src/content/examples/en/05_Image/01_Background_Image.mdx new file mode 100644 index 0000000000..7352637d26 --- /dev/null +++ b/src/content/examples/en/05_Image/01_Background_Image.mdx @@ -0,0 +1,14 @@ +--- +title: Background Image +arialabel: >- + An astronaut on a planet with a horizontal yellow line traveling from the top + to the bottom of the image +--- + + +This example presents the fastest way to load a +background image. To load an image as the background, +it must be the same width and height as the program. +

To run this example locally, you will need an +image file, and a running +local server.

diff --git a/src/content/examples/en/05_Image/02_Transparency.js b/src/content/examples/en/05_Image/02_Transparency.js new file mode 100644 index 0000000000..8ddf57f709 --- /dev/null +++ b/src/content/examples/en/05_Image/02_Transparency.js @@ -0,0 +1,17 @@ + +let img; +let offset = 0; +let easing = 0.05; + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // Load an image into the program +} + +function draw() { + image(img, 0, 0); // Display at full opacity + let dx = mouseX - img.width / 2 - offset; + offset += dx * easing; + tint(255, 127); // Display at half opacity + image(img, offset, 0); +} diff --git a/src/content/examples/en/05_Image/02_Transparency.mdx b/src/content/examples/en/05_Image/02_Transparency.mdx new file mode 100644 index 0000000000..b9522256a3 --- /dev/null +++ b/src/content/examples/en/05_Image/02_Transparency.mdx @@ -0,0 +1,15 @@ +--- +title: Transparency +arialabel: >- + An astronaut on planet as the background with a slightly transparent version + of this image on top that moves with the horizontal direction of the user’s + mouse +--- + + +Move the pointer left and right across the image to change its +position. This program overlays one image over another by modifying the +alpha value of the image with the tint() function. +

To run this example locally, you will need an +image file, and a running +local server.

diff --git a/src/content/examples/en/05_Image/03_Alpha_Mask.js b/src/content/examples/en/05_Image/03_Alpha_Mask.js new file mode 100644 index 0000000000..9ee863a031 --- /dev/null +++ b/src/content/examples/en/05_Image/03_Alpha_Mask.js @@ -0,0 +1,20 @@ + +let img; +let imgMask; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); + imgMask = loadImage('assets/mask.png'); +} + +function setup() { + createCanvas(720, 400); + img.mask(imgMask); + imageMode(CENTER); +} + +function draw() { + background(0, 102, 153); + image(img, width / 2, height / 2); + image(img, mouseX, mouseY); +} diff --git a/src/content/examples/en/05_Image/03_Alpha_Mask.mdx b/src/content/examples/en/05_Image/03_Alpha_Mask.mdx new file mode 100644 index 0000000000..d71b8721a1 --- /dev/null +++ b/src/content/examples/en/05_Image/03_Alpha_Mask.mdx @@ -0,0 +1,15 @@ +--- +title: Alpha Mask +arialabel: >- + An astronaut on a planet as the background with a slightly transparent version + of this image on top that moves with the user’s mouse. Both have a light blue + gradient on the right side. +--- + + +Loads a "mask" for an image to specify the transparency in +different parts of the image. The two images are blended together using +the mask() method of p5.Image. +

To run this example locally, you will need two +image files, and a running +local server.

diff --git a/src/content/examples/en/05_Image/04_Create_Image.js b/src/content/examples/en/05_Image/04_Create_Image.js new file mode 100644 index 0000000000..7f4d93842a --- /dev/null +++ b/src/content/examples/en/05_Image/04_Create_Image.js @@ -0,0 +1,21 @@ + +let img; // Declare variable 'img'. + +function setup() { + createCanvas(720, 400); + img = createImage(230, 230); + img.loadPixels(); + for (let x = 0; x < img.width; x++) { + for (let y = 0; y < img.height; y++) { + let a = map(y, 0, img.height, 255, 0); + img.set(x, y, [0, 153, 204, a]); + } + } + img.updatePixels(); +} + +function draw() { + background(0); + image(img, 90, 80); + image(img, mouseX - img.width / 2, mouseY - img.height / 2); +} diff --git a/src/content/examples/en/05_Image/04_Create_Image.mdx b/src/content/examples/en/05_Image/04_Create_Image.mdx new file mode 100644 index 0000000000..8aa122d8c6 --- /dev/null +++ b/src/content/examples/en/05_Image/04_Create_Image.mdx @@ -0,0 +1,10 @@ +--- +title: Create Image +arialabel: >- + Black background with a blue gradient square on the left. Another blue + gradient square follows the user’s mouse as it moves +--- + + +The createImage() function provides a fresh buffer of pixels to +play with. This example creates an image gradient. diff --git a/src/content/examples/en/05_Image/05_Pointillism.js b/src/content/examples/en/05_Image/05_Pointillism.js new file mode 100644 index 0000000000..71bbf7f805 --- /dev/null +++ b/src/content/examples/en/05_Image/05_Pointillism.js @@ -0,0 +1,26 @@ + +let img; +let smallPoint, largePoint; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 400); + smallPoint = 4; + largePoint = 40; + imageMode(CENTER); + noStroke(); + background(255); + img.loadPixels(); +} + +function draw() { + let pointillize = map(mouseX, 0, width, smallPoint, largePoint); + let x = floor(random(img.width)); + let y = floor(random(img.height)); + let pix = img.get(x, y); + fill(pix, 128); + ellipse(x, y, pointillize, pointillize); +} diff --git a/src/content/examples/en/05_Image/05_Pointillism.mdx b/src/content/examples/en/05_Image/05_Pointillism.mdx new file mode 100644 index 0000000000..af83e8e8e1 --- /dev/null +++ b/src/content/examples/en/05_Image/05_Pointillism.mdx @@ -0,0 +1,15 @@ +--- +title: Pointillism +arialabel: >- + Dots generate on the screen. As the user’s mouse moves left the dots become + smaller and as the user’s mouse moves right, the dots become bigger. The + colors of the dots are dependent on an image of choice +--- + + +By Dan Shiffman. Mouse horizontal location controls size of +dots. Creates a simple pointillist effect using ellipses colored according +to pixels in an image. +

To run this example locally, you will need an +image file, and a running +local server.

diff --git a/src/content/examples/en/05_Image/06_Blur.mdx b/src/content/examples/en/05_Image/06_Blur.mdx new file mode 100644 index 0000000000..928905fb1f --- /dev/null +++ b/src/content/examples/en/05_Image/06_Blur.mdx @@ -0,0 +1,106 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + // to consider all neighboring pixels we use a 3x3 array + // and normalize these values + // v is the normalized value + let v = 1.0 / 9.0; + // kernel is the 3x3 matrix of normalized values + let kernel = [ + [v, v, v], + [v, v, v], + [v, v, v] + ]; + + // preload() runs once, before setup() + // loadImage() needs to occur here instead of setup() + // if loadImage() is called in setup(), the image won't appear + // since noLoop() restricts draw() to execute only once + // (one execution of draw() is not enough time for the image to load), + // preload() makes sure image is loaded before anything else occurs + function preload() { + // load the original image + img = loadImage('assets/rover.png'); + } + + // setup() runs once after preload + function setup() { + // create canvas + createCanvas(710, 400); + // noLoop() makes draw() run only once, not in a loop + noLoop(); + } + + // draw() runs after setup(), normally on a loop + // in this case it runs only once, because of noDraw() + function draw() { + // place the original image on the upper left corner + image(img, 0, 0); + + // create a new image, same dimensions as img + edgeImg = createImage(img.width, img.height); + + // load its pixels + edgeImg.loadPixels(); + + // two for() loops, to iterate in x axis and y axis + // since the kernel assumes that the pixel + // has pixels above, under, left, and right + // we need to skip the first and last column and row + // x then goes from 1 to width - 1 + // y then goes from 1 to height - 1 + for (let x = 1; x < img.width; x++) { + for (let y = 1; y < img.height; y++) { + // kernel sum for the current pixel starts as 0 + let sum = 0; + + // kx, ky variables for iterating over the kernel + // kx, ky have three different values: -1, 0, 1 + for (kx = -1; kx <= 1; kx++) { + for (ky = -1; ky <= 1; ky++) { + let xpos = x + kx; + let ypos = y + ky; + + // since our image is grayscale, + // RGB values are identical + // we retrieve the red value for this example + // (green and blue work as well) + let val = red(img.get(xpos, ypos)); + + // accumulate the kernel sum + // kernel is a 3x3 matrix + // kx and ky have values -1, 0, 1 + // if we add 1 to kx and ky, we get 0, 1, 2 + // with that we can use it to iterate over kernel + // and calculate the accumulated sum + sum += kernel[kx + 1][ky + 1] * val; + } + } + + // set the value of the edgeImg pixel to the kernel sum + edgeImg.set(x, y, color(sum)); + } + } + // updatePixels() to write the changes on edgeImg + edgeImg.updatePixels(); + + // draw edgeImg at the right of the original image + image(edgeImg, img.width, 0); + } +title: Blur +arialabel: >- + Astronaut rendered in black and white on the left and a blurred version of the + image on the right +description: >- + A low-pass filter that blurs an image. This program analyzes every pixel in an + image and blends it with all the neighboring pixels to blur the image. + +

This example is ported from the Blur example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/05_Image/07_EdgeDetection.mdx b/src/content/examples/en/05_Image/07_EdgeDetection.mdx new file mode 100644 index 0000000000..6bb0c5be33 --- /dev/null +++ b/src/content/examples/en/05_Image/07_EdgeDetection.mdx @@ -0,0 +1,109 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + // this program analyzes every pixel in an image + // in relation to the neighbouring pixels + // to sharpen the image + + // to consider all neighboring pixels we use a 3x3 array + // and normalize these values + // kernel is the 3x3 matrix of normalized values + let kernel = [ + [-1, -1, -1], + [-1, 9, -1], + [-1, -1, -1] + ]; + + // preload() runs once, before setup() + // loadImage() needs to occur here instead of setup() + // if loadImage() is called in setup(), the image won't appear + // since noLoop() restricts draw() to execute only once + // (one execution of draw() is not enough time for the image to load), + // preload() makes sure image is loaded before anything else occurs + function preload() { + // load the original image + img = loadImage('assets/rover.png'); + } + + // setup() runs after preload, once() + function setup() { + // create canvas + createCanvas(710, 400); + // noLoop() makes draw() run only once, not in a loop + noLoop(); + } + + // draw() runs after setup(), normally on a loop + // in this case it runs only once, because of noDraw() + function draw() { + // place the original image on the upper left corner + image(img, 0, 0); + + // create a new image, same dimensions as img + edgeImg = createImage(img.width, img.height); + + // load its pixels + edgeImg.loadPixels(); + + // two for() loops, to iterate in x axis and y axis + // since the kernel assumes that the pixel + // has pixels above, under, left, and right + // we need to skip the first and last column and row + // x then goes from 1 to width - 1 + // y then goes from 1 to height - 1 + + for (let x = 1; x < img.width - 1; x++) { + for (let y = 1; y < img.height - 1; y++) { + // kernel sum for the current pixel starts as 0 + let sum = 0; + + // kx, ky variables for iterating over the kernel + // kx, ky have three different values: -1, 0, 1 + for (kx = -1; kx <= 1; kx++) { + for (ky = -1; ky <= 1; ky++) { + let xpos = x + kx; + let ypos = y + ky; + let pos = (y + ky) * img.width + (x + kx); + // since our image is grayscale, + // RGB values are identical + // we retrieve the red value for this example + let val = red(img.get(xpos, ypos)); + // accumulate the kernel sum + // kernel is a 3x3 matrix + // kx and ky have values -1, 0, 1 + // if we add 1 to kx and ky, we get 0, 1, 2 + // with that we can use it to iterate over kernel + // and calculate the accumulated sum + sum += kernel[ky + 1][kx + 1] * val; + } + } + + // set the pixel value of the edgeImg + edgeImg.set(x, y, color(sum, sum, sum)); + } + } + + // updatePixels() to write the changes on edgeImg + edgeImg.updatePixels(); + + // draw edgeImg at the right of the original image + image(edgeImg, img.width, 0); + } +title: Edge Detection +arialabel: >- + Astronaut rendered in black and white on the left and a highly sharpened + version of the image on the right +description: >- + A high-pass filter sharpens an image. This program analyzes every pixel in an + image in relation to the neighboring pixels to sharpen the image. + +

This example is ported from the Edge Detection + example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/05_Image/08_Brightness.mdx b/src/content/examples/en/05_Image/08_Brightness.mdx new file mode 100644 index 0000000000..1a1a1e802b --- /dev/null +++ b/src/content/examples/en/05_Image/08_Brightness.mdx @@ -0,0 +1,78 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + // This program adjusts the brightness + // of a part of the image by + // calculating the distance of + // each pixel to the mouse. + let img; + // preload() runs once, before setup() + // loadImage() needs to occur here instead of setup() + // preload() makes sure image is loaded before anything else occurs + function preload() { + // load the original image + img = loadImage('assets/rover_wide.jpg'); + } + // setup() runs after preload, once() + function setup() { + createCanvas(710, 400); + pixelDensity(1); + frameRate(30); + } + + function draw() { + image(img, 0, 0); + // Only need to load the pixels[] array once, because we're only + // manipulating pixels[] inside draw(), not drawing shapes. + loadPixels(); + // We must also call loadPixels() on the PImage since we are going to read its pixels. + img.loadPixels(); + for (let x = 0; x < img.width; x++) { + for (let y = 0; y < img.height; y++) { + // Calculate the 1D location from a 2D grid + let loc = (x + y * img.width) * 4; + // Get the R,G,B values from image + let r, g, b; + r = img.pixels[loc]; + // g = img.pixels[loc+1]; + // b = img.pixels[loc+2]; + // Calculate an amount to change brightness based on proximity to the mouse + // The closer the pixel is to the mouse, the lower the value of "distance" + let maxdist = 50; //dist(0,0,width,height); + let d = dist(x, y, mouseX, mouseY); + let adjustbrightness = (255 * (maxdist - d)) / maxdist; + r += adjustbrightness; + // g += adjustbrightness; + // b += adjustbrightness; + // Constrain RGB to make sure they are within 0-255 color range + r = constrain(r, 0, 255); + // g = constrain(g, 0, 255); + // b = constrain(b, 0, 255); + // Make a new color and set pixel in the window + let pixloc = (y * width + x) * 4; + pixels[pixloc] = r; + pixels[pixloc + 1] = r; + pixels[pixloc + 2] = r; + pixels[pixloc + 3] = 255; // Always have to set alpha + } + } + updatePixels(); + } +title: Brightness +arialabel: >- + Astronaut rendered in black and white is covered with a black screen. The + user’s mouse acts as a flashlight and parts of the image are illuminated as + the user’s mouse travels over +description: >- + This program adjusts the brightness of a part of the image by calculating the + distance of each pixel to the mouse. + +

This example is ported from the Brightness example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/05_Image/09_Convolution.js b/src/content/examples/en/05_Image/09_Convolution.js new file mode 100644 index 0000000000..ee52243c32 --- /dev/null +++ b/src/content/examples/en/05_Image/09_Convolution.js @@ -0,0 +1,86 @@ + + +let img; +let w = 80; + +// It's possible to convolve the image with many different +// matrices to produce different effects. This is a high-pass +// filter; it accentuates the edges. +const matrix = [ + [-1, -1, -1], + [-1, 9, -1], + [-1, -1, -1] +]; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 400); + img.loadPixels(); + + // pixelDensity(1) for not scaling pixel density to display density + // for more information, check the reference of pixelDensity() + pixelDensity(1); +} + +function draw() { + // We're only going to process a portion of the image + // so let's set the whole image as the background first + background(img); + + // Calculate the small rectangle we will process + const xstart = constrain(mouseX - w / 2, 0, img.width); + const ystart = constrain(mouseY - w / 2, 0, img.height); + const xend = constrain(mouseX + w / 2, 0, img.width); + const yend = constrain(mouseY + w / 2, 0, img.height); + const matrixsize = 3; + + loadPixels(); + // Begin our loop for every pixel in the smaller image + for (let x = xstart; x < xend; x++) { + for (let y = ystart; y < yend; y++) { + let c = convolution(x, y, matrix, matrixsize, img); + + // retrieve the RGBA values from c and update pixels() + let loc = (x + y * img.width) * 4; + pixels[loc] = red(c); + pixels[loc + 1] = green(c); + pixels[loc + 2] = blue(c); + pixels[loc + 3] = alpha(c); + } + } + updatePixels(); +} + +function convolution(x, y, matrix, matrixsize, img) { + let rtotal = 0.0; + let gtotal = 0.0; + let btotal = 0.0; + const offset = Math.floor(matrixsize / 2); + for (let i = 0; i < matrixsize; i++) { + for (let j = 0; j < matrixsize; j++) { + // What pixel are we testing + const xloc = x + i - offset; + const yloc = y + j - offset; + let loc = (xloc + img.width * yloc) * 4; + + // Make sure we haven't walked off our image, we could do better here + loc = constrain(loc, 0, img.pixels.length - 1); + + // Calculate the convolution + // retrieve RGB values + rtotal += img.pixels[loc] * matrix[i][j]; + gtotal += img.pixels[loc + 1] * matrix[i][j]; + btotal += img.pixels[loc + 2] * matrix[i][j]; + } + } + // Make sure RGB is within range + rtotal = constrain(rtotal, 0, 255); + gtotal = constrain(gtotal, 0, 255); + btotal = constrain(btotal, 0, 255); + + // Return the resulting color + return color(rtotal, gtotal, btotal); +} diff --git a/src/content/examples/en/05_Image/09_Convolution.mdx b/src/content/examples/en/05_Image/09_Convolution.mdx new file mode 100644 index 0000000000..56ffaaa7be --- /dev/null +++ b/src/content/examples/en/05_Image/09_Convolution.mdx @@ -0,0 +1,12 @@ +--- +title: Convolution +arialabel: >- + An astronaut on a planet. As the user’s mouse moves, a square section + increasing the sharpness of the image also moves +--- + + +Applies a convolution matrix to a portion of an image. Move mouse to apply filter to different parts of the image. This example is a port of Dan Shiffman's example for Processing. Original comments written by Dan unless otherwise specified. +

To run this example locally, you will need an +image file, and a running +local server.

diff --git a/src/content/examples/en/05_Image/10_Copy_Method.js b/src/content/examples/en/05_Image/10_Copy_Method.js new file mode 100644 index 0000000000..0da42598f5 --- /dev/null +++ b/src/content/examples/en/05_Image/10_Copy_Method.js @@ -0,0 +1,16 @@ + +let draft, ready; +function preload() { + ready = loadImage('assets/parrot-color.png'); + draft = loadImage('assets/parrot-bw.png'); +} +function setup() { + createCanvas(600, 400); + noCursor(); + cursor('assets/brush.png', 20, -10); + image(ready, 0, 0); + image(draft, 0, 0); +} +function mouseDragged() { + copy(ready, mouseX, mouseY, 20, 20, mouseX, mouseY, 20, 20); +} diff --git a/src/content/examples/en/05_Image/10_Copy_Method.mdx b/src/content/examples/en/05_Image/10_Copy_Method.mdx new file mode 100644 index 0000000000..d78153fa80 --- /dev/null +++ b/src/content/examples/en/05_Image/10_Copy_Method.mdx @@ -0,0 +1,9 @@ +--- +title: Copy() method +arialabel: >- + Parrot rendered in black and white. The user’s cursor is a paint brush and as + the user presses and holds on the image, the area becomes colored +--- + + +An example of how to simulate coloring image with the copy() method. diff --git a/src/content/examples/en/06_Image_Processing/00_ Pixel_Array.js b/src/content/examples/en/06_Image_Processing/00_ Pixel_Array.js new file mode 100644 index 0000000000..7d7fdfa18b --- /dev/null +++ b/src/content/examples/en/06_Image_Processing/00_ Pixel_Array.js @@ -0,0 +1,38 @@ + + +let img; +let direction = 1; +let signal = 0; + +function setup() { + createCanvas(640, 360); + noFill(); + stroke(255); + frameRate(30); + img = loadImage('assets/sea.jpg'); +} + +function draw() { + if (signal > img.width * img.height - 1 || signal < 0) { + direction = direction * -1; + } + + if (mouseIsPressed) { + let mx = constrain(mouseX, 0, img.width - 1); + let my = constrain(mouseY, 0, img.height - 1); + signal = my * img.width + mx; + } else { + signal += 0.33 * direction; + } + + let sx = int(signal) % img.width; + let sy = int(signal) / img.width; + if (keyIsPressed) { + set(0, 0, img); // fast way to draw an image + point(sx, sy); + rect(sx - 5, sy - 5, 10, 10); + } else { + let c = img.get(sx, sy); + background(c); + } +} \ No newline at end of file diff --git a/src/content/examples/en/06_Image_Processing/00_ Pixel_Array.mdx b/src/content/examples/en/06_Image_Processing/00_ Pixel_Array.mdx new file mode 100644 index 0000000000..93ce88389c --- /dev/null +++ b/src/content/examples/en/06_Image_Processing/00_ Pixel_Array.mdx @@ -0,0 +1,9 @@ +--- +title: Pixel Array +--- + + +Click and drag the mouse up and down to control the signal +and press and hold any key to see the current pixel being read. +This program sequentially reads the color of every pixel of an image +and displays this color to fill the window. diff --git a/src/content/examples/en/06_Image_Processing/01_ Histogram.js b/src/content/examples/en/06_Image_Processing/01_ Histogram.js new file mode 100644 index 0000000000..df4a7ebc8a --- /dev/null +++ b/src/content/examples/en/06_Image_Processing/01_ Histogram.js @@ -0,0 +1,43 @@ + + +let img; +let hist = []; + +function preload() { + // Load an image from the data directory + // Load a different image by modifying the comments + img = loadImage('assets/frontier.jpg'); +} + +function setup() { + createCanvas(640, 360); + image(img, 0, 0); + + // Initialize the histogram + for (let i = 0; i < 100; i++) { + hist.push(0); + } + + // Calculate the histogram + for (let i = 0; i < img.width; i++) { + for (let j = 0; j < img.height; j++) { + let bright = int(brightness(img.get(i, j))); + hist[bright]++; + } + } +} + +function draw(){ + // Find the largest value in the histogram + let histMax = max(hist); + stroke(255); + // Draw half of the histogram (skip every second value) + for (let i = 0; i < img.width; i += 2) { + // Map i (from 0..img.width) to a location in the histogram (0..100) + let which = int(map(i, 0, img.width, 0, 100)); + // Convert the histogram value to a location between + // the bottom and the top of the picture + let y = int(map(hist[which], 0, histMax, img.height, 0)); + line(i, img.height, i, y); + } +} diff --git a/src/content/examples/en/06_Image_Processing/01_ Histogram.mdx b/src/content/examples/en/06_Image_Processing/01_ Histogram.mdx new file mode 100644 index 0000000000..1b7b1b2218 --- /dev/null +++ b/src/content/examples/en/06_Image_Processing/01_ Histogram.mdx @@ -0,0 +1,10 @@ +--- +title: Histogram +--- + + +Calculates the histogram of an image. +A histogram is the frequency distribution of the gray levels with the number of +pure black values displayed on the left and number of pure white values on the right. +Note that this sketch will behave differently on Android, since most images will +no longer be full 24-bit color. diff --git a/src/content/examples/en/07_Color/00_Hue.js b/src/content/examples/en/07_Color/00_Hue.js new file mode 100644 index 0000000000..7fc318b303 --- /dev/null +++ b/src/content/examples/en/07_Color/00_Hue.js @@ -0,0 +1,21 @@ + +function setup() { + createCanvas(400, 400) ; + colorMode(HSB); +} + +function draw() { + background (220) + noStroke(); + + for (let i = 0;i<12;i++){ + + //with each iteration of the loop + //the hue steps down by 25 + + //fill(hue,saturation,brightness) + fill (360-i*25,100,100) ; + + rect (0,i*height/12,width,height/12) ; + } +} diff --git a/src/content/examples/en/07_Color/00_Hue.mdx b/src/content/examples/en/07_Color/00_Hue.mdx new file mode 100644 index 0000000000..6f0baefbc8 --- /dev/null +++ b/src/content/examples/en/07_Color/00_Hue.mdx @@ -0,0 +1,9 @@ +--- +title: Hue +arialabel: 'Horizontal bars that step through different hues, controlled using a loop' +--- + + +Hue is that attribute of a color by the virtue of +which it is perceptible as red, green, blue etc. It is independent +of saturation(intensity) and brightness. diff --git a/src/content/examples/en/07_Color/01_Saturation.js b/src/content/examples/en/07_Color/01_Saturation.js new file mode 100644 index 0000000000..2fd0fa8264 --- /dev/null +++ b/src/content/examples/en/07_Color/01_Saturation.js @@ -0,0 +1,21 @@ + +function setup() { + createCanvas(400, 400) ; + colorMode(HSB); +} + +function draw() { + background (220) + noStroke(); + + for (let i = 0;i<6;i++){ + + //with each iteration of the loop + //the saturation steps down by 20 + + //fill(hue,saturation,brightness) + fill (28,100 - i*20,95) ; + + rect (0,i*height/6,width,height/6) ; + } +} diff --git a/src/content/examples/en/07_Color/01_Saturation.mdx b/src/content/examples/en/07_Color/01_Saturation.mdx new file mode 100644 index 0000000000..30fc032908 --- /dev/null +++ b/src/content/examples/en/07_Color/01_Saturation.mdx @@ -0,0 +1,11 @@ +--- +title: Saturation +arialabel: >- + Horizontal bars that step through saturation(high to low) of a color, + controlled using a loop +--- + + +Saturation is the strength or purity of the color and +represents the amount of gray in proportion to the hue. A "saturated" +color is pure and an "unsaturated" color has a large percentage of gray. diff --git a/src/content/examples/en/07_Color/02_Brightness.js b/src/content/examples/en/07_Color/02_Brightness.js new file mode 100644 index 0000000000..e8286aa37a --- /dev/null +++ b/src/content/examples/en/07_Color/02_Brightness.js @@ -0,0 +1,21 @@ + +function setup() { + createCanvas(400, 400) ; + colorMode(HSB); +} + +function draw() { + background (220) + noStroke(); + + for (let i = 0;i<6;i++){ + + //with each iteration of the loop + //the brightness steps down by 20 + + //fill(hue,saturation,brightness) + fill (28,100,100-i*20) ; + + rect (0,i*height/6,width,height/6) ; + } +} diff --git a/src/content/examples/en/07_Color/02_Brightness.mdx b/src/content/examples/en/07_Color/02_Brightness.mdx new file mode 100644 index 0000000000..c1e1530f3d --- /dev/null +++ b/src/content/examples/en/07_Color/02_Brightness.mdx @@ -0,0 +1,10 @@ +--- +title: Brightness +arialabel: >- + Horizontal bars that step through brightness(high to low) of a color, + controlled using a loop +--- + + +Lightness is the amount of black or white that’s been mixed with a hue. +Adding white makes the color lighter and adding black makes it darker. diff --git a/src/content/examples/en/07_Color/03_Color_Wheel.js b/src/content/examples/en/07_Color/03_Color_Wheel.js new file mode 100644 index 0000000000..658eee0091 --- /dev/null +++ b/src/content/examples/en/07_Color/03_Color_Wheel.js @@ -0,0 +1,32 @@ + +function setup() { + createCanvas(400, 400) ; + colorMode(HSB); + + //setting angle mode to degrees + //to aid in positioning of circles + angleMode(DEGREES); + } + + function draw() { + background (220) + noStroke(); + + //loop steps through 36 times drawing + //a circle with a separate hue each time + + for (let i = 0;i<36;i++){ + + //determines position of circles + x = 200 + 100*cos(i*10); + y = 200 + 100*sin(i*10); + + //i * 10 allows to cover the entire hue range + //the first circle has a hue of 0*10 = 0 + // last circle has has a hue of 35*10 = 350 + // hue of 0 and 360 are identical + + fill(i*10,100,100); + circle(x,y,50); + } + } \ No newline at end of file diff --git a/src/content/examples/en/07_Color/03_Color_Wheel.mdx b/src/content/examples/en/07_Color/03_Color_Wheel.mdx new file mode 100644 index 0000000000..84889d8657 --- /dev/null +++ b/src/content/examples/en/07_Color/03_Color_Wheel.mdx @@ -0,0 +1,10 @@ +--- +title: Color Wheel +arialabel: >- + 36 Circles in a circular arrangement cycling through different hues of the + color wheel +--- + + +A color wheel is an organization of color hues around a circle, +which shows the relationships between primary colors, secondary colors, tertiary colors etc. diff --git a/src/content/examples/en/07_Color/04_Color_Variables.js b/src/content/examples/en/07_Color/04_Color_Variables.js new file mode 100644 index 0000000000..e07415dde3 --- /dev/null +++ b/src/content/examples/en/07_Color/04_Color_Variables.js @@ -0,0 +1,36 @@ + +function setup() { + createCanvas(710, 400); + noStroke(); + background(51, 0, 0); + + let inside = color(204, 102, 0); + let middle = color(204, 153, 0); + let outside = color(153, 51, 0); + + // These statements are equivalent to the statements above. + // Programmers may use the format they prefer. + //let inside = color('#CC6600'); + //let middle = color('#CC9900'); + //let outside = color('#993300'); + + push(); + translate(80, 80); + fill(outside); + rect(0, 0, 200, 200); + fill(middle); + rect(40, 60, 120, 120); + fill(inside); + rect(60, 90, 80, 80); + pop(); + + push(); + translate(360, 80); + fill(inside); + rect(0, 0, 200, 200); + fill(outside); + rect(40, 60, 120, 120); + fill(middle); + rect(60, 90, 80, 80); + pop(); +} diff --git a/src/content/examples/en/07_Color/04_Color_Variables.mdx b/src/content/examples/en/07_Color/04_Color_Variables.mdx new file mode 100644 index 0000000000..554fbdfb9d --- /dev/null +++ b/src/content/examples/en/07_Color/04_Color_Variables.mdx @@ -0,0 +1,12 @@ +--- +title: Color Variables +arialabel: >- + Two squares on a brown background. Both squares are made up of two squares in + a larger square. On the left, the outer square is burnt umber, the middle + square is golden, and the center square is orange. On the right, the outer + square is orange, the middle is burnt umber, and the middle is golden +--- + + +(Homage to Albers.) This example creates variables for colors +that may be referred to in the program by a name, rather than a number. diff --git a/src/content/examples/en/07_Color/05_Relativity.js b/src/content/examples/en/07_Color/05_Relativity.js new file mode 100644 index 0000000000..e39ad26f23 --- /dev/null +++ b/src/content/examples/en/07_Color/05_Relativity.js @@ -0,0 +1,29 @@ + +let a, b, c, d, e; + +function setup() { + createCanvas(710, 400); + noStroke(); + a = color(165, 167, 20); + b = color(77, 86, 59); + c = color(42, 106, 105); + d = color(165, 89, 20); + e = color(146, 150, 127); + noLoop(); // Draw only one time +} + +function draw() { + drawBand(a, b, c, d, e, 0, width / 128); + drawBand(c, a, d, b, e, height / 2, width / 128); +} + +function drawBand(v, w, x, y, z, ypos, barWidth) { + let num = 5; + let colorOrder = [v, w, x, y, z]; + for (let i = 0; i < width; i += barWidth * num) { + for (let j = 0; j < num; j++) { + fill(colorOrder[j]); + rect(i + j * barWidth, ypos, barWidth, height / 2); + } + } +} diff --git a/src/content/examples/en/07_Color/05_Relativity.mdx b/src/content/examples/en/07_Color/05_Relativity.mdx new file mode 100644 index 0000000000..b589ee2d3c --- /dev/null +++ b/src/content/examples/en/07_Color/05_Relativity.mdx @@ -0,0 +1,12 @@ +--- +title: Relativity +arialabel: >- + 4 vertical stripes in grey, blue, green, and orange. They are displayed in a + different order on the top half of the screen compared to the bottom half and + this causes the colors to be perceived differently +--- + + +Each color is perceived in relation to other colors. The top +and bottom bars each contain the same component colors, but a different +display order causes individual colors to appear differently. diff --git a/src/content/examples/en/07_Color/06_Linear_Gradient.js b/src/content/examples/en/07_Color/06_Linear_Gradient.js new file mode 100644 index 0000000000..71d32713f7 --- /dev/null +++ b/src/content/examples/en/07_Color/06_Linear_Gradient.js @@ -0,0 +1,48 @@ + +// Constants +const Y_AXIS = 1; +const X_AXIS = 2; +let b1, b2, c1, c2; + +function setup() { + createCanvas(710, 400); + + // Define colors + b1 = color(255); + b2 = color(0); + c1 = color(204, 102, 0); + c2 = color(0, 102, 153); + + noLoop(); +} + +function draw() { + // Background + setGradient(0, 0, width / 2, height, b1, b2, X_AXIS); + setGradient(width / 2, 0, width / 2, height, b2, b1, X_AXIS); + // Foreground + setGradient(50, 90, 540, 80, c1, c2, Y_AXIS); + setGradient(50, 190, 540, 80, c2, c1, X_AXIS); +} + +function setGradient(x, y, w, h, c1, c2, axis) { + noFill(); + + if (axis === Y_AXIS) { + // Top to bottom gradient + for (let i = y; i <= y + h; i++) { + let inter = map(i, y, y + h, 0, 1); + let c = lerpColor(c1, c2, inter); + stroke(c); + line(x, i, x + w, i); + } + } else if (axis === X_AXIS) { + // Left to right gradient + for (let i = x; i <= x + w; i++) { + let inter = map(i, x, x + w, 0, 1); + let c = lerpColor(c1, c2, inter); + stroke(c); + line(i, y, i, y + h); + } + } +} diff --git a/src/content/examples/en/07_Color/06_Linear_Gradient.mdx b/src/content/examples/en/07_Color/06_Linear_Gradient.mdx new file mode 100644 index 0000000000..115b27d7e5 --- /dev/null +++ b/src/content/examples/en/07_Color/06_Linear_Gradient.mdx @@ -0,0 +1,13 @@ +--- +title: Linear Gradient +arialabel: >- + The background is white on the left and right sides and gradients to a black + at the center. There are two long rectangles on the background gradient. The + top rectangle has orange on the top of the rectangle and gradients to blue on + the bottom. The bottom rectangle starts with blue on the left side and + gradients to orange on the right +--- + + +The lerpColor() function is useful for interpolating between +two colors. diff --git a/src/content/examples/en/07_Color/07_Radial_Gradient.js b/src/content/examples/en/07_Color/07_Radial_Gradient.js new file mode 100644 index 0000000000..0efd3a0701 --- /dev/null +++ b/src/content/examples/en/07_Color/07_Radial_Gradient.js @@ -0,0 +1,29 @@ + +let dim; + +function setup() { + createCanvas(710, 400); + dim = width / 2; + background(0); + colorMode(HSB, 360, 100, 100); + noStroke(); + ellipseMode(RADIUS); + frameRate(1); +} + +function draw() { + background(0); + for (let x = 0; x <= width; x += dim) { + drawGradient(x, height / 2); + } +} + +function drawGradient(x, y) { + let radius = dim / 2; + let h = random(0, 360); + for (let r = radius; r > 0; --r) { + fill(h, 90, 90); + ellipse(x, y, r, r); + h = (h + 1) % 360; + } +} diff --git a/src/content/examples/en/07_Color/07_Radial_Gradient.mdx b/src/content/examples/en/07_Color/07_Radial_Gradient.mdx new file mode 100644 index 0000000000..4434aa8aed --- /dev/null +++ b/src/content/examples/en/07_Color/07_Radial_Gradient.mdx @@ -0,0 +1,11 @@ +--- +title: Radial Gradient +arialabel: >- + Three circles on a black background. The middle circle is completely visible + but the user can only see half of the other two. There is a gradiant from the + center of the circle to the outer edge that changes every second +--- + + +Draws a series of concentric circles to create a gradient +from one color to another. diff --git a/src/content/examples/en/07_Color/08_Lerp_Color.js b/src/content/examples/en/07_Color/08_Lerp_Color.js new file mode 100644 index 0000000000..7bbe0e6e00 --- /dev/null +++ b/src/content/examples/en/07_Color/08_Lerp_Color.js @@ -0,0 +1,32 @@ + +function setup() { + createCanvas(400, 400); + colorMode(HSB); +} + +function draw() { + background(220); + noStroke(); + + //try changing these colors + colorA = color(100,100,100); + colorB = color(250,100,20); + + for (let i = 0;i<12;i++){ + + //converts i to a fraction between 0 and 1 + position = map(i,0,12,0,1); + + //that position determines where the LerpedColor + //is between colorA and colorB + LerpedColor = lerpColor(colorA,colorB,position); + + fill (LerpedColor) ; + rect (0,i*height/12,width,height/12) ; + } + + //Labels + text("Color A",10,20); + fill("#FFF"); + text("Color B",10,390); +} \ No newline at end of file diff --git a/src/content/examples/en/07_Color/08_Lerp_Color.mdx b/src/content/examples/en/07_Color/08_Lerp_Color.mdx new file mode 100644 index 0000000000..b12c9094f3 --- /dev/null +++ b/src/content/examples/en/07_Color/08_Lerp_Color.mdx @@ -0,0 +1,10 @@ +--- +title: Lerp Color +arialabel: >- + Horizontal bars that interpolate between two colors (red and blue), controlled + using a loop +--- + + +Lerp Color blends two different colors to produce a range of colors +that exist between the chosen color values. diff --git a/src/content/examples/en/08_Math/00_incrementdecrement.js b/src/content/examples/en/08_Math/00_incrementdecrement.js new file mode 100644 index 0000000000..969a01af8a --- /dev/null +++ b/src/content/examples/en/08_Math/00_incrementdecrement.js @@ -0,0 +1,38 @@ + +let a; +let b; +let direction; + +function setup() { + createCanvas(710, 400); + colorMode(RGB, width); + a = 0; + b = width; + direction = true; + frameRate(30); +} + +function draw() { + a++; + if (a > width) { + a = 0; + direction = !direction; + } + if (direction === true) { + stroke(a); + } else { + stroke(width - a); + } + line(a, 0, a, height / 2); + + b--; + if (b < 0) { + b = width; + } + if (direction == true) { + stroke(width - b); + } else { + stroke(b); + } + line(b, height / 2 + 1, b, height); +} diff --git a/src/content/examples/en/08_Math/00_incrementdecrement.mdx b/src/content/examples/en/08_Math/00_incrementdecrement.mdx new file mode 100644 index 0000000000..56a8722645 --- /dev/null +++ b/src/content/examples/en/08_Math/00_incrementdecrement.mdx @@ -0,0 +1,10 @@ +--- +title: Increment Decrement +arialabel: >- + Two black gradient rectangles on the bottom right and top left of the screen + travel horizontally to the other side and leave a gradient grey path behind +--- + + +Writing "a++" is equivalent to "a = a + 1". +Writing "a--" is equivalent to "a = a - 1". diff --git a/src/content/examples/en/08_Math/01_operatorprecedence.js b/src/content/examples/en/08_Math/01_operatorprecedence.js new file mode 100644 index 0000000000..b6b3cf4acf --- /dev/null +++ b/src/content/examples/en/08_Math/01_operatorprecedence.js @@ -0,0 +1,43 @@ + +// The highest precedence is at the top of the list and +// the lowest is at the bottom. +// Multiplicative: * / % +// Additive: + - +// Relational: < > <= >= +// Equality: == != +// Logical AND: && +// Logical OR: || +// Assignment: = += -= *= /= %= +function setup() { + createCanvas(710, 400); + background(51); + noFill(); + stroke(51); + + stroke(204); + for (let i = 0; i < width - 20; i += 4) { + // The 30 is added to 70 and then evaluated + // if it is greater than the current value of "i" + // For clarity, write as "if (i > (30 + 70)) {" + if (i > 30 + 70) { + line(i, 0, i, 50); + } + } + + stroke(255); + // The 2 is multiplied by the 8 and the result is added to the 4 + // For clarity, write as "rect(5 + (2 * 8), 0, 90, 20);" + rect(4 + 2 * 8, 52, 290, 48); + rect((4 + 2) * 8, 100, 290, 49); + + stroke(153); + for (let i = 0; i < width; i += 2) { + // The relational statements are evaluated + // first, and then the logical AND statements and + // finally the logical OR. For clarity, write as: + // "if(((i > 20) && (i < 50)) || ((i > 100) && (i < width-20))) {" + if ((i > 20 && i < 50) || (i > 100 && i < width - 20)) { + line(i, 151, i, height - 1); + } + } +} diff --git a/src/content/examples/en/08_Math/01_operatorprecedence.mdx b/src/content/examples/en/08_Math/01_operatorprecedence.mdx new file mode 100644 index 0000000000..dc312abda7 --- /dev/null +++ b/src/content/examples/en/08_Math/01_operatorprecedence.mdx @@ -0,0 +1,17 @@ +--- +title: Operator Precedence +arialabel: >- + Grey background with two rectangles outlined in white on the left, and white + vertical lines on the top and bottom +--- + + +If you don't explicitly state the order in which an +expression is evaluated, they are evaluated based on the operator +precedence. For example, in the statement "4+2*8", the 2 will +first be multiplied by 8 and then the result will be added to 4. +This is because the "*" has a higher precedence than the "+". To avoid +ambiguity in reading the program, it is recommended that is statement +is written as "4+(2\*8)". The order of evaluation can be controlled +through placement of parenthesis in the code. A table of operator +precedence follows below. diff --git a/src/content/examples/en/08_Math/02_distance1d.js b/src/content/examples/en/08_Math/02_distance1d.js new file mode 100644 index 0000000000..a870e893dc --- /dev/null +++ b/src/content/examples/en/08_Math/02_distance1d.js @@ -0,0 +1,61 @@ + +let xpos1; +let xpos2; +let xpos3; +let xpos4; +let thin = 8; +let thick = 36; + +function setup() { + createCanvas(710, 400); + noStroke(); + xpos1 = width / 2; + xpos2 = width / 2; + xpos3 = width / 2; + xpos4 = width / 2; +} + +function draw() { + background(0); + + let mx = mouseX * 0.4 - width / 5.0; + + fill(102); + rect(xpos2, 0, thick, height / 2); + fill(204); + rect(xpos1, 0, thin, height / 2); + fill(102); + rect(xpos4, height / 2, thick, height / 2); + fill(204); + rect(xpos3, height / 2, thin, height / 2); + + xpos1 += mx / 16; + xpos2 += mx / 64; + xpos3 -= mx / 16; + xpos4 -= mx / 64; + + if (xpos1 < -thin) { + xpos1 = width; + } + if (xpos1 > width) { + xpos1 = -thin; + } + if (xpos2 < -thick) { + xpos2 = width; + } + if (xpos2 > width) { + xpos2 = -thick; + } + if (xpos3 < -thin) { + xpos3 = width; + } + if (xpos3 > width) { + xpos3 = -thin; + } + if (xpos4 < -thick) { + xpos4 = width; + } + if (xpos4 > width) { + xpos4 = -thick; + } +} diff --git a/src/content/examples/en/08_Math/02_distance1d.mdx b/src/content/examples/en/08_Math/02_distance1d.mdx new file mode 100644 index 0000000000..dc361a41e4 --- /dev/null +++ b/src/content/examples/en/08_Math/02_distance1d.mdx @@ -0,0 +1,11 @@ +--- +title: Distance 1D +arialabel: >- + One thin grey bar and wider grey bar travel on the top half of the screen, and + another set of these two bars travel on the bottom half. The bars change speed + and direction as the user’s mouse moves across the screen +--- + + +Move the mouse left and right to control +the speed and direction of the moving shapes. diff --git a/src/content/examples/en/08_Math/03_distance2d.js b/src/content/examples/en/08_Math/03_distance2d.js new file mode 100644 index 0000000000..9d42f65389 --- /dev/null +++ b/src/content/examples/en/08_Math/03_distance2d.js @@ -0,0 +1,20 @@ + +let max_distance; + +function setup() { + createCanvas(710, 400); + noStroke(); + max_distance = dist(0, 0, width, height); +} + +function draw() { + background(0); + + for (let i = 0; i <= width; i += 20) { + for (let j = 0; j <= height; j += 20) { + let size = dist(mouseX, mouseY, i, j); + size = (size / max_distance) * 66; + ellipse(i, j, size, size); + } + } +} diff --git a/src/content/examples/en/08_Math/03_distance2d.mdx b/src/content/examples/en/08_Math/03_distance2d.mdx new file mode 100644 index 0000000000..0af7b41a61 --- /dev/null +++ b/src/content/examples/en/08_Math/03_distance2d.mdx @@ -0,0 +1,11 @@ +--- +title: Distance 2D +arialabel: >- + The user’s mouse creates a gradient of circles that decrease in size the + closer they are to the mouse as it moves across the screen +--- + + +Move the mouse across the image to obscure +and reveal the matrix. Measures the distance from the mouse +to each circle and sets the size proportionally. diff --git a/src/content/examples/en/08_Math/04_sine.js b/src/content/examples/en/08_Math/04_sine.js new file mode 100644 index 0000000000..7280055c85 --- /dev/null +++ b/src/content/examples/en/08_Math/04_sine.js @@ -0,0 +1,24 @@ + +let diameter; +let angle = 0; + +function setup() { + createCanvas(710, 400); + diameter = height - 10; + noStroke(); + fill(255, 204, 0); +} + +function draw() { + background(0); + + let d1 = 10 + (sin(angle) * diameter) / 2 + diameter / 2; + let d2 = 10 + (sin(angle + PI / 2) * diameter) / 2 + diameter / 2; + let d3 = 10 + (sin(angle + PI) * diameter) / 2 + diameter / 2; + + ellipse(0, height / 2, d1, d1); + ellipse(width / 2, height / 2, d2, d2); + ellipse(width, height / 2, d3, d3); + + angle += 0.02; +} diff --git a/src/content/examples/en/08_Math/04_sine.mdx b/src/content/examples/en/08_Math/04_sine.mdx new file mode 100644 index 0000000000..cfb7fdab5a --- /dev/null +++ b/src/content/examples/en/08_Math/04_sine.mdx @@ -0,0 +1,7 @@ +--- +title: Sine +arialabel: Three yellow circles grow larger and smaller on a black background +--- + + +Smoothly scaling size with the sin() function. diff --git a/src/content/examples/en/08_Math/05_sincosine.js b/src/content/examples/en/08_Math/05_sincosine.js new file mode 100644 index 0000000000..3325602946 --- /dev/null +++ b/src/content/examples/en/08_Math/05_sincosine.js @@ -0,0 +1,37 @@ + +let angle1 = 0; +let angle2 = 0; +let scalar = 70; + +function setup() { + createCanvas(710, 400); + noStroke(); + rectMode(CENTER); +} + +function draw() { + background(0); + + let ang1 = radians(angle1); + let ang2 = radians(angle2); + + let x1 = width / 2 + scalar * cos(ang1); + let x2 = width / 2 + scalar * cos(ang2); + + let y1 = height / 2 + scalar * sin(ang1); + let y2 = height / 2 + scalar * sin(ang2); + + fill(255); + rect(width * 0.5, height * 0.5, 140, 140); + + fill(0, 102, 153); + ellipse(x1, height * 0.5 - 120, scalar, scalar); + ellipse(x2, height * 0.5 + 120, scalar, scalar); + + fill(255, 204, 0); + ellipse(width * 0.5 - 120, y1, scalar, scalar); + ellipse(width * 0.5 + 120, y2, scalar, scalar); + + angle1 += 2; + angle2 += 3; +} diff --git a/src/content/examples/en/08_Math/05_sincosine.mdx b/src/content/examples/en/08_Math/05_sincosine.mdx new file mode 100644 index 0000000000..82f39ff7c7 --- /dev/null +++ b/src/content/examples/en/08_Math/05_sincosine.mdx @@ -0,0 +1,12 @@ +--- +title: Sine Cosine +arialabel: >- + Two blue and two yellow circles move side to side on each side of a white + square +--- + + +Linear movement with sin() and cos(). +Numbers between 0 and 2π (2π which angles roughly 6.28) +are put into these functions and numbers between -1 and 1 are returned. +These values are then scaled to produce larger movements. diff --git a/src/content/examples/en/08_Math/06_sinewave.js b/src/content/examples/en/08_Math/06_sinewave.js new file mode 100644 index 0000000000..f384e879e5 --- /dev/null +++ b/src/content/examples/en/08_Math/06_sinewave.js @@ -0,0 +1,44 @@ + + +let xspacing = 16; // Distance between each horizontal location +let w; // Width of entire wave +let theta = 0.0; // Start angle at 0 +let amplitude = 75.0; // Height of wave +let period = 500.0; // How many pixels before the wave repeats +let dx; // Value for incrementing x +let yvalues; // Using an array to store height values for the wave + +function setup() { + createCanvas(710, 400); + w = width + 16; + dx = (TWO_PI / period) * xspacing; + yvalues = new Array(floor(w / xspacing)); +} + +function draw() { + background(0); + calcWave(); + renderWave(); +} + +function calcWave() { + // Increment theta (try different values for + // 'angular velocity' here) + theta += 0.02; + + // For every x value, calculate a y value with sine function + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = sin(x) * amplitude; + x += dx; + } +} + +function renderWave() { + noStroke(); + fill(255); + // A simple way to draw the wave with an ellipse at each location + for (let x = 0; x < yvalues.length; x++) { + ellipse(x * xspacing, height / 2 + yvalues[x], 16, 16); + } +} diff --git a/src/content/examples/en/08_Math/06_sinewave.mdx b/src/content/examples/en/08_Math/06_sinewave.mdx new file mode 100644 index 0000000000..b52d877a5d --- /dev/null +++ b/src/content/examples/en/08_Math/06_sinewave.mdx @@ -0,0 +1,8 @@ +--- +title: Sine Wave +arialabel: White circles line up to form a sine wave that moves across the black screen +--- + + +Render a simple sine wave. +Original by Daniel Shiffman. diff --git a/src/content/examples/en/08_Math/07_additivewave.js b/src/content/examples/en/08_Math/07_additivewave.js new file mode 100644 index 0000000000..3ec3ec2272 --- /dev/null +++ b/src/content/examples/en/08_Math/07_additivewave.js @@ -0,0 +1,66 @@ + +let xspacing = 8; // Distance between each horizontal location +let w; // Width of entire wave +let maxwaves = 4; // total # of waves to add together + +let theta = 0.0; +let amplitude = new Array(maxwaves); // Height of wave +// Value for incrementing X, to be calculated +// as a function of period and xspacing +let dx = new Array(maxwaves); +// Using an array to store height values +// for the wave (not entirely necessary) +let yvalues; + +function setup() { + createCanvas(710, 400); + frameRate(30); + colorMode(RGB, 255, 255, 255, 100); + w = width + 16; + + for (let i = 0; i < maxwaves; i++) { + amplitude[i] = random(10, 30); + let period = random(100, 300); // Num pixels before wave repeats + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new Array(floor(w / xspacing)); +} + +function draw() { + background(0); + calcWave(); + renderWave(); +} + +function calcWave() { + // Increment theta (try different values + // for 'angular velocity' here + theta += 0.02; + + // Set all height values to zero + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // Accumulate wave height values + for (let j = 0; j < maxwaves; j++) { + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + // Every other wave is cosine instead of sine + if (j % 2 == 0) yvalues[i] += sin(x) * amplitude[j]; + else yvalues[i] += cos(x) * amplitude[j]; + x += dx[j]; + } + } +} + +function renderWave() { + // A simple way to draw the wave with an ellipse at each location + noStroke(); + fill(255, 50); + ellipseMode(CENTER); + for (let x = 0; x < yvalues.length; x++) { + ellipse(x * xspacing, width / 2 + yvalues[x], 16, 16); + } +} diff --git a/src/content/examples/en/08_Math/07_additivewave.mdx b/src/content/examples/en/08_Math/07_additivewave.mdx new file mode 100644 index 0000000000..4852b8c11c --- /dev/null +++ b/src/content/examples/en/08_Math/07_additivewave.mdx @@ -0,0 +1,10 @@ +--- +title: Additive Wave +arialabel: >- + Slightly opaque white circles line up to form waves that moves ross the black + screen +--- + + +Create a more complex wave by adding two waves together. +Original by Daniel Shiffman diff --git a/src/content/examples/en/08_Math/08_polartocartesian.js b/src/content/examples/en/08_Math/08_polartocartesian.js new file mode 100644 index 0000000000..8812d4a43d --- /dev/null +++ b/src/content/examples/en/08_Math/08_polartocartesian.js @@ -0,0 +1,39 @@ + +let r; + +// Angle and angular velocity, accleration +let theta; +let theta_vel; +let theta_acc; + +function setup() { + createCanvas(710, 400); + + // Initialize all values + r = height * 0.45; + theta = 0; + theta_vel = 0; + theta_acc = 0.0001; +} + +function draw() { + background(0); + + // Translate the origin point to the center of the screen + translate(width / 2, height / 2); + + // Convert polar to cartesian + let x = r * cos(theta); + let y = r * sin(theta); + + // Draw the ellipse at the cartesian coordinate + ellipseMode(CENTER); + noStroke(); + fill(200); + ellipse(x, y, 32, 32); + + // Apply acceleration and velocity to angle + // (r remains static in this example) + theta_vel += theta_acc; + theta += theta_vel; +} diff --git a/src/content/examples/en/08_Math/08_polartocartesian.mdx b/src/content/examples/en/08_Math/08_polartocartesian.mdx new file mode 100644 index 0000000000..3791533d30 --- /dev/null +++ b/src/content/examples/en/08_Math/08_polartocartesian.mdx @@ -0,0 +1,9 @@ +--- +title: PolarToCartesian +arialabel: Grey circle travels faster and faster in a circle path on a black background +--- + + +Convert a polar coordinate (r,θ) +to cartesian (x,y): x = r cos(θ), y = r sin(θ) +Original by Daniel Shiffman. diff --git a/src/content/examples/en/08_Math/09_arctangent.mdx b/src/content/examples/en/08_Math/09_arctangent.mdx new file mode 100644 index 0000000000..4f78b16815 --- /dev/null +++ b/src/content/examples/en/08_Math/09_arctangent.mdx @@ -0,0 +1,57 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let e1, e2, e3; + + function setup() { + createCanvas(720, 400); + noStroke(); + e1 = new Eye(250, 16, 120); + e2 = new Eye(164, 185, 80); + e3 = new Eye(420, 230, 220); + } + + function draw() { + background(102); + e1.update(mouseX, mouseY); + e2.update(mouseX, mouseY); + e3.update(mouseX, mouseY); + e1.display(); + e2.display(); + e3.display(); + } + + function Eye(tx, ty, ts) { + this.x = tx; + this.y = ty; + this.size = ts; + this.angle = 0; + + this.update = function(mx, my) { + this.angle = atan2(my - this.y, mx - this.x); + }; + + this.display = function() { + push(); + translate(this.x, this.y); + fill(255); + ellipse(0, 0, this.size, this.size); + rotate(this.angle); + fill(153, 204, 0); + ellipse(this.size / 4, 0, this.size / 2, this.size / 2); + pop(); + }; + } +title: Arctangent +arialabel: >- + Three white circles have smaller green circles within them resembling eyes + where the pupil, represented by the green circle, looks in the direction of + where the user’s mouse is +description: >- + Move the mouse to change the direction of the eyes.
The atan2() function + computes the angle from each eye to the cursor. +--- + + +# Example diff --git a/src/content/examples/en/08_Math/10_Interpolate.js b/src/content/examples/en/08_Math/10_Interpolate.js new file mode 100644 index 0000000000..2a1772e39c --- /dev/null +++ b/src/content/examples/en/08_Math/10_Interpolate.js @@ -0,0 +1,26 @@ + + +let x = 0; +let y = 0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(51); + + // lerp() calculates a number between two numbers at a specific increment. + // The amt parameter is the amount to interpolate between the two values + // where 0.0 equal to the first point, 0.1 is very near the first point, 0.5 + // is half-way in between, etc. + + // Here we are moving 5% of the way to the mouse location each frame + x = lerp(x, mouseX, 0.05); + y = lerp(y, mouseY, 0.05); + + fill(255); + stroke(255); + ellipse(x, y, 66, 66); +} diff --git a/src/content/examples/en/08_Math/10_Interpolate.mdx b/src/content/examples/en/08_Math/10_Interpolate.mdx new file mode 100644 index 0000000000..ece0253f2e --- /dev/null +++ b/src/content/examples/en/08_Math/10_Interpolate.mdx @@ -0,0 +1,11 @@ +--- +title: Linear Interpolation +arialabel: White circle follows the user’s mouse around the screen +--- + + +Move the mouse across the screen and the symbol will follow. +Between drawing each frame of the animation, the ellipse moves part +of the distance (0.05) from its current position toward the cursor using +the lerp() function. +This is the same as the Easing under input only with lerp() instead.. diff --git a/src/content/examples/en/08_Math/11_doubleRandom.js b/src/content/examples/en/08_Math/11_doubleRandom.js new file mode 100644 index 0000000000..495a6d0df3 --- /dev/null +++ b/src/content/examples/en/08_Math/11_doubleRandom.js @@ -0,0 +1,18 @@ + +let totalPts = 300; +let steps = totalPts + 1; + +function setup() { + createCanvas(710, 400); + stroke(255); + frameRate(1); +} + +function draw() { + background(0); + let rand = 0; + for (let i = 1; i < steps; i++) { + point((width / steps) * i, height / 2 + random(-rand, rand)); + rand += random(-5, 5); + } +} diff --git a/src/content/examples/en/08_Math/11_doubleRandom.mdx b/src/content/examples/en/08_Math/11_doubleRandom.mdx new file mode 100644 index 0000000000..494c14c954 --- /dev/null +++ b/src/content/examples/en/08_Math/11_doubleRandom.mdx @@ -0,0 +1,11 @@ +--- +title: Double Random +arialabel: >- + Little white dots clump around the horizontal axis on the middle of the screen + and change positions every second between being more condensed and scattered +--- + + +Using two random() calls and the point() +function to create an irregular sawtooth line. +Original by by Ira Greenberg. diff --git a/src/content/examples/en/08_Math/12_random.js b/src/content/examples/en/08_Math/12_random.js new file mode 100644 index 0000000000..e5f89b703e --- /dev/null +++ b/src/content/examples/en/08_Math/12_random.js @@ -0,0 +1,15 @@ + +function setup() { + createCanvas(710, 400); + background(0); + strokeWeight(20); + frameRate(2); +} + +function draw() { + for (let i = 0; i < width; i++) { + let r = random(255); + stroke(r); + line(i, 0, i, height); + } +} diff --git a/src/content/examples/en/08_Math/12_random.mdx b/src/content/examples/en/08_Math/12_random.mdx new file mode 100644 index 0000000000..b19d58e32e --- /dev/null +++ b/src/content/examples/en/08_Math/12_random.mdx @@ -0,0 +1,8 @@ +--- +title: Random +arialabel: Various shades of grey bars change patterns randomly every half a second +--- + + +Random numbers create the basis of this image. +Each time the program is loaded the result is different. diff --git a/src/content/examples/en/08_Math/13_noise1D.js b/src/content/examples/en/08_Math/13_noise1D.js new file mode 100644 index 0000000000..379a6e2a2d --- /dev/null +++ b/src/content/examples/en/08_Math/13_noise1D.js @@ -0,0 +1,28 @@ + +let xoff = 0.0; +let xincrement = 0.01; + +function setup() { + createCanvas(710, 400); + background(0); + noStroke(); +} + +function draw() { + // Create an alpha blended background + fill(0, 10); + rect(0, 0, width, height); + + //let n = random(0,width); // Try this line instead of noise + + // Get a noise value based on xoff and scale + // it according to the window's width + let n = noise(xoff) * width; + + // With each cycle, increment xoff + xoff += xincrement; + + // Draw the ellipse at the value produced by perlin noise + fill(200); + ellipse(n, height / 2, 64, 64); +} diff --git a/src/content/examples/en/08_Math/13_noise1D.mdx b/src/content/examples/en/08_Math/13_noise1D.mdx new file mode 100644 index 0000000000..b31ad80daf --- /dev/null +++ b/src/content/examples/en/08_Math/13_noise1D.mdx @@ -0,0 +1,7 @@ +--- +title: Noise1D +arialabel: White circle travels side to side based on perlin noise +--- + + +Using 1D Perlin Noise to assign location. diff --git a/src/content/examples/en/08_Math/14_noisewave.js b/src/content/examples/en/08_Math/14_noisewave.js new file mode 100644 index 0000000000..036f206df4 --- /dev/null +++ b/src/content/examples/en/08_Math/14_noisewave.js @@ -0,0 +1,38 @@ + +let yoff = 0.0; // 2nd dimension of perlin noise + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(51); + + fill(255); + // We are going to draw a polygon out of the wave points + beginShape(); + + let xoff = 0; // Option #1: 2D Noise + // let xoff = yoff; // Option #2: 1D Noise + + // Iterate over horizontal pixels + for (let x = 0; x <= width; x += 10) { + // Calculate a y value according to noise, map to + + // Option #1: 2D Noise + let y = map(noise(xoff, yoff), 0, 1, 200, 300); + + // Option #2: 1D Noise + // let y = map(noise(xoff), 0, 1, 200,300); + + // Set the vertex + vertex(x, y); + // Increment x dimension for noise + xoff += 0.05; + } + // increment y dimension for noise + yoff += 0.01; + vertex(width, height); + vertex(0, height); + endShape(CLOSE); +} diff --git a/src/content/examples/en/08_Math/14_noisewave.mdx b/src/content/examples/en/08_Math/14_noisewave.mdx new file mode 100644 index 0000000000..a6accc9db0 --- /dev/null +++ b/src/content/examples/en/08_Math/14_noisewave.mdx @@ -0,0 +1,8 @@ +--- +title: Noise Wave +arialabel: Wave shapes are generated by perlin noise +--- + + +Using Perlin Noise to generate a wave-like pattern. +Original by Daniel Shiffman. diff --git a/src/content/examples/en/08_Math/15_Noise2D.js b/src/content/examples/en/08_Math/15_Noise2D.js new file mode 100644 index 0000000000..5bdd5473e1 --- /dev/null +++ b/src/content/examples/en/08_Math/15_Noise2D.js @@ -0,0 +1,45 @@ + + +let noiseScale = 0.02; + +function setup() { + createCanvas(640, 360); +} + +function drawNoise(x, y, w, h) { + for (let pixelY = y; pixelY < y + h; pixelY++) { + for (let pixelX = x; pixelX < x + w; pixelX++) { + let noiseVal = + noise((mouseX + pixelX) * noiseScale, (mouseY + pixelY) * noiseScale) * 255; + + let index = 4 * (pixelY * width + pixelX); + + pixels[index] = noiseVal; + pixels[index + 1] = noiseVal; + pixels[index + 2] = noiseVal; + pixels[index + 3] = 255; + } + } +} + +function draw() { + background(0); + + loadPixels(); + + // Draw the left half of image + noiseDetail(2, 0.2); + drawNoise(0, 0, width / 2, height - 30); + + // Draw the right half of image + noiseDetail(5, 0.5); + drawNoise(width / 2, 0, width / 2, height - 30); + + updatePixels(); + + //Show the details of two partitions + textSize(18); + fill(255, 255, 255); + text("Noise2D with 2 octaves and 0.2 falloff", 10, 350); + text("Noise2D with 5 octaves and 0.5 falloff", 330, 350); +} diff --git a/src/content/examples/en/08_Math/15_Noise2D.mdx b/src/content/examples/en/08_Math/15_Noise2D.mdx new file mode 100644 index 0000000000..13f7305ccc --- /dev/null +++ b/src/content/examples/en/08_Math/15_Noise2D.mdx @@ -0,0 +1,7 @@ +--- +title: Noise2D +arialabel: 'Two gradient, perlin noises, one on the left and one on the right' +--- + + +Create a 2D noise with different parameters. diff --git a/src/content/examples/en/08_Math/16_Noise3D.js b/src/content/examples/en/08_Math/16_Noise3D.js new file mode 100644 index 0000000000..9228d58850 --- /dev/null +++ b/src/content/examples/en/08_Math/16_Noise3D.js @@ -0,0 +1,44 @@ + + +let noiseVal; +//Increment x by 0.01 +let x_increment = 0.01; +//Increment z by 0.02 every draw() cycle +let z_increment = 0.02; + +//Offset values +let z_off, y_off, x_off; + +function setup() { + //Create the Canvas + createCanvas(640, 360); + //Define frame rate + frameRate(20); + //Initial value of z_off + z_off = 0; +} + +function draw() { + x_off = 0; + y_off = 0; + //Make the background black + background(0); + //Adjust the noice detail + noiseDetail(8, 0.65); + + //For each x,y calculate noice value + for (let y = 0; y < height; y++) { + x_off += x_increment; + y_off = 0; + + for (let x = 0; x < width; x++) { + //Calculate and Draw each pixel + noiseVal = noise(x_off, y_off, z_off); + stroke(noiseVal * 255); + y_off += x_increment; + point(x, y); + } + } + + z_off += z_increment; +} diff --git a/src/content/examples/en/08_Math/16_Noise3D.mdx b/src/content/examples/en/08_Math/16_Noise3D.mdx new file mode 100644 index 0000000000..202b6b8255 --- /dev/null +++ b/src/content/examples/en/08_Math/16_Noise3D.mdx @@ -0,0 +1,7 @@ +--- +title: Noise3D +arialabel: Gradient noise +--- + + +Using 3D noise to create simple animated texture. diff --git a/src/content/examples/en/08_Math/17_Randomchords.js b/src/content/examples/en/08_Math/17_Randomchords.js new file mode 100644 index 0000000000..f283305b83 --- /dev/null +++ b/src/content/examples/en/08_Math/17_Randomchords.js @@ -0,0 +1,30 @@ + + +function setup() { + createCanvas(400, 400); + background(255, 255, 255); + + // translucent stroke using alpha value + stroke(0, 0, 0, 15); +} + +function draw() { + // draw two random chords each frame + randomChord(); + randomChord(); +} + +function randomChord() { + // find a random point on a circle + let angle1 = random(0, 2 * PI); + let xpos1 = 200 + 200 * cos(angle1); + let ypos1 = 200 + 200 * sin(angle1); + + // find another random point on the circle + let angle2 = random(0, 2 * PI); + let xpos2 = 200 + 200 * cos(angle2); + let ypos2 = 200 + 200 * sin(angle2); + + // draw a line between them + line(xpos1, ypos1, xpos2, ypos2); +} diff --git a/src/content/examples/en/08_Math/17_Randomchords.mdx b/src/content/examples/en/08_Math/17_Randomchords.mdx new file mode 100644 index 0000000000..b1bf193e29 --- /dev/null +++ b/src/content/examples/en/08_Math/17_Randomchords.mdx @@ -0,0 +1,11 @@ +--- +title: Random Chords +arialabel: >- + Random lines are drawn from one side of a circle to the other until it looks + like a shaded sphere +--- + + +Accumulates random chords of a circle. Each chord in translucent +so they accumulate to give the illusion of a shaded sphere. +Contributed by Aatish Bhatia, inspired by Anders Hoff diff --git a/src/content/examples/en/08_Math/18_randomGaussian.mdx b/src/content/examples/en/08_Math/18_randomGaussian.mdx new file mode 100644 index 0000000000..6e83fa5ca1 --- /dev/null +++ b/src/content/examples/en/08_Math/18_randomGaussian.mdx @@ -0,0 +1,41 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |2+ + + + function setup() { + createCanvas(720, 400); + background(0); + } + + function draw() { + + // Get a gaussian random number w/ mean of 0 and standard deviation of 1.0 + let val = randomGaussian(); + + let sd = 60; // Define a standard deviation + let mean = width/2; // Define a mean value (middle of the screen along the x-axis) + let x = ( val * sd ) + mean; // Scale the gaussian random number by standard deviation and mean + + noStroke(); + fill(255, 10); + ellipse(x, height/2, 32, 32); // Draw an ellipse at our "normal" random location + } + +title: Random Gaussian +arialabel: >- + Translucent white circles are drawn in a line left and right multiple times + until they overlap to form a white streak +description: >- + This sketch draws ellipses with x and y locations tied to a gaussian + distribution of random numbers. + +

This example is ported from the Random Gaussian + example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/08_Math/19_Map.js b/src/content/examples/en/08_Math/19_Map.js new file mode 100644 index 0000000000..c5c3cc5b5d --- /dev/null +++ b/src/content/examples/en/08_Math/19_Map.js @@ -0,0 +1,15 @@ + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(0); + // Scale the mouseX value from 0 to 720 to a range between 0 and 175 + let c = map(mouseX, 0, width, 0, 175); + // Scale the mouseX value from 0 to 720 to a range between 40 and 300 + let d = map(mouseX, 0, width, 40, 300); + fill(255, c, 0); + ellipse(width/2, height/2, d, d); +} diff --git a/src/content/examples/en/08_Math/19_Map.mdx b/src/content/examples/en/08_Math/19_Map.mdx new file mode 100644 index 0000000000..1b7b80871f --- /dev/null +++ b/src/content/examples/en/08_Math/19_Map.mdx @@ -0,0 +1,13 @@ +--- +title: Map +arialabel: >- + Red circle grows larger and turns more yellow as the user’s mouse moves right + on the screen and does the opposite as the user’s mouse moves left +--- + + +Use the map() function to take any number and scale it to a +new number that is more useful for the project that you are working on. +For example, use the numbers from the mouse position to control the size or color of a shape. +In this example, the mouse’s x-coordinate (numbers between 0 and 360) are scaled to new numbers +to define the color and size of a circle. diff --git a/src/content/examples/en/08_Math/20_Graphing2DEquations.js b/src/content/examples/en/08_Math/20_Graphing2DEquations.js new file mode 100644 index 0000000000..09f32f0a41 --- /dev/null +++ b/src/content/examples/en/08_Math/20_Graphing2DEquations.js @@ -0,0 +1,48 @@ + +function setup() { + createCanvas(710, 400); + pixelDensity(1); +} + +function draw() { + loadPixels(); + let n = (mouseX * 10.0) / width; + const w = 16.0; // 2D space width + const h = 16.0; // 2D space height + const dx = w / width; // Increment x this amount per pixel + const dy = h / height; // Increment y this amount per pixel + let x = -w / 2; // Start x at -1 * width / 2 + let y; + + let r; + let theta; + let val; + + let bw; //variable to store grayscale + let i; + let j; + let cols = width; + let rows = height; + + for (i = 0; i < cols; i += 1) { + y = -h / 2; + for (j = 0; j < rows; j += 1) { + r = sqrt(x * x + y * y); // Convert cartesian to polar + theta = atan2(y, x); // Convert cartesian to polar + // Compute 2D polar coordinate function + val = sin(n * cos(r) + 5 * theta); // Results in a value between -1 and 1 + //var val = cos(r); // Another simple function + //var val = sin(theta); // Another simple function + bw = color(((val + 1) * 255) / 2); + index = 4 * (i + j * width); + pixels[index] = red(bw); + pixels[index + 1] = green(bw); + pixels[index + 2] = blue(bw); + pixels[index + 3] = alpha(bw); + + y += dy; + } + x += dx; + } + updatePixels(); +} diff --git a/src/content/examples/en/08_Math/20_Graphing2DEquations.mdx b/src/content/examples/en/08_Math/20_Graphing2DEquations.mdx new file mode 100644 index 0000000000..ca37db7ec1 --- /dev/null +++ b/src/content/examples/en/08_Math/20_Graphing2DEquations.mdx @@ -0,0 +1,9 @@ +--- +title: Graphing 2D Equations +arialabel: >- + Rays in a black and white pattern swirl together as the user’s mouse moves + right and unswirl as the user’s mouse moves left +--- + + +Graphics the following equation: sin(n cos(r) + 5θ) where n is a function of horizontal mouse location. Original by Daniel Shiffman diff --git a/src/content/examples/en/08_Math/21_parametricEquation.js b/src/content/examples/en/08_Math/21_parametricEquation.js new file mode 100644 index 0000000000..116d3acf9f --- /dev/null +++ b/src/content/examples/en/08_Math/21_parametricEquation.js @@ -0,0 +1,38 @@ + + +function setup(){ + createCanvas(720,400); +} + +// the parameter at which x and y depends is usually taken as either t or symbol of theta +let t = 0; +function draw(){ + background('#fff'); + translate(width/2,height/2); + stroke('#0f0f0f'); + strokeWeight(1.5); + //loop for adding 100 lines + for(let i = 0;i<100;i++){ + line(x1(t+i),y1(t+i),x2(t+i)+20,y2(t+i)+20); + } + t+=0.15; +} +// function to change initial x co-ordinate of the line +function x1(t){ + return sin(t/10)*125+sin(t/20)*125+sin(t/30)*125; +} + +// function to change initial y co-ordinate of the line +function y1(t){ + return cos(t/10)*125+cos(t/20)*125+cos(t/30)*125; +} + +// function to change final x co-ordinate of the line +function x2(t){ + return sin(t/15)*125+sin(t/25)*125+sin(t/35)*125; +} + +// function to change final y co-ordinate of the line +function y2(t){ + return cos(t/15)*125+cos(t/25)*125+cos(t/35)*125; +} \ No newline at end of file diff --git a/src/content/examples/en/08_Math/21_parametricEquation.mdx b/src/content/examples/en/08_Math/21_parametricEquation.mdx new file mode 100644 index 0000000000..8bb1069864 --- /dev/null +++ b/src/content/examples/en/08_Math/21_parametricEquation.mdx @@ -0,0 +1,10 @@ +--- +title: Parametric Equations +arialabel: Black vertical lines travel in a spiral pattern in a 3D space +--- + + +A parametric equation is where x and y +coordinates are both written in terms of another letter. This is +called a parameter and is usually given in the letter t or θ. +The inspiration was taken from the YouTube channel of Alexander Miller. diff --git a/src/content/examples/en/08_Math/22_trigonometryAndParticles.js b/src/content/examples/en/08_Math/22_trigonometryAndParticles.js new file mode 100644 index 0000000000..f01f32c23e --- /dev/null +++ b/src/content/examples/en/08_Math/22_trigonometryAndParticles.js @@ -0,0 +1,60 @@ + + +let f = 0; +let value = 0; +let clicked = 0; +let x = 0; +let y = 0; +function Super_Tornado() { + ratio = frameCount * 0.01; + points = []; + fill(255); + for (let i = 0; i <= 360; i += 0.1) { + let theta = radians(i * ratio); + if (value == 0) { + x = cos(theta) * i; + y = sin(theta) * i; + } + if (value == 1) { + x = cos(1 / theta) * i * tan(i); + y = sin(1 / theta) * i * tan(i); + } + if (value == 2) { + x = cos(theta) * log(i) * tan(i); + y = sin(1 / theta) * log(i) * tan(i); + } + if (value == 3) { + x = cos(theta) * i * tan(i); + y = sin(log(theta)) * i / tan(i); + } + if (value == 4) { + x = cos(theta) * i / 3 * sin(theta) * tan(f + 1); + y = sin(1 / theta) * i / 3 * log(i) * tan(i); + } + ellipse(x, y, 3, 3); + points.push({ + 'x': x, + 'y': y + }) + } +} +function setup() { + createCanvas(400, 400); + noStroke(); +} +function draw() { + background(30); + translate(width / 2, height / 2); + ratio = frameCount * 0.01; + points = []; + Super_Tornado(); +} +function mouseClicked() { + if (clicked < 5) { + clicked++; + value++; + } else { + clicked = 0; + value = 0; + } +} \ No newline at end of file diff --git a/src/content/examples/en/08_Math/22_trigonometryAndParticles.mdx b/src/content/examples/en/08_Math/22_trigonometryAndParticles.mdx new file mode 100644 index 0000000000..2a7e46f017 --- /dev/null +++ b/src/content/examples/en/08_Math/22_trigonometryAndParticles.mdx @@ -0,0 +1,8 @@ +--- +title: Trigonometry and Particles +arialabel: multiple white dot moving in pattern following trigonometry function +--- + + +Creative particle movement using cos(), sin() and tan(). You can sort +through the different functions. diff --git a/src/content/examples/en/09_Simulate/00_Forces.js b/src/content/examples/en/09_Simulate/00_Forces.js new file mode 100644 index 0000000000..67fec0bea0 --- /dev/null +++ b/src/content/examples/en/09_Simulate/00_Forces.js @@ -0,0 +1,137 @@ + +// Demonstration of multiple force acting on +// bodies (Mover class) +// Bodies experience gravity continuously +// Bodies experience fluid resistance when in "water" + +// Nine moving bodies +let movers = []; + +// Liquid +let liquid; + +function setup() { + createCanvas(640, 360); + reset(); + // Create liquid object + liquid = new Liquid(0, height / 2, width, height / 2, 0.1); +} + +function draw() { + background(127); + + // Draw water + liquid.display(); + + for (let i = 0; i < movers.length; i++) { + // Is the Mover in the liquid? + if (liquid.contains(movers[i])) { + // Calculate drag force + let dragForce = liquid.calculateDrag(movers[i]); + // Apply drag force to Mover + movers[i].applyForce(dragForce); + } + + // Gravity is scaled by mass here! + let gravity = createVector(0, 0.1 * movers[i].mass); + // Apply gravity + movers[i].applyForce(gravity); + + // Update and display + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } +} + +function mousePressed() { + reset(); +} + +// Restart all the Mover objects randomly +function reset() { + for (let i = 0; i < 9; i++) { + movers[i] = new Mover(random(0.5, 3), 40 + i * 70, 0); + } +} + +let Liquid = function(x, y, w, h, c) { + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.c = c; +}; + +// Is the Mover in the Liquid? +Liquid.prototype.contains = function(m) { + let l = m.position; + return ( + l.x > this.x && + l.x < this.x + this.w && + l.y > this.y && + l.y < this.y + this.h + ); +}; + +// Calculate drag force +Liquid.prototype.calculateDrag = function(m) { + // Magnitude is coefficient * speed squared + let speed = m.velocity.mag(); + let dragMagnitude = this.c * speed * speed; + + // Direction is inverse of velocity + let dragForce = m.velocity.copy(); + dragForce.mult(-1); + + // Scale according to magnitude + // dragForce.setMag(dragMagnitude); + dragForce.normalize(); + dragForce.mult(dragMagnitude); + return dragForce; +}; + +Liquid.prototype.display = function() { + noStroke(); + fill(50); + rect(this.x, this.y, this.w, this.h); +}; + +function Mover(m, x, y) { + this.mass = m; + this.position = createVector(x, y); + this.velocity = createVector(0, 0); + this.acceleration = createVector(0, 0); +} + +// Newton's 2nd law: F = M * A +// or A = F / M +Mover.prototype.applyForce = function(force) { + let f = p5.Vector.div(force, this.mass); + this.acceleration.add(f); +}; + +Mover.prototype.update = function() { + // Velocity changes according to acceleration + this.velocity.add(this.acceleration); + // position changes by velocity + this.position.add(this.velocity); + // We must clear acceleration each frame + this.acceleration.mult(0); +}; + +Mover.prototype.display = function() { + stroke(0); + strokeWeight(2); + fill(255, 127); + ellipse(this.position.x, this.position.y, this.mass * 16, this.mass * 16); +}; + +// Bounce off bottom of window +Mover.prototype.checkEdges = function() { + if (this.position.y > height - this.mass * 8) { + // A little dampening when hitting the bottom + this.velocity.y *= -0.9; + this.position.y = height - this.mass * 8; + } +}; diff --git a/src/content/examples/en/09_Simulate/00_Forces.mdx b/src/content/examples/en/09_Simulate/00_Forces.mdx new file mode 100644 index 0000000000..346ab36547 --- /dev/null +++ b/src/content/examples/en/09_Simulate/00_Forces.mdx @@ -0,0 +1,11 @@ +--- +title: Forces +arialabel: >- + 9 grey balls drop from the top of the window and slow down as they reach the + bottom half of the screen which is dark grey in color. Their change in speed + mimics objects slowing down due to water resistance +--- + + +Demonstration of multiple force acting on bodies +(natureofcode.com) diff --git a/src/content/examples/en/09_Simulate/01_ParticleSystem.js b/src/content/examples/en/09_Simulate/01_ParticleSystem.js new file mode 100644 index 0000000000..403e14d102 --- /dev/null +++ b/src/content/examples/en/09_Simulate/01_ParticleSystem.js @@ -0,0 +1,65 @@ + +let system; + +function setup() { + createCanvas(720, 400); + system = new ParticleSystem(createVector(width / 2, 50)); +} + +function draw() { + background(51); + system.addParticle(); + system.run(); +} + +// A simple Particle class +let Particle = function(position) { + this.acceleration = createVector(0, 0.05); + this.velocity = createVector(random(-1, 1), random(-1, 0)); + this.position = position.copy(); + this.lifespan = 255; +}; + +Particle.prototype.run = function() { + this.update(); + this.display(); +}; + +// Method to update position +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// Method to display +Particle.prototype.display = function() { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// Is the particle still useful? +Particle.prototype.isDead = function(){ + return this.lifespan < 0; +}; + +let ParticleSystem = function(position) { + this.origin = position.copy(); + this.particles = []; +}; + +ParticleSystem.prototype.addParticle = function() { + this.particles.push(new Particle(this.origin)); +}; + +ParticleSystem.prototype.run = function() { + for (let i = this.particles.length-1; i >= 0; i--) { + let p = this.particles[i]; + p.run(); + if (p.isDead()) { + this.particles.splice(i, 1); + } + } +}; diff --git a/src/content/examples/en/09_Simulate/01_ParticleSystem.mdx b/src/content/examples/en/09_Simulate/01_ParticleSystem.mdx new file mode 100644 index 0000000000..9fccb901d0 --- /dev/null +++ b/src/content/examples/en/09_Simulate/01_ParticleSystem.mdx @@ -0,0 +1,8 @@ +--- +title: Particle System +arialabel: Light grey circles flowing out from a point like a sparkler +--- + + +This is a basic Particle System +(natureofcode.com) diff --git a/src/content/examples/en/09_Simulate/02_Flocking.js b/src/content/examples/en/09_Simulate/02_Flocking.js new file mode 100644 index 0000000000..a6ba7d404b --- /dev/null +++ b/src/content/examples/en/09_Simulate/02_Flocking.js @@ -0,0 +1,222 @@ + + + +let flock; + +function setup() { + createCanvas(640, 360); + createP("Drag the mouse to generate new boids."); + + flock = new Flock(); + // Add an initial set of boids into the system + for (let i = 0; i < 100; i++) { + let b = new Boid(width / 2,height / 2); + flock.addBoid(b); + } +} + +function draw() { + background(51); + flock.run(); +} + +// Add a new boid into the System +function mouseDragged() { + flock.addBoid(new Boid(mouseX, mouseY)); +} + +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Flock object +// Does very little, simply manages the array of all the boids + +function Flock() { + // An array for all the boids + this.boids = []; // Initialize the array +} + +Flock.prototype.run = function() { + for (let i = 0; i < this.boids.length; i++) { + this.boids[i].run(this.boids); // Passing the entire list of boids to each boid individually + } +} + +Flock.prototype.addBoid = function(b) { + this.boids.push(b); +} + +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Boid class +// Methods for Separation, Cohesion, Alignment added + +function Boid(x, y) { + this.acceleration = createVector(0, 0); + this.velocity = createVector(random(-1, 1), random(-1, 1)); + this.position = createVector(x, y); + this.r = 3.0; + this.maxspeed = 3; // Maximum speed + this.maxforce = 0.05; // Maximum steering force +} + +Boid.prototype.run = function(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); +} + +Boid.prototype.applyForce = function(force) { + // We could add mass here if we want A = F / M + this.acceleration.add(force); +} + +// We accumulate a new acceleration each time based on three rules +Boid.prototype.flock = function(boids) { + let sep = this.separate(boids); // Separation + let ali = this.align(boids); // Alignment + let coh = this.cohesion(boids); // Cohesion + // Arbitrarily weight these forces + sep.mult(1.5); + ali.mult(1.0); + coh.mult(1.0); + // Add the force vectors to acceleration + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); +} + +// Method to update location +Boid.prototype.update = function() { + // Update velocity + this.velocity.add(this.acceleration); + // Limit speed + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // Reset accelertion to 0 each cycle + this.acceleration.mult(0); +} + +// A method that calculates and applies a steering force towards a target +// STEER = DESIRED MINUS VELOCITY +Boid.prototype.seek = function(target) { + let desired = p5.Vector.sub(target,this.position); // A vector pointing from the location to the target + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(this.maxspeed); + // Steering = Desired minus Velocity + let steer = p5.Vector.sub(desired,this.velocity); + steer.limit(this.maxforce); // Limit to maximum steering force + return steer; +} + +Boid.prototype.render = function() { + // Draw a triangle rotated in the direction of velocity + let theta = this.velocity.heading() + radians(90); + fill(127); + stroke(200); + push(); + translate(this.position.x, this.position.y); + rotate(theta); + beginShape(); + vertex(0, -this.r * 2); + vertex(-this.r, this.r * 2); + vertex(this.r, this.r * 2); + endShape(CLOSE); + pop(); +} + +// Wraparound +Boid.prototype.borders = function() { + if (this.position.x < -this.r) this.position.x = width + this.r; + if (this.position.y < -this.r) this.position.y = height + this.r; + if (this.position.x > width + this.r) this.position.x = -this.r; + if (this.position.y > height + this.r) this.position.y = -this.r; +} + +// Separation +// Method checks for nearby boids and steers away +Boid.prototype.separate = function(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // For every boid in the system, check if it's too close + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position,boids[i].position); + // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) + if ((d > 0) && (d < desiredseparation)) { + // Calculate vector pointing away from neighbor + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // Weight by distance + steer.add(diff); + count++; // Keep track of how many + } + } + // Average -- divide by how many + if (count > 0) { + steer.div(count); + } + + // As long as the vector is greater than 0 + if (steer.mag() > 0) { + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; +} + +// Alignment +// For every nearby boid in the system, calculate the average velocity +Boid.prototype.align = function(boids) { + let neighbordist = 50; + let sum = createVector(0,0); + let count = 0; + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position,boids[i].position); + if ((d > 0) && (d < neighbordist)) { + sum.add(boids[i].velocity); + count++; + } + } + if (count > 0) { + sum.div(count); + sum.normalize(); + sum.mult(this.maxspeed); + let steer = p5.Vector.sub(sum, this.velocity); + steer.limit(this.maxforce); + return steer; + } else { + return createVector(0, 0); + } +} + +// Cohesion +// For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location +Boid.prototype.cohesion = function(boids) { + let neighbordist = 50; + let sum = createVector(0, 0); // Start with empty vector to accumulate all locations + let count = 0; + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position,boids[i].position); + if ((d > 0) && (d < neighbordist)) { + sum.add(boids[i].position); // Add location + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // Steer towards the location + } else { + return createVector(0, 0); + } +} + + diff --git a/src/content/examples/en/09_Simulate/02_Flocking.mdx b/src/content/examples/en/09_Simulate/02_Flocking.mdx new file mode 100644 index 0000000000..48e16e2490 --- /dev/null +++ b/src/content/examples/en/09_Simulate/02_Flocking.mdx @@ -0,0 +1,11 @@ +--- +title: Flocking +arialabel: Groups of little grey triangles moving across a darker grey background +--- + + +Demonstration of Craig Reynolds' "Flocking" behavior. +See: http://www.red3d.com/cwr/ +Rules: Cohesion, Separation, Alignment +(from natureofcode.com). +Drag mouse to add boids into the system. diff --git a/src/content/examples/en/09_Simulate/03_WolframCA.js b/src/content/examples/en/09_Simulate/03_WolframCA.js new file mode 100644 index 0000000000..78f579a03f --- /dev/null +++ b/src/content/examples/en/09_Simulate/03_WolframCA.js @@ -0,0 +1,69 @@ + + +let w = 10; +// An array of 0s and 1s +let cells; + + // We arbitrarily start with just the middle cell having a state of "1" +let generation = 0; + +// An array to store the ruleset, for example {0,1,1,0,1,1,0,1} +let ruleset = [0, 1, 0, 1, 1, 0, 1, 0]; + +function setup() { + createCanvas(640, 400); + cells = Array(floor(width / w)); + for (let i = 0; i < cells.length; i++) { + cells[i] = 0; + } + cells[cells.length/2] = 1; + +} + +function draw() { + for (let i = 0; i < cells.length; i++) { + if (cells[i] === 1) { + fill(200); + } else { + fill(51); + noStroke(); + rect(i * w, generation * w, w, w); + } + } + if (generation < height/w) { + generate(); + } +} + +// The process of creating the new generation +function generate() { + // First we create an empty array for the new values + let nextgen = Array(cells.length); + // For every spot, determine new state by examing current state, and neighbor states + // Ignore edges that only have one neighor + for (let i = 1; i < cells.length-1; i++) { + let left = cells[i-1]; // Left neighbor state + let me = cells[i]; // Current state + let right = cells[i+1]; // Right neighbor state + nextgen[i] = rules(left, me, right); // Compute next generation state based on ruleset + } + // The current generation is the new generation + cells = nextgen; + generation++; +} + + +// Implementing the Wolfram rules +// Could be improved and made more concise, but here we can explicitly see what is going on for each case +function rules(a, b, c) { + if (a == 1 && b == 1 && c == 1) return ruleset[0]; + if (a == 1 && b == 1 && c == 0) return ruleset[1]; + if (a == 1 && b == 0 && c == 1) return ruleset[2]; + if (a == 1 && b == 0 && c == 0) return ruleset[3]; + if (a == 0 && b == 1 && c == 1) return ruleset[4]; + if (a == 0 && b == 1 && c == 0) return ruleset[5]; + if (a == 0 && b == 0 && c == 1) return ruleset[6]; + if (a == 0 && b == 0 && c == 0) return ruleset[7]; + return 0; +} + diff --git a/src/content/examples/en/09_Simulate/03_WolframCA.mdx b/src/content/examples/en/09_Simulate/03_WolframCA.mdx new file mode 100644 index 0000000000..41e4eb2ae6 --- /dev/null +++ b/src/content/examples/en/09_Simulate/03_WolframCA.mdx @@ -0,0 +1,10 @@ +--- +title: Wolfram CA +arialabel: >- + 1-dimensional cellular automata is depicted which is a pyramid shape with a + design consisting of white squares that create a pixelated look +--- + + +Simple demonstration of a Wolfram 1-dimensional cellular automata +(natureofcode.com) diff --git a/src/content/examples/en/09_Simulate/04_GameOfLife.js b/src/content/examples/en/09_Simulate/04_GameOfLife.js new file mode 100644 index 0000000000..8f98dbb00a --- /dev/null +++ b/src/content/examples/en/09_Simulate/04_GameOfLife.js @@ -0,0 +1,92 @@ + + +let w; +let columns; +let rows; +let board; +let next; + +function setup() { + // Set simulation framerate to 10 to avoid flickering + frameRate(10); + createCanvas(720, 400); + w = 20; + // Calculate columns and rows + columns = floor(width / w); + rows = floor(height / w); + // Wacky way to make a 2D array is JS + board = new Array(columns); + for (let i = 0; i < columns; i++) { + board[i] = new Array(rows); + } + // Going to use multiple 2D arrays and swap them + next = new Array(columns); + for (i = 0; i < columns; i++) { + next[i] = new Array(rows); + } + init(); +} + +function draw() { + background(255); + generate(); + for ( let i = 0; i < columns;i++) { + for ( let j = 0; j < rows;j++) { + if ((board[i][j] == 1)) fill(0); + else fill(255); + stroke(0); + rect(i * w, j * w, w-1, w-1); + } + } + +} + +// reset board when mouse is pressed +function mousePressed() { + init(); +} + +// Fill board randomly +function init() { + for (let i = 0; i < columns; i++) { + for (let j = 0; j < rows; j++) { + // Lining the edges with 0s + if (i == 0 || j == 0 || i == columns-1 || j == rows-1) board[i][j] = 0; + // Filling the rest randomly + else board[i][j] = floor(random(2)); + next[i][j] = 0; + } + } +} + +// The process of creating the new generation +function generate() { + + // Loop through every spot in our 2D array and check spots neighbors + for (let x = 1; x < columns - 1; x++) { + for (let y = 1; y < rows - 1; y++) { + // Add up all the states in a 3x3 surrounding grid + let neighbors = 0; + for (let i = -1; i <= 1; i++) { + for (let j = -1; j <= 1; j++) { + neighbors += board[x+i][y+j]; + } + } + + // A little trick to subtract the current cell's state since + // we added it in the above loop + neighbors -= board[x][y]; + // Rules of Life + if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0; // Loneliness + else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0; // Overpopulation + else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1; // Reproduction + else next[x][y] = board[x][y]; // Stasis + } + } + + // Swap! + let temp = board; + board = next; + next = temp; +} + diff --git a/src/content/examples/en/09_Simulate/04_GameOfLife.mdx b/src/content/examples/en/09_Simulate/04_GameOfLife.mdx new file mode 100644 index 0000000000..2a36744954 --- /dev/null +++ b/src/content/examples/en/09_Simulate/04_GameOfLife.mdx @@ -0,0 +1,10 @@ +--- +title: Game of Life +arialabel: >- + Grid of white squares on a black background with some squares flickering + between white and black to generate random patterns +--- + + +A basic implementation of John Conway's Game of Life CA +(natureofcode.com) diff --git a/src/content/examples/en/09_Simulate/05_MultipleParticleSystems.mdx b/src/content/examples/en/09_Simulate/05_MultipleParticleSystems.mdx new file mode 100644 index 0000000000..5deafffcf5 --- /dev/null +++ b/src/content/examples/en/09_Simulate/05_MultipleParticleSystems.mdx @@ -0,0 +1,152 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let systems; + + function setup() { + createCanvas(710, 400); + systems = []; + } + + function draw() { + background(51); + background(0); + for (i = 0; i < systems.length; i++) { + systems[i].run(); + systems[i].addParticle(); + } + if (systems.length == 0) { + fill(255); + textAlign(CENTER); + textSize(32); + text("click mouse to add particle systems", width / 2, height / 2); + } + } + + function mousePressed() { + this.p = new ParticleSystem(createVector(mouseX, mouseY)); + systems.push(p); + } + + // A simple Particle class + let Particle = function(position) { + this.acceleration = createVector(0, 0.05); + this.velocity = createVector(random(-1, 1), random(-1, 0)); + this.position = position.copy(); + this.lifespan = 255.0; + }; + + Particle.prototype.run = function() { + this.update(); + this.display(); + }; + + // Method to update position + Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; + }; + + // Method to display + Particle.prototype.display = function () { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); + }; + + // Is the particle still useful? + Particle.prototype.isDead = function () { + if (this.lifespan < 0) { + return true; + } else { + return false; + } + }; + + let ParticleSystem = function (position) { + this.origin = position.copy(); + this.particles = []; + }; + + ParticleSystem.prototype.addParticle = function () { + // Add either a Particle or CrazyParticle to the system + if (int(random(0, 2)) == 0) { + p = new Particle(this.origin); + } + else { + p = new CrazyParticle(this.origin); + } + this.particles.push(p); + }; + + ParticleSystem.prototype.run = function () { + for (let i = this.particles.length - 1; i >= 0; i--) { + let p = this.particles[i]; + p.run(); + if (p.isDead()) { + this.particles.splice(i, 1); + } + } + }; + + // A subclass of Particle + + function CrazyParticle(origin) { + // Call the parent constructor, making sure (using Function#call) + // that "this" is set correctly during the call + Particle.call(this, origin); + + // Initialize our added properties + this.theta = 0.0; + }; + + // Create a Crazy.prototype object that inherits from Particle.prototype. + // Note: A common error here is to use "new Particle()" to create the + // Crazy.prototype. That's incorrect for several reasons, not least + // that we don't have anything to give Particle for the "origin" + // argument. The correct place to call Particle is above, where we call + // it from Crazy. + CrazyParticle.prototype = Object.create(Particle.prototype); // See note below + + // Set the "constructor" property to refer to CrazyParticle + CrazyParticle.prototype.constructor = CrazyParticle; + + // Notice we don't have the method run() here; it is inherited from Particle + + // This update() method overrides the parent class update() method + CrazyParticle.prototype.update=function() { + Particle.prototype.update.call(this); + // Increment rotation based on horizontal velocity + this.theta += (this.velocity.x * this.velocity.mag()) / 10.0; + } + + // This display() method overrides the parent class display() method + CrazyParticle.prototype.display=function() { + // Render the ellipse just like in a regular particle + Particle.prototype.display.call(this); + // Then add a rotating line + push(); + translate(this.position.x, this.position.y); + rotate(this.theta); + stroke(255, this.lifespan); + line(0, 0, 25, 0); + pop(); + } +title: Multiple Particle Systems +arialabel: >- + When the user clicks anywhere on the black background, a particle system + begins where light grey circles flow out from the point like a sparkler +description: >- + Click the mouse to generate a burst of particles at mouse location.
Each + burst is one instance of a particle system with Particles and CrazyParticles + (a subclass of Particle).
Note use of Inheritance and Polymorphism + here.
+ + Original by Daniel Shiffman. +--- + + +# Example diff --git a/src/content/examples/en/09_Simulate/06_Spirograph.mdx b/src/content/examples/en/09_Simulate/06_Spirograph.mdx new file mode 100644 index 0000000000..1fee2c8b5a --- /dev/null +++ b/src/content/examples/en/09_Simulate/06_Spirograph.mdx @@ -0,0 +1,91 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let NUMSINES = 20; // how many of these things can we do at once? + let sines = new Array(NUMSINES); // an array to hold all the current angles + let rad; // an initial radius value for the central sine + let i; // a counter variable + + // play with these to get a sense of what's going on: + let fund = 0.005; // the speed of the central sine + let ratio = 1; // what multiplier for speed is each additional sine? + let alpha = 50; // how opaque is the tracing system + + let trace = false; // are we tracing? + + function setup() { + createCanvas(710, 400); + + rad = height / 4; // compute radius for central circle + background(204); // clear the screen + + for (let i = 0; i- + A spirograph is created by interlocking black circle outlines rotating around + each other on a grey background. When the user clicks the space bar, the + background turns white and paths of circles of various sizes in an indigo + color are visible +description: >- + This sketch uses simple transformations to create a + + Spirograph-like effect with interlocking circles (called sines). + + Press the spacebar to switch between tracing and showing the underlying + geometry.
+ + Example created by R. Luke + DuBois.
+ + http://en.wikipedia.org/wiki/Spirograph +--- + + +# Example diff --git a/src/content/examples/en/09_Simulate/07_LSystems.mdx b/src/content/examples/en/09_Simulate/07_LSystems.mdx new file mode 100644 index 0000000000..f65aa4233a --- /dev/null +++ b/src/content/examples/en/09_Simulate/07_LSystems.mdx @@ -0,0 +1,122 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |- + + // TURTLE STUFF: + let x, y; // the current position of the turtle + let currentangle = 0; // which way the turtle is pointing + let step = 20; // how much the turtle moves with each 'F' + let angle = 90; // how much the turtle turns with a '-' or '+' + + // LINDENMAYER STUFF (L-SYSTEMS) + let thestring = 'A'; // "axiom" or start of the string + let numloops = 5; // how many iterations to pre-compute + let therules = []; // array for rules + therules[0] = ['A', '-BF+AFA+FB-']; // first rule + therules[1] = ['B', '+AF-BFB-FA+']; // second rule + + let whereinstring = 0; // where in the L-system are we? + + function setup() { + createCanvas(710, 400); + background(255); + stroke(0, 0, 0, 255); + + // start the x and y position at lower-left corner + x = 0; + y = height-1; + + // COMPUTE THE L-SYSTEM + for (let i = 0; i < numloops; i++) { + thestring = lindenmayer(thestring); + } + } + + function draw() { + + // draw the current character in the string: + drawIt(thestring[whereinstring]); + + // increment the point for where we're reading the string. + // wrap around at the end. + whereinstring++; + if (whereinstring > thestring.length-1) whereinstring = 0; + + } + + // interpret an L-system + function lindenmayer(s) { + let outputstring = ''; // start a blank output string + + // iterate through 'therules' looking for symbol matches: + for (let i = 0; i < s.length; i++) { + let ismatch = 0; // by default, no match + for (let j = 0; j < therules.length; j++) { + if (s[i] == therules[j][0]) { + outputstring += therules[j][1]; // write substitution + ismatch = 1; // we have a match, so don't copy over symbol + break; // get outta this for() loop + } + } + // if nothing matches, just copy the symbol over. + if (ismatch == 0) outputstring+= s[i]; + } + + return outputstring; // send out the modified string + } + + // this is a custom function that draws turtle commands + function drawIt(k) { + + if (k=='F') { // draw forward + // polar to cartesian based on step and currentangle: + let x1 = x + step*cos(radians(currentangle)); + let y1 = y + step*sin(radians(currentangle)); + line(x, y, x1, y1); // connect the old and the new + + // update the turtle's position: + x = x1; + y = y1; + } else if (k == '+') { + currentangle += angle; // turn left + } else if (k == '-') { + currentangle -= angle; // turn right + } + + // give me some random color values: + let r = random(128, 255); + let g = random(0, 192); + let b = random(0, 50); + let a = random(50, 100); + + // pick a gaussian (D&D) distribution for the radius: + let radius = 0; + radius += random(0, 15); + radius += random(0, 15); + radius += random(0, 15); + radius = radius / 3; + + // draw the stuff: + fill(r, g, b, a); + ellipse(x, y, radius, radius); + } +title: L-Systems +arialabel: >- + Circles of various colors and patterns connected to each other by + perpendicular black lines are drawn on the screen to form a grid formation +description: >- + This sketch creates an automated drawing based on a Lindenmayer + + or (L-) system. L-systems are often used in procedural graphics to make + + natural, geometric, or interesting "fractal-style" patterns.
+ + Example created by R. Luke + DuBois.
+ + https://en.wikipedia.org/wiki/L-system +--- + + +# Example diff --git a/src/content/examples/en/09_Simulate/08_Spring.js b/src/content/examples/en/09_Simulate/08_Spring.js new file mode 100644 index 0000000000..c15e5227f8 --- /dev/null +++ b/src/content/examples/en/09_Simulate/08_Spring.js @@ -0,0 +1,88 @@ + +// Spring drawing constants for top bar +let springHeight = 32, + left, + right, + maxHeight = 200, + minHeight = 100, + over = false, + move = false; + +// Spring simulation constants +let M = 0.8, // Mass + K = 0.2, // Spring constant + D = 0.92, // Damping + R = 150; // Rest position + +// Spring simulation variables +let ps = R, // Position + vs = 0.0, // Velocity + as = 0, // Acceleration + f = 0; // Force + +function setup() { + createCanvas(710, 400); + rectMode(CORNERS); + noStroke(); + left = width / 2 - 100; + right = width / 2 + 100; +} + +function draw() { + background(102); + updateSpring(); + drawSpring(); +} + +function drawSpring() { + // Draw base + fill(0.2); + let baseWidth = 0.5 * ps + -8; + rect(width / 2 - baseWidth, ps + springHeight, width / 2 + baseWidth, height); + + // Set color and draw top bar + if (over || move) { + fill(255); + } else { + fill(204); + } + + rect(left, ps, right, ps + springHeight); +} + +function updateSpring() { + // Update the spring position + if ( !move ) { + f = -K * ( ps - R ); // f=-ky + as = f / M; // Set the acceleration, f=ma == a=f/m + vs = D * (vs + as); // Set the velocity + ps = ps + vs; // Updated position + } + + if (abs(vs) < 0.1) { + vs = 0.0; + } + + // Test if mouse if over the top bar + if (mouseX > left && mouseX < right && mouseY > ps && mouseY < ps + springHeight) { + over = true; + } else { + over = false; + } + + // Set and constrain the position of top bar + if (move) { + ps = mouseY - springHeight / 2; + ps = constrain(ps, minHeight, maxHeight); + } +} + +function mousePressed() { + if (over) { + move = true; + } +} + +function mouseReleased() { + move = false; +} diff --git a/src/content/examples/en/09_Simulate/08_Spring.mdx b/src/content/examples/en/09_Simulate/08_Spring.mdx new file mode 100644 index 0000000000..8a62404bc3 --- /dev/null +++ b/src/content/examples/en/09_Simulate/08_Spring.mdx @@ -0,0 +1,12 @@ +--- +title: Spring +arialabel: >- + Light grey horizontal rectangle on a black vertical rectangle on a grey + background. The user can move the horizontal rectangle up and down. Upon + releasing the horizontal rectangle, the system moves like a spring and the + vertical rectangle expands and compresses as the horizontal rectangle moves up + and down. +--- + + +Click, drag, and release the horizontal bar to start the spring. diff --git a/src/content/examples/en/09_Simulate/09_Springs.mdx b/src/content/examples/en/09_Simulate/09_Springs.mdx new file mode 100644 index 0000000000..9d5067ab0f --- /dev/null +++ b/src/content/examples/en/09_Simulate/09_Springs.mdx @@ -0,0 +1,161 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |- + + let num = 3; + let springs = []; + + function setup() { + createCanvas(710, 400); + noStroke(); + + springs[0] = new Spring(240, 260, 40, 0.98, 8.0, 0.1, springs, 0); + springs[1] = new Spring(320, 210, 120, 0.95, 9.0, 0.1, springs, 1); + springs[2] = new Spring(180, 170, 200, 0.90, 9.9, 0.1, springs, 2); + } + + function draw() { + background(51); + + for (let i = 0; i < num; i++) { + springs[i].update(); + springs[i].display(); + } + } + + function mousePressed() { + for (let i = 0; i < num; i++) { + springs[i].pressed(); + } + } + + function mouseReleased() { + for (let i = 0; i < num; i++) { + springs[i].released(); + } + } + + // Spring class + function Spring (_x, _y, _s, _d, _m, _k_in, _others, _id) { + // Screen values + // this.xpos = _x; + // this.ypos = _y; + + this.x_pos = _x; + this.y_pos= _y; + + this.size = 20; + this.size = _s; + + this.over = false; + this.move = false; + + // Spring simulation constants + this.mass = _m; // Mass + this.k = 0.2; // Spring constant + this.k = _k_in; + this.damp = _d; // Damping + this.rest_posx = _x; // Rest position X + this.rest_posy = _y; // Rest position Y + + // Spring simulation variables + //float pos = 20.0; // Position + this.velx = 0.0; // X Velocity + this.vely = 0.0; // Y Velocity + this.accel = 0; // Acceleration + this.force = 0; // Force + + this.friends = _others; + this.id = _id; + + this.update = function() { + + if (this.move) { + this.rest_posy = mouseY; + this.rest_posx = mouseX; + } + + this.force = -this.k * (this.y_pos - this.rest_posy); // f=-ky + this.accel = this.force / this.mass; // Set the acceleration, f=ma == a=f/m + this.vely = this.damp * (this.vely + this.accel); // Set the velocity + this.y_pos = this.y_pos + this.vely; // Updated position + + + this.force = -this.k * (this.x_pos - this.rest_posx); // f=-ky + this.accel = this.force / this.mass; // Set the acceleration, f=ma == a=f/m + this.velx = this.damp * (this.velx + this.accel); // Set the velocity + this.x_pos = this.x_pos + this.velx; // Updated position + + + if ((this.overEvent() || this.move) && !(this.otherOver()) ) { + this.over = true; + } else { + this.over = false; + } + } + + // Test to see if mouse is over this spring + this.overEvent = function() { + let disX = this.x_pos - mouseX; + let disY = this.y_pos - mouseY; + let dis = createVector(disX, disY); + if (dis.mag() < this.size / 2 ) { + return true; + } else { + return false; + } + } + + // Make sure no other springs are active + this.otherOver = function() { + for (let i = 0; i < num; i++) { + if (i != this.id) { + if (this.friends[i].over == true) { + return true; + } + } + } + return false; + } + + this.display = function() { + if (this.over) { + fill(153); + } else { + fill(255); + } + ellipse(this.x_pos, this.y_pos, this.size, this.size); + } + + this.pressed = function() { + if (this.over) { + this.move = true; + } else { + this.move = false; + } + } + + this.released = function() { + this.move = false; + this.rest_posx = this.y_pos; + this.rest_posy = this.y_pos; + } + }; +title: Springs +arialabel: >- + Three white circles on a dark grey background. The user can drag each circle + and the circle springs back and forth till finally settling in the original + position +description: >- + Move the mouse over one of the circles and click to re-position. + + When you release the mouse, it will snap back into position. + + Each circle has a slightly different behavior. + +

This example is ported from the Processing website +--- + + +# Example diff --git a/src/content/examples/en/09_Simulate/10_SoftBody.mdx b/src/content/examples/en/09_Simulate/10_SoftBody.mdx new file mode 100644 index 0000000000..0690f480b0 --- /dev/null +++ b/src/content/examples/en/09_Simulate/10_SoftBody.mdx @@ -0,0 +1,120 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + // center point + let centerX = 0.0, centerY = 0.0; + + let radius = 45, rotAngle = -90; + let accelX = 0.0, accelY = 0.0; + let deltaX = 0.0, deltaY = 0.0; + let springing = 0.0009, damping = 0.98; + + //corner nodes + let nodes = 5; + + //zero fill arrays + let nodeStartX = []; + let nodeStartY = []; + let nodeX = []; + let nodeY = []; + let angle = []; + let frequency = []; + + // soft-body dynamics + let organicConstant = 1.0; + + function setup() { + createCanvas(710, 400); + + //center shape in window + centerX = width / 2; + centerY = height / 2; + + //initialize arrays to 0 + for (let i = 0; i < nodes; i++){ + nodeStartX[i] = 0; + nodeStartY[i] = 0; + nodeY[i] = 0; + nodeY[i] = 0; + angle[i] = 0; + } + + // iniitalize frequencies for corner nodes + for (let i = 0; i < nodes; i++){ + frequency[i] = random(5, 12); + } + + noStroke(); + frameRate(30); + } + + function draw() { + //fade background + fill(0, 100); + rect(0, 0, width, height); + drawShape(); + moveShape(); + } + + function drawShape() { + // calculate node starting locations + for (let i = 0; i < nodes; i++){ + nodeStartX[i] = centerX + cos(radians(rotAngle)) * radius; + nodeStartY[i] = centerY + sin(radians(rotAngle)) * radius; + rotAngle += 360.0 / nodes; + } + + // draw polygon + curveTightness(organicConstant); + fill(255); + beginShape(); + for (let i = 0; i < nodes; i++){ + curveVertex(nodeX[i], nodeY[i]); + } + for (let i = 0; i < nodes-1; i++){ + curveVertex(nodeX[i], nodeY[i]); + } + endShape(CLOSE); + } + + function moveShape() { + //move center point + deltaX = mouseX - centerX; + deltaY = mouseY - centerY; + + // create springing effect + deltaX *= springing; + deltaY *= springing; + accelX += deltaX; + accelY += deltaY; + + // move predator's center + centerX += accelX; + centerY += accelY; + + // slow down springing + accelX *= damping; + accelY *= damping; + + // change curve tightness + organicConstant = 1 - ((abs(accelX) + abs(accelY)) * 0.1); + + //move nodes + for (let i = 0; i < nodes; i++){ + nodeX[i] = nodeStartX[i] + sin(radians(angle[i])) * (accelX * 2); + nodeY[i] = nodeStartY[i] + sin(radians(angle[i])) * (accelY * 2); + angle[i] += frequency[i]; + } + } +title: Soft Body +arialabel: >- + White pentagon on a black screen that morphs into a blob as it follows the + user’s mouse +description: |- + Original example by Ira Greenberg. +

Softbody dynamics simulation using curveVertex() and curveTightness(). +--- + + +# Example diff --git a/src/content/examples/en/09_Simulate/11_SmokeParticleSystem.js b/src/content/examples/en/09_Simulate/11_SmokeParticleSystem.js new file mode 100644 index 0000000000..c9395bbcd1 --- /dev/null +++ b/src/content/examples/en/09_Simulate/11_SmokeParticleSystem.js @@ -0,0 +1,176 @@ + + +// texture for the particle +let particle_texture = null; + +// variable holding our particle system +let ps = null; + +function preload() { + particle_texture = loadImage("assets/particle_texture.png"); +} + +function setup() { + + //set the canvas size + createCanvas(640, 360); + + //initialize our particle system + ps = new ParticleSystem(0, createVector(width / 2, height - 60), particle_texture); +} + +function draw() { + background(0); + + let dx = map(mouseX, 0, width, -0.2, 0.2); + let wind = createVector(dx, 0); + + ps.applyForce(wind); + ps.run(); + for (let i = 0; i < 2; i++) { + ps.addParticle(); + } + + // Draw an arrow representing the wind force + drawVector(wind, createVector(width / 2, 50, 0), 500); +} + +/** + * This function draws an arrow showing the direction our "wind" is blowing. + */ +function drawVector(v, loc, scale){ + push(); + let arrowsize = 4; + translate(loc.x, loc.y); + stroke(255); + rotate(v.heading()); + + let len = v.mag() * scale; + line(0, 0, len,0); + line(len, 0, len-arrowsize, +arrowsize / 2); + line(len, 0, len-arrowsize, -arrowsize / 2); + pop(); +} +//========= PARTICLE SYSTEM =========== + +/** + * A basic particle system class + * @param num the number of particles + * @param v the origin of the particle system + * @param img_ a texture for each particle in the system + * @constructor + */ +let ParticleSystem = function(num, v, img_) { + + this.particles = []; + this.origin = v.copy(); // we make sure to copy the vector value in case we accidentally mutate the original by accident + this.img = img_ + for(let i = 0; i < num; ++i){ + this.particles.push(new Particle(this.origin, this.img)); + } +}; + +/** + * This function runs the entire particle system. + */ +ParticleSystem.prototype.run = function() { + + // cache length of the array we're going to loop into a variable + // You may see .length in a for loop, from time to time but + // we cache it here because otherwise the length is re-calculated for each iteration of a loop + let len = this.particles.length; + + //loop through and run particles + for (let i = len - 1; i >= 0; i--) { + let particle = this.particles[i]; + particle.run(); + + // if the particle is dead, we remove it. + // javascript arrays don't have a "remove" function but "splice" works just as well. + // we feed it an index to start at, then how many numbers from that point to remove. + if (particle.isDead()) { + this.particles.splice(i, 1); + } + } +} + +/** + * Method to add a force vector to all particles currently in the system + * @param dir a p5.Vector describing the direction of the force. + */ +ParticleSystem.prototype.applyForce = function(dir) { + let len = this.particles.length; + for(let i = 0; i < len; ++i){ + this.particles[i].applyForce(dir); + } +} + +/** + * Adds a new particle to the system at the origin of the system and with + * the originally set texture. + */ +ParticleSystem.prototype.addParticle = function() { + this.particles.push(new Particle(this.origin, this.img)); +} + +//========= PARTICLE =========== +/** + * A simple Particle class, renders the particle as an image + */ +let Particle = function (pos, img_) { + this.loc = pos.copy(); + + let vx = randomGaussian() * 0.3; + let vy = randomGaussian() * 0.3 - 1.0; + + this.vel = createVector(vx, vy); + this.acc = createVector(); + this.lifespan = 100.0; + this.texture = img_; +} + +/** + * Simulataneously updates and displays a particle. + */ +Particle.prototype.run = function() { + this.update(); + this.render(); +} + +/** + * A function to display a particle + */ +Particle.prototype.render = function() { + imageMode(CENTER); + tint(255, this.lifespan); + image(this.texture, this.loc.x, this.loc.y); +} + +/** + * A method to apply a force vector to a particle. + */ +Particle.prototype.applyForce = function(f) { + this.acc.add(f); +} + +/** + * This method checks to see if the particle has reached the end of it's lifespan, + * if it has, return true, otherwise return false. + */ +Particle.prototype.isDead = function () { + if (this.lifespan <= 0.0) { + return true; + } else { + return false; + } +} + +/** + * This method updates the position of the particle. + */ +Particle.prototype.update = function() { + this.vel.add(this.acc); + this.loc.add(this.vel); + this.lifespan -= 2.5; + this.acc.mult(0); +} diff --git a/src/content/examples/en/09_Simulate/11_SmokeParticleSystem.mdx b/src/content/examples/en/09_Simulate/11_SmokeParticleSystem.mdx new file mode 100644 index 0000000000..04ec6a7d33 --- /dev/null +++ b/src/content/examples/en/09_Simulate/11_SmokeParticleSystem.mdx @@ -0,0 +1,3 @@ + + +undefined diff --git a/src/content/examples/en/09_Simulate/12_BrownianMotion.js b/src/content/examples/en/09_Simulate/12_BrownianMotion.js new file mode 100644 index 0000000000..973a4fcfb9 --- /dev/null +++ b/src/content/examples/en/09_Simulate/12_BrownianMotion.js @@ -0,0 +1,42 @@ + + +let num = 2000; +let range = 6; + +let ax = []; +let ay = []; + + +function setup() { + createCanvas(710, 400); + for ( let i = 0; i < num; i++ ) { + ax[i] = width / 2; + ay[i] = height / 2; + } + frameRate(30); +} + +function draw() { + background(51); + + // Shift all elements 1 place to the left + for ( let i = 1; i < num; i++ ) { + ax[i - 1] = ax[i]; + ay[i - 1] = ay[i]; + } + + // Put a new value at the end of the array + ax[num - 1] += random(-range, range); + ay[num - 1] += random(-range, range); + + // Constrain all points to the screen + ax[num - 1] = constrain(ax[num - 1], 0, width); + ay[num - 1] = constrain(ay[num - 1], 0, height); + + // Draw a line connecting the points + for ( let j = 1; j < num; j++ ) { + let val = j / num * 204.0 + 51; + stroke(val); + line(ax[j - 1], ay[j - 1], ax[j], ay[j]); + } +} \ No newline at end of file diff --git a/src/content/examples/en/09_Simulate/12_BrownianMotion.mdx b/src/content/examples/en/09_Simulate/12_BrownianMotion.mdx new file mode 100644 index 0000000000..3f602b6d01 --- /dev/null +++ b/src/content/examples/en/09_Simulate/12_BrownianMotion.mdx @@ -0,0 +1,8 @@ +--- +title: Brownian Motion +arialabel: A continuous white line draws squiggles on a grey background +--- + + +Recording random movement as a continuous line. +Port of original example from the Processing examples page. diff --git a/src/content/examples/en/09_Simulate/13_Chain.mdx b/src/content/examples/en/09_Simulate/13_Chain.mdx new file mode 100644 index 0000000000..8a67c04a47 --- /dev/null +++ b/src/content/examples/en/09_Simulate/13_Chain.mdx @@ -0,0 +1,69 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |- + + let s1, s2; + let gravity = 9.0; + let mass = 2.0; + + function setup() { + createCanvas(720, 400); + fill(255, 126); + // Inputs: x, y, mass, gravity + s1 = new Spring2D(0.0, width / 2, mass, gravity); + s2 = new Spring2D(0.0, width / 2, mass, gravity); + } + + function draw() { + background(0); + s1.update(mouseX, mouseY); + s1.display(mouseX, mouseY); + s2.update(s1.x, s1.y); + s2.display(s1.x, s1.y); + } + + function Spring2D(xpos, ypos, m, g) { + this.x = xpos;// The x- and y-coordinates + this.y = ypos; + this.vx = 0; // The x- and y-axis velocities + this.vy = 0; + this.mass = m; + this.gravity = g; + this.radius = 30; + this.stiffness = 0.2; + this.damping = 0.7; + + this.update = function(targetX, targetY) { + let forceX = (targetX - this.x) * this.stiffness; + let ax = forceX / this.mass; + this.vx = this.damping * (this.vx + ax); + this.x += this.vx; + let forceY = (targetY - this.y) * this.stiffness; + forceY += this.gravity; + let ay = forceY / this.mass; + this.vy = this.damping * (this.vy + ay); + this.y += this.vy; + } + + this.display = function(nx, ny) { + noStroke(); + ellipse(this.x, this.y, this.radius * 2, this.radius * 2); + stroke(255); + line(this.x, this.y, nx, ny); + } + } +title: Chain +arialabel: >- + Two slightly opaque white circles connected by a white line. The user’s mouse + moves the top of the string and the circles follow but are also affected by + gravity. +description: >- + One mass is attached to the mouse position and the other is attached the + position of the other mass. The gravity in the environment pulls down on both. + +

This example is ported from the Processing website +--- + + +# Example diff --git a/src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.js b/src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.js new file mode 100644 index 0000000000..1a985af1aa --- /dev/null +++ b/src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.js @@ -0,0 +1,58 @@ + + +let snowflakes = []; // array to hold snowflake objects + +function setup() { + createCanvas(400, 600); + fill(240); + noStroke(); +} + +function draw() { + background('brown'); + let t = frameCount / 60; // update time + + // create a random number of snowflakes each frame + for (let i = 0; i < random(5); i++) { + snowflakes.push(new snowflake()); // append snowflake object + } + + // loop through snowflakes with a for..of loop + for (let flake of snowflakes) { + flake.update(t); // update snowflake position + flake.display(); // draw snowflake + } +} + +// snowflake class +function snowflake() { + // initialize coordinates + this.posX = 0; + this.posY = random(-50, 0); + this.initialangle = random(0, 2 * PI); + this.size = random(2, 5); + + // radius of snowflake spiral + // chosen so the snowflakes are uniformly spread out in area + this.radius = sqrt(random(pow(width / 2, 2))); + + this.update = function(time) { + // x position follows a circle + let w = 0.6; // angular speed + let angle = w * time + this.initialangle; + this.posX = width / 2 + this.radius * sin(angle); + + // different size snowflakes fall at slightly different y speeds + this.posY += pow(this.size, 0.5); + + // delete snowflake if past end of screen + if (this.posY > height) { + let index = snowflakes.indexOf(this); + snowflakes.splice(index, 1); + } + }; + + this.display = function() { + ellipse(this.posX, this.posY, this.size); + }; +} diff --git a/src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.mdx b/src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.mdx new file mode 100644 index 0000000000..6bbf205515 --- /dev/null +++ b/src/content/examples/en/09_Simulate/14_SnowflakeParticleSystem.mdx @@ -0,0 +1,9 @@ +--- +title: Snowflakes +arialabel: White snowflakes fall in a random pattern from the top of a red background +--- + + +Particle system simulating the motion of falling snowflakes. +Uses an array of objects to hold the snowflake particles. +Contributed by Aatish Bhatia. diff --git a/src/content/examples/en/09_Simulate/15_penrose_tiles.js b/src/content/examples/en/09_Simulate/15_penrose_tiles.js new file mode 100644 index 0000000000..963c898fd6 --- /dev/null +++ b/src/content/examples/en/09_Simulate/15_penrose_tiles.js @@ -0,0 +1,121 @@ + + +let ds; + +function setup() { + createCanvas(710, 400); + ds = new PenroseLSystem(); + //please, play around with the following line + ds.simulate(5); +} + +function draw() { + background(0); + ds.render(); +} + +function PenroseLSystem() { + this.steps = 0; + + //these are axiom and rules for the penrose rhombus l-system + //a reference would be cool, but I couldn't find a good one + this.axiom = "[X]++[X]++[X]++[X]++[X]"; + this.ruleW = "YF++ZF----XF[-YF----WF]++"; + this.ruleX = "+YF--ZF[---WF--XF]+"; + this.ruleY = "-WF++XF[+++YF++ZF]-"; + this.ruleZ = "--YF++++WF[+ZF++++XF]--XF"; + + //please play around with the following two lines + this.startLength = 460.0; + this.theta = TWO_PI / 10.0; //36 degrees, try TWO_PI / 6.0, ... + this.reset(); +} + +PenroseLSystem.prototype.simulate = function (gen) { + while (this.getAge() < gen) { + this.iterate(this.production); + } +} + +PenroseLSystem.prototype.reset = function () { + this.production = this.axiom; + this.drawLength = this.startLength; + this.generations = 0; + } + +PenroseLSystem.prototype.getAge = function () { + return this.generations; + } + +//apply substitution rules to create new iteration of production string +PenroseLSystem.prototype.iterate = function() { + let newProduction = ""; + + for(let i=0; i < this.production.length; ++i) { + let step = this.production.charAt(i); + //if current character is 'W', replace current character + //by corresponding rule + if (step == 'W') { + newProduction = newProduction + this.ruleW; + } + else if (step == 'X') { + newProduction = newProduction + this.ruleX; + } + else if (step == 'Y') { + newProduction = newProduction + this.ruleY; + } + else if (step == 'Z') { + newProduction = newProduction + this.ruleZ; + } + else { + //drop all 'F' characters, don't touch other + //characters (i.e. '+', '-', '[', ']' + if (step != 'F') { + newProduction = newProduction + step; + } + } + } + + this.drawLength = this.drawLength * 0.5; + this.generations++; + this.production = newProduction; +} + +//convert production string to a turtle graphic +PenroseLSystem.prototype.render = function () { + translate(width / 2, height / 2); + + this.steps += 20; + if(this.steps > this.production.length) { + this.steps = this.production.length; + } + + for(let i=0; i- + A penrose tile pattern is created by white rhombi being drawn on a black + background +--- + + +This is a port by David Blitz of the "Penrose Tile" example from processing.org/examples diff --git a/src/content/examples/en/09_Simulate/16_Recursive_Tree.js b/src/content/examples/en/09_Simulate/16_Recursive_Tree.js new file mode 100644 index 0000000000..33defe00b3 --- /dev/null +++ b/src/content/examples/en/09_Simulate/16_Recursive_Tree.js @@ -0,0 +1,49 @@ + +let theta; + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(0); + frameRate(30); + stroke(255); + // Let's pick an angle 0 to 90 degrees based on the mouse position + let a = (mouseX / width) * 90; + // Convert it to radians + theta = radians(a); + // Start the tree from the bottom of the screen + translate(width/2,height); + // Draw a line 120 pixels + line(0,0,0,-120); + // Move to the end of that line + translate(0,-120); + // Start the recursive branching! + branch(120); + +} + +function branch(h) { + // Each branch will be 2/3rds the size of the previous one + h *= 0.66; + + // All recursive functions must have an exit condition!!!! + // Here, ours is when the length of the branch is 2 pixels or less + if (h > 2) { + push(); // Save the current state of transformation (i.e. where are we now) + rotate(theta); // Rotate by theta + line(0, 0, 0, -h); // Draw the branch + translate(0, -h); // Move to the end of the branch + branch(h); // Ok, now call myself to draw two new branches!! + pop(); // Whenever we get back here, we "pop" in order to restore the previous matrix state + + // Repeat the same thing, only branch off to the "left" this time! + push(); + rotate(-theta); + line(0, 0, 0, -h); + translate(0, -h); + branch(h); + pop(); + } +} diff --git a/src/content/examples/en/09_Simulate/16_Recursive_Tree.mdx b/src/content/examples/en/09_Simulate/16_Recursive_Tree.mdx new file mode 100644 index 0000000000..fe372ef9b9 --- /dev/null +++ b/src/content/examples/en/09_Simulate/16_Recursive_Tree.mdx @@ -0,0 +1,14 @@ +--- +title: Recursive Tree +arialabel: >- + If the user’s mouse is on the far left side of the screen, there is a white + vertical line on a black background. As the user’s mouse moves right, the top + of the vertical line begins to expand into branches of a tree until it curves + down into a very geometric tree +--- + + +Renders a simple tree-like structure via recursion. +The branching angle is calculated as a function of the horizontal mouse +location. Move the mouse left and right to change the angle. +Based on Daniel Shiffman's Recursive Tree Example for Processing. diff --git a/src/content/examples/en/09_Simulate/17_Mandelbrot.js b/src/content/examples/en/09_Simulate/17_Mandelbrot.js new file mode 100644 index 0000000000..0088ced999 --- /dev/null +++ b/src/content/examples/en/09_Simulate/17_Mandelbrot.js @@ -0,0 +1,82 @@ + + +function setup() { + createCanvas(710, 400); + pixelDensity(1); + noLoop(); +} + +function draw() { + background(0); + + // Establish a range of values on the complex plane + // A different range will allow us to "zoom" in or out on the fractal + + // It all starts with the width, try higher or lower values + const w = 4; + const h = (w * height) / width; + + // Start at negative half the width and height + const xmin = -w/2; + const ymin = -h/2; + + // Make sure we can write to the pixels[] array. + // Only need to do this once since we don't do any other drawing. + loadPixels(); + + // Maximum number of iterations for each point on the complex plane + const maxiterations = 100; + + // x goes from xmin to xmax + const xmax = xmin + w; + // y goes from ymin to ymax + const ymax = ymin + h; + + // Calculate amount we increment x,y for each pixel + const dx = (xmax - xmin) / (width); + const dy = (ymax - ymin) / (height); + + // Start y + let y = ymin; + for (let j = 0; j < height; j++) { + // Start x + let x = xmin; + for (let i = 0; i < width; i++) { + + // Now we test, as we iterate z = z^2 + cm does z tend towards infinity? + let a = x; + let b = y; + let n = 0; + while (n < maxiterations) { + const aa = a * a; + const bb = b * b; + const twoab = 2.0 * a * b; + a = aa - bb + x; + b = twoab + y; + // Infinty in our finite world is simple, let's just consider it 16 + if (dist(aa, bb, 0, 0) > 16) { + break; // Bail + } + n++; + } + + // We color each pixel based on how long it takes to get to infinity + // If we never got there, let's pick the color black + const pix = (i+j*width)*4; + const norm = map(n, 0, maxiterations, 0, 1); + let bright = map(sqrt(norm), 0, 1, 0, 255); + if (n == maxiterations) { + bright = 0; + } else { + // Gosh, we could make fancy colors here if we wanted + pixels[pix + 0] = bright; + pixels[pix + 1] = bright; + pixels[pix + 2] = bright; + pixels[pix + 3] = 255; + } + x += dx; + } + y += dy; + } + updatePixels(); +} diff --git a/src/content/examples/en/09_Simulate/17_Mandelbrot.mdx b/src/content/examples/en/09_Simulate/17_Mandelbrot.mdx new file mode 100644 index 0000000000..c92b0ca99d --- /dev/null +++ b/src/content/examples/en/09_Simulate/17_Mandelbrot.mdx @@ -0,0 +1,10 @@ +--- +title: The Mandelbrot Set +arialabel: >- + A fractal that roughly resembles a series of heart-shaped disks, to which + smaller disks are attached and consists of a connected set +--- + + +Simple rendering of the Mandelbrot set. +Based on Daniel Shiffman's Mandelbrot Example for Processing. diff --git a/src/content/examples/en/09_Simulate/18_Koch.js b/src/content/examples/en/09_Simulate/18_Koch.js new file mode 100644 index 0000000000..3f6b8c1e54 --- /dev/null +++ b/src/content/examples/en/09_Simulate/18_Koch.js @@ -0,0 +1,137 @@ + + +let k; + +function setup() { + createCanvas(710, 400); + frameRate(1); // Animate slowly + k = new KochFractal(); +} + +function draw() { + background(0); + // Draws the snowflake! + k.render(); + // Iterate + k.nextLevel(); + // Let's not do it more than 5 times. . . + if (k.getCount() > 5) { + k.restart(); + } +} + +// A class to describe one line segment in the fractal +// Includes methods to calculate midp5.Vectors along the line according to the Koch algorithm + +class KochLine { + constructor(a,b) { + // Two p5.Vectors, + // start is the "left" p5.Vector and + // end is the "right p5.Vector + this.start = a.copy(); + this.end = b.copy(); + } + + display() { + stroke(255); + line(this.start.x, this.start.y, this.end.x, this.end.y); + } + + kochA() { + return this.start.copy(); + } + + // This is easy, just 1/3 of the way + kochB() { + let v = p5.Vector.sub(this.end, this.start); + v.div(3); + v.add(this.start); + return v; + } + + // More complicated, have to use a little trig to figure out where this p5.Vector is! + kochC() { + let a = this.start.copy(); // Start at the beginning + let v = p5.Vector.sub(this.end, this.start); + v.div(3); + a.add(v); // Move to point B + v.rotate(-PI/3); // Rotate 60 degrees + a.add(v); // Move to point C + return a; + } + + // Easy, just 2/3 of the way + kochD() { + let v = p5.Vector.sub(this.end, this.start); + v.mult(2/3.0); + v.add(this.start); + return v; + } + + kochE() { + return this.end.copy(); + } +} + +// A class to manage the list of line segments in the snowflake pattern + +class KochFractal { + constructor() { + this.start = createVector(0,height-20); // A p5.Vector for the start + this.end = createVector(width,height-20); // A p5.Vector for the end + this.lines = []; // An array to keep track of all the lines + this.count = 0; + this.restart(); + } + + nextLevel() { + // For every line that is in the arraylist + // create 4 more lines in a new arraylist + this.lines = this.iterate(this.lines); + this.count++; + } + + restart() { + this.count = 0; // Reset count + this.lines = []; // Empty the array list + this.lines.push(new KochLine(this.start,this.end)); // Add the initial line (from one end p5.Vector to the other) + } + + getCount() { + return this.count; + } + + // This is easy, just draw all the lines + render() { + for(let i = 0; i < this.lines.length; i++) { + this.lines[i].display(); + } + } + + // This is where the **MAGIC** happens + // Step 1: Create an empty arraylist + // Step 2: For every line currently in the arraylist + // - calculate 4 line segments based on Koch algorithm + // - add all 4 line segments into the new arraylist + // Step 3: Return the new arraylist and it becomes the list of line segments for the structure + + // As we do this over and over again, each line gets broken into 4 lines, which gets broken into 4 lines, and so on. . . + iterate(before) { + let now = []; // Create emtpy list + for(let i = 0; i < this.lines.length; i++) { + let l = this.lines[i]; + // Calculate 5 koch p5.Vectors (done for us by the line object) + let a = l.kochA(); + let b = l.kochB(); + let c = l.kochC(); + let d = l.kochD(); + let e = l.kochE(); + // Make line segments between all the p5.Vectors and add them + now.push(new KochLine(a,b)); + now.push(new KochLine(b,c)); + now.push(new KochLine(c,d)); + now.push(new KochLine(d,e)); + } + return now; + } +} diff --git a/src/content/examples/en/09_Simulate/18_Koch.mdx b/src/content/examples/en/09_Simulate/18_Koch.mdx new file mode 100644 index 0000000000..f7c3f1f3da --- /dev/null +++ b/src/content/examples/en/09_Simulate/18_Koch.mdx @@ -0,0 +1,11 @@ +--- +title: Koch Curve +arialabel: >- + Koch snowflake is created by a single horizontal white line on a black + background that then morphs into a triangle in the middle, and then each side + of the triangle also becomes two more triangles, and this repeats 5 times +--- + + +Renders a simple fractal, the Koch snowflake. Each recursive level is drawn in sequence. +By Daniel Shiffman diff --git a/src/content/examples/en/09_Simulate/19_Bubblesort.js b/src/content/examples/en/09_Simulate/19_Bubblesort.js new file mode 100644 index 0000000000..6fe180087f --- /dev/null +++ b/src/content/examples/en/09_Simulate/19_Bubblesort.js @@ -0,0 +1,61 @@ + + +let values = []; +let i = 0; +let j = 0; + +// The statements in the setup() function +// execute once when the program begins +// The array is filled with random values in setup() function. +function setup() { + createCanvas(720, 400); + for(let i = 0;i values[j+1]){ + values[j] = values[j+1]; + values[j+1] = temp; + } + j++; + + if(j>=values.length-i-1){ + j = 0; + i++; + } + } + else{ + noLoop(); + } + } +} + +// The simulateSorting() function helps in animating +// the whole bubble sort algorithm +// by drawing the rectangles using values +// in the array as the length of the rectangle. +function simulateSorting(){ + for(let i = 0;i- + Dark grey bars of different heights on a light grey background are sorted from + tallest to shortest from the right to the left side of the screen +--- + + +Sorts the randomly distributed bars +according to their height in ascending order +while simulating the whole sorting process. +Took references from Coding Challenge by The Coding Train. diff --git a/src/content/examples/en/09_Simulate/20_SteepingFeet.js b/src/content/examples/en/09_Simulate/20_SteepingFeet.js new file mode 100644 index 0000000000..3042da7e91 --- /dev/null +++ b/src/content/examples/en/09_Simulate/20_SteepingFeet.js @@ -0,0 +1,73 @@ + + +// this class describes the structure +// and movements of the brick +class Brick{ + constructor(bc, y){ + this.brickColor = bc; + this.yPos = y; + this.xPos = 0; + } + + // this function creates the brick + createBrick(){ + fill(this.brickColor); + rect(this.xPos, this.yPos, 100, 50); + } + + // this function sets the speed + // of movement of the brick to 1 + setSpeed(){ + this.xSpeed = 1; + } + + // this function sets the bricks in motion + moveBrick(){ + this.xPos+=this.xSpeed; + if(this.xPos+100 >= width || this.xPos <= 0){ + this.xSpeed*=-1; + } + } +} + +function setup() { + createCanvas(720, 400); + createP("Keep the mouse clicked").style('color','#ffffff'); + createP("to check whether the bricks").style('color','#ffffff'); + createP("are moving at same speed or not").style('color','#ffffff'); +} + +// creating two bricks of +// colors white and black +let brick1 = new Brick("white",100); +let brick2 = new Brick("black",250); + +// This function sets speed of +// brick 1 and brick2 to 1. +brick1.setSpeed(); +brick2.setSpeed(); + +function draw () { + background(0); + if(mouseIsPressed){ + background(50); + } + brick1.createBrick(); + brick1.moveBrick(); + if(!mouseIsPressed){ + createBars(); + } + brick2.createBrick(); + brick2.moveBrick(); +} + +// this function creates the black and +// white bars across the screen +function createBars() { + let len = 12; + for(let i = 0;i- + Vertical black and white lines. A white rectangle moves across the screen + under the white vertical lines and on top of the black ones. A black rectangle + moves across the screen on top of both colored lines. +--- + + +Stepping feet illusion is a very famous psychological experiment +Both the bricks will appear to move at different speed +even though they are moving at the same speed. +Click the mouse inside Canvas to confirm that +they are moving at the same speed. +Contributed by Sagar Arora. diff --git a/src/content/examples/en/09_Simulate/21_Particle.js b/src/content/examples/en/09_Simulate/21_Particle.js new file mode 100644 index 0000000000..186b8f7ecb --- /dev/null +++ b/src/content/examples/en/09_Simulate/21_Particle.js @@ -0,0 +1,63 @@ + + + +// this class describes the properties of a single particle. +class Particle { +// setting the co-ordinates, radius and the +// speed of a particle in both the co-ordinates axes. + constructor(){ + this.x = random(0,width); + this.y = random(0,height); + this.r = random(1,8); + this.xSpeed = random(-2,2); + this.ySpeed = random(-1,1.5); + } + +// creation of a particle. + createParticle() { + noStroke(); + fill('rgba(200,169,169,0.5)'); + circle(this.x,this.y,this.r); + } + +// setting the particle in motion. + moveParticle() { + if(this.x < 0 || this.x > width) + this.xSpeed*=-1; + if(this.y < 0 || this.y > height) + this.ySpeed*=-1; + this.x+=this.xSpeed; + this.y+=this.ySpeed; + } + +// this function creates the connections(lines) +// between particles which are less than a certain distance apart + joinParticles(particles) { + particles.forEach(element =>{ + let dis = dist(this.x,this.y,element.x,element.y); + if(dis<85) { + stroke('rgba(255,255,255,0.04)'); + line(this.x,this.y,element.x,element.y); + } + }); + } +} + +// an array to add multiple particles +let particles = []; + +function setup() { + createCanvas(720, 400); + for(let i = 0;i- + Small light grey circles connected by thin lines floating around a black + background +--- + + +There is a light-weight JavaScript library named +particle.js which creates a very pleasing particle system. +This is an attempt to recreate that particle system using p5.js. +Inspired by Particle.js, contributed by Sagar Arora. diff --git a/src/content/examples/en/09_Simulate/22_Quicksort.mdx b/src/content/examples/en/09_Simulate/22_Quicksort.mdx new file mode 100644 index 0000000000..5d9f56e76b --- /dev/null +++ b/src/content/examples/en/09_Simulate/22_Quicksort.mdx @@ -0,0 +1,137 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |- + + + // width of each bar is taken as 8. + let values = []; + // The array 'states' helps in identifying the pivot index + // at every step, and also the subarray which is being sorted + // at any given time. + let states = []; + + // The setup() function is called once when the program + // starts. Here, we fill the array 'values' with random values + // and the array 'states' with a value of -1 for each position. + function setup() { + createCanvas(710, 400); + for(let i = 0; i < width/8; i++) { + values.push(random(height)); + states.push(-1); + } + quickSort(0, values.length - 1); + } + + // The statements in draw() function are executed continuously + // until the program is stopped. Each statement is executed + // sequentially and after the last line is read, the first + // line is executed again. + function draw() { + background(140); + for(let i = 0; i < values.length; i++) { + // color coding + if (states[i] == 0) { + // color for the bar at the pivot index + fill('#E0777D'); + } else if (states[i] == 1) { + // color for the bars being sorted currently + fill('#D6FFB7'); + } else { + fill(255); + } + rect(i * 8, height - values[i], 8, values[i]); + } + } + + async function quickSort(start, end) { + if (start > end) { // Nothing to sort! + return; + } + // partition() returns the index of the pivot element. + // Once partition() is executed, all elements to the + // left of the pivot element are smaller than it and + // all elements to its right are larger than it. + let index = await partition(start, end); + // restore original state + states[index] = -1; + await Promise.all( + [quickSort(start, index - 1), + quickSort(index + 1, end) + ]); + } + + // We have chosen the element at the last index as + // the pivot element, but we could've made different + // choices, e.g. take the first element as pivot. + async function partition(start, end) { + for (let i = start; i < end; i++) { + // identify the elements being considered currently + states[i] = 1; + } + // Quicksort algorithm + let pivotIndex = start; + // make pivot index distinct + states[pivotIndex] = 0; + let pivotElement = values[end]; + for (let i = start; i < end; i++) { + if (values[i] < pivotElement) { + await swap(i, pivotIndex); + states[pivotIndex] = -1; + pivotIndex++; + states[pivotIndex] = 0; + } + } + await swap(end, pivotIndex); + for (let i = start; i < end; i++) { + // restore original state + if (i != pivotIndex) { + states[i] = -1; + } + } + return pivotIndex; + } + + // swaps elements of 'values' at indices 'i' and 'j' + async function swap(i, j) { + // adjust the pace of the simulation by changing the + // value + await sleep(25); + let temp = values[i]; + values[i] = values[j]; + values[j] = temp; + } + + // custom helper function to deliberately slow down + // the sorting process and make visualization easy + function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + } +title: Quicksort +arialabel: >- + Bars of random heights are sorted from shortest to tallest left to right. The + bars turn sage green and coral as they are sorted +description: |- + This is a simulation of the Quicksort + sorting algorithm. We start with an array of bars + and sort them according to their height in ascending + order. References taken from a coding challenge by + The Coding Train.

+ Quicksort is a divide-and-conquer algorithm: it + performs sorting by dividing the original array into + smaller subarrays and solving them independently, + loosely speaking. It involves picking an element of + the array as the pivot element and partitioning the + given array around the picked pivot.
+ Partitioning refers to arranging the given array(or + subarray) in such a way that all elements to the left + of the pivot element are smaller than it and all + elements to its right are larger than it. Thus, we have + a reference point from where we proceed to sort the + left and right 'halves' of the array, and eventually + arrive at an array sorted in ascending order. + + More
+--- + + +# Example diff --git a/src/content/examples/en/10_Interaction/10_Tickle.js b/src/content/examples/en/10_Interaction/10_Tickle.js new file mode 100644 index 0000000000..4f5458ea8c --- /dev/null +++ b/src/content/examples/en/10_Interaction/10_Tickle.js @@ -0,0 +1,44 @@ + +let message = 'tickle', + font, + bounds, // holds x, y, w, h of the text's bounding box + fontsize = 60, + x, + y; // x and y coordinates of the text + +function preload() { + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // set up the font + textFont(font); + textSize(fontsize); + + // get the width and height of the text so we can center it initially + bounds = font.textBounds(message, 0, 0, fontsize); + x = width / 2 - bounds.w / 2; + y = height / 2 - bounds.h / 2; +} + +function draw() { + background(204, 120); + + // write the text in black and get its bounding box + fill(0); + text(message, x, y); + bounds = font.textBounds(message, x, y, fontsize); + + // check if the mouse is inside the bounding box and tickle if so + if ( + mouseX >= bounds.x && + mouseX <= bounds.x + bounds.w && + mouseY >= bounds.y && + mouseY <= bounds.y + bounds.h + ) { + x += random(-5, 5); + y += random(-5, 5); + } +} diff --git a/src/content/examples/en/10_Interaction/10_Tickle.mdx b/src/content/examples/en/10_Interaction/10_Tickle.mdx new file mode 100644 index 0000000000..12fb90df51 --- /dev/null +++ b/src/content/examples/en/10_Interaction/10_Tickle.mdx @@ -0,0 +1,10 @@ +--- +title: Tickle +arialabel: >- + The word “tickle” in black is on a light gray background. As the user hovers + the word, the word shakes and moves as if being tickled +--- + + +The word "tickle" jitters when the cursor hovers over. +Sometimes, it can be tickled off the screen. diff --git a/src/content/examples/en/10_Interaction/20_Follow1.js b/src/content/examples/en/10_Interaction/20_Follow1.js new file mode 100644 index 0000000000..c6f205c015 --- /dev/null +++ b/src/content/examples/en/10_Interaction/20_Follow1.js @@ -0,0 +1,32 @@ + +let x = 100, + y = 100, + angle1 = 0.0, + segLength = 50; + +function setup() { + createCanvas(710, 400); + strokeWeight(20.0); + stroke(255, 100); +} + +function draw() { + background(0); + + dx = mouseX - x; + dy = mouseY - y; + angle1 = atan2(dy, dx); + x = mouseX - cos(angle1) * segLength; + y = mouseY - sin(angle1) * segLength; + + segment(x, y, angle1); + ellipse(x, y, 20, 20); +} + +function segment(x, y, a) { + push(); + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); + pop(); +} diff --git a/src/content/examples/en/10_Interaction/20_Follow1.mdx b/src/content/examples/en/10_Interaction/20_Follow1.mdx new file mode 100644 index 0000000000..1a9293e854 --- /dev/null +++ b/src/content/examples/en/10_Interaction/20_Follow1.mdx @@ -0,0 +1,10 @@ +--- +title: Follow 1 +arialabel: >- + Circle connected to a long oval. The user’s mouse is attached to the end of + the oval. When the mouse moves, the oval and circle moves with it. +--- + + +A line segment is pushed and pulled by the cursor. +Based on code from Keith Peters. diff --git a/src/content/examples/en/10_Interaction/21_Follow2.js b/src/content/examples/en/10_Interaction/21_Follow2.js new file mode 100644 index 0000000000..72d74388a1 --- /dev/null +++ b/src/content/examples/en/10_Interaction/21_Follow2.js @@ -0,0 +1,33 @@ + +let x = [0, 0], + y = [0, 0], + segLength = 50; + +function setup() { + createCanvas(710, 400); + strokeWeight(20.0); + stroke(255, 100); +} + +function draw() { + background(0); + dragSegment(0, mouseX, mouseY); + dragSegment(1, x[0], y[0]); +} + +function dragSegment(i, xin, yin) { + const dx = xin - x[i]; + const dy = yin - y[i]; + const angle = atan2(dy, dx); + x[i] = xin - cos(angle) * segLength; + y[i] = yin - sin(angle) * segLength; + segment(x[i], y[i], angle); +} + +function segment(x, y, a) { + push(); + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); + pop(); +} diff --git a/src/content/examples/en/10_Interaction/21_Follow2.mdx b/src/content/examples/en/10_Interaction/21_Follow2.mdx new file mode 100644 index 0000000000..cd420a0be5 --- /dev/null +++ b/src/content/examples/en/10_Interaction/21_Follow2.mdx @@ -0,0 +1,11 @@ +--- +title: Follow 2 +arialabel: >- + Two long ovals connected at the end. The user’s mouse is attached to the end + of one of the ovals and when the mouse moves, the two ovals move as well +--- + + +A two-segmented arm follows the cursor position. The relative +angle between the segments is calculated with atan2() and the position +calculated with sin() and cos(). Based on code from Keith Peters. diff --git a/src/content/examples/en/10_Interaction/22_Follow3.js b/src/content/examples/en/10_Interaction/22_Follow3.js new file mode 100644 index 0000000000..58e72d29fd --- /dev/null +++ b/src/content/examples/en/10_Interaction/22_Follow3.js @@ -0,0 +1,41 @@ + +let x = [], + y = [], + segNum = 20, + segLength = 18; + +for (let i = 0; i < segNum; i++) { + x[i] = 0; + y[i] = 0; +} + +function setup() { + createCanvas(710, 400); + strokeWeight(9); + stroke(255, 100); +} + +function draw() { + background(0); + dragSegment(0, mouseX, mouseY); + for (let i = 0; i < x.length - 1; i++) { + dragSegment(i + 1, x[i], y[i]); + } +} + +function dragSegment(i, xin, yin) { + const dx = xin - x[i]; + const dy = yin - y[i]; + const angle = atan2(dy, dx); + x[i] = xin - cos(angle) * segLength; + y[i] = yin - sin(angle) * segLength; + segment(x[i], y[i], angle); +} + +function segment(x, y, a) { + push(); + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); + pop(); +} diff --git a/src/content/examples/en/10_Interaction/22_Follow3.mdx b/src/content/examples/en/10_Interaction/22_Follow3.mdx new file mode 100644 index 0000000000..0ece6ca610 --- /dev/null +++ b/src/content/examples/en/10_Interaction/22_Follow3.mdx @@ -0,0 +1,9 @@ +--- +title: Follow 3 +arialabel: Long segmented snake shape follows the user’s mouse as it moves +--- + + +A segmented line follows the mouse. The relative angle from +each segment to the next is calculated with atan2() and the position of +the next is calculated with sin() and cos(). Based on code from Keith Peters. diff --git a/src/content/examples/en/10_Interaction/23_snake.js b/src/content/examples/en/10_Interaction/23_snake.js new file mode 100644 index 0000000000..f95c9d8fb9 --- /dev/null +++ b/src/content/examples/en/10_Interaction/23_snake.js @@ -0,0 +1,166 @@ + + +// the snake is divided into small segments, which are drawn and edited on each 'draw' call +let numSegments = 10; +let direction = 'right'; + +const xStart = 0; //starting x coordinate for snake +const yStart = 250; //starting y coordinate for snake +const diff = 10; + +let xCor = []; +let yCor = []; + +let xFruit = 0; +let yFruit = 0; +let scoreElem; + +function setup() { + scoreElem = createDiv('Score = 0'); + scoreElem.position(20, 20); + scoreElem.id = 'score'; + scoreElem.style('color', 'white'); + + createCanvas(500, 500); + frameRate(15); + stroke(255); + strokeWeight(10); + updateFruitCoordinates(); + + for (let i = 0; i < numSegments; i++) { + xCor.push(xStart + i * diff); + yCor.push(yStart); + } +} + +function draw() { + background(0); + for (let i = 0; i < numSegments - 1; i++) { + line(xCor[i], yCor[i], xCor[i + 1], yCor[i + 1]); + } + updateSnakeCoordinates(); + checkGameStatus(); + checkForFruit(); +} + +/** + The segments are updated based on the direction of the snake. + All segments from 0 to n-1 are just copied over to 1 till n, i.e. segment 0 + gets the value of segment 1, segment 1 gets the value of segment 2, and so on, + and this results in the movement of the snake. + + The last segment is added based on the direction in which the snake is going, + if it's going left or right, the last segment's x coordinate is increased by a + predefined value 'diff' than its second to last segment. And if it's going up + or down, the segment's y coordinate is affected. +*/ +function updateSnakeCoordinates() { + for (let i = 0; i < numSegments - 1; i++) { + xCor[i] = xCor[i + 1]; + yCor[i] = yCor[i + 1]; + } + switch (direction) { + case 'right': + xCor[numSegments - 1] = xCor[numSegments - 2] + diff; + yCor[numSegments - 1] = yCor[numSegments - 2]; + break; + case 'up': + xCor[numSegments - 1] = xCor[numSegments - 2]; + yCor[numSegments - 1] = yCor[numSegments - 2] - diff; + break; + case 'left': + xCor[numSegments - 1] = xCor[numSegments - 2] - diff; + yCor[numSegments - 1] = yCor[numSegments - 2]; + break; + case 'down': + xCor[numSegments - 1] = xCor[numSegments - 2]; + yCor[numSegments - 1] = yCor[numSegments - 2] + diff; + break; + } +} + +/** + I always check the snake's head position xCor[xCor.length - 1] and + yCor[yCor.length - 1] to see if it touches the game's boundaries + or if the snake hits itself. +*/ +function checkGameStatus() { + if ( + xCor[xCor.length - 1] > width || + xCor[xCor.length - 1] < 0 || + yCor[yCor.length - 1] > height || + yCor[yCor.length - 1] < 0 || + checkSnakeCollision() + ) { + noLoop(); + const scoreVal = parseInt(scoreElem.html().substring(8)); + scoreElem.html('Game ended! Your score was : ' + scoreVal); + } +} + +/** + If the snake hits itself, that means the snake head's (x,y) coordinate + has to be the same as one of its own segment's (x,y) coordinate. +*/ +function checkSnakeCollision() { + const snakeHeadX = xCor[xCor.length - 1]; + const snakeHeadY = yCor[yCor.length - 1]; + for (let i = 0; i < xCor.length - 1; i++) { + if (xCor[i] === snakeHeadX && yCor[i] === snakeHeadY) { + return true; + } + } +} + +/** + Whenever the snake consumes a fruit, I increment the number of segments, + and just insert the tail segment again at the start of the array (basically + I add the last segment again at the tail, thereby extending the tail) +*/ +function checkForFruit() { + point(xFruit, yFruit); + if (xCor[xCor.length - 1] === xFruit && yCor[yCor.length - 1] === yFruit) { + const prevScore = parseInt(scoreElem.html().substring(8)); + scoreElem.html('Score = ' + (prevScore + 1)); + xCor.unshift(xCor[0]); + yCor.unshift(yCor[0]); + numSegments++; + updateFruitCoordinates(); + } +} + +function updateFruitCoordinates() { + /** + The complex math logic is because I wanted the point to lie + in between 100 and width-100, and be rounded off to the nearest + number divisible by 10, since I move the snake in multiples of 10. + */ + + xFruit = floor(random(10, (width - 100) / 10)) * 10; + yFruit = floor(random(10, (height - 100) / 10)) * 10; +} + +function keyPressed() { + switch (keyCode) { + case 74: + if (direction !== 'right') { + direction = 'left'; + } + break; + case 76: + if (direction !== 'left') { + direction = 'right'; + } + break; + case 73: + if (direction !== 'down') { + direction = 'up'; + } + break; + case 75: + if (direction !== 'up') { + direction = 'down'; + } + break; + } +} diff --git a/src/content/examples/en/10_Interaction/23_snake.mdx b/src/content/examples/en/10_Interaction/23_snake.mdx new file mode 100644 index 0000000000..04ec6a7d33 --- /dev/null +++ b/src/content/examples/en/10_Interaction/23_snake.mdx @@ -0,0 +1,3 @@ + + +undefined diff --git a/src/content/examples/en/10_Interaction/24_Wavemaker.js b/src/content/examples/en/10_Interaction/24_Wavemaker.js new file mode 100644 index 0000000000..ef66d61419 --- /dev/null +++ b/src/content/examples/en/10_Interaction/24_Wavemaker.js @@ -0,0 +1,32 @@ + + +let t = 0; // time variable + +function setup() { + createCanvas(600, 600); + noStroke(); + fill(40, 200, 40); +} + +function draw() { + background(10, 10); // translucent background (creates trails) + + // make a x and y grid of ellipses + for (let x = 0; x <= width; x = x + 30) { + for (let y = 0; y <= height; y = y + 30) { + // starting point of each circle depends on mouse position + const xAngle = map(mouseX, 0, width, -4 * PI, 4 * PI, true); + const yAngle = map(mouseY, 0, height, -4 * PI, 4 * PI, true); + // and also varies based on the particle's location + const angle = xAngle * (x / width) + yAngle * (y / height); + + // each particle moves in a circle + const myX = x + 20 * cos(2 * PI * t + angle); + const myY = y + 20 * sin(2 * PI * t + angle); + + ellipse(myX, myY, 10); // draw particle + } + } + + t = t + 0.01; // update time +} diff --git a/src/content/examples/en/10_Interaction/24_Wavemaker.mdx b/src/content/examples/en/10_Interaction/24_Wavemaker.mdx new file mode 100644 index 0000000000..af85ee3c8f --- /dev/null +++ b/src/content/examples/en/10_Interaction/24_Wavemaker.mdx @@ -0,0 +1,11 @@ +--- +title: Wavemaker +arialabel: >- + Water like waves of neon green lines moving in circular patterns. The user’s + mouse can change the direction of the current in the waves +--- + + +This illustrates how waves (like water waves) emerge +from particles oscillating in place. Move your mouse to direct the wave. +Contributed by Aatish Bhatia, inspired by Orbiters by Dave Whyte. diff --git a/src/content/examples/en/10_Interaction/25_reach1.js b/src/content/examples/en/10_Interaction/25_reach1.js new file mode 100644 index 0000000000..fa260717a4 --- /dev/null +++ b/src/content/examples/en/10_Interaction/25_reach1.js @@ -0,0 +1,52 @@ + +let segLength = 80, + x, + y, + x2, + y2; + +function setup() { + createCanvas(710, 400); + strokeWeight(20); + stroke(255, 100); + + x = width / 2; + y = height / 2; + x2 = x; + y2 = y; +} + +function draw() { + background(0); + dragSegment(0, mouseX, mouseY); + for (let i = 0; i < x.length - 1; i++) { + dragSegment(i + 1, x[i], y[i]); + } +} + +function dragSegment(i, xin, yin) { + background(0); + + dx = mouseX - x; + dy = mouseY - y; + angle1 = atan2(dy, dx); + + tx = mouseX - cos(angle1) * segLength; + ty = mouseY - sin(angle1) * segLength; + dx = tx - x2; + dy = ty - y2; + angle2 = atan2(dy, dx); + x = x2 + cos(angle2) * segLength; + y = y2 + sin(angle2) * segLength; + + segment(x, y, angle1); + segment(x2, y2, angle2); +} + +function segment(x, y, a) { + push(); + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); + pop(); +} diff --git a/src/content/examples/en/10_Interaction/25_reach1.mdx b/src/content/examples/en/10_Interaction/25_reach1.mdx new file mode 100644 index 0000000000..6749276455 --- /dev/null +++ b/src/content/examples/en/10_Interaction/25_reach1.mdx @@ -0,0 +1,12 @@ +--- +title: Reach 1 +arialabel: >- + Two long ovals connected at the end. The user’s mouse is attached to the end + of one of the ovals and when the mouse moves, the two ovals move as well. + However, the end of the other oval is permanently attached to the middle of + the background. +--- + + +The arm follows the position of the mouse by calculating the +angles with atan2(). Based on code from Keith Peters. diff --git a/src/content/examples/en/10_Interaction/26_reach2.js b/src/content/examples/en/10_Interaction/26_reach2.js new file mode 100644 index 0000000000..b2645c4fe2 --- /dev/null +++ b/src/content/examples/en/10_Interaction/26_reach2.js @@ -0,0 +1,60 @@ + +let numSegments = 10, + x = [], + y = [], + angle = [], + segLength = 26, + targetX, + targetY; + +for (let i = 0; i < numSegments; i++) { + x[i] = 0; + y[i] = 0; + angle[i] = 0; +} + +function setup() { + createCanvas(710, 400); + strokeWeight(20); + stroke(255, 100); + + x[x.length - 1] = width / 2; // Set base x-coordinate + y[x.length - 1] = height; // Set base y-coordinate +} + +function draw() { + background(0); + + reachSegment(0, mouseX, mouseY); + for (let i = 1; i < numSegments; i++) { + reachSegment(i, targetX, targetY); + } + for (let j = x.length - 1; j >= 1; j--) { + positionSegment(j, j - 1); + } + for (let k = 0; k < x.length; k++) { + segment(x[k], y[k], angle[k], (k + 1) * 2); + } +} + +function positionSegment(a, b) { + x[b] = x[a] + cos(angle[a]) * segLength; + y[b] = y[a] + sin(angle[a]) * segLength; +} + +function reachSegment(i, xin, yin) { + const dx = xin - x[i]; + const dy = yin - y[i]; + angle[i] = atan2(dy, dx); + targetX = xin - cos(angle[i]) * segLength; + targetY = yin - sin(angle[i]) * segLength; +} + +function segment(x, y, a, sw) { + strokeWeight(sw); + push(); + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); + pop(); +} diff --git a/src/content/examples/en/10_Interaction/26_reach2.mdx b/src/content/examples/en/10_Interaction/26_reach2.mdx new file mode 100644 index 0000000000..32e04be757 --- /dev/null +++ b/src/content/examples/en/10_Interaction/26_reach2.mdx @@ -0,0 +1,10 @@ +--- +title: Reach 2 +arialabel: >- + Grey triangle segmented and attached to the bottom of the black screen. The + tip of the triangle follows the direction of the user’s mouse +--- + + +The arm follows the position of the mouse by calculating the +angles with atan2(). Based on code from Keith Peters. diff --git a/src/content/examples/en/10_Interaction/27_reach3.js b/src/content/examples/en/10_Interaction/27_reach3.js new file mode 100644 index 0000000000..0137787aaa --- /dev/null +++ b/src/content/examples/en/10_Interaction/27_reach3.js @@ -0,0 +1,76 @@ + +let numSegments = 8, + x = [], + y = [], + angle = [], + segLength = 26, + targetX, + targetY, + ballX = 50, + ballY = 50, + ballXDirection = 1, + ballYDirection = -1; + +for (let i = 0; i < numSegments; i++) { + x[i] = 0; + y[i] = 0; + angle[i] = 0; +} + +function setup() { + createCanvas(710, 400); + strokeWeight(20); + stroke(255, 100); + noFill(); + + x[x.length - 1] = width / 2; // Set base x-coordinate + y[x.length - 1] = height; // Set base y-coordinate +} + +function draw() { + background(0); + + strokeWeight(20); + ballX = ballX + 1.0 * ballXDirection; + ballY = ballY + 0.8 * ballYDirection; + if (ballX > width - 25 || ballX < 25) { + ballXDirection *= -1; + } + if (ballY > height - 25 || ballY < 25) { + ballYDirection *= -1; + } + ellipse(ballX, ballY, 30, 30); + + reachSegment(0, ballX, ballY); + for (let i = 1; i < numSegments; i++) { + reachSegment(i, targetX, targetY); + } + for (let j = x.length - 1; j >= 1; j--) { + positionSegment(j, j - 1); + } + for (let k = 0; k < x.length; k++) { + segment(x[k], y[k], angle[k], (k + 1) * 2); + } +} + +function positionSegment(a, b) { + x[b] = x[a] + cos(angle[a]) * segLength; + y[b] = y[a] + sin(angle[a]) * segLength; +} + +function reachSegment(i, xin, yin) { + const dx = xin - x[i]; + const dy = yin - y[i]; + angle[i] = atan2(dy, dx); + targetX = xin - cos(angle[i]) * segLength; + targetY = yin - sin(angle[i]) * segLength; +} + +function segment(x, y, a, sw) { + strokeWeight(sw); + push(); + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); + pop(); +} diff --git a/src/content/examples/en/10_Interaction/27_reach3.mdx b/src/content/examples/en/10_Interaction/27_reach3.mdx new file mode 100644 index 0000000000..3825c5a6d7 --- /dev/null +++ b/src/content/examples/en/10_Interaction/27_reach3.mdx @@ -0,0 +1,11 @@ +--- +title: Reach 3 +arialabel: >- + Grey triangle segmented and attached to the bottom of the black screen. The + tip of the triangle follows the direction of a grey circular donut shape that + is also bouncing around the screen +--- + + +The arm follows the position of the ball by calculating the +angles with atan2(). Based on code from Keith Peters. diff --git a/src/content/examples/en/10_Interaction/28_ArduinoSensor.js b/src/content/examples/en/10_Interaction/28_ArduinoSensor.js new file mode 100644 index 0000000000..f782453f44 --- /dev/null +++ b/src/content/examples/en/10_Interaction/28_ArduinoSensor.js @@ -0,0 +1,20 @@ + + +function setup() { + createCanvas(400, 400); + noStroke(); + fill('#ff00aa22'); + receiveSensorData(handleData); +} + +function handleData(data, connection) { + + console.log(data); // output the values to log + // data[0] is the 1st value, data[1] 2nd, etc. + + // draw stuff! Browse http://p5js.org/reference/ + background('#ddd'); + ellipse(100, 200, data[0]+10, data[0]+10); + + // connection.send('send data back to the Arduino if its listening'); +} diff --git a/src/content/examples/en/10_Interaction/28_ArduinoSensor.mdx b/src/content/examples/en/10_Interaction/28_ArduinoSensor.mdx new file mode 100644 index 0000000000..3f7a148be7 --- /dev/null +++ b/src/content/examples/en/10_Interaction/28_ArduinoSensor.mdx @@ -0,0 +1,20 @@ +--- +title: Arduino sensor data via WebJack +--- + + +WebJack is a way to read data from an Arduino (and other sources) +using audio -- it basically turns your Arduino into an audio modem. + +https://github.com/publiclab/webjack + +Note: WebJack and p5-webjack libraries must be added to your index.html as follows: +
\
+
\
+ +Working example: https://editor.p5js.org/jywarren/sketches/rkztwSt8M + +Testing audio: https://www.youtube.com/watch?v=GtJW1Dlt3cg +Load this sketch onto an Arduino: +https://create.arduino.cc/editor/jywarren/023158d8-be51-4c78-99ff-36c63126b554/preview +Arduino will output audio from pin 3 + ground. Use microphone or an audio cable. diff --git a/src/content/examples/en/10_Interaction/29_kaleidoscope.js b/src/content/examples/en/10_Interaction/29_kaleidoscope.js new file mode 100644 index 0000000000..9d0c0c2eec --- /dev/null +++ b/src/content/examples/en/10_Interaction/29_kaleidoscope.js @@ -0,0 +1,69 @@ + +// Symmetry corresponding to the number of reflections. Change the number for different number of reflections +let symmetry = 6; + +let angle = 360 / symmetry; +let saveButton, clearButton, mouseButton, keyboardButton; +let slider; + +function setup() { + createCanvas(710, 710); + angleMode(DEGREES); + background(127); + + // Creating the save button for the file + saveButton = createButton('save'); + saveButton.mousePressed(saveFile); + + // Creating the clear screen button + clearButton = createButton('clear'); + clearButton.mousePressed(clearScreen); + + // Creating the button for Full Screen + fullscreenButton = createButton('Full Screen'); + fullscreenButton.mousePressed(screenFull); + + // Setting up the slider for the thickness of the brush + brushSizeSlider = createButton('Brush Size Slider'); + sizeSlider = createSlider(1, 32, 4, 0.1); +} + +// Save File Function +function saveFile() { + save('design.jpg'); +} + +// Clear Screen function +function clearScreen() { + background(127); +} + +// Full Screen Function +function screenFull() { + let fs = fullscreen(); + fullscreen(!fs); +} + +function draw() { + translate(width / 2, height / 2); + + if (mouseX > 0 && mouseX < width && mouseY > 0 && mouseY < height) { + let mx = mouseX - width / 2; + let my = mouseY - height / 2; + let pmx = pmouseX - width / 2; + let pmy = pmouseY - height / 2; + + if (mouseIsPressed) { + for (let i = 0; i < symmetry; i++) { + rotate(angle); + let sw = sizeSlider.value(); + strokeWeight(sw); + line(mx, my, pmx, pmy); + push(); + scale(1, -1); + line(mx, my, pmx, pmy); + pop(); + } + } + } +} diff --git a/src/content/examples/en/10_Interaction/29_kaleidoscope.mdx b/src/content/examples/en/10_Interaction/29_kaleidoscope.mdx new file mode 100644 index 0000000000..4864e62feb --- /dev/null +++ b/src/content/examples/en/10_Interaction/29_kaleidoscope.mdx @@ -0,0 +1,9 @@ +--- +title: Kaleidoscope +arialabel: >- + User draws thick black lines on the grey background and it is mirrored 5 times + in a circle like a kaleidoscope +--- + + +A kaleidoscope is an optical instrument with two or more reflecting surfaces tilted to each other in an angle. This example tries to replicate the behavior of a kaleidoscope. Set the number of reflections at the symmetry variable and start drawing on the screen. Paste the below code in the Editor and click on the save button if you wish to download a .jpg file of the art that you have created. diff --git a/src/content/examples/en/11_Objects/01_Objects.js b/src/content/examples/en/11_Objects/01_Objects.js new file mode 100644 index 0000000000..9a0e751992 --- /dev/null +++ b/src/content/examples/en/11_Objects/01_Objects.js @@ -0,0 +1,34 @@ + + +let bug; // Declare object + +function setup() { + createCanvas(710, 400); + // Create object + bug = new Jitter(); +} + +function draw() { + background(50, 89, 100); + bug.move(); + bug.display(); +} + +// Jitter class +class Jitter { + constructor() { + this.x = random(width); + this.y = random(height); + this.diameter = random(10, 30); + this.speed = 1; + } + + move() { + this.x += random(-this.speed, this.speed); + this.y += random(-this.speed, this.speed); + } + + display() { + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} diff --git a/src/content/examples/en/11_Objects/01_Objects.mdx b/src/content/examples/en/11_Objects/01_Objects.mdx new file mode 100644 index 0000000000..8422e5004b --- /dev/null +++ b/src/content/examples/en/11_Objects/01_Objects.mdx @@ -0,0 +1,11 @@ +--- +title: Objects +arialabel: >- + Small white circle on dark navy background that moves in small amounts in + various directions by a small amount by itself like it is jittering +--- + + +Create a Jitter class, instantiate an object, +and move it around the screen. Adapted from Getting Started with +Processing by Casey Reas and Ben Fry. diff --git a/src/content/examples/en/11_Objects/02_Multiple_Objects.js b/src/content/examples/en/11_Objects/02_Multiple_Objects.js new file mode 100644 index 0000000000..e38862da97 --- /dev/null +++ b/src/content/examples/en/11_Objects/02_Multiple_Objects.js @@ -0,0 +1,46 @@ + + +let bug1; // Declare objects +let bug2; +let bug3; +let bug4; + +function setup() { + createCanvas(710, 400); + // Create object + bug1 = new Jitter(); + bug2 = new Jitter(); + bug3 = new Jitter(); + bug4 = new Jitter(); +} + +function draw() { + background(50, 89, 100); + bug1.move(); + bug1.display(); + bug2.move(); + bug2.display(); + bug3.move(); + bug3.display(); + bug4.move(); + bug4.display(); +} + +// Jitter class +class Jitter { + constructor() { + this.x = random(width); + this.y = random(height); + this.diameter = random(10, 30); + this.speed = 1; + } + + move() { + this.x += random(-this.speed, this.speed); + this.y += random(-this.speed, this.speed); + } + + display() { + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} diff --git a/src/content/examples/en/11_Objects/02_Multiple_Objects.mdx b/src/content/examples/en/11_Objects/02_Multiple_Objects.mdx new file mode 100644 index 0000000000..f43e1a77fe --- /dev/null +++ b/src/content/examples/en/11_Objects/02_Multiple_Objects.mdx @@ -0,0 +1,10 @@ +--- +title: Multiple Objects +arialabel: >- + Four small white circles places randomly on a dark navy background that move + in small amounts in various directions by itself like they are jittering +--- + + +Create a Jitter class, instantiate multiple objects, +and move it around the screen. diff --git a/src/content/examples/en/11_Objects/03_Objects_Array.js b/src/content/examples/en/11_Objects/03_Objects_Array.js new file mode 100644 index 0000000000..311015b33b --- /dev/null +++ b/src/content/examples/en/11_Objects/03_Objects_Array.js @@ -0,0 +1,38 @@ + + +let bugs = []; // array of Jitter objects + +function setup() { + createCanvas(710, 400); + // Create objects + for (let i = 0; i < 50; i++) { + bugs.push(new Jitter()); + } +} + +function draw() { + background(50, 89, 100); + for (let i = 0; i < bugs.length; i++) { + bugs[i].move(); + bugs[i].display(); + } +} + +// Jitter class +class Jitter { + constructor() { + this.x = random(width); + this.y = random(height); + this.diameter = random(10, 30); + this.speed = 1; + } + + move() { + this.x += random(-this.speed, this.speed); + this.y += random(-this.speed, this.speed); + } + + display() { + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} diff --git a/src/content/examples/en/11_Objects/03_Objects_Array.mdx b/src/content/examples/en/11_Objects/03_Objects_Array.mdx new file mode 100644 index 0000000000..a8c678700d --- /dev/null +++ b/src/content/examples/en/11_Objects/03_Objects_Array.mdx @@ -0,0 +1,11 @@ +--- +title: Array of Objects +arialabel: >- + Multiple sizes of small white circles placed randomly on a dark navy + background that move in small amounts in various directions by itself like + they are jittering +--- + + +Create a Jitter class, instantiate an array of objects +and move them around the screen. diff --git a/src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.js b/src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.js new file mode 100644 index 0000000000..6382454f39 --- /dev/null +++ b/src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.js @@ -0,0 +1,60 @@ + + +let r1, r2, r3, r4; + +function setup() { +createCanvas(710, 400); +fill(255, 204); +noStroke(); +r1 = new MRect(1, 134.0, 0.532, 0.1 * height, 10.0, 60.0); +r2 = new MRect(2, 44.0, 0.166, 0.3 * height, 5.0, 50.0); +r3 = new MRect(2, 58.0, 0.332, 0.4 * height, 10.0, 35.0); +r4 = new MRect(1, 120.0, 0.0498, 0.9 * height, 15.0, 60.0); +} + +function draw() { +background(0); + +r1.display(); +r2.display(); +r3.display(); +r4.display(); + +r1.move(mouseX - width / 2, mouseY + height * 0.1, 30); +r2.move((mouseX + width * 0.05) % width, mouseY + height * 0.025, 20); +r3.move(mouseX / 4, mouseY - height * 0.025, 40); +r4.move(mouseX - width / 2, height - mouseY, 50); +} + +class MRect { + constructor(iw, ixp, ih, iyp, id, it) { + this.w = iw; // single bar width + this.xpos = ixp; // rect xposition + this.h = ih; // rect height + this.ypos = iyp; // rect yposition + this.d = id; // single bar distance + this.t = it; // number of bars + } + + move(posX, posY, damping) { + let dif = this.ypos - posY; + if (abs(dif) > 1) { + this.ypos -= dif / damping; + } + dif = this.xpos - posX; + if (abs(dif) > 1) { + this.xpos -= dif / damping; + } + } + + display() { + for (let i = 0; i < this.t; i++) { + rect( + this.xpos + i * (this.d + this.w), + this.ypos, + this.w, + height * this.h + ); + } + } +} diff --git a/src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.mdx b/src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.mdx new file mode 100644 index 0000000000..a202e6ded6 --- /dev/null +++ b/src/content/examples/en/11_Objects/03_Objects_Optional_Arguments.mdx @@ -0,0 +1,11 @@ +--- +title: Objects 2 +arialabel: >- + 4 sets of vertical white lines that form rectangles of different sizes on a + black background. They move around as the user’s mouse moves +--- + + +Ported from example by hbarragan. Move the cursor across the +image to change the speed and positions of the geometry. The class MRect +defines a group of lines. diff --git a/src/content/examples/en/12_Lights/02_Directional.js b/src/content/examples/en/12_Lights/02_Directional.js new file mode 100644 index 0000000000..6cef8fae24 --- /dev/null +++ b/src/content/examples/en/12_Lights/02_Directional.js @@ -0,0 +1,20 @@ + +const radius = 200; + +function setup() { + createCanvas(710, 400, WEBGL); + noStroke(); + fill(200); +} + +function draw() { + noStroke(); + background(0); + const dirY = (mouseY / height - 0.5) * 4; + const dirX = (mouseX / width - 0.5) * 4; + directionalLight(204, 204, 204, dirX, dirY, 1); + translate(-1.5 * radius, 0, 0); + sphere(radius); + translate(3 * radius, 0, 0); + sphere(radius); +} diff --git a/src/content/examples/en/12_Lights/02_Directional.mdx b/src/content/examples/en/12_Lights/02_Directional.mdx new file mode 100644 index 0000000000..bf9fc0611c --- /dev/null +++ b/src/content/examples/en/12_Lights/02_Directional.mdx @@ -0,0 +1,13 @@ +--- +title: Directional +arialabel: >- + Two spheres on both sides of a black screen that is lit by the mouse which + acts as a light source. You can move this light source by moving your mouse to + shine on different parts of the sphere and create different shadows +--- + + +Move the mouse to change the direction of the light. +Directional light comes from one direction and is stronger when hitting a +surface squarely and weaker if it hits at a a gentle angle. After hitting a +surface, a directional light scatters in all directions. diff --git a/src/content/examples/en/12_Lights/05_Mixture.js b/src/content/examples/en/12_Lights/05_Mixture.js new file mode 100644 index 0000000000..a224c1cdf2 --- /dev/null +++ b/src/content/examples/en/12_Lights/05_Mixture.js @@ -0,0 +1,40 @@ + +function setup() { + createCanvas(710, 400, WEBGL); + noStroke(); +} + +function draw() { + background(0); + + // ambient light + ambientLight(0, 255/4, 0); + + // to set the light position, + // think of the world's coordinate as: + // -width/2,-height/2 -------- width/2,-height/2 + // | | + // | 0,0 | + // | | + // -width/2,height/2--------width/2,height/2 + + // blue directional light from the left + directionalLight(0, 0, 255, -1, 0, 0); + + // calculate distance from center to mouseX + let lightX = mouseX - width / 2; + let lightY = mouseY - height / 2; + + // red spotlight + // axis located at lightX, lightY, 500 + // axis direction of light: 0, 0, -1 + spotLight(255, 0, 0, lightX, lightY, 500, 0, 0, -1); + + // rotate on X axis + rotateX(-PI/4); + // rotate on Y axis + rotateY(PI/4); + + // place box on (0, 0, 0), size 100 + box(100); +} diff --git a/src/content/examples/en/12_Lights/05_Mixture.mdx b/src/content/examples/en/12_Lights/05_Mixture.mdx new file mode 100644 index 0000000000..0877efa150 --- /dev/null +++ b/src/content/examples/en/12_Lights/05_Mixture.mdx @@ -0,0 +1,10 @@ +--- +title: Mixture +arialabel: >- + Cube where we can see three sides, one blue and two forest green on a black + background. An orange light shines where your mouse is when it is placed in + the cube +--- + + +Display a box with three different kinds of lights. diff --git a/src/content/examples/en/13_Motion/01_non_orthogonal_reflection.js b/src/content/examples/en/13_Motion/01_non_orthogonal_reflection.js new file mode 100644 index 0000000000..4aedc10b1a --- /dev/null +++ b/src/content/examples/en/13_Motion/01_non_orthogonal_reflection.js @@ -0,0 +1,106 @@ + + +//Position of left hand side of floor +let base1; + +//Position of right hand side of floor +let base2; +//Length of floor +//let baseLength; + +// Variables related to moving ball +let position; +let velocity; +let r = 6; +let speed = 3.5; + +function setup() { + createCanvas(710, 400); + + fill(128); + base1 = createVector(0, height - 150); + base2 = createVector(width, height); + //createGround(); + + //start ellipse at middle top of screen + position = createVector(width / 2, 0); + + //calculate initial random velocity + velocity = p5.Vector.random2D(); + velocity.mult(speed); +} + +function draw() { + //draw background + fill(0, 12); + noStroke(); + rect(0, 0, width, height); + + //draw base + fill(200); + quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height); + + //calculate base top normal + let baseDelta = p5.Vector.sub(base2, base1); + baseDelta.normalize(); + let normal = createVector(-baseDelta.y, baseDelta.x); + let intercept = p5.Vector.dot(base1, normal); + + //draw ellipse + noStroke(); + fill(255); + ellipse(position.x, position.y, r * 2, r * 2); + + //move ellipse + position.add(velocity); + + //normalized incidence vector + incidence = p5.Vector.mult(velocity, -1); + incidence.normalize(); + + // detect and handle collision with base + if (p5.Vector.dot(normal, position) > intercept) { + //calculate dot product of incident vector and base top + let dot = incidence.dot(normal); + + //calculate reflection vector + //assign reflection vector to direction vector + velocity.set( + 2 * normal.x * dot - incidence.x, + 2 * normal.y * dot - incidence.y, + 0 + ); + velocity.mult(speed); + + // draw base top normal at collision point + stroke(255, 128, 0); + line( + position.x, + position.y, + position.x - normal.x * 100, + position.y - normal.y * 100 + ); + } + //} + + // detect boundary collision + // right + if (position.x > width - r) { + position.x = width - r; + velocity.x *= -1; + } + // left + if (position.x < r) { + position.x = r; + velocity.x *= -1; + } + // top + if (position.y < r) { + position.y = r; + velocity.y *= -1; + + //randomize base top + base1.y = random(height - 100, height); + base2.y = random(height - 100, height); + } +} diff --git a/src/content/examples/en/13_Motion/01_non_orthogonal_reflection.mdx b/src/content/examples/en/13_Motion/01_non_orthogonal_reflection.mdx new file mode 100644 index 0000000000..c5b0e589e7 --- /dev/null +++ b/src/content/examples/en/13_Motion/01_non_orthogonal_reflection.mdx @@ -0,0 +1,10 @@ +--- +title: Non Orthogonal Reflection +arialabel: >- + A white circle bounces around a black screen and on a grey slanted floor + leaving a white streak behind it. The grey slanted floor changes every couple + of frames +--- + + +This is a port by David Blitz of the "Reflection 1" example from processing.org/examples diff --git a/src/content/examples/en/13_Motion/02_Linear_Motion.js b/src/content/examples/en/13_Motion/02_Linear_Motion.js new file mode 100644 index 0000000000..7eb2e53bd9 --- /dev/null +++ b/src/content/examples/en/13_Motion/02_Linear_Motion.js @@ -0,0 +1,18 @@ + + +let a; + +function setup() { + createCanvas(720, 400); + stroke(255); + a = height / 2; +} + +function draw() { + background(51); + line(0, a, width, a); + a = a - 0.5; + if (a < 0) { + a = height; + } +} diff --git a/src/content/examples/en/13_Motion/02_Linear_Motion.mdx b/src/content/examples/en/13_Motion/02_Linear_Motion.mdx new file mode 100644 index 0000000000..6f34bae348 --- /dev/null +++ b/src/content/examples/en/13_Motion/02_Linear_Motion.mdx @@ -0,0 +1,11 @@ +--- +title: Linear +arialabel: >- + Horizontal white line on a black background traveling from the bottom to the + top of the screen parallel to the x axis +--- + + +Changing a variable to create a moving line. +When the line moves off the edge of the window, +the variable is set to 0, which places the line back at the bottom of the screen. diff --git a/src/content/examples/en/13_Motion/03_Bounce.js b/src/content/examples/en/13_Motion/03_Bounce.js new file mode 100644 index 0000000000..08b17469f0 --- /dev/null +++ b/src/content/examples/en/13_Motion/03_Bounce.js @@ -0,0 +1,40 @@ + + +let rad = 60; // Width of the shape +let xpos, ypos; // Starting position of shape + +let xspeed = 2.8; // Speed of the shape +let yspeed = 2.2; // Speed of the shape + +let xdirection = 1; // Left or Right +let ydirection = 1; // Top to Bottom + +function setup() { + createCanvas(720, 400); + noStroke(); + frameRate(30); + ellipseMode(RADIUS); + // Set the starting position of the shape + xpos = width / 2; + ypos = height / 2; +} + +function draw() { + background(102); + + // Update the position of the shape + xpos = xpos + xspeed * xdirection; + ypos = ypos + yspeed * ydirection; + + // Test to see if the shape exceeds the boundaries of the screen + // If it does, reverse its direction by multiplying by -1 + if (xpos > width - rad || xpos < rad) { + xdirection *= -1; + } + if (ypos > height - rad || ypos < rad) { + ydirection *= -1; + } + + // Draw the shape + ellipse(xpos, ypos, rad, rad); +} diff --git a/src/content/examples/en/13_Motion/03_Bounce.mdx b/src/content/examples/en/13_Motion/03_Bounce.mdx new file mode 100644 index 0000000000..a3d656d9a2 --- /dev/null +++ b/src/content/examples/en/13_Motion/03_Bounce.mdx @@ -0,0 +1,9 @@ +--- +title: Bounce +arialabel: >- + White circle moving on a grey background. When it hits the edge of the + background window, it changes it’s direction +--- + + +When the shape hits the edge of the window, it reverses its direction. diff --git a/src/content/examples/en/13_Motion/04_Bouncy_Bubbles.js b/src/content/examples/en/13_Motion/04_Bouncy_Bubbles.js new file mode 100644 index 0000000000..8ac09d6392 --- /dev/null +++ b/src/content/examples/en/13_Motion/04_Bouncy_Bubbles.js @@ -0,0 +1,91 @@ + + +let numBalls = 13; +let spring = 0.05; +let gravity = 0.03; +let friction = -0.9; +let balls = []; + +function setup() { + createCanvas(720, 400); + for (let i = 0; i < numBalls; i++) { + balls[i] = new Ball( + random(width), + random(height), + random(30, 70), + i, + balls + ); + } + noStroke(); + fill(255, 204); +} + +function draw() { + background(0); + balls.forEach(ball => { + ball.collide(); + ball.move(); + ball.display(); + }); +} + +class Ball { + constructor(xin, yin, din, idin, oin) { + this.x = xin; + this.y = yin; + this.vx = 0; + this.vy = 0; + this.diameter = din; + this.id = idin; + this.others = oin; + } + + collide() { + for (let i = this.id + 1; i < numBalls; i++) { + // console.log(others[i]); + let dx = this.others[i].x - this.x; + let dy = this.others[i].y - this.y; + let distance = sqrt(dx * dx + dy * dy); + let minDist = this.others[i].diameter / 2 + this.diameter / 2; + // console.log(distance); + //console.log(minDist); + if (distance < minDist) { + //console.log("2"); + let angle = atan2(dy, dx); + let targetX = this.x + cos(angle) * minDist; + let targetY = this.y + sin(angle) * minDist; + let ax = (targetX - this.others[i].x) * spring; + let ay = (targetY - this.others[i].y) * spring; + this.vx -= ax; + this.vy -= ay; + this.others[i].vx += ax; + this.others[i].vy += ay; + } + } + } + + move() { + this.vy += gravity; + this.x += this.vx; + this.y += this.vy; + if (this.x + this.diameter / 2 > width) { + this.x = width - this.diameter / 2; + this.vx *= friction; + } else if (this.x - this.diameter / 2 < 0) { + this.x = this.diameter / 2; + this.vx *= friction; + } + if (this.y + this.diameter / 2 > height) { + this.y = height - this.diameter / 2; + this.vy *= friction; + } else if (this.y - this.diameter / 2 < 0) { + this.y = this.diameter / 2; + this.vy *= friction; + } + } + + display() { + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} diff --git a/src/content/examples/en/13_Motion/04_Bouncy_Bubbles.mdx b/src/content/examples/en/13_Motion/04_Bouncy_Bubbles.mdx new file mode 100644 index 0000000000..5e3606b375 --- /dev/null +++ b/src/content/examples/en/13_Motion/04_Bouncy_Bubbles.mdx @@ -0,0 +1,9 @@ +--- +title: Bouncy Bubbles +arialabel: >- + Grey circles of varying sizes bounce off the sides of the canvas and each + other, eventually settling on the bottom of the screen +--- + + +based on code from Keith Peters. Multiple-object collision.. diff --git a/src/content/examples/en/13_Motion/05_Morph.js b/src/content/examples/en/13_Motion/05_Morph.js new file mode 100644 index 0000000000..4464534563 --- /dev/null +++ b/src/content/examples/en/13_Motion/05_Morph.js @@ -0,0 +1,89 @@ + + +// Two ArrayLists to store the vertices for two shapes +// This example assumes that each shape will have the same +// number of vertices, i.e. the size of each ArrayList will be the same +let circle = []; +let square = []; + +// An ArrayList for a third set of vertices, the ones we will be drawing +// in the window +let morph = []; + +// This boolean variable will control if we are morphing to a circle or square +let state = false; + +function setup() { + createCanvas(720, 400); + + // Create a circle using vectors pointing from center + for (let angle = 0; angle < 360; angle += 9) { + // Note we are not starting from 0 in order to match the + // path of a circle. + let v = p5.Vector.fromAngle(radians(angle - 135)); + v.mult(100); + circle.push(v); + // Let's fill out morph ArrayList with blank PVectors while we are at it + morph.push(createVector()); + } + + // A square is a bunch of vertices along straight lines + // Top of square + for (let x = -50; x < 50; x += 10) { + square.push(createVector(x, -50)); + } + // Right side + for (let y = -50; y < 50; y += 10) { + square.push(createVector(50, y)); + } + // Bottom + for (let x = 50; x > -50; x -= 10) { + square.push(createVector(x, 50)); + } + // Left side + for (let y = 50; y > -50; y -= 10) { + square.push(createVector(-50, y)); + } +} + +function draw() { + background(51); + + // We will keep how far the vertices are from their target + let totalDistance = 0; + + // Look at each vertex + for (let i = 0; i < circle.length; i++) { + let v1; + // Are we lerping to the circle or square? + if (state) { + v1 = circle[i]; + } else { + v1 = square[i]; + } + // Get the vertex we will draw + let v2 = morph[i]; + // Lerp to the target + v2.lerp(v1, 0.1); + // Check how far we are from target + totalDistance += p5.Vector.dist(v1, v2); + } + + // If all the vertices are close, switch shape + if (totalDistance < 0.1) { + state = !state; + } + + // Draw relative to center + translate(width / 2, height / 2); + strokeWeight(4); + // Draw a polygon that makes up all the vertices + beginShape(); + noFill(); + stroke(255); + + morph.forEach(v => { + vertex(v.x, v.y); + }); + endShape(CLOSE); +} diff --git a/src/content/examples/en/13_Motion/05_Morph.mdx b/src/content/examples/en/13_Motion/05_Morph.mdx new file mode 100644 index 0000000000..77bc1e9699 --- /dev/null +++ b/src/content/examples/en/13_Motion/05_Morph.mdx @@ -0,0 +1,9 @@ +--- +title: Morph +arialabel: >- + On a dark grey background, white outline of a square changes into a circle as + the sides of the square curve into a circle shape +--- + + +Changing one shape into another by interpolating vertices from one to another. diff --git a/src/content/examples/en/13_Motion/06_Moving_On_Curves.js b/src/content/examples/en/13_Motion/06_Moving_On_Curves.js new file mode 100644 index 0000000000..60d23f879a --- /dev/null +++ b/src/content/examples/en/13_Motion/06_Moving_On_Curves.js @@ -0,0 +1,42 @@ + + +let beginX = 20.0; // Initial x-coordinate +let beginY = 10.0; // Initial y-coordinate +let endX = 570.0; // Final x-coordinate +let endY = 320.0; // Final y-coordinate +let distX; // X-axis distance to move +let distY; // Y-axis distance to move +let exponent = 4; // Determines the curve +let x = 0.0; // Current x-coordinate +let y = 0.0; // Current y-coordinate +let step = 0.01; // Size of each step along the path +let pct = 0.0; // Percentage traveled (0.0 to 1.0) + +function setup() { + createCanvas(720, 400); + noStroke(); + distX = endX - beginX; + distY = endY - beginY; +} + +function draw() { + fill(0, 2); + rect(0, 0, width, height); + pct += step; + if (pct < 1.0) { + x = beginX + pct * distX; + y = beginY + pow(pct, exponent) * distY; + } + fill(255); + ellipse(x, y, 20, 20); +} + +function mousePressed() { + pct = 0.0; + beginX = x; + beginY = y; + endX = mouseX; + endY = mouseY; + distX = endX - beginX; + distY = endY - beginY; +} diff --git a/src/content/examples/en/13_Motion/06_Moving_On_Curves.mdx b/src/content/examples/en/13_Motion/06_Moving_On_Curves.mdx new file mode 100644 index 0000000000..519eefc921 --- /dev/null +++ b/src/content/examples/en/13_Motion/06_Moving_On_Curves.mdx @@ -0,0 +1,10 @@ +--- +title: Moving On Curves +arialabel: >- + White circle travels across the grey screen on the curve y=x^4. It leaves + behind an outline of its path +--- + + +In this example, the circles moves along the curve y = x^4. +Click the mouse to have it move to a new position. diff --git a/src/content/examples/en/13_Motion/07_Circle_Collision.mdx b/src/content/examples/en/13_Motion/07_Circle_Collision.mdx new file mode 100644 index 0000000000..355d564b9a --- /dev/null +++ b/src/content/examples/en/13_Motion/07_Circle_Collision.mdx @@ -0,0 +1,156 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + class Ball { + constructor(x, y, r) { + this.position = new p5.Vector(x, y); + this.velocity = p5.Vector.random2D(); + this.velocity.mult(3); + this.r = r; + this.m = r * 0.1; + } + update() { + this.position.add(this.velocity); + } + + checkBoundaryCollision() { + if (this.position.x > width - this.r) { + this.position.x = width - this.r; + this.velocity.x *= -1; + } else if (this.position.x < this.r) { + this.position.x = this.r; + this.velocity.x *= -1; + } else if (this.position.y > height - this.r) { + this.position.y = height - this.r; + this.velocity.y *= -1; + } else if (this.position.y < this.r) { + this.position.y = this.r; + this.velocity.y *= -1; + } + } + + checkCollision(other) { + // Get distances between the balls components + let distanceVect = p5.Vector.sub(other.position, this.position); + + // Calculate magnitude of the vector separating the balls + let distanceVectMag = distanceVect.mag(); + + // Minimum distance before they are touching + let minDistance = this.r + other.r; + + if (distanceVectMag < minDistance) { + let distanceCorrection = (minDistance - distanceVectMag) / 2.0; + let d = distanceVect.copy(); + let correctionVector = d.normalize().mult(distanceCorrection); + other.position.add(correctionVector); + this.position.sub(correctionVector); + + // get angle of distanceVect + let theta = distanceVect.heading(); + // precalculate trig values + let sine = sin(theta); + let cosine = cos(theta); + + /* bTemp will hold rotated ball this.positions. You + just need to worry about bTemp[1] this.position*/ + let bTemp = [new p5.Vector(), new p5.Vector()]; + + /* this ball's this.position is relative to the other + so you can use the vector between them (bVect) as the + reference point in the rotation expressions. + bTemp[0].this.position.x and bTemp[0].this.position.y will initialize + automatically to 0.0, which is what you want + since b[1] will rotate around b[0] */ + bTemp[1].x = cosine * distanceVect.x + sine * distanceVect.y; + bTemp[1].y = cosine * distanceVect.y - sine * distanceVect.x; + + // rotate Temporary velocities + let vTemp = [new p5.Vector(), new p5.Vector()]; + + vTemp[0].x = cosine * this.velocity.x + sine * this.velocity.y; + vTemp[0].y = cosine * this.velocity.y - sine * this.velocity.x; + vTemp[1].x = cosine * other.velocity.x + sine * other.velocity.y; + vTemp[1].y = cosine * other.velocity.y - sine * other.velocity.x; + + /* Now that velocities are rotated, you can use 1D + conservation of momentum equations to calculate + the final this.velocity along the x-axis. */ + let vFinal = [new p5.Vector(), new p5.Vector()]; + + // final rotated this.velocity for b[0] + vFinal[0].x = + ((this.m - other.m) * vTemp[0].x + 2 * other.m * vTemp[1].x) / + (this.m + other.m); + vFinal[0].y = vTemp[0].y; + + // final rotated this.velocity for b[0] + vFinal[1].x = + ((other.m - this.m) * vTemp[1].x + 2 * this.m * vTemp[0].x) / + (this.m + other.m); + vFinal[1].y = vTemp[1].y; + + // hack to avoid clumping + bTemp[0].x += vFinal[0].x; + bTemp[1].x += vFinal[1].x; + + /* Rotate ball this.positions and velocities back + Reverse signs in trig expressions to rotate + in the opposite direction */ + // rotate balls + let bFinal = [new p5.Vector(), new p5.Vector()]; + + bFinal[0].x = cosine * bTemp[0].x - sine * bTemp[0].y; + bFinal[0].y = cosine * bTemp[0].y + sine * bTemp[0].x; + bFinal[1].x = cosine * bTemp[1].x - sine * bTemp[1].y; + bFinal[1].y = cosine * bTemp[1].y + sine * bTemp[1].x; + + // update balls to screen this.position + other.position.x = this.position.x + bFinal[1].x; + other.position.y = this.position.y + bFinal[1].y; + + this.position.add(bFinal[0]); + + // update velocities + this.velocity.x = cosine * vFinal[0].x - sine * vFinal[0].y; + this.velocity.y = cosine * vFinal[0].y + sine * vFinal[0].x; + other.velocity.x = cosine * vFinal[1].x - sine * vFinal[1].y; + other.velocity.y = cosine * vFinal[1].y + sine * vFinal[1].x; + } + } + + display() { + noStroke(); + fill(204); + ellipse(this.position.x, this.position.y, this.r * 2, this.r * 2); + } + } + let balls = [new Ball(100, 400, 20), new Ball(700, 400, 80)]; + console.log(balls); + function setup() { + createCanvas(710, 400); + } + + function draw() { + background(51); + for (let i = 0; i < balls.length; i++) { + let b = balls[i]; + b.update(); + b.display(); + b.checkBoundaryCollision(); + balls[0].checkCollision(balls[1]); + } + } +title: Circle Collision +arialabel: >- + One large light grey circle and one small grey circle collide and bounce off + each other as they bounce off each other and off the edges of the dark grey + background +description: >- + This is a port of the "Circle Collision" example from processing.org/examples +
This example uses vectors for better visualization of physical Quantity +--- + + +# Example diff --git a/src/content/examples/en/15_Instance_Mode/01_Instantiating.js b/src/content/examples/en/15_Instance_Mode/01_Instantiating.js new file mode 100644 index 0000000000..5d3ea335de --- /dev/null +++ b/src/content/examples/en/15_Instance_Mode/01_Instantiating.js @@ -0,0 +1,31 @@ + +let sketch = function(p) { + let x = 100; + let y = 100; + + p.setup = function() { + p.createCanvas(700, 410); + }; + + p.draw = function() { + p.background(0); + p.fill(255); + p.rect(x, y, 50, 50); + }; +}; + +let myp5 = new p5(sketch); + +// Compare to "global mode" +// let x = 100; +// let y = 100; + +// function setup() { +// createCanvas(200,200); +// } + +// function draw() { +// background(0); +// fill(255); +// ellipse(x,y,50,50); +// } diff --git a/src/content/examples/en/15_Instance_Mode/01_Instantiating.mdx b/src/content/examples/en/15_Instance_Mode/01_Instantiating.mdx new file mode 100644 index 0000000000..4bf1e6c32e --- /dev/null +++ b/src/content/examples/en/15_Instance_Mode/01_Instantiating.mdx @@ -0,0 +1,8 @@ +--- +title: Instantiation +arialabel: White square in the upper left quadrant on black background +--- + + +Create a p5 instance, which keeps all variables +out of the global scope of your page. diff --git a/src/content/examples/en/16_Dom/03_Input_Button.js b/src/content/examples/en/16_Dom/03_Input_Button.js new file mode 100644 index 0000000000..3387b60ce8 --- /dev/null +++ b/src/content/examples/en/16_Dom/03_Input_Button.js @@ -0,0 +1,35 @@ + +let input, button, greeting; + +function setup() { + // create canvas + createCanvas(710, 400); + + input = createInput(); + input.position(20, 65); + + button = createButton('submit'); + button.position(input.x + input.width, 65); + button.mousePressed(greet); + + greeting = createElement('h2', 'what is your name?'); + greeting.position(20, 5); + + textAlign(CENTER); + textSize(50); +} + +function greet() { + const name = input.value(); + greeting.html('hello ' + name + '!'); + input.value(''); + + for (let i = 0; i < 200; i++) { + push(); + fill(random(255), 255, 255); + translate(random(width), random(height)); + rotate(random(2 * PI)); + text(name, 0, 0); + pop(); + } +} diff --git a/src/content/examples/en/16_Dom/03_Input_Button.mdx b/src/content/examples/en/16_Dom/03_Input_Button.mdx new file mode 100644 index 0000000000..a8da05c521 --- /dev/null +++ b/src/content/examples/en/16_Dom/03_Input_Button.mdx @@ -0,0 +1,11 @@ +--- +title: Input and Button +arialabel: >- + “What is your name?” is written in the top left of the window with a text + input box and a submit button under. After inputting text and submitting, the + text submitted is generated multiple times to cover the background in a random + formation in various shades of cyan. +--- + + +Input text and click the button to see it affect the the canvas. diff --git a/src/content/examples/en/16_Dom/04_Slider.js b/src/content/examples/en/16_Dom/04_Slider.js new file mode 100644 index 0000000000..efe5c696af --- /dev/null +++ b/src/content/examples/en/16_Dom/04_Slider.js @@ -0,0 +1,27 @@ + +let rSlider, gSlider, bSlider; + +function setup() { + // create canvas + createCanvas(710, 400); + textSize(15); + noStroke(); + + // create sliders + rSlider = createSlider(0, 255, 100); + rSlider.position(20, 20); + gSlider = createSlider(0, 255, 0); + gSlider.position(20, 50); + bSlider = createSlider(0, 255, 255); + bSlider.position(20, 80); +} + +function draw() { + const r = rSlider.value(); + const g = gSlider.value(); + const b = bSlider.value(); + background(r, g, b); + text('red', rSlider.x * 2 + rSlider.width, 35); + text('green', gSlider.x * 2 + gSlider.width, 65); + text('blue', bSlider.x * 2 + bSlider.width, 95); +} diff --git a/src/content/examples/en/16_Dom/04_Slider.mdx b/src/content/examples/en/16_Dom/04_Slider.mdx new file mode 100644 index 0000000000..2d1f486fef --- /dev/null +++ b/src/content/examples/en/16_Dom/04_Slider.mdx @@ -0,0 +1,11 @@ +--- +title: Slider +arialabel: >- + The background starts off in a vibrant shade of purple with three sliders in + the upper left corner labeled red, green, and blue. The user can drag each + slider and the color of the background will change accordingly with the + increase or decrease of each of these three colors. +--- + + +Move the sliders to control the R, G, B values of the background. diff --git a/src/content/examples/en/16_Dom/07_Modify_DOM.js b/src/content/examples/en/16_Dom/07_Modify_DOM.js new file mode 100644 index 0000000000..ec97117a64 --- /dev/null +++ b/src/content/examples/en/16_Dom/07_Modify_DOM.js @@ -0,0 +1,49 @@ + +let dancingWords = []; + +class DanceSpan { + constructor(element, x, y) { + element.position(x, y); + this.element = element; + this.x = x; + this.y = y; + } + + brownian() { + this.x += random(-6, 6); + this.y += random(-6, 6); + this.element.position(this.x, this.y); + } +} + +function setup() { + // This paragraph is created aside of the main block of code. + // It's to differentiate the creation of an element from its + // selection. Selected elements don't need to be created by + // p5js, they can be just plain HTML. + createP( + 'I learn in this Letter, that Don Peter of Aragon, ' + + ' comes this night to Messina' + ).addClass('text').hide(); + + // This line grabs the paragraph just created, but it would + // also grab any other elements with class 'text' in the HTML + // page. + const texts = selectAll('.text'); + + for (let i = 0; i < texts.length; i++) { + const paragraph = texts[i].html(); + const words = paragraph.split(' '); + for (let j = 0; j < words.length; j++) { + const spannedWord = createSpan(words[j]); + const dw = new DanceSpan(spannedWord, random(600), random(200)); + dancingWords.push(dw); + } + } +} + +function draw() { + for (let i = 0; i < dancingWords.length; i++) { + dancingWords[i].brownian(); + } +} diff --git a/src/content/examples/en/16_Dom/07_Modify_DOM.mdx b/src/content/examples/en/16_Dom/07_Modify_DOM.mdx new file mode 100644 index 0000000000..4afb9efbe9 --- /dev/null +++ b/src/content/examples/en/16_Dom/07_Modify_DOM.mdx @@ -0,0 +1,8 @@ +--- +title: Modifying the DOM +arialabel: Words in black font jittering on a white background +--- + + +Create DOM elements and modify their properties every time +draw() is called. diff --git a/src/content/examples/en/16_Dom/08_Video.js b/src/content/examples/en/16_Dom/08_Video.js new file mode 100644 index 0000000000..79715ac834 --- /dev/null +++ b/src/content/examples/en/16_Dom/08_Video.js @@ -0,0 +1,24 @@ + +let playing = false; +let fingers; +let button; + +function setup() { + noCanvas(); + // specify multiple formats for different browsers + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + button = createButton('play'); + button.mousePressed(toggleVid); // attach button listener +} + +// plays or pauses the video depending on current state +function toggleVid() { + if (playing) { + fingers.pause(); + button.html('play'); + } else { + fingers.loop(); + button.html('pause'); + } + playing = !playing; +} diff --git a/src/content/examples/en/16_Dom/08_Video.mdx b/src/content/examples/en/16_Dom/08_Video.mdx new file mode 100644 index 0000000000..b48fab8163 --- /dev/null +++ b/src/content/examples/en/16_Dom/08_Video.mdx @@ -0,0 +1,8 @@ +--- +title: Video +arialabel: Video of fingers walking +--- + + +Load a video with multiple formats and toggle between playing +and paused with a button press. diff --git a/src/content/examples/en/16_Dom/09_Video_Canvas.js b/src/content/examples/en/16_Dom/09_Video_Canvas.js new file mode 100644 index 0000000000..a93719ca14 --- /dev/null +++ b/src/content/examples/en/16_Dom/09_Video_Canvas.js @@ -0,0 +1,22 @@ + +let fingers; + +function setup() { + createCanvas(710, 400); + // specify multiple formats for different browsers + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + fingers.hide(); // by default video shows up in separate dom + // element. hide it and draw it to the canvas + // instead +} + +function draw() { + background(150); + image(fingers, 10, 10); // draw the video frame to canvas + filter(GRAY); + image(fingers, 150, 150); // draw a second copy to canvas +} + +function mousePressed() { + fingers.loop(); // set the video to loop and start playing +} diff --git a/src/content/examples/en/16_Dom/09_Video_Canvas.mdx b/src/content/examples/en/16_Dom/09_Video_Canvas.mdx new file mode 100644 index 0000000000..145b0ad201 --- /dev/null +++ b/src/content/examples/en/16_Dom/09_Video_Canvas.mdx @@ -0,0 +1,11 @@ +--- +title: Video Canvas +arialabel: >- + grey background with two identical videos playing. One in color and one in + black and white. +--- + + +Load a video with multiple formats and draw it to the canvas. +To run this example locally, you will need a running +local server. diff --git a/src/content/examples/en/16_Dom/10_Video_Pixels.js b/src/content/examples/en/16_Dom/10_Video_Pixels.js new file mode 100644 index 0000000000..37f2130985 --- /dev/null +++ b/src/content/examples/en/16_Dom/10_Video_Pixels.js @@ -0,0 +1,26 @@ + +let fingers; + +function setup() { + createCanvas(320, 240); + // specify multiple formats for different browsers + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + fingers.loop(); + fingers.hide(); + noStroke(); + fill(0); +} + +function draw() { + background(255); + fingers.loadPixels(); + const stepSize = round(constrain(mouseX / 8, 6, 32)); + for (let y = 0; y < height; y += stepSize) { + for (let x = 0; x < width; x += stepSize) { + const i = y * width + x; + const darkness = (255 - fingers.pixels[i * 4]) / 255; + const radius = stepSize * darkness; + ellipse(x, y, radius, radius); + } + } +} diff --git a/src/content/examples/en/16_Dom/10_Video_Pixels.mdx b/src/content/examples/en/16_Dom/10_Video_Pixels.mdx new file mode 100644 index 0000000000..fe1551dff3 --- /dev/null +++ b/src/content/examples/en/16_Dom/10_Video_Pixels.mdx @@ -0,0 +1,12 @@ +--- +title: Video Pixels +arialabel: >- + Video is turned into black circles to look like pixels. Pixel size increases + as the user’s mouse is dragged to the right and decreases as the user’s mouse + is dragged to the left +--- + + +Load a video, manipulate its pixels and draw to canvas. +To run this example locally, you will need a running +local server. diff --git a/src/content/examples/en/16_Dom/11_Capture.js b/src/content/examples/en/16_Dom/11_Capture.js new file mode 100644 index 0000000000..75920e2bfc --- /dev/null +++ b/src/content/examples/en/16_Dom/11_Capture.js @@ -0,0 +1,15 @@ + +let capture; + +function setup() { + createCanvas(390, 240); + capture = createCapture(VIDEO); + capture.size(320, 240); + //capture.hide(); +} + +function draw() { + background(255); + image(capture, 0, 0, 320, 240); + filter(INVERT); +} diff --git a/src/content/examples/en/16_Dom/11_Capture.mdx b/src/content/examples/en/16_Dom/11_Capture.mdx new file mode 100644 index 0000000000..bb14121b50 --- /dev/null +++ b/src/content/examples/en/16_Dom/11_Capture.mdx @@ -0,0 +1,10 @@ +--- +title: Video Capture +arialabel: Takes feed from the user’s computer camera and displays it in the window +--- + + +Capture video from the webcam and display +on the canvas as well with invert filter. Note that by +default the capture feed shows up, too. You can hide the +feed by uncommenting the capture.hide() line. diff --git a/src/content/examples/en/16_Dom/12_Drop.js b/src/content/examples/en/16_Dom/12_Drop.js new file mode 100644 index 0000000000..01307c2a16 --- /dev/null +++ b/src/content/examples/en/16_Dom/12_Drop.js @@ -0,0 +1,30 @@ + + +function setup() { + // create canvas + const c = createCanvas(710, 400); + background(100); + // Add an event for when a file is dropped onto the canvas + c.drop(gotFile); +} + +function draw() { + fill(255); + noStroke(); + textSize(24); + textAlign(CENTER); + text('Drag an image file onto the canvas.', width / 2, height / 2); + noLoop(); +} + +function gotFile(file) { + // If it's an image file + if (file.type === 'image') { + // Create an image DOM element but don't show it + const img = createImg(file.data).hide(); + // Draw the image onto the canvas + image(img, 0, 0, width, height); + } else { + console.log('Not an image file!'); + } +} diff --git a/src/content/examples/en/16_Dom/12_Drop.mdx b/src/content/examples/en/16_Dom/12_Drop.mdx new file mode 100644 index 0000000000..82d0a3aa26 --- /dev/null +++ b/src/content/examples/en/16_Dom/12_Drop.mdx @@ -0,0 +1,9 @@ +--- +title: Drop +arialabel: >- + Empty grey canvas that displays an image if it is dragged from the user’s + computer to the grey canvas +--- + + +Drag an image file onto the canvas to see it displayed. diff --git a/src/content/examples/en/17_Drawing/00_Continuous_Lines.js b/src/content/examples/en/17_Drawing/00_Continuous_Lines.js new file mode 100644 index 0000000000..74f8588ac6 --- /dev/null +++ b/src/content/examples/en/17_Drawing/00_Continuous_Lines.js @@ -0,0 +1,12 @@ + +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + stroke(255); + if (mouseIsPressed === true) { + line(mouseX, mouseY, pmouseX, pmouseY); + } +} diff --git a/src/content/examples/en/17_Drawing/00_Continuous_Lines.mdx b/src/content/examples/en/17_Drawing/00_Continuous_Lines.mdx new file mode 100644 index 0000000000..853559e655 --- /dev/null +++ b/src/content/examples/en/17_Drawing/00_Continuous_Lines.mdx @@ -0,0 +1,9 @@ +--- +title: Continuous Lines +arialabel: >- + Thin white line draws on a dark grey background as the user clicks and drags + their mouse +--- + + +Click and drag the mouse to draw a line. diff --git a/src/content/examples/en/17_Drawing/01_Pattern.js b/src/content/examples/en/17_Drawing/01_Pattern.js new file mode 100644 index 0000000000..26d35464b1 --- /dev/null +++ b/src/content/examples/en/17_Drawing/01_Pattern.js @@ -0,0 +1,23 @@ + +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + // Call the variableEllipse() method and send it the + // parameters for the current mouse position + // and the previous mouse position + variableEllipse(mouseX, mouseY, pmouseX, pmouseY); +} + +// The simple method variableEllipse() was created specifically +// for this program. It calculates the speed of the mouse +// and draws a small ellipse if the mouse is moving slowly +// and draws a large ellipse if the mouse is moving quickly + +function variableEllipse(x, y, px, py) { + let speed = abs(x - px) + abs(y - py); + stroke(speed); + ellipse(x, y, speed, speed); +} diff --git a/src/content/examples/en/17_Drawing/01_Pattern.mdx b/src/content/examples/en/17_Drawing/01_Pattern.mdx new file mode 100644 index 0000000000..22d88caa6e --- /dev/null +++ b/src/content/examples/en/17_Drawing/01_Pattern.mdx @@ -0,0 +1,11 @@ +--- +title: Patterns +arialabel: >- + Continuous circles draw on a dark grey background as you move your mouse. The + circles get bigger as you move your mouse faster and smaller as you move your + mouse slower +--- + + +Move the cursor over the image to draw with a software tool +which responds to the speed of the mouse. diff --git a/src/content/examples/en/17_Drawing/02_Pulses.js b/src/content/examples/en/17_Drawing/02_Pulses.js new file mode 100644 index 0000000000..3ce812558c --- /dev/null +++ b/src/content/examples/en/17_Drawing/02_Pulses.js @@ -0,0 +1,25 @@ + +let angle = 0; + +function setup() { + createCanvas(710, 400); + background(102); + noStroke(); + fill(0, 102); +} + +function draw() { + // Draw only when mouse is pressed + if (mouseIsPressed === true) { + angle += 5; + let val = cos(radians(angle)) * 12.0; + for (let a = 0; a < 360; a += 75) { + let xoff = cos(radians(a)) * val; + let yoff = sin(radians(a)) * val; + fill(0); + ellipse(mouseX + xoff, mouseY + yoff, val, val); + } + fill(255); + ellipse(mouseX, mouseY, 2, 2); + } +} diff --git a/src/content/examples/en/17_Drawing/02_Pulses.mdx b/src/content/examples/en/17_Drawing/02_Pulses.mdx new file mode 100644 index 0000000000..64fe858ec3 --- /dev/null +++ b/src/content/examples/en/17_Drawing/02_Pulses.mdx @@ -0,0 +1,14 @@ +--- +title: Pulses +arialabel: >- + Continuous black flowers with a white circle center draw on a dark grey + background as you move your mouse. The circles get bigger as you move your + mouse faster and smaller as you move your mouse slower. When you stop your + mouse, the last flower rotates slightly. +--- + + +Software drawing instruments can follow a rhythm or abide by +rules independent of drawn gestures. This is a form of collaborative drawing +in which the draftsperson controls some aspects of the image and the software +controls others. diff --git a/src/content/examples/en/18_Transform/00_Translate.js b/src/content/examples/en/18_Transform/00_Translate.js new file mode 100644 index 0000000000..8a8e2dd942 --- /dev/null +++ b/src/content/examples/en/18_Transform/00_Translate.js @@ -0,0 +1,34 @@ + + +let x = 0; +let y = 0; +let dim = 80.0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(102); + // Animate by increasing our x value + x = x + 0.8; + // If the shape goes off the canvas, reset the position + if (x > width + dim) { + x = -dim; + } + + // Even though our rect command draws the shape with its + // center at the origin, translate moves it to the new + // x and y position + translate(x, height / 2 - dim / 2); + fill(255); + rect(-dim / 2, -dim / 2, dim, dim); + + // Transforms accumulate. Notice how this rect moves + // twice as fast as the other, but it has the same + // parameter for the x-axis value + translate(x, dim); + fill(0); + rect(-dim / 2, -dim / 2, dim, dim); +} diff --git a/src/content/examples/en/18_Transform/00_Translate.mdx b/src/content/examples/en/18_Transform/00_Translate.mdx new file mode 100644 index 0000000000..c293843844 --- /dev/null +++ b/src/content/examples/en/18_Transform/00_Translate.mdx @@ -0,0 +1,12 @@ +--- +title: Translate +arialabel: >- + Two squares one white one black travel horizontally across a grey background. + The black square moves faster than the white +--- + + +The translate() function allows objects to be +moved to any location within the window. The first parameter +sets the x-axis offset and the second parameter sets the +y-axis offset. This example shows how transforms accumulate. diff --git a/src/content/examples/en/18_Transform/01_Scale.js b/src/content/examples/en/18_Transform/01_Scale.js new file mode 100644 index 0000000000..b610673883 --- /dev/null +++ b/src/content/examples/en/18_Transform/01_Scale.js @@ -0,0 +1,38 @@ + + +let a = 0.0; +let s = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + //Draw all rectangles from their center as opposed to + // the default upper left corner + rectMode(CENTER); +} + +function draw() { + background(102); + + //Slowly increase 'a' and then animate 's' with + //a smooth cyclical motion by finding the cosine of 'a' + a = a + 0.04; + s = cos(a) * 2; + + //Translate our rectangle from the origin to the middle of + //the canvas, then scale it with 's' + translate(width / 2, height / 2); + scale(s); + fill(51); + rect(0, 0, 50, 50); + + //Translate and scale are accumulating, so this translate + //moves the second rectangle further right than the first + //and the scale is getting doubled. Note that cosine is + //making 's' both negative and positive, thus it cycles + //from left to right. + translate(75, 0); + fill(255); + scale(s); + rect(0, 0, 50, 50); +} diff --git a/src/content/examples/en/18_Transform/01_Scale.mdx b/src/content/examples/en/18_Transform/01_Scale.mdx new file mode 100644 index 0000000000..1926b59dfa --- /dev/null +++ b/src/content/examples/en/18_Transform/01_Scale.mdx @@ -0,0 +1,12 @@ +--- +title: Scale +arialabel: Two squares one white and one black grow and shrink on a grey background +--- + + +Paramenters for the scale() function are values +specified as decimal percentages. For example, the method +call scale(2.0) will increase the dimension of the shape by +200 percent. Objects always scale from the origin. This example +shows how transforms accumulate and also how scale and translate +interact depending on their order. diff --git a/src/content/examples/en/18_Transform/02_Rotate.js b/src/content/examples/en/18_Transform/02_Rotate.js new file mode 100644 index 0000000000..f9bdcad2d2 --- /dev/null +++ b/src/content/examples/en/18_Transform/02_Rotate.js @@ -0,0 +1,32 @@ + + +let angle = 0.0; +let jitter = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + fill(255); + //Draw the rectangle from the center and it will also be the + //rotate around that center + rectMode(CENTER); +} + +function draw() { + background(51); + + // during even-numbered seconds (0, 2, 4, 6...) add jitter to + // the rotation + if (second() % 2 === 0) { + jitter = random(-0.1, 0.1); + } + //increase the angle value using the most recent jitter value + angle = angle + jitter; + //use cosine to get a smooth CW and CCW motion when not jittering + let c = cos(angle); + //move the shape to the center of the canvas + translate(width / 2, height / 2); + //apply the final rotation + rotate(c); + rect(0, 0, 180, 180); +} diff --git a/src/content/examples/en/18_Transform/02_Rotate.mdx b/src/content/examples/en/18_Transform/02_Rotate.mdx new file mode 100644 index 0000000000..b7d4ffac21 --- /dev/null +++ b/src/content/examples/en/18_Transform/02_Rotate.mdx @@ -0,0 +1,15 @@ +--- +title: Rotate +arialabel: White square on a dark grey background rotates side to side +--- + + +Rotating a square around the Z axis. +To get the results you expect, send the rotate function angle +parameters that are values between 0 and PI\*2 (TWO\_PI which is +roughly 6.28). If you prefer to think about angles as degrees +(0-360), you can use the radians() method to convert your values. +For example: rotate(radians(90)) is identical to the statement +rotate(PI/2). In this example, every even numbered second a jitter +is added to the rotation. During odd seconds, rotation moves CW and +CCW at the speed determined by the last jitter value. diff --git a/src/content/examples/en/18_Transform/03_Arm.js b/src/content/examples/en/18_Transform/03_Arm.js new file mode 100644 index 0000000000..373dade9f4 --- /dev/null +++ b/src/content/examples/en/18_Transform/03_Arm.js @@ -0,0 +1,41 @@ + + +let x, y; +let angle1 = 0.0; +let angle2 = 0.0; +let segLength = 100; + +function setup() { + createCanvas(720, 400); + strokeWeight(30); + + //Stroke with a semi-transparent white + stroke(255, 160); + + //Position the "shoulder" of the arm in the center of the canvas + x = width * 0.5; + y = height * 0.5; +} + +function draw() { + background(0); + + //Change the angle of the segments according to the mouse positions + angle1 = (mouseX / float(width) - 0.5) * -TWO_PI; + angle2 = (mouseY / float(height) - 0.5) * PI; + + //use push and pop to "contain" the transforms. Note that + // even though we draw the segments using a custom function, + // the transforms still accumulate + push(); + segment(x, y, angle1); + segment(segLength, 0, angle2); + pop(); +} + +//a custom function for drawing segments +function segment(x, y, a) { + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); +} diff --git a/src/content/examples/en/18_Transform/03_Arm.mdx b/src/content/examples/en/18_Transform/03_Arm.mdx new file mode 100644 index 0000000000..284ab5208e --- /dev/null +++ b/src/content/examples/en/18_Transform/03_Arm.mdx @@ -0,0 +1,15 @@ +--- +title: Arm +arialabel: >- + Two ovals connected at the end to form an arm shape. One end is fixed at the + center of the black background. The arm shape moves in a circular motion as + the mouse moves around the screen +--- + + +This example uses transform matrices to create +an arm. The angle of each segment is controlled with the +mouseX and mouseY position. The transformations applied to +the first segment are also applied to the second segment +because they are inside the same push() and +pop() matrix group. diff --git a/src/content/examples/en/19_Typography/00_Letters.js b/src/content/examples/en/19_Typography/00_Letters.js new file mode 100644 index 0000000000..32a81fbfff --- /dev/null +++ b/src/content/examples/en/19_Typography/00_Letters.js @@ -0,0 +1,58 @@ + +let font, + fontsize = 32; + +function preload() { + // Ensure the .ttf or .otf font stored in the assets directory + // is loaded before setup() and draw() are called + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // Set text characteristics + textFont(font); + textSize(fontsize); + textAlign(CENTER, CENTER); +} + +function draw() { + background(160); + + // Set the gap between letters and the left and top margin + let gap = 52; + let margin = 10; + translate(margin * 4, margin * 4); + + // Set the counter to start at the character you want + // in this case 35, which is the # symbol + let counter = 35; + + // Loop as long as there is space on the canvas + for (let y = 0; y < height - gap; y += gap) { + for (let x = 0; x < width - gap; x += gap) { + // Use the counter to retrieve individual letters by their Unicode number + let letter = char(counter); + + // Add different color to the vowels and other characters + if ( + letter === 'A' || + letter === 'E' || + letter === 'I' || + letter === 'O' || + letter === 'U' + ) { + fill('#ed225d'); + } else { + fill(255); + } + + // Draw the letter to the screen + text(letter, x, y); + + // Increment the counter + counter++; + } + } +} diff --git a/src/content/examples/en/19_Typography/00_Letters.mdx b/src/content/examples/en/19_Typography/00_Letters.mdx new file mode 100644 index 0000000000..f7184e1e42 --- /dev/null +++ b/src/content/examples/en/19_Typography/00_Letters.mdx @@ -0,0 +1,12 @@ +--- +title: Letters +arialabel: >- + Letters and characters on a grey background. All are white except the vowels + are pink. +--- + + +Letters can be drawn to the screen by loading a font, setting +its characteristics and then drawing the letters. This example uses a for +loop and unicode reference numbers to automatically fill the canvas with +characters in a grid. Vowels are selected and given a specific fill color. diff --git a/src/content/examples/en/19_Typography/01_Words.js b/src/content/examples/en/19_Typography/01_Words.js new file mode 100644 index 0000000000..4faa9a5703 --- /dev/null +++ b/src/content/examples/en/19_Typography/01_Words.js @@ -0,0 +1,54 @@ + +let font, + fontsize = 40; + +function preload() { + // Ensure the .ttf or .otf font stored in the assets directory + // is loaded before setup() and draw() are called + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // Set text characteristics + textFont(font); + textSize(fontsize); + textAlign(CENTER, CENTER); +} + +function draw() { + background(160); + + // Align the text to the right + // and run drawWords() in the left third of the canvas + textAlign(RIGHT); + drawWords(width * 0.25); + + // Align the text in the center + // and run drawWords() in the middle of the canvas + textAlign(CENTER); + drawWords(width * 0.5); + + // Align the text to the left + // and run drawWords() in the right third of the canvas + textAlign(LEFT); + drawWords(width * 0.75); +} + +function drawWords(x) { + // The text() function needs three parameters: + // the text to draw, the horizontal position, + // and the vertical position + fill(0); + text('ichi', x, 80); + + fill(65); + text('ni', x, 150); + + fill(190); + text('san', x, 220); + + fill(255); + text('shi', x, 290); +} diff --git a/src/content/examples/en/19_Typography/01_Words.mdx b/src/content/examples/en/19_Typography/01_Words.mdx new file mode 100644 index 0000000000..8f79784dcd --- /dev/null +++ b/src/content/examples/en/19_Typography/01_Words.mdx @@ -0,0 +1,12 @@ +--- +title: Words +arialabel: >- + Three columns of the words “ichi,” “ni,” “san,” and “shi” gradienting from + black to white on a gray background. The first column is right aligned, the + middle column is center aligned, and the left column is left aligned +--- + + +The text() function is used for writing words to the screen. +The words can be aligned left, center, or right with the textAlign() +function, and like with shapes, words can be colored with fill(). diff --git a/src/content/examples/en/19_Typography/02_Text_Rotation.mdx b/src/content/examples/en/19_Typography/02_Text_Rotation.mdx new file mode 100644 index 0000000000..03e999fde3 --- /dev/null +++ b/src/content/examples/en/19_Typography/02_Text_Rotation.mdx @@ -0,0 +1,78 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + + let font, + fontsize = 32; + + let angleRotate = 0.0; + + function setup() { + createCanvas(710, 400); + background(0); + + // Ensure the .ttf or .otf font stored in the assets directory + // is loaded before setup() and draw() are called + font = loadFont('assets/SourceSansPro-Regular.otf'); + + // Set text characteristics + textFont(font); + } + + function draw() { + background(0); + + strokeWeight(1); + stroke(153); + + push(); + let angle1 = radians(45); + translate(100, 180); + rotate(angle1); + // Draw the letter to the screen + text("45 DEGREES", 0, 0); + line(0, 0, 150, 0); + pop(); + + push(); + let angle2 = radians(270); + translate(200, 180); + rotate(angle2); + // Draw the letter to the screen + text("270 DEGREES", 0, 0); + line(0, 0, 150, 0); + pop(); + + push(); + translate(440, 180); + rotate(radians(angleRotate)); + text(int(angleRotate) % 360 + " DEGREES ", 0, 0); + line(0, 0, 150, 0); + pop(); + + angleRotate += 0.25; + + stroke(255, 0, 0); + strokeWeight(4); + point(100, 180); + point(200, 180); + point(440, 180); + } +title: Text Rotation +arialabel: >- + Three white lines on a black screen. One at 45 degrees, one at 270 degrees, + and one line that turns clockwise and the degree label changes as the line + turns. +description: >- + Draws letters to the screen and rotates them at different angles. + +

This example is ported from the Text Rotation + example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/20_3D/00_geometries.js b/src/content/examples/en/20_3D/00_geometries.js new file mode 100644 index 0000000000..f5df5eda2b --- /dev/null +++ b/src/content/examples/en/20_3D/00_geometries.js @@ -0,0 +1,70 @@ + + +function setup() { + createCanvas(710, 400, WEBGL); + + describe( + 'a 3d example containing seven primitive objects, a plane, box, cylinder, cone, torus, sphere, and ellipsoid.' + ); +} + +function draw() { + background(250); + + normalMaterial(); + push(); + translate(-240, -100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + plane(70); + pop(); + + push(); + translate(0, -100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(70, 70, 70); + pop(); + + push(); + translate(240, -100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cylinder(70, 70); + pop(); + + push(); + translate(-250, 100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cone(50, 70); + pop(); + + push(); + translate(-75, 100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + torus(50, 20); + pop(); + + push(); + translate(100, 100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + sphere(50); + pop(); + + push(); + translate(275, 100, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + ellipsoid(30, 40, 40); + pop(); +} diff --git a/src/content/examples/en/20_3D/00_geometries.mdx b/src/content/examples/en/20_3D/00_geometries.mdx new file mode 100644 index 0000000000..751dbae7fb --- /dev/null +++ b/src/content/examples/en/20_3D/00_geometries.mdx @@ -0,0 +1,9 @@ +--- +title: Geometries +arialabel: >- + Seven 3D shapes in neon gradient rotating on a white background. Shapes + include cube, cylinder, ring, pyramid, sphere, plane, and ellipsoid. +--- + + +There are seven 3D primitives in p5 now. diff --git a/src/content/examples/en/20_3D/01_sine_cosine_in_3D.js b/src/content/examples/en/20_3D/01_sine_cosine_in_3D.js new file mode 100644 index 0000000000..ad0a0cd002 --- /dev/null +++ b/src/content/examples/en/20_3D/01_sine_cosine_in_3D.js @@ -0,0 +1,25 @@ + +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + rotateY(frameCount * 0.01); + + for (let j = 0; j < 5; j++) { + push(); + for (let i = 0; i < 80; i++) { + translate( + sin(frameCount * 0.001 + j) * 100, + sin(frameCount * 0.001 + j) * 100, + i * 0.1 + ); + rotateZ(frameCount * 0.002); + push(); + sphere(8, 6, 4); + pop(); + } + pop(); + } +} diff --git a/src/content/examples/en/20_3D/01_sine_cosine_in_3D.mdx b/src/content/examples/en/20_3D/01_sine_cosine_in_3D.mdx new file mode 100644 index 0000000000..4f13c8055a --- /dev/null +++ b/src/content/examples/en/20_3D/01_sine_cosine_in_3D.mdx @@ -0,0 +1,7 @@ +--- +title: Sine Cosine in 3D +arialabel: Geometric spheres moving in different spiral shapes in a 3D space +--- + + +Sine, cosine and push / pop could be applied in 3D as well. diff --git a/src/content/examples/en/20_3D/02_multiple_lights.js b/src/content/examples/en/20_3D/02_multiple_lights.js new file mode 100644 index 0000000000..c0c528afff --- /dev/null +++ b/src/content/examples/en/20_3D/02_multiple_lights.js @@ -0,0 +1,36 @@ + +function setup() { + createCanvas(710, 400, WEBGL); + + describe( + 'a 3d example containing a spinning box and a sphere, each lit with a number of different lights, including ambient (gray), directional (red), spotlight (green), and point (blue).' + ); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + // ambient light is gray + ambientLight(50); + // directional light is red + directionalLight(255, 0, 0, 0.25, 0.25, 0); + // spotlight is green + spotLight(0, 255, 0, 150, 0, 250, 0, 0, -1); + // point light is blue + pointLight(0, 0, 255, locX, locY, 250); + + push(); + translate(-width / 4, 0, 0); + rotateZ(frameCount * 0.02); + rotateX(frameCount * 0.02); + specularMaterial(250); + box(100, 100, 100); + pop(); + + translate(width / 4, 0, 0); + ambientMaterial(250); + sphere(120, 24); +} diff --git a/src/content/examples/en/20_3D/02_multiple_lights.mdx b/src/content/examples/en/20_3D/02_multiple_lights.mdx new file mode 100644 index 0000000000..8418d7a80a --- /dev/null +++ b/src/content/examples/en/20_3D/02_multiple_lights.mdx @@ -0,0 +1,10 @@ +--- +title: Multiple Lights +arialabel: >- + Rotating iridescent cube on the left of the screen and an iridescent sphere on + the right. The user’s mouse acts as a light illuminating the shapes and can + control the direction of the light +--- + + +All types of lights could be used in one sketch. diff --git a/src/content/examples/en/20_3D/03_materials.js b/src/content/examples/en/20_3D/03_materials.js new file mode 100644 index 0000000000..f60b41919b --- /dev/null +++ b/src/content/examples/en/20_3D/03_materials.js @@ -0,0 +1,60 @@ + +let img; +function setup() { + createCanvas(710, 400, WEBGL); + img = loadImage('assets/cat.jpg'); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + ambientLight(60, 60, 60); + pointLight(255, 255, 255, locX, locY, 100); + + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + texture(img); + box(80); + pop(); + + push(); + translate(-width / 4, -height / 4, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + fill(250, 0, 0); + torus(80, 20, 64, 64); + pop(); + + push(); + translate(width / 4, -height / 4, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + normalMaterial(); + torus(80, 20, 64, 64); + pop(); + + push(); + translate(-width / 4, height / 4, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + ambientMaterial(250); + torus(80, 20, 64, 64); + pop(); + + push(); + translate(width / 4, height / 4, 0); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + specularMaterial(250); + torus(80, 20, 64, 64); + pop(); +} diff --git a/src/content/examples/en/20_3D/03_materials.mdx b/src/content/examples/en/20_3D/03_materials.mdx new file mode 100644 index 0000000000..321d1ce223 --- /dev/null +++ b/src/content/examples/en/20_3D/03_materials.mdx @@ -0,0 +1,11 @@ +--- +title: Materials +arialabel: >- + Four rings and one cube of various materials rotate on a black background. As + the user’s mouse moves across the window, the position of the light changes. +--- + + +There are five types of materials supported. +They respond to light differently. +Move your mouse to change the light position. diff --git a/src/content/examples/en/20_3D/04_textures.js b/src/content/examples/en/20_3D/04_textures.js new file mode 100644 index 0000000000..3c281711fa --- /dev/null +++ b/src/content/examples/en/20_3D/04_textures.js @@ -0,0 +1,37 @@ + +// video source: https://vimeo.com/90312869 +let img; +let vid; +let theta = 0; + +function setup() { + createCanvas(710, 400, WEBGL); + + img = loadImage('assets/cat.jpg'); + vid = createVideo(['assets/360video_256crop_v2.mp4']); + vid.elt.muted = true; + vid.loop(); + vid.hide(); +} + +function draw() { + background(250); + translate(-220, 0, 0); + push(); + rotateZ(theta * mouseX * 0.001); + rotateX(theta * mouseX * 0.001); + rotateY(theta * mouseX * 0.001); + //pass image as texture + texture(vid); + sphere(150); + pop(); + translate(440, 0, 0); + push(); + rotateZ(theta * 0.1); + rotateX(theta * 0.1); + rotateY(theta * 0.1); + texture(img); + box(100, 100, 100); + pop(); + theta += 0.05; +} diff --git a/src/content/examples/en/20_3D/04_textures.mdx b/src/content/examples/en/20_3D/04_textures.mdx new file mode 100644 index 0000000000..83a787a93d --- /dev/null +++ b/src/content/examples/en/20_3D/04_textures.mdx @@ -0,0 +1,9 @@ +--- +title: Textures +arialabel: >- + One sphere and one cube rotating on a white background. The sphere is covered + with a video display and the cube is covered with an image. +--- + + +Images and videos are supported for texture. diff --git a/src/content/examples/en/20_3D/05_ray_casting.mdx b/src/content/examples/en/20_3D/05_ray_casting.mdx new file mode 100644 index 0000000000..f5deaf9851 --- /dev/null +++ b/src/content/examples/en/20_3D/05_ray_casting.mdx @@ -0,0 +1,112 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + const objects = []; + let eyeZ; + + function setup() { + createCanvas(710, 400, WEBGL); + + eyeZ = 800; // The default distance the camera is away from the origin. + + objects.push(new IntersectPlane(1, 0, 0, -100, 0, 0)); // Left wall + objects.push(new IntersectPlane(1, 0, 0, 100, 0, 0)); // Right wall + objects.push(new IntersectPlane(0, 1, 0, 0, -100, 0)); // Bottom wall + objects.push(new IntersectPlane(0, 1, 0, 0, 100, 0)); // Top wall + objects.push(new IntersectPlane(0, 0, 1, 0, 0, 0)); // Back wall + + noStroke(); + ambientMaterial(250); + } + + function draw() { + background(0); + + // Lights + pointLight(255, 255, 255, 0, 0, 400); + ambientLight(244, 122, 158); + + // Left wall + push(); + translate(-100, 0, 200); + rotateY((90 * PI) / 180); + plane(400, 200); + pop(); + + // Right wall + push(); + translate(100, 0, 200); + rotateY((90 * PI) / 180); + plane(400, 200); + pop(); + + // Bottom wall + push(); + translate(0, 100, 200); + rotateX((90 * PI) / 180); + plane(200, 400); + pop(); + + // Top wall + push(); + translate(0, -100, 200); + rotateX((90 * PI) / 180); + plane(200, 400); + pop(); + + plane(200, 200); // Back wall + + const x = mouseX - width / 2; + const y = mouseY - height / 2; + + const Q = createVector(0, 0, eyeZ); // A point on the ray and the default position of the camera. + const v = createVector(x, y, -eyeZ); // The direction vector of the ray. + + let intersect; // The point of intersection between the ray and a plane. + let closestLambda = eyeZ * 10; // The draw distance. + + for (let x = 0; x < objects.length; x += 1) { + let object = objects[x]; + let lambda = object.getLambda(Q, v); // The value of lambda where the ray intersects the object + + if (lambda < closestLambda && lambda > 0) { + // Find the position of the intersection of the ray and the object. + intersect = p5.Vector.add(Q, p5.Vector.mult(v, lambda)); + closestLambda = lambda; + } + } + + // Cursor + push(); + translate(intersect); + fill(237, 34, 93); + sphere(10); + pop(); + } + + // Class for a plane that extends to infinity. + class IntersectPlane { + constructor(n1, n2, n3, p1, p2, p3) { + this.normal = createVector(n1, n2, n3); // The normal vector of the plane + this.point = createVector(p1, p2, p3); // A point on the plane + this.d = this.point.dot(this.normal); + } + + getLambda(Q, v) { + return (-this.d - this.normal.dot(Q)) / this.normal.dot(v); + } + } +title: Ray Casting +arialabel: >- + White square in the middle of a screen split diagonally between light pink and + dark pink. The white square is a back wall and the pinks form 4 other walls. + The user’s mouse controls a circle which turns into a 3D bump as it moves + along the walls close to the front. +description: |- + Original example by Jonathan Watson. +

Detecting the position of the mouse in 3D space with ray casting. +--- + + +# Example diff --git a/src/content/examples/en/20_3D/07_orbit_control.js b/src/content/examples/en/20_3D/07_orbit_control.js new file mode 100644 index 0000000000..8c32165570 --- /dev/null +++ b/src/content/examples/en/20_3D/07_orbit_control.js @@ -0,0 +1,35 @@ + +let cam; +function setup() { + createCanvas(710, 400, WEBGL); + cam = createCamera(); + cam.setPosition(0, 0, 0); +} + +function draw() { + background(250); + let radius = width * 1.5; + + //drag to move the world. + orbitControl(); + + normalMaterial(); + for (let i = 0; i <= 12; i++) { + for (let j = 0; j <= 12; j++) { + push(); + let a = (j / 12) * PI; + let b = (i / 12) * PI; + translate( + sin(2 * a) * radius * sin(b), + (cos(b) * radius) / 2, + cos(2 * a) * radius * sin(b) + ); + if (j % 2 === 0) { + cone(30, 30); + } else { + box(30, 30, 30); + } + pop(); + } + } +} diff --git a/src/content/examples/en/20_3D/07_orbit_control.mdx b/src/content/examples/en/20_3D/07_orbit_control.mdx new file mode 100644 index 0000000000..09c0c7e2c6 --- /dev/null +++ b/src/content/examples/en/20_3D/07_orbit_control.mdx @@ -0,0 +1,10 @@ +--- +title: Orbit Control +arialabel: >- + Users can click on the screen and drag to move themselves around a 3D space. + It consists of a white background with columns of purple cubes and green + pyramids arched in curves. +--- + + +Orbit control allows you to drag and move around the world. diff --git a/src/content/examples/en/20_3D/08_basic_shader.mdx b/src/content/examples/en/20_3D/08_basic_shader.mdx new file mode 100644 index 0000000000..83aa85de71 --- /dev/null +++ b/src/content/examples/en/20_3D/08_basic_shader.mdx @@ -0,0 +1,37 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + + // this variable will hold our shader object + let theShader; + + function preload(){ + // load the shader + theShader = loadShader('assets/basic.vert', 'assets/basic.frag'); + } + + function setup() { + // shaders require WEBGL mode to work + createCanvas(710, 400, WEBGL); + noStroke(); + } + + function draw() { + // shader() sets the active shader with our shader + shader(theShader); + + // rect gives us some geometry on the screen + rect(0,0,width, height); + } +title: Basic Shader +arialabel: Background with a cyan to purple gradient +description: >- + This is a basic example showing how to load shaders in p5.js. + +
To learn more about using shaders in p5.js: p5.js Shaders +--- + + +# Example diff --git a/src/content/examples/en/20_3D/09_shader_as_a_texture.mdx b/src/content/examples/en/20_3D/09_shader_as_a_texture.mdx new file mode 100644 index 0000000000..c3daa33160 --- /dev/null +++ b/src/content/examples/en/20_3D/09_shader_as_a_texture.mdx @@ -0,0 +1,78 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |2 + + + // this variable will hold our shader object + let theShader; + // this variable will hold our createGraphics layer + let shaderTexture; + + let theta = 0; + + let x; + let y; + let outsideRadius = 200; + let insideRadius = 100; + + function preload(){ + // load the shader + theShader = loadShader('assets/texture.vert','assets/texture.frag'); + } + + function setup() { + // shaders require WEBGL mode to work + createCanvas(710, 400, WEBGL); + noStroke(); + + // initialize the createGraphics layers + shaderTexture = createGraphics(710, 400, WEBGL); + + // turn off the createGraphics layers stroke + shaderTexture.noStroke(); + + x = -50; + y = 0; + } + + function draw() { + + // instead of just setting the active shader we are passing it to the createGraphics layer + shaderTexture.shader(theShader); + + // here we're using setUniform() to send our uniform values to the shader + theShader.setUniform("resolution", [width, height]); + theShader.setUniform("time", millis() / 1000.0); + theShader.setUniform("mouse", [mouseX, map(mouseY, 0, height, height, 0)]); + + // passing the shaderTexture layer geometry to render on + shaderTexture.rect(0,0,width,height); + + background(255); + + // pass the shader as a texture + texture(shaderTexture); + + translate(-150, 0, 0); + push(); + rotateZ(theta * mouseX * 0.0001); + rotateX(theta * mouseX * 0.0001); + rotateY(theta * mouseX * 0.0001); + theta += 0.05; + sphere(125); + pop(); + + // passing a fifth parameter to ellipse for smooth edges in 3D + ellipse(260,0,200,200,100); + } +title: Shader as a Texture +arialabel: Sphere broken up into a square grid with a gradient in each grid. +description: >- + Shaders can be applied to 2D/3D shapes as textures. + +
To learn more about using shaders in p5.js: p5.js Shaders +--- + + +# Example diff --git a/src/content/examples/en/20_3D/10_passing_shader_uniforms.mdx b/src/content/examples/en/20_3D/10_passing_shader_uniforms.mdx new file mode 100644 index 0000000000..a8877e1a4d --- /dev/null +++ b/src/content/examples/en/20_3D/10_passing_shader_uniforms.mdx @@ -0,0 +1,49 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |2 + + + // this variable will hold our shader object + let theShader; + + function preload(){ + // load the shader + theShader = loadShader('assets/uniforms.vert', 'assets/uniforms.frag'); + } + + function setup() { + // shaders require WEBGL mode to work + createCanvas(710, 400, WEBGL); + noStroke(); + + describe('a 2d example containing a sage green polygon, rotating in the middle of the sketch. As the mouse moves horizontally, the number of sides for the polygon change.') + } + + function draw() { + // shader() sets the active shader with our shader + shader(theShader); + + // lets send the resolution, mouse, and time to our shader + // the mouse x position will change the number of sides + // before sending mouse + time we modify the data so it's more easily usable by the shader + theShader.setUniform('resolution', [width * displayDensity(), height * displayDensity()]); + theShader.setUniform('mouse', map(mouseX, 0, width, 0, 7)); + theShader.setUniform('time', frameCount * 0.01); + + // rect gives us some geometry on the screen + rect(0,0,width, height); + } +title: Passing Shader Uniforms +arialabel: >- + Sage green shape in the middle of a dark purple background. As the user’s + mouse moves left, the shape has less sides and as the user’s mouse moves + right, the shape has more sides +description: >- + Uniforms are the way in which information is passed from p5 to the shader. + +
To learn more about using shaders in p5.js: p5.js Shaders +--- + + +# Example diff --git a/src/content/examples/en/20_3D/11_shader_using_webcam.mdx b/src/content/examples/en/20_3D/11_shader_using_webcam.mdx new file mode 100644 index 0000000000..f52d6a1b67 --- /dev/null +++ b/src/content/examples/en/20_3D/11_shader_using_webcam.mdx @@ -0,0 +1,47 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |2 + + + // this variable will hold our shader object + let theShader; + // this variable will hold our webcam video + let cam; + + function preload(){ + // load the shader + theShader = loadShader('assets/webcam.vert', 'assets/webcam.frag'); + } + + function setup() { + // shaders require WEBGL mode to work + createCanvas(710, 400, WEBGL); + noStroke(); + + cam = createCapture(VIDEO); + cam.size(710, 400); + + cam.hide(); + } + + function draw() { + // shader() sets the active shader with our shader + shader(theShader); + + // passing cam as a texture + theShader.setUniform('tex0', cam); + + // rect gives us some geometry on the screen + rect(0,0,width,height); + } +title: Shader Using Webcam +arialabel: Neon texture added to the scene displayed by the user’s built-in webcam +description: >- + The webcam can be passed to shaders as a texture. + +
To learn more about using shaders in p5.js: p5.js Shaders +--- + + +# Example diff --git a/src/content/examples/en/20_3D/12_framebuffer_blur.js b/src/content/examples/en/20_3D/12_framebuffer_blur.js new file mode 100644 index 0000000000..b1d1b4f45f --- /dev/null +++ b/src/content/examples/en/20_3D/12_framebuffer_blur.js @@ -0,0 +1,101 @@ + +let layer; +let blur; + +function setup() { + createCanvas(windowWidth, windowHeight, WEBGL); + layer = createFramebuffer(); + blur = createShader(vert, frag); + noStroke(); +} + +function draw() { + // Draw a scene + layer.begin(); + background(255); + ambientLight(100); + directionalLight(255, 255, 255, -1, 1, -1); + ambientMaterial(255, 0, 0); + fill(255, 255, 100); + specularMaterial(255); + shininess(150); + + rotateY(millis() * 0.001); + for (let i = 0; i < 5; i++) { + push(); + translate((i-2)*100, 0, 0); + sphere(); + pop(); + } + layer.end(); + + // Render the scene with depth of field blur + shader(blur); + blur.setUniform('img', layer.color); + blur.setUniform('depth', layer.depth); + rect(0, 0, width, height); +} + +function windowResized() { + resizeCanvas(windowWidth, windowHeight); +} + +let vert = ` +precision highp float; +attribute vec3 aPosition; +attribute vec2 aTexCoord; +varying vec2 vTexCoord; +void main() { + vec4 positionVec4 = vec4(aPosition, 1.0); + positionVec4.xy = positionVec4.xy * 2.0 - 1.0; + positionVec4.y *= -1.0; + gl_Position = positionVec4; + vTexCoord = aTexCoord; +}`; + +let frag = ` +precision highp float; +varying vec2 vTexCoord; +uniform sampler2D img; +uniform sampler2D depth; +float getBlurriness(float d) { + // Blur more the farther away we go from the + // focal point at depth=0.9 + return abs(d - 0.9) * 40.; +} +float maxBlurDistance(float blurriness) { + return blurriness * 0.01; +} +void main() { + vec4 color = texture2D(img, vTexCoord); + float samples = 1.; + float centerDepth = texture2D(depth, vTexCoord).r; + float blurriness = getBlurriness(centerDepth); + for (int sample = 0; sample < 20; sample++) { + // Sample nearby pixels in a spiral going out from the + // current pixel + float angle = float(sample); + float distance = float(sample)/20. + * maxBlurDistance(blurriness); + vec2 offset = vec2(cos(angle), sin(angle)) * distance; + + // How close is the object at the nearby pixel? + float sampleDepth = texture2D(depth, vTexCoord + offset).r; + + // How far should its blur reach? + float sampleBlurDistance = + maxBlurDistance(getBlurriness(sampleDepth)); + + // If it's in front of the current pixel, or its blur overlaps + // with the current pixel, add its color to the average + if ( + sampleDepth >= centerDepth || + sampleBlurDistance >= distance + ) { + color += texture2D(img, vTexCoord + offset); + samples++; + } + } + color /= samples; + gl_FragColor = color; +}`; diff --git a/src/content/examples/en/20_3D/12_framebuffer_blur.mdx b/src/content/examples/en/20_3D/12_framebuffer_blur.mdx new file mode 100644 index 0000000000..96e3265035 --- /dev/null +++ b/src/content/examples/en/20_3D/12_framebuffer_blur.mdx @@ -0,0 +1,10 @@ +--- +title: Blur using Framebuffer Depth +arialabel: >- + A line of five spheres rotating in front of the camera, with ones too close + and too far to the camera appearing blurred +--- + + +A shader that uses depth information from a p5.Framebuffer to +draw a scene with focal blur. diff --git a/src/content/examples/en/20_3D/12_simple_feedback.js b/src/content/examples/en/20_3D/12_simple_feedback.js new file mode 100644 index 0000000000..c8aed07c04 --- /dev/null +++ b/src/content/examples/en/20_3D/12_simple_feedback.js @@ -0,0 +1,49 @@ + + +let pg, swap; + +function setup() { + createCanvas(710, 400); + + // this will hold the previous frame + pg = createGraphics(710, 400, WEBGL); + // this will hold our main graphic + swap = createGraphics(710, 400, WEBGL); + + describe( + 'a slowly oscillating, radiating white sphere that fades into a dark gray background through a feedback visual effect' + ); +} + +function draw() { + // clears and resets the p5.Graphics so that 3D objects draw correctly + pg.reset(); + + // draw the previous frame + pg.texture(swap); + pg.noStroke(); + pg.plane(width, height); + + // draw our sphere on top + pg.push(); + // slowly move the sphere in a circle + pg.translate(sin(millis() / 200) * 5, cos(millis() / 200) * 5, 0); + pg.fill(255); + pg.sphere(90); + pg.pop(); + + // draw a slightly scaled up copy of the texture + swap.push(); + swap.scale(1.1, 1.1); + swap.texture(pg); + swap.noStroke(); + swap.plane(width, height); + swap.pop(); + + // an opaque rectangle is drawn over top to control the feedback decay + swap.fill(0, 50); + swap.rect(-width / 2, -height / 2, width, height); + + // draw the output to the screen + image(swap, 0, 0); +} diff --git a/src/content/examples/en/20_3D/12_simple_feedback.mdx b/src/content/examples/en/20_3D/12_simple_feedback.mdx new file mode 100644 index 0000000000..c4b932b85c --- /dev/null +++ b/src/content/examples/en/20_3D/12_simple_feedback.mdx @@ -0,0 +1,10 @@ +--- +title: Simple Feedback +arialabel: An example of a simple feedback effect using two buffers. +--- + + +A simple feedback effect that is achieved by using two WebGL graphics buffers. +This effect works by drawing the previous frame to a second +createGraphics() buffer, which can be blended with the current frame. This +takes advantage of texture mapping in WebGL. diff --git a/src/content/examples/en/21_Input/00_Clock.js b/src/content/examples/en/21_Input/00_Clock.js new file mode 100644 index 0000000000..7e371f1045 --- /dev/null +++ b/src/content/examples/en/21_Input/00_Clock.js @@ -0,0 +1,57 @@ + +let cx, cy; +let secondsRadius; +let minutesRadius; +let hoursRadius; +let clockDiameter; + +function setup() { + createCanvas(720, 400); + stroke(255); + + let radius = min(width, height) / 2; + secondsRadius = radius * 0.71; + minutesRadius = radius * 0.6; + hoursRadius = radius * 0.5; + clockDiameter = radius * 1.7; + + cx = width / 2; + cy = height / 2; +} + +function draw() { + background(230); + + // Draw the clock background + noStroke(); + fill(244, 122, 158); + ellipse(cx, cy, clockDiameter + 25, clockDiameter + 25); + fill(237, 34, 93); + ellipse(cx, cy, clockDiameter, clockDiameter); + + // Angles for sin() and cos() start at 3 o'clock; + // subtract HALF_PI to make them start at the top + let s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI; + let m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI; + let h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI; + + // Draw the hands of the clock + stroke(255); + strokeWeight(1); + line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius); + strokeWeight(2); + line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius); + strokeWeight(4); + line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius); + + // Draw the minute ticks + strokeWeight(2); + beginShape(POINTS); + for (let a = 0; a < 360; a += 6) { + let angle = radians(a); + let x = cx + cos(angle) * secondsRadius; + let y = cy + sin(angle) * secondsRadius; + vertex(x, y); + } + endShape(); +} diff --git a/src/content/examples/en/21_Input/00_Clock.mdx b/src/content/examples/en/21_Input/00_Clock.mdx new file mode 100644 index 0000000000..4279e3170e --- /dev/null +++ b/src/content/examples/en/21_Input/00_Clock.mdx @@ -0,0 +1,9 @@ +--- +title: Clock +arialabel: Functioning pink clock on a grey background +--- + + +The current time can be read with the second(), +minute(), and hour() functions. In this example, sin() and +cos() values are used to set the position of the hands. diff --git a/src/content/examples/en/21_Input/01_Constrain.js b/src/content/examples/en/21_Input/01_Constrain.js new file mode 100644 index 0000000000..d3719ece45 --- /dev/null +++ b/src/content/examples/en/21_Input/01_Constrain.js @@ -0,0 +1,32 @@ + +let mx = 1; +let my = 1; +let easing = 0.05; +let radius = 24; +let edge = 100; +let inner = edge + radius; + +function setup() { + createCanvas(720, 400); + noStroke(); + ellipseMode(RADIUS); + rectMode(CORNERS); +} + +function draw() { + background(230); + + if (abs(mouseX - mx) > 0.1) { + mx = mx + (mouseX - mx) * easing; + } + if (abs(mouseY - my) > 0.1) { + my = my + (mouseY - my) * easing; + } + + mx = constrain(mx, inner, width - inner); + my = constrain(my, inner, height - inner); + fill(237, 34, 93); + rect(edge, edge, width - edge, height - edge); + fill(255); + ellipse(mx, my, radius, radius); +} diff --git a/src/content/examples/en/21_Input/01_Constrain.mdx b/src/content/examples/en/21_Input/01_Constrain.mdx new file mode 100644 index 0000000000..26fa2fae74 --- /dev/null +++ b/src/content/examples/en/21_Input/01_Constrain.mdx @@ -0,0 +1,10 @@ +--- +title: Constrain +arialabel: >- + Pink rectangle on a grey background. A user uses their mouse to move a white + circle within the pink rectangle +--- + + +Move the mouse across the screen to move +the circle. The program constrains the circle to its box. diff --git a/src/content/examples/en/21_Input/02_Easing.js b/src/content/examples/en/21_Input/02_Easing.js new file mode 100644 index 0000000000..73ddb083c7 --- /dev/null +++ b/src/content/examples/en/21_Input/02_Easing.js @@ -0,0 +1,22 @@ + +let x = 1; +let y = 1; +let easing = 0.05; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(237, 34, 93); + let targetX = mouseX; + let dx = targetX - x; + x += dx * easing; + + let targetY = mouseY; + let dy = targetY - y; + y += dy * easing; + + ellipse(x, y, 66, 66); +} diff --git a/src/content/examples/en/21_Input/02_Easing.mdx b/src/content/examples/en/21_Input/02_Easing.mdx new file mode 100644 index 0000000000..6cb0801d88 --- /dev/null +++ b/src/content/examples/en/21_Input/02_Easing.mdx @@ -0,0 +1,14 @@ +--- +title: Easing +arialabel: >- + Pink background with a white circle that the user can move around by hovering + over the circle +--- + + +Move the mouse across the screen and the symbol +will follow. Between drawing each frame of the animation, the +program calculates the difference between the position of the +symbol and the cursor. If the distance is larger than 1 pixel, +the symbol moves part of the distance (0.05) from its current +position toward the cursor. diff --git a/src/content/examples/en/21_Input/03_Keyboard.js b/src/content/examples/en/21_Input/03_Keyboard.js new file mode 100644 index 0000000000..aaf76a7c65 --- /dev/null +++ b/src/content/examples/en/21_Input/03_Keyboard.js @@ -0,0 +1,32 @@ + +let rectWidth; + +function setup() { + createCanvas(720, 400); + noStroke(); + background(230); + rectWidth = width / 4; +} + +function draw() { + // keep draw() here to continue looping while waiting for keys +} + +function keyPressed() { + let keyIndex = -1; + if (key >= 'a' && key <= 'z') { + keyIndex = key.charCodeAt(0) - 'a'.charCodeAt(0); + } + if (keyIndex === -1) { + // If it's not a letter key, clear the screen + background(230); + } else { + // It's a letter key, fill a rectangle + randFill_r = Math.floor(Math.random() * 255 + 1); + randFill_g = Math.floor(Math.random() * 255 + 1); + randFill_b = Math.floor(Math.random() * 255 + 1); + fill(randFill_r, randFill_g, randFill_b); + let x = map(keyIndex, 0, 25, 0, width - rectWidth); + rect(x, 0, rectWidth, height); + } +} diff --git a/src/content/examples/en/21_Input/03_Keyboard.mdx b/src/content/examples/en/21_Input/03_Keyboard.mdx new file mode 100644 index 0000000000..5364155783 --- /dev/null +++ b/src/content/examples/en/21_Input/03_Keyboard.mdx @@ -0,0 +1,12 @@ +--- +title: Keyboard +arialabel: >- + Each letter on the keyboard draws a different color rectangle on the grey + screen when pressed +--- + + +Click on the image to give it focus and +press the letter keys to create forms in time and space. +Each key has a unique identifying number. These numbers +can be used to position shapes in space. diff --git a/src/content/examples/en/21_Input/04_Milliseconds.mdx b/src/content/examples/en/21_Input/04_Milliseconds.mdx new file mode 100644 index 0000000000..128202f867 --- /dev/null +++ b/src/content/examples/en/21_Input/04_Milliseconds.mdx @@ -0,0 +1,41 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |- + + + let scale; + + function setup() { + createCanvas(720, 400); + noStroke(); + scale = width/20; + } + + function draw() { + let i; + for ( i = 0; i < scale; i++) { + colorMode(RGB, (i+1) * scale * 10); + fill(millis()%((i+1) * scale * 10)); + rect(i*scale, 0, scale, height); + } + } +title: Milliseconds +arialabel: >- + Background broken down in bars of various shades of grey. The fill of some of + the bars randomly changes every millisecond to other shades of grey. +description: >- + A millisecond is 1/1000 of a second. Processing keeps track of the number of + milliseconds a + + program has run. By modifying this number with the modulo(%) operator, + different patterns in time are created. + +

This example is ported from the Milliseconds + example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/21_Input/05_Mouse1D.js b/src/content/examples/en/21_Input/05_Mouse1D.js new file mode 100644 index 0000000000..acdbabaae9 --- /dev/null +++ b/src/content/examples/en/21_Input/05_Mouse1D.js @@ -0,0 +1,19 @@ + +function setup() { + createCanvas(720, 400); + noStroke(); + rectMode(CENTER); +} + +function draw() { + background(230); + + let r1 = map(mouseX, 0, width, 0, height); + let r2 = height - r1; + + fill(237, 34, 93, r1); + rect(width / 2 + r1 / 2, height / 2, r1, r1); + + fill(237, 34, 93, r2); + rect(width / 2 - r2 / 2, height / 2, r2, r2); +} diff --git a/src/content/examples/en/21_Input/05_Mouse1D.mdx b/src/content/examples/en/21_Input/05_Mouse1D.mdx new file mode 100644 index 0000000000..9524b2efc4 --- /dev/null +++ b/src/content/examples/en/21_Input/05_Mouse1D.mdx @@ -0,0 +1,13 @@ +--- +title: Mouse 1D +arialabel: >- + Two fuschia squares on a grey background. As the user’s mouse moves to the + left of the window, the fuschia square on the left increases to fill up the + left half of the window as the right square disappears and vice versa as the + user’s mouse moves right. +--- + + +Move the mouse left and right to +shift the balance. The "mouseX" variable is used +to control both the size and color of the rectangles. diff --git a/src/content/examples/en/21_Input/06_Mouse2D.js b/src/content/examples/en/21_Input/06_Mouse2D.js new file mode 100644 index 0000000000..d7cc0e3b3b --- /dev/null +++ b/src/content/examples/en/21_Input/06_Mouse2D.js @@ -0,0 +1,16 @@ + +function setup() { + createCanvas(720, 400); + noStroke(); + rectMode(CENTER); +} + +function draw() { + background(230); + fill(244, 122, 158); + rect(mouseX, height / 2, mouseY / 2 + 10, mouseY / 2 + 10); + fill(237, 34, 93); + let inverseX = width - mouseX; + let inverseY = height - mouseY; + rect(inverseX, height / 2, inverseY / 2 + 10, inverseY / 2 + 10); +} diff --git a/src/content/examples/en/21_Input/06_Mouse2D.mdx b/src/content/examples/en/21_Input/06_Mouse2D.mdx new file mode 100644 index 0000000000..af4e1daa9e --- /dev/null +++ b/src/content/examples/en/21_Input/06_Mouse2D.mdx @@ -0,0 +1,11 @@ +--- +title: Mouse 2D +arialabel: >- + Two fuschia squares on a grey background. As the user’s mouse moves left, the + squares rotate around each other in the left direction and vice versa as the + user’s mouse moves right +--- + + +Moving the mouse changes the position and +size of each box. diff --git a/src/content/examples/en/21_Input/07_Mouse_Functions.js b/src/content/examples/en/21_Input/07_Mouse_Functions.js new file mode 100644 index 0000000000..0ee49dcdd2 --- /dev/null +++ b/src/content/examples/en/21_Input/07_Mouse_Functions.js @@ -0,0 +1,63 @@ + +let bx; +let by; +let boxSize = 75; +let overBox = false; +let locked = false; +let xOffset = 0.0; +let yOffset = 0.0; + +function setup() { + createCanvas(720, 400); + bx = width / 2.0; + by = height / 2.0; + rectMode(RADIUS); + strokeWeight(2); +} + +function draw() { + background(237, 34, 93); + + // Test if the cursor is over the box + if ( + mouseX > bx - boxSize && + mouseX < bx + boxSize && + mouseY > by - boxSize && + mouseY < by + boxSize + ) { + overBox = true; + if (!locked) { + stroke(255); + fill(244, 122, 158); + } + } else { + stroke(156, 39, 176); + fill(244, 122, 158); + overBox = false; + } + + // Draw the box + rect(bx, by, boxSize, boxSize); +} + +function mousePressed() { + if (overBox) { + locked = true; + fill(255, 255, 255); + } else { + locked = false; + } + xOffset = mouseX - bx; + yOffset = mouseY - by; +} + +function mouseDragged() { + if (locked) { + bx = mouseX - xOffset; + by = mouseY - yOffset; + } +} + +function mouseReleased() { + locked = false; +} diff --git a/src/content/examples/en/21_Input/07_Mouse_Functions.mdx b/src/content/examples/en/21_Input/07_Mouse_Functions.mdx new file mode 100644 index 0000000000..6393221693 --- /dev/null +++ b/src/content/examples/en/21_Input/07_Mouse_Functions.mdx @@ -0,0 +1,9 @@ +--- +title: Mouse Functions +arialabel: >- + Fuschia background with a slightly opaque white square. The user can click on + the square, which turns it white, and drag it around the background. +--- + + +Click on the box and drag it across the screen. diff --git a/src/content/examples/en/21_Input/08_Mouse_Signals.js b/src/content/examples/en/21_Input/08_Mouse_Signals.js new file mode 100644 index 0000000000..5671a698a1 --- /dev/null +++ b/src/content/examples/en/21_Input/08_Mouse_Signals.js @@ -0,0 +1,46 @@ + +let xvals = []; +let yvals = []; +let bvals = []; + +function setup() { + createCanvas(720, 400); + strokeWeight(2); +} + +function draw() { + background(237, 34, 93); + + for (let i = 1; i < width; i++) { + xvals[i - 1] = xvals[i]; + yvals[i - 1] = yvals[i]; + bvals[i - 1] = bvals[i]; + } + // Add the new values to the end of the array + xvals[width - 1] = mouseX; + yvals[width - 1] = mouseY; + + if (mouseIsPressed) { + bvals[width - 1] = 0; + } else { + bvals[width - 1] = 255; + } + + fill(255); + noStroke(); + rect(0, height / 3, width, height / 3 + 1); + + for (let i = 1; i < width; i++) { + stroke(255); + point(i, xvals[i] / 3); + stroke(0); + point(i, height / 3 + yvals[i] / 3); + stroke(255); + line( + i, + (2 * height) / 3 + bvals[i] / 3, + i, + (2 * height) / 3 + bvals[i - 1] / 3 + ); + } +} diff --git a/src/content/examples/en/21_Input/08_Mouse_Signals.mdx b/src/content/examples/en/21_Input/08_Mouse_Signals.mdx new file mode 100644 index 0000000000..4570e4ceb0 --- /dev/null +++ b/src/content/examples/en/21_Input/08_Mouse_Signals.mdx @@ -0,0 +1,13 @@ +--- +title: Mouse Signals +arialabel: >- + Three rows: fuschia on the top and bottom rows and white in the middle row. + The top row tracks the x-coordinates of the mouse, the middle row tracks the + y-coordinates, and the bottom row tracks whether or not the mouse is pressed. +--- + + +Move and click the mouse to generate signals. +The top row is the signal from "mouseX", the middle row is +the signal from "mouseY", and the bottom row is the signal +from "mouseIsPressed". diff --git a/src/content/examples/en/21_Input/09_MouseIsPressed.js b/src/content/examples/en/21_Input/09_MouseIsPressed.js new file mode 100644 index 0000000000..3b637aa1be --- /dev/null +++ b/src/content/examples/en/21_Input/09_MouseIsPressed.js @@ -0,0 +1,16 @@ + +function setup() { + createCanvas(720, 400); + background(230); + strokeWeight(2); +} + +function draw() { + if (mouseIsPressed) { + stroke(255); + } else { + stroke(237, 34, 93); + } + line(mouseX - 66, mouseY, mouseX + 66, mouseY); + line(mouseX, mouseY - 66, mouseX, mouseY + 66); +} diff --git a/src/content/examples/en/21_Input/09_MouseIsPressed.mdx b/src/content/examples/en/21_Input/09_MouseIsPressed.mdx new file mode 100644 index 0000000000..3eeb5a3187 --- /dev/null +++ b/src/content/examples/en/21_Input/09_MouseIsPressed.mdx @@ -0,0 +1,10 @@ +--- +title: Mouse Press +arialabel: >- + User draws pink crosses on a grey background and can change the cross color to + white by clicking the mouse. +--- + + +Move the mouse to position the shape. +Press the mouse button to invert the color. diff --git a/src/content/examples/en/21_Input/10_Rollover.mdx b/src/content/examples/en/21_Input/10_Rollover.mdx new file mode 100644 index 0000000000..c02cd245ad --- /dev/null +++ b/src/content/examples/en/21_Input/10_Rollover.mdx @@ -0,0 +1,94 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |- + + let squareX, squareY; // Position of square button + let circleX, circleY; // Position of circle button + let squareSize = 90; // Width/height of square + let circleSize = 93; // Diameter of circle + + let squareColor; + let circleColor; + let baseColor; + + let squareOver = false; + let circleOver = false; + + function setup() { + createCanvas(710, 400); + squareColor = color(0); + circleColor = color(255); + baseColor = color(102); + circleX = width/2+circleSize/2+10; + circleY = height/2; + squareX = width/2-squareSize-10; + squareY = height/2-squareSize/2; + } + + function draw() { + update(mouseX, mouseY); + + noStroke(); + if (squareOver) { + background(squareColor); + } else if (circleOver) { + background(circleColor); + } else { + background(baseColor); + } + + stroke(255); + fill(squareColor); + square(squareX, squareY, squareSize); + stroke(0); + fill(circleColor); + circle(circleX, circleY, circleSize); + } + + function update(x, y) { + if( overCircle(circleX, circleY, circleSize) ) { + circleOver = true; + squareOver = false; + } else if ( overSquare(squareX, squareY, squareSize) ) { + squareOver = true; + circleOver = false; + } else { + circleOver = squareOver = false; + } + } + + function overSquare(x, y, size) { + if (mouseX >= x && mouseX <= x+size && + mouseY >= y && mouseY <= y+size) { + return true; + } else { + return false; + } + } + + function overCircle(x, y, diameter) { + const disX = x - mouseX; + const disY = y - mouseY; + if(sqrt(sq(disX) + sq(disY)) < diameter/2 ) { + return true; + } else { + return false; + } + } +title: Rollover +arialabel: >- + Black square and white circle on grey background. The background turns black + as the user’s mouth hovers over the black square and the background turns + white as the user’s mouth hovers over the white square. +description: >- + Roll over the colored squares in the center of the image to change the color + of the outside rectangle. + +

This example is ported from the Rollover example + + on the Processing website +--- + + +# Example diff --git a/src/content/examples/en/21_Input/11_Storing_Input.js b/src/content/examples/en/21_Input/11_Storing_Input.js new file mode 100644 index 0000000000..362655f1ff --- /dev/null +++ b/src/content/examples/en/21_Input/11_Storing_Input.js @@ -0,0 +1,30 @@ + +let num = 60; +let mx = []; +let my = []; + +function setup() { + createCanvas(720, 400); + noStroke(); + fill(255, 153); + for (let i = 0; i < num; i++) { + mx.push(i); + my.push(i); + } +} + +function draw() { + background(237, 34, 93); + + // Cycle through the array, using a different entry on each frame. + // Using modulo (%) like this is faster than moving all the values over. + let which = frameCount % num; + mx[which] = mouseX; + my[which] = mouseY; + + for (let i = 0; i < num; i++) { + // which+1 is the smallest (the oldest in the array) + let index = (which + 1 + i) % num; + ellipse(mx[index], my[index], i, i); + } +} diff --git a/src/content/examples/en/21_Input/11_Storing_Input.mdx b/src/content/examples/en/21_Input/11_Storing_Input.mdx new file mode 100644 index 0000000000..7f52bdbc8e --- /dev/null +++ b/src/content/examples/en/21_Input/11_Storing_Input.mdx @@ -0,0 +1,14 @@ +--- +title: Storing Input +arialabel: >- + User draws white circles on a fuschia background. Circles fade in color as the + next circle is drawn. +--- + + +Move the mouse across the screen to +change the position of the circles. The positions +of the mouse are recorded into an array and played +back every frame. Between each frame, the newest +value are added to the end of each array and the +oldest value is deleted. diff --git a/src/content/examples/en/22_Advanced_Data/00_Load_Saved_JSON.mdx b/src/content/examples/en/22_Advanced_Data/00_Load_Saved_JSON.mdx new file mode 100644 index 0000000000..66053e13c8 --- /dev/null +++ b/src/content/examples/en/22_Advanced_Data/00_Load_Saved_JSON.mdx @@ -0,0 +1,130 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: > + + + // Bubble class + + class Bubble { + constructor(x, y, diameter, name) { + this.x = x; + this.y = y; + this.diameter = diameter; + this.radius = diameter / 2; + this.name = name; + + this.over = false; + } + + // Check if mouse is over the bubble + rollover(px, py) { + let d = dist(px, py, this.x, this.y); + this.over = d < this.radius; + } + + // Display the Bubble + display() { + stroke(0); + strokeWeight(0.8); + noFill(); + ellipse(this.x, this.y, this.diameter, this.diameter); + if (this.over) { + fill(0); + textAlign(CENTER); + text(this.name, this.x, this.y + this.radius + 20); + } + } + } + + + let data = {}; // Global object to hold results from the loadJSON call + + let bubbles = []; // Global array to hold all bubble objects + + + // Put any asynchronous data loading in preload to complete before "setup" is + run + + function preload() { + data = loadJSON('assets/bubbles.json'); + } + + + // Convert saved Bubble data into Bubble Objects + + function loadData() { + let bubbleData = data['bubbles']; + for (let i = 0; i < bubbleData.length; i++) { + // Get each object in the array + let bubble = bubbleData[i]; + // Get a position object + let position = bubble['position']; + // Get x,y from position + let x = position['x']; + let y = position['y']; + + // Get diameter and label + let diameter = bubble['diameter']; + let label = bubble['label']; + + // Put object in array + bubbles.push(new Bubble(x, y, diameter, label)); + } + } + + + // Create a new Bubble each time the mouse is clicked. + + function mousePressed() { + // Add diameter and label to bubble + let diameter = random(40, 80); + let label = 'New Label'; + + // Append the new JSON bubble object to the array + bubbles.push(new Bubble(mouseX, mouseY, diameter, label)); + + // Prune Bubble Count if there are too many + if (bubbles.length > 10) { + bubbles.shift(); // remove first item from array + } + } + + + function setup() { + createCanvas(640, 360); + loadData(); + } + + + function draw() { + background(255); + + // Display all bubbles + for (let i = 0; i < bubbles.length; i++) { + bubbles[i].display(); + bubbles[i].rollover(mouseX, mouseY); + } + + // Label directions at bottom + textAlign(LEFT); + fill(0); + text('Click to add bubbles.', 10, height - 10); + } +title: Load Saved JSON +arialabel: 'When the user clicks on the screen, a small white circle appears with a label' +description: >- + Create a Bubble class, instantiate multiple bubbles using data from + + a JSON file, and display results on the screen. + + Because web browsers differ in where they save files, we do not make use of + + saveJSON(), unlike the Processing example.

+ + Based on Daniel Shiffman's LoadSaveJSON + Example for Processing. +--- + + +# Example diff --git a/src/content/examples/en/22_Advanced_Data/01_Load_Saved_Table.mdx b/src/content/examples/en/22_Advanced_Data/01_Load_Saved_Table.mdx new file mode 100644 index 0000000000..335ecff1b6 --- /dev/null +++ b/src/content/examples/en/22_Advanced_Data/01_Load_Saved_Table.mdx @@ -0,0 +1,136 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: > + + + // Bubble class + + class Bubble { + constructor(x, y, diameter, name) { + this.x = x; + this.y = y; + this.diameter = diameter; + this.radius = diameter / 2; + this.name = name; + + this.over = false; + } + + // Check if mouse is over the bubble + rollover(px, py) { + let d = dist(px, py, this.x, this.y); + this.over = d < this.radius; + } + + // Display the Bubble + display() { + stroke(0); + strokeWeight(0.8); + noFill(); + ellipse(this.x, this.y, this.diameter, this.diameter); + if (this.over) { + fill(0); + textAlign(CENTER); + text(this.name, this.x, this.y + this.radius + 20); + } + } + } + + + let table; // Global object to hold results from the loadTable call + + let bubbles = []; // Global array to hold all bubble objects + + + // Put any asynchronous data loading in preload to complete before "setup" is + run + + function preload() { + table = loadTable("assets/bubbles.csv", "header"); + } + + + // Convert saved Bubble data into Bubble Objects + + function loadData() { + const bubbleData = table.getRows(); + // The size of the array of Bubble objects is determined by the total number of rows in the CSV + const length = table.getRowCount(); + + for (let i = 0; i < length; i++) { + // Get position, diameter, name, + const x = bubbleData[i].getNum("x"); + const y = bubbleData[i].getNum("y"); + const diameter = bubbleData[i].getNum("diameter"); + const name = bubbleData[i].getString("name"); + + // Put object in array + bubbles.push(new Bubble(x, y, diameter, name)); + } + } + + + // Create a new Bubble each time the mouse is clicked. + + function mousePressed() { + // Create a new row + let row = table.addRow(); + + let name = "New Bubble"; + let diameter = random(40, 80); + + // Set the values of that row + row.setNum("x", mouseX); + row.setNum("y", mouseY); + row.setNum("diameter", diameter); + row.setString("name", name); + + bubbles.push(new Bubble(mouseX, mouseY, diameter, name)); + + // If the table has more than 10 rows + if (table.getRowCount() > 10) { + // Delete the oldest row + table.removeRow(0); + bubbles.shift(); + } + } + + + function setup() { + createCanvas(640, 360); + loadData(); + } + + + function draw() { + background(255); + + // Display all bubbles + for (let i = 0; i < bubbles.length; i++) { + bubbles[i].display(); + bubbles[i].rollover(mouseX, mouseY); + } + + // Label directions at bottom + textAlign(LEFT); + fill(0); + text("Click to add bubbles.", 10, height - 10); + } +title: Load Saved Table +arialabel: Four white circles with labels +description: >- + Create a Bubble class, instantiate multiple bubbles using data from + + a csv file, and display results on the screen. + + Because web browsers differ in where they save files, we do not make use of + + saveTable(), unlike the Processing example.

+ + Based on Daniel Shiffman's LoadSaveTable + Example for Processing. +--- + + +# Example diff --git a/src/content/examples/en/33_Sound/00_Load_and_Play_Sound.mdx b/src/content/examples/en/33_Sound/00_Load_and_Play_Sound.mdx new file mode 100644 index 0000000000..4c47bbf2d4 --- /dev/null +++ b/src/content/examples/en/33_Sound/00_Load_and_Play_Sound.mdx @@ -0,0 +1,39 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let song; + + function setup() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); + createCanvas(720, 200); + background(255, 0, 0); + } + + function mousePressed() { + if (song.isPlaying()) { + // .isPlaying() returns a boolean + song.stop(); + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } + } +title: Load and Play Sound +arialabel: Red screen turns green when the user clicks on it and plays music +description: >- + Load sound during preload(). Play a sound when canvas is clicked. + +

To run this example locally, you will need + the + + p5.sound library + + a sound file, and a running local + server. +--- + + +# Example diff --git a/src/content/examples/en/33_Sound/01_Preload_Sound.mdx b/src/content/examples/en/33_Sound/01_Preload_Sound.mdx new file mode 100644 index 0000000000..ff0d71a700 --- /dev/null +++ b/src/content/examples/en/33_Sound/01_Preload_Sound.mdx @@ -0,0 +1,53 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + + let song; + + function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); + } + + function setup() { + createCanvas(710, 200); + song.loop(); // song is ready to play during setup() because it was loaded during preload + background(0, 255, 0); + } + + function mousePressed() { + if (song.isPlaying()) { + // .isPlaying() returns a boolean + song.pause(); // .play() will resume from .pause() position + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } + } +title: Preload SoundFile +arialabel: >- + On page load, a green screen plays music. When the user clicks on it, the + screen turns red and stops playing music +description: >- + Call loadSound() during preload() to ensure that the + + sound is completely loaded before setup() is called. It's best to always + + call loadSound() in preload(), otherwise sounds won't necessarily be loaded + + by the time you want to play them in your sketch. + + +

To run this example locally, you will need + the + + p5.sound library + + a sound file, and a running local + server. +--- + + +# Example diff --git a/src/content/examples/en/33_Sound/02_soundFormats.js b/src/content/examples/en/33_Sound/02_soundFormats.js new file mode 100644 index 0000000000..77a0a94f8f --- /dev/null +++ b/src/content/examples/en/33_Sound/02_soundFormats.js @@ -0,0 +1,31 @@ + +let song; + +function preload() { + // we have included both an .ogg file and an .mp3 file + soundFormats('ogg', 'mp3'); + + // if mp3 is not supported by this browser, + // loadSound will load the ogg file + // we have included with our sketch + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + + // song loaded during preload(), ready to play in setup() + song.play(); + background(0, 255, 0); +} + +function mousePressed() { + if (song.isPlaying()) { + // .isPlaying() returns a boolean + song.pause(); + background(255, 0, 0); + } else { + song.play(); // playback will resume from the pause position + background(0, 255, 0); + } +} diff --git a/src/content/examples/en/33_Sound/02_soundFormats.mdx b/src/content/examples/en/33_Sound/02_soundFormats.mdx new file mode 100644 index 0000000000..6211033c93 --- /dev/null +++ b/src/content/examples/en/33_Sound/02_soundFormats.mdx @@ -0,0 +1,29 @@ +--- +title: soundFormats +arialabel: >- + On page load, a green screen plays music. When the user clicks on it, the + screen turns red and stops playing music +--- + + +

Technically, due to patent issues, there is no single +sound format that is supported by all web browsers. While +mp3 is supported across the +latest versions of major browsers on OS X and Windows, for example, +it may not be available on some less mainstream operating systems and +browsers.

+ +

To ensure full compatibility, you can include the same sound file +in multiple formats, e.g. 'sound.mp3' and 'sound.ogg'. (Ogg is an +open source alternative to mp3.) You can convert audio files +into web friendly formats for free online at media.io

. + +

The soundFormats() method tells loadSound which formats +we have included with our sketch. Then, loadSound will +attempt to load the first format that is supported by the +client's web browser.

+ +

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/03_Play_Mode.js b/src/content/examples/en/33_Sound/03_Play_Mode.js new file mode 100644 index 0000000000..19007bc37c --- /dev/null +++ b/src/content/examples/en/33_Sound/03_Play_Mode.js @@ -0,0 +1,32 @@ + +let playMode = 'sustain'; +let sample; + +function setup() { + createCanvas(710, 50); + soundFormats('mp3', 'ogg'); + sample = loadSound('assets/Damscray_-_Dancing_Tiger_02.mp3'); +} + +function draw() { + background(255, 255, 0); + let str = 'Click here to play! Press key to toggle play mode.'; + str += ' Current Play Mode: ' + playMode + '.'; + text(str, 10, height / 2); +} + +function mouseClicked() { + sample.play(); +} +function keyPressed(k) { + togglePlayMode(); +} + +function togglePlayMode() { + if (playMode === 'sustain') { + playMode = 'restart'; + } else { + playMode = 'sustain'; + } + sample.playMode(playMode); +} diff --git a/src/content/examples/en/33_Sound/03_Play_Mode.mdx b/src/content/examples/en/33_Sound/03_Play_Mode.mdx new file mode 100644 index 0000000000..bc97391b4b --- /dev/null +++ b/src/content/examples/en/33_Sound/03_Play_Mode.mdx @@ -0,0 +1,13 @@ +--- +title: Play Mode +arialabel: Yellow screen plays music when user clicks on it +--- + + +

In 'sustain' mode, the sound will overlap with itself. +In 'restart' mode it will stop and then start again. +Click mouse to play a sound file. +Trigger lots of sounds at once! Press any key to change playmode.

+

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/04_Pan_SoundFile.js b/src/content/examples/en/33_Sound/04_Pan_SoundFile.js new file mode 100644 index 0000000000..79c32306dd --- /dev/null +++ b/src/content/examples/en/33_Sound/04_Pan_SoundFile.js @@ -0,0 +1,26 @@ + +let ball = {}; +let soundFile; + +function preload() { + soundFormats('mp3', 'ogg'); + soundFile = loadSound('assets/beatbox.ogg'); +} + +function setup() { + createCanvas(710, 100); +} + +function draw() { + background(0); + ball.x = constrain(mouseX, 0, width); + ellipse(ball.x, height / 2, 100, 100); +} + +function mousePressed() { + // map the ball's x location to a panning degree + // between -1.0 (left) and 1.0 (right) + let panning = map(ball.x, 0, width, -1.0, 1.0); + soundFile.pan(panning); + soundFile.play(); +} diff --git a/src/content/examples/en/33_Sound/04_Pan_SoundFile.mdx b/src/content/examples/en/33_Sound/04_Pan_SoundFile.mdx new file mode 100644 index 0000000000..000bb57c7a --- /dev/null +++ b/src/content/examples/en/33_Sound/04_Pan_SoundFile.mdx @@ -0,0 +1,14 @@ +--- +title: Pan Sound +arialabel: >- + User moves a white ball on black screen, sound effect plays when the user + clicks the screen and the sound comes out more of the speaker closer to the + side the ball is on +--- + + +

Click mouse to play the sound. +Ball position follows mouse and correlates to panning of sound.

+

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/05_Sound_Effect.js b/src/content/examples/en/33_Sound/05_Sound_Effect.js new file mode 100644 index 0000000000..d8c2af819b --- /dev/null +++ b/src/content/examples/en/33_Sound/05_Sound_Effect.js @@ -0,0 +1,63 @@ + +// Adapted from Learning Processing by Daniel Shiffman +// http://www.learningprocessing.com +// Doorbell sample by Corsica_S via freesound.org, +// Creative Commons BY 3.0 + +// A Class to describe a "doorbell" (really a button) +class Doorbell { + constructor(x_, y_, r_) { + // Location and size + this.x = x_; + this.y = y_; + this.r = r_; + } + // Is a point inside the doorbell? (used for mouse rollover, etc.) + contains(mx, my) { + return dist(mx, my, this.x, this.y) < this.r; + } + + // Show the doorbell (hardcoded colors, could be improved) + display(mx, my) { + if (this.contains(mx, my)) { + fill(100); + } else { + fill(175); + } + stroke(0); + strokeWeight(4); + ellipseMode(RADIUS); + ellipse(this.x, this.y, this.r, this.r); + } +} + +// A sound file object +let dingdong; + +// A doorbell object (that will trigger the sound) +let doorbell; + +function setup() { + createCanvas(200, 200); + + // Load the sound file. + // We have included both an MP3 and an OGG version. + soundFormats('mp3', 'ogg'); + dingdong = loadSound('assets/doorbell.mp3'); + + // Create a new doorbell + doorbell = new Doorbell(width / 2, height / 2, 32); +} + +function draw() { + background(255); + // Show the doorbell + doorbell.display(mouseX, mouseY); +} + +function mousePressed() { + // If the user clicks on the doorbell, play the sound! + if (doorbell.contains(mouseX, mouseY)) { + dingdong.play(); + } +} diff --git a/src/content/examples/en/33_Sound/05_Sound_Effect.mdx b/src/content/examples/en/33_Sound/05_Sound_Effect.mdx new file mode 100644 index 0000000000..a497c1ae52 --- /dev/null +++ b/src/content/examples/en/33_Sound/05_Sound_Effect.mdx @@ -0,0 +1,10 @@ +--- +title: Sound Effect +arialabel: Grey circle on a white screen that plays a doorbell sound when pressed on +--- + + +

Play a sound effect when the mouse is clicked inside the circle.

+

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/06_Manipulate_Sound.js b/src/content/examples/en/33_Sound/06_Manipulate_Sound.js new file mode 100644 index 0000000000..143fad55fe --- /dev/null +++ b/src/content/examples/en/33_Sound/06_Manipulate_Sound.js @@ -0,0 +1,39 @@ + +// A sound file object +let song; + +function preload() { + // Load a sound file + song = loadSound('assets/Damscray_DancingTiger.mp3'); +} + +function setup() { + createCanvas(710, 400); + + // Loop the sound forever + // (well, at least until stop() is called) + song.loop(); +} + +function draw() { + background(200); + + // Set the volume to a range between 0 and 1.0 + let volume = map(mouseX, 0, width, 0, 1); + volume = constrain(volume, 0, 1); + song.amp(volume); + + // Set the rate to a range between 0.1 and 4 + // Changing the rate alters the pitch + let speed = map(mouseY, 0.1, height, 0, 2); + speed = constrain(speed, 0.01, 4); + song.rate(speed); + + // Draw some circles to show what is going on + stroke(0); + fill(51, 100); + ellipse(mouseX, 100, 48, 48); + stroke(0); + fill(51, 100); + ellipse(100, mouseY, 48, 48); +} diff --git a/src/content/examples/en/33_Sound/06_Manipulate_Sound.mdx b/src/content/examples/en/33_Sound/06_Manipulate_Sound.mdx new file mode 100644 index 0000000000..1f8c64ea71 --- /dev/null +++ b/src/content/examples/en/33_Sound/06_Manipulate_Sound.mdx @@ -0,0 +1,16 @@ +--- +title: Playback Rate +arialabel: >- + Two grey circles on a light grey background that move as the user moves their + mouse and plays different noises based on their distance from each other +--- + + +

Load a SoundFile and map its playback rate to +mouseY, volume to mouseX. Playback rate is the speed with +which the web audio context processings the sound file information. +Slower rates not only increase the duration of the sound, but also +decrease the pitch because it is being played back at a slower frequency.

+

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/07_Amplitude_Analysis.mdx b/src/content/examples/en/33_Sound/07_Amplitude_Analysis.mdx new file mode 100644 index 0000000000..29c8692d33 --- /dev/null +++ b/src/content/examples/en/33_Sound/07_Amplitude_Analysis.mdx @@ -0,0 +1,76 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let song, analyzer; + + function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); + } + + function setup() { + createCanvas(710, 200); + song.loop(); + + // create a new Amplitude analyzer + analyzer = new p5.Amplitude(); + + // Patch the input to an volume analyzer + analyzer.setInput(song); + } + + function draw() { + background(255); + + // Get the average (root mean square) amplitude + let rms = analyzer.getLevel(); + fill(127); + stroke(0); + + // Draw an ellipse with size based on volume + ellipse(width / 2, height / 2, 10 + rms * 200, 10 + rms * 200); + } +title: Measuring Amplitude +arialabel: >- + Grey circle that increases and decreases in size based on the amplitude of the + music playing +description: >- +

Analyze the amplitude of sound with + + p5.Amplitude.

+ +

Amplitude is the magnitude of vibration. Sound is vibration, + so its amplitude is is closely related to volume / loudness.

+ +

The getLevel() method takes an array + + of amplitude values collected over a small period of time (1024 samples). + + Then it returns the Root Mean Square (RMS) of these values.

+ + +

The original amplitude values for digital audio are between -1.0 and 1.0. + + But the RMS will always be positive, because it is squared. + + And, rather than use instantanous amplitude readings that are sampled at a + rate + + of 44,100 times per second, the RMS is an average over time (1024 samples, in + this case), + + which better represents how we hear amplitude. + +

+ +

To run this example locally, you will need the + + p5.sound library + + a sound file, and a running local + server.

+--- + + +# Example diff --git a/src/content/examples/en/33_Sound/08_Noise_Envelope.js b/src/content/examples/en/33_Sound/08_Noise_Envelope.js new file mode 100644 index 0000000000..8a6932f50c --- /dev/null +++ b/src/content/examples/en/33_Sound/08_Noise_Envelope.js @@ -0,0 +1,38 @@ + +let noise, env, analyzer; + +function setup() { + createCanvas(710, 200); + noise = new p5.Noise(); // other types include 'brown' and 'pink' + noise.start(); + + // multiply noise volume by 0 + // (keep it quiet until we're ready to make noise!) + noise.amp(0); + + env = new p5.Env(); + // set attackTime, decayTime, sustainRatio, releaseTime + env.setADSR(0.001, 0.1, 0.2, 0.1); + // set attackLevel, releaseLevel + env.setRange(1, 0); + + // p5.Amplitude will analyze all sound in the sketch + // unless the setInput() method is used to specify an input. + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // get volume reading from the p5.Amplitude analyzer + let level = analyzer.getLevel(); + + // use level to draw a green rectangle + let levelHeight = map(level, 0, 0.4, 0, height); + fill(100, 250, 100); + rect(0, height, width, -levelHeight); +} + +function mousePressed() { + env.play(noise); +} diff --git a/src/content/examples/en/33_Sound/08_Noise_Envelope.mdx b/src/content/examples/en/33_Sound/08_Noise_Envelope.mdx new file mode 100644 index 0000000000..86fda0fd4d --- /dev/null +++ b/src/content/examples/en/33_Sound/08_Noise_Envelope.mdx @@ -0,0 +1,22 @@ +--- +title: Noise Drum Envelope +arialabel: >- + Lime green rectangle rises from the bottom of a black screen when the screen + is clicked on and plays a sound effect +--- + + +

White Noise is a random audio signal with equal energy +at every part of the frequency spectrum

+ +

An Envelope is a series of fades, defined +as time / value pairs.

+ +

In this example, the p5.Env +will be used to "play" the p5.Noise like a drum by controlling its output +amplitude. A p5.Amplitude will get the level of all sound in the sketch, and +we'll use this value to draw a green rectangle that shows the envelope +in action.

+

To run this example locally, you will need the +p5.sound library and a +sound file.

diff --git a/src/content/examples/en/33_Sound/09_Note_Envelope.js b/src/content/examples/en/33_Sound/09_Note_Envelope.js new file mode 100644 index 0000000000..bf75f75f6c --- /dev/null +++ b/src/content/examples/en/33_Sound/09_Note_Envelope.js @@ -0,0 +1,46 @@ + +let osc, envelope, fft; + +let scaleArray = [60, 62, 64, 65, 67, 69, 71, 72]; +let note = 0; + +function setup() { + createCanvas(710, 200); + osc = new p5.SinOsc(); + + // Instantiate the envelope + envelope = new p5.Env(); + + // set attackTime, decayTime, sustainRatio, releaseTime + envelope.setADSR(0.001, 0.5, 0.1, 0.5); + + // set attackLevel, releaseLevel + envelope.setRange(1, 0); + + osc.start(); + + fft = new p5.FFT(); + noStroke(); +} + +function draw() { + background(20); + + if (frameCount % 60 === 0 || frameCount === 1) { + let midiValue = scaleArray[note]; + let freqValue = midiToFreq(midiValue); + osc.freq(freqValue); + + envelope.play(osc, 0, 0.1); + note = (note + 1) % scaleArray.length; + } + + // plot FFT.analyze() frequency analysis on the canvas + let spectrum = fft.analyze(); + for (let i = 0; i < spectrum.length / 20; i++) { + fill(spectrum[i], spectrum[i] / 10, 0); + let x = map(i, 0, spectrum.length / 20, 0, width); + let h = map(spectrum[i], 0, 255, 0, height); + rect(x, height, spectrum.length / 20, -h); + } +} diff --git a/src/content/examples/en/33_Sound/09_Note_Envelope.mdx b/src/content/examples/en/33_Sound/09_Note_Envelope.mdx new file mode 100644 index 0000000000..fefe86af63 --- /dev/null +++ b/src/content/examples/en/33_Sound/09_Note_Envelope.mdx @@ -0,0 +1,19 @@ +--- +title: Note Envelope +arialabel: Red bars rise on the screen based on the amplitude and the note played +--- + + +

An Envelope is a series of fades, defined +as time / value pairs. In this example, the envelope +will be used to "play" a note by controlling the output +amplitude of an oscillator.

+The p5.Oscillator sends its output through +an internal Web Audio GainNode (p5.Oscillator.output). +By default, that node has a constant value of 0.5. It can +be reset with the osc.amp() method. Or, in this example, an +Envelope takes control of that node, turning the amplitude +up and down like a volume knob.

+

To run this example locally, you will need the +p5.sound library and a +sound file.

diff --git a/src/content/examples/en/33_Sound/10_Oscillator_Waveform.js b/src/content/examples/en/33_Sound/10_Oscillator_Waveform.js new file mode 100644 index 0000000000..062fe45e9d --- /dev/null +++ b/src/content/examples/en/33_Sound/10_Oscillator_Waveform.js @@ -0,0 +1,33 @@ + +let osc, fft; + +function setup() { + createCanvas(720, 256); + + osc = new p5.TriOsc(); // set frequency and type + osc.amp(0.5); + + fft = new p5.FFT(); + osc.start(); +} + +function draw() { + background(255); + + let waveform = fft.waveform(); // analyze the waveform + beginShape(); + strokeWeight(5); + for (let i = 0; i < waveform.length; i++) { + let x = map(i, 0, waveform.length, 0, width); + let y = map(waveform[i], -1, 1, height, 0); + vertex(x, y); + } + endShape(); + + // change oscillator frequency based on mouseX + let freq = map(mouseX, 0, width, 40, 880); + osc.freq(freq); + + let amp = map(mouseY, 0, height, 1, 0.01); + osc.amp(amp); +} diff --git a/src/content/examples/en/33_Sound/10_Oscillator_Waveform.mdx b/src/content/examples/en/33_Sound/10_Oscillator_Waveform.mdx new file mode 100644 index 0000000000..3648cbc10a --- /dev/null +++ b/src/content/examples/en/33_Sound/10_Oscillator_Waveform.mdx @@ -0,0 +1,14 @@ +--- +title: Oscillator Frequency +arialabel: >- + The wavelength travels across the screen and as the user’s mouse moves left, + the wavelength is longer and the frequency is slower and both increase as the + mouse moves right +--- + + +

Control an Oscillator and view the waveform using FFT. +MouseX is mapped to frequency, mouseY is mapped to amplitude.

+

To run this example locally, you will need the +p5.sound library and a +sound file.

diff --git a/src/content/examples/en/33_Sound/11_Live_Input.js b/src/content/examples/en/33_Sound/11_Live_Input.js new file mode 100644 index 0000000000..b551db0ab7 --- /dev/null +++ b/src/content/examples/en/33_Sound/11_Live_Input.js @@ -0,0 +1,26 @@ + +let mic; + +function setup() { + createCanvas(710, 200); + + // Create an Audio input + mic = new p5.AudioIn(); + + // start the Audio Input. + // By default, it does not .connect() (to the computer speakers) + mic.start(); +} + +function draw() { + background(200); + + // Get the overall volume (between 0 and 1.0) + let vol = mic.getLevel(); + fill(127); + stroke(0); + + // Draw an ellipse with height based on volume + let h = map(vol, 0, 1, height, 0); + ellipse(width / 2, h - 25, 50, 50); +} diff --git a/src/content/examples/en/33_Sound/11_Live_Input.mdx b/src/content/examples/en/33_Sound/11_Live_Input.mdx new file mode 100644 index 0000000000..b791de569b --- /dev/null +++ b/src/content/examples/en/33_Sound/11_Live_Input.mdx @@ -0,0 +1,16 @@ +--- +title: Mic Input +arialabel: >- + Grey circle rises from the bottom of the screen based on the amplitude of the + user’s audio input into their mic +--- + + +

Get audio input from your computer's microphone. +Make noise to float the ellipse.

+

Note: p5.AudioIn contains its own p5.Amplitude object, +so you can call getLevel on p5.AudioIn without +creating a p5.Amplitude.

+

To run this example locally, you will need the +p5.sound library +and a running local server.

diff --git a/src/content/examples/en/33_Sound/12_FFT_Spectrum.js b/src/content/examples/en/33_Sound/12_FFT_Spectrum.js new file mode 100644 index 0000000000..8b125762a7 --- /dev/null +++ b/src/content/examples/en/33_Sound/12_FFT_Spectrum.js @@ -0,0 +1,24 @@ + +let mic, fft; + +function setup() { + createCanvas(710, 400); + noFill(); + + mic = new p5.AudioIn(); + mic.start(); + fft = new p5.FFT(); + fft.setInput(mic); +} + +function draw() { + background(200); + + let spectrum = fft.analyze(); + + beginShape(); + for (i = 0; i < spectrum.length; i++) { + vertex(i, map(spectrum[i], 0, 255, height, 0)); + } + endShape(); +} diff --git a/src/content/examples/en/33_Sound/12_FFT_Spectrum.mdx b/src/content/examples/en/33_Sound/12_FFT_Spectrum.mdx new file mode 100644 index 0000000000..ebe39635b4 --- /dev/null +++ b/src/content/examples/en/33_Sound/12_FFT_Spectrum.mdx @@ -0,0 +1,12 @@ +--- +title: Frequency Spectrum +arialabel: >- + Audio waves are graphed on a grey screen based on the user’s audio input into + their mic +--- + + +

Visualize the frequency spectrum of live audio input.

+

To run this example locally, you will need the +p5.sound library +and a running local server.

diff --git a/src/content/examples/en/33_Sound/13_Mic_Threshold.js b/src/content/examples/en/33_Sound/13_Mic_Threshold.js new file mode 100644 index 0000000000..0098bf7675 --- /dev/null +++ b/src/content/examples/en/33_Sound/13_Mic_Threshold.js @@ -0,0 +1,42 @@ + +// Adapted from Learning Processing, Daniel Shiffman +// learningprocessing.com +let input; +let analyzer; + +function setup() { + createCanvas(710, 200); + background(255); + + // Create an Audio input + input = new p5.AudioIn(); + + input.start(); +} + +function draw() { + // Get the overall volume (between 0 and 1.0) + let volume = input.getLevel(); + + // If the volume > 0.1, a rect is drawn at a random location. + // The louder the volume, the larger the rectangle. + let threshold = 0.1; + if (volume > threshold) { + stroke(0); + fill(0, 100); + rect(random(40, width), random(height), volume * 50, volume * 50); + } + + // Graph the overall potential volume, w/ a line at the threshold + let y = map(volume, 0, 1, height, 0); + let ythreshold = map(threshold, 0, 1, height, 0); + + noStroke(); + fill(175); + rect(0, 0, 20, height); + // Then draw a rectangle on the graph, sized according to volume + fill(0); + rect(0, y, 20, y); + stroke(0); + line(0, ythreshold, 19, ythreshold); +} diff --git a/src/content/examples/en/33_Sound/13_Mic_Threshold.mdx b/src/content/examples/en/33_Sound/13_Mic_Threshold.mdx new file mode 100644 index 0000000000..0f8a7557ac --- /dev/null +++ b/src/content/examples/en/33_Sound/13_Mic_Threshold.mdx @@ -0,0 +1,14 @@ +--- +title: Mic Threshold +arialabel: >- + Black rectangle is drawn on the bottom of a bar based on the amplitude of the + user’s audio input. At a certain minimum amplitude, grey squares are randomly + drawn on the right side of the screen +--- + + +

Trigger an event (draw a rectangle) when the Audio Input +volume surpasses a threshold.

+

To run this example locally, you will need the +p5.sound library +and a running local server.

diff --git a/src/content/examples/en/33_Sound/14_Filter_LowPass.js b/src/content/examples/en/33_Sound/14_Filter_LowPass.js new file mode 100644 index 0000000000..91880f870c --- /dev/null +++ b/src/content/examples/en/33_Sound/14_Filter_LowPass.js @@ -0,0 +1,52 @@ + +let soundFile; +let fft; + +let filter, filterFreq, filterRes; + +function preload() { + soundFormats('mp3', 'ogg'); + soundFile = loadSound('assets/beat'); +} + +function setup() { + createCanvas(710, 256); + fill(255, 40, 255); + + // loop the sound file + soundFile.loop(); + + filter = new p5.LowPass(); + + // Disconnect soundfile from master output. + // Then, connect it to the filter, so that we only hear the filtered sound + soundFile.disconnect(); + soundFile.connect(filter); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // Map mouseX to a the cutoff frequency from the lowest + // frequency (10Hz) to the highest (22050Hz) that humans can hear + filterFreq = map(mouseX, 0, width, 10, 22050); + + // Map mouseY to resonance (volume boost) at the cutoff frequency + filterRes = map(mouseY, 0, height, 15, 5); + + // set filter parameters + filter.set(filterFreq, filterRes); + + // Draw every value in the FFT spectrum analysis where + // x = lowest (10Hz) to highest (22050Hz) frequencies, + // h = energy (amplitude / volume) at that frequency + let spectrum = fft.analyze(); + noStroke(); + for (let i = 0; i < spectrum.length; i++) { + let x = map(i, 0, spectrum.length, 0, width); + let h = -height + map(spectrum[i], 0, 255, height, 0); + rect(x, height, width / spectrum.length, h); + } +} diff --git a/src/content/examples/en/33_Sound/14_Filter_LowPass.mdx b/src/content/examples/en/33_Sound/14_Filter_LowPass.mdx new file mode 100644 index 0000000000..6ab63fdee2 --- /dev/null +++ b/src/content/examples/en/33_Sound/14_Filter_LowPass.mdx @@ -0,0 +1,16 @@ +--- +title: Filter LowPass +arialabel: >- + The lowpass filter changes intensity as the user’s mouse moves left and right + on the screen +--- + + +Apply a p5.LowPass filter to a p5.SoundFile. +Visualize the sound with FFT. +Map mouseX to the the filter's cutoff frequency +and mouseY to resonance/width of the a BandPass filter + +

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/15_Filter_BandPass.js b/src/content/examples/en/33_Sound/15_Filter_BandPass.js new file mode 100644 index 0000000000..e8db0994ee --- /dev/null +++ b/src/content/examples/en/33_Sound/15_Filter_BandPass.js @@ -0,0 +1,41 @@ + +let noise; +let fft; +let filter, filterFreq, filterWidth; + +function setup() { + createCanvas(710, 256); + fill(255, 40, 255); + + filter = new p5.BandPass(); + + noise = new p5.Noise(); + + noise.disconnect(); // Disconnect soundfile from master output... + filter.process(noise); // ...and connect to filter so we'll only hear BandPass. + noise.start(); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // Map mouseX to a bandpass freq from the FFT spectrum range: 10Hz - 22050Hz + filterFreq = map(mouseX, 0, width, 10, 22050); + // Map mouseY to resonance/width + filterWidth = map(mouseY, 0, height, 0, 90); + // set filter parameters + filter.set(filterFreq, filterWidth); + + // Draw every value in the FFT spectrum analysis where + // x = lowest (10Hz) to highest (22050Hz) frequencies, + // h = energy / amplitude at that frequency + let spectrum = fft.analyze(); + noStroke(); + for (let i = 0; i < spectrum.length; i++) { + let x = map(i, 0, spectrum.length, 0, width); + let h = -height + map(spectrum[i], 0, 255, height, 0); + rect(x, height, width / spectrum.length, h); + } +} diff --git a/src/content/examples/en/33_Sound/15_Filter_BandPass.mdx b/src/content/examples/en/33_Sound/15_Filter_BandPass.mdx new file mode 100644 index 0000000000..79b783a7ce --- /dev/null +++ b/src/content/examples/en/33_Sound/15_Filter_BandPass.mdx @@ -0,0 +1,16 @@ +--- +title: Filter BandPass +arialabel: >- + The bandpass filter changes intensity as the user’s mouse moves left and right + on the screen +--- + + +Apply a p5.BandPass filter to white noise. +Visualize the sound with FFT. +Map mouseX to the bandpass frequency +and mouseY to resonance/width of the a BandPass filter + +

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/16_Delay.js b/src/content/examples/en/33_Sound/16_Delay.js new file mode 100644 index 0000000000..011418c09f --- /dev/null +++ b/src/content/examples/en/33_Sound/16_Delay.js @@ -0,0 +1,45 @@ + + +let soundFile, analyzer, delay; + +function preload() { + soundFormats('ogg', 'mp3'); + soundFile = loadSound('assets/beatbox.mp3'); +} + +function setup() { + createCanvas(710, 400); + + soundFile.disconnect(); // so we'll only hear delay + + delay = new p5.Delay(); + delay.process(soundFile, 0.12, 0.7, 2300); + delay.setType('pingPong'); // a stereo effect + + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // get volume reading from the p5.Amplitude analyzer + let level = analyzer.getLevel(); + + // use level to draw a green rectangle + let levelHeight = map(level, 0, 0.1, 0, height); + fill(100, 250, 100); + rect(0, height, width, -levelHeight); + + let filterFreq = map(mouseX, 0, width, 60, 15000); + filterFreq = constrain(filterFreq, 60, 15000); + let filterRes = map(mouseY, 0, height, 3, 0.01); + filterRes = constrain(filterRes, 0.01, 3); + delay.filter(filterFreq, filterRes); + let delTime = map(mouseY, 0, width, 0.2, 0.01); + delTime = constrain(delTime, 0.01, 0.2); + delay.delayTime(delTime); +} + +function mousePressed() { + soundFile.play(); +} diff --git a/src/content/examples/en/33_Sound/16_Delay.mdx b/src/content/examples/en/33_Sound/16_Delay.mdx new file mode 100644 index 0000000000..9f4882d1bb --- /dev/null +++ b/src/content/examples/en/33_Sound/16_Delay.mdx @@ -0,0 +1,17 @@ +--- +title: Delay +arialabel: >- + When the user clicks their mouse on the black screen, music plays, and a lime + green rectangle appears from the bottom at a height level correlating with the + amplitude of the sound as it plays +--- + + +Click the mouse to hear the p5.Delay process a SoundFile. +MouseX controls the p5.Delay Filter Frequency. +MouseY controls both the p5.Delay Time and Resonance. +Visualize the resulting sound's volume with an Amplitude object. + +

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/17_Reverb.js b/src/content/examples/en/33_Sound/17_Reverb.js new file mode 100644 index 0000000000..b2d0a354f3 --- /dev/null +++ b/src/content/examples/en/33_Sound/17_Reverb.js @@ -0,0 +1,28 @@ + +let sound, reverb; + +function preload() { + soundFormats('mp3', 'ogg'); + soundFile = loadSound('assets/Damscray_DancingTiger'); + + // disconnect the default connection + // so that we only hear the sound via the reverb.process + soundFile.disconnect(); +} + +function setup() { + createCanvas(720, 100); + background(0); + + reverb = new p5.Reverb(); + + // sonnects soundFile to reverb with a + // reverbTime of 6 seconds, decayRate of 0.2% + reverb.process(soundFile, 6, 0.2); + + reverb.amp(4); // turn it up! +} + +function mousePressed() { + soundFile.play(); +} diff --git a/src/content/examples/en/33_Sound/17_Reverb.mdx b/src/content/examples/en/33_Sound/17_Reverb.mdx new file mode 100644 index 0000000000..976ba182f8 --- /dev/null +++ b/src/content/examples/en/33_Sound/17_Reverb.mdx @@ -0,0 +1,12 @@ +--- +title: Reverb +arialabel: 'When the user clicks on the black screen, sound with reverb is played' +--- + + +Reverb gives depth and perceived space to a sound. Here, +noise is processed with reverb. + +

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/18_Convolution_Reverb.mdx b/src/content/examples/en/33_Sound/18_Convolution_Reverb.mdx new file mode 100644 index 0000000000..94863b302c --- /dev/null +++ b/src/content/examples/en/33_Sound/18_Convolution_Reverb.mdx @@ -0,0 +1,110 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let sound, env, cVerb, fft; + let currentIR = 0; + let rawImpulse; + + function preload() { + // we have included both MP3 and OGG versions of all the impulses/sounds + soundFormats('ogg', 'mp3'); + + // create a p5.Convolver + cVerb = createConvolver('assets/bx-spring'); + + // add Impulse Responses to cVerb.impulses array, in addition to bx-spring + cVerb.addImpulse('assets/small-plate'); + cVerb.addImpulse('assets/drum'); + cVerb.addImpulse('assets/beatbox'); + cVerb.addImpulse('assets/concrete-tunnel'); + + // load a sound that will be processed by the p5.ConvultionReverb + sound = loadSound('assets/Damscray_DancingTiger'); + } + + function setup() { + createCanvas(710, 400); + rawImpulse = loadSound('assets/' + cVerb.impulses[currentIR].name); + + // disconnect from master output... + sound.disconnect(); + // ... and process with cVerb + // so that we only hear the reverb + cVerb.process(sound); + + fft = new p5.FFT(); + } + + function draw() { + background(30); + fill(0, 255, 40); + + let spectrum = fft.analyze(); + + // Draw every value in the frequencySpectrum array as a rectangle + noStroke(); + for (let i = 0; i < spectrum.length; i++) { + let x = map(i, 0, spectrum.length, 0, width); + let h = -height + map(spectrum[i], 0, 255, height, 0); + rect(x, height, width / spectrum.length, h); + } + } + + function mousePressed() { + // cycle through the array of cVerb.impulses + currentIR++; + if (currentIR >= cVerb.impulses.length) { + currentIR = 0; + } + cVerb.toggleImpulse(currentIR); + + // play the sound through the impulse + sound.play(); + + // display the current Impulse Response name (the filepath) + println('Convolution Impulse Response: ' + cVerb.impulses[currentIR].name); + + rawImpulse.setPath('assets/' + cVerb.impulses[currentIR].name); + } + + // play the impulse (without convolution) + function keyPressed() { + rawImpulse.play(); + } +title: Convolution Reverb +arialabel: >- + Sound with reverb plays when the user clicks the screen and lime green bars + appear based on the amplitude of the sound +description: >- +

The p5.Convolver can recreate the sound of actual + + spaces using convolution. Convolution takes an Impulse Response, + + (the sound of a room reverberating), and uses that to + + recreate the sound of that space.

Click to play a sound through + + convolution. Every time you click, the sound is convolved with + + a different Impulse Response. To hear the Impulse Response itself, + + press any key.

+ + +

To run this example locally, you will need the + + p5.sound library + + a sound file, and a running local server. + + These convolution samples are Creative Commons BY + + + + recordinghopkins

+--- + + +# Example diff --git a/src/content/examples/en/33_Sound/19_Record_Save.js b/src/content/examples/en/33_Sound/19_Record_Save.js new file mode 100644 index 0000000000..b96c92811e --- /dev/null +++ b/src/content/examples/en/33_Sound/19_Record_Save.js @@ -0,0 +1,48 @@ + +let mic, recorder, soundFile; + +let state = 0; // mousePress will increment from Record, to Stop, to Play + +function setup() { + createCanvas(400, 400); + background(200); + fill(0); + text('Enable mic and click the mouse to begin recording', 20, 20); + + // create an audio in + mic = new p5.AudioIn(); + + // users must manually enable their browser microphone for recording to work properly! + mic.start(); + + // create a sound recorder + recorder = new p5.SoundRecorder(); + + // connect the mic to the recorder + recorder.setInput(mic); + + // create an empty sound file that we will use to playback the recording + soundFile = new p5.SoundFile(); +} + +function mousePressed() { + // use the '.enabled' boolean to make sure user enabled the mic (otherwise we'd record silence) + if (state === 0 && mic.enabled) { + // Tell recorder to record to a p5.SoundFile which we will use for playback + recorder.record(soundFile); + + background(255, 0, 0); + text('Recording now! Click to stop.', 20, 20); + state++; + } else if (state === 1) { + recorder.stop(); // stop recorder, and send the result to soundFile + + background(0, 255, 0); + text('Recording stopped. Click to play & save', 20, 20); + state++; + } else if (state === 2) { + soundFile.play(); // play the result! + saveSound(soundFile, 'mySound.wav'); // save file + state++; + } +} diff --git a/src/content/examples/en/33_Sound/19_Record_Save.mdx b/src/content/examples/en/33_Sound/19_Record_Save.mdx new file mode 100644 index 0000000000..78f60f790e --- /dev/null +++ b/src/content/examples/en/33_Sound/19_Record_Save.mdx @@ -0,0 +1,18 @@ +--- +title: Record Save Audio +arialabel: >- + The user clicks the grey screen to begin recording audio input through their + mic. When recording the screen turns red. The user clicks their mouse again to + end recording and the screen turns green. If the user clicks their mouse again + the audio recording is saved to their downloads as a wav file +--- + + +Record a sound, play it back and save +it as a .wav file to the client's computer. +We need three objects: a p5.AudioIn (mic / sound source), +p5.SoundRecorder (records the sound), and a +p5.SoundFile (play back / save). +

To run this example locally, you will need the +p5.sound library +a sound file, and a running local server.

diff --git a/src/content/examples/en/33_Sound/21_FreqModulation.mdx b/src/content/examples/en/33_Sound/21_FreqModulation.mdx new file mode 100644 index 0000000000..3444380ffe --- /dev/null +++ b/src/content/examples/en/33_Sound/21_FreqModulation.mdx @@ -0,0 +1,232 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + + let carrier; // this is the oscillator we will hear + let modulator; // this oscillator will modulate the frequency of the carrier + + let analyzer; // we'll use this visualize the waveform + + // the carrier frequency pre-modulation + let carrierBaseFreq = 220; + + // min/max ranges for modulator + let modMaxFreq = 112; + let modMinFreq = 0; + let modMaxDepth = 150; + let modMinDepth = -150; + + function setup() { + let cnv = createCanvas(800, 400); + noFill(); + + carrier = new p5.Oscillator('sine'); + carrier.amp(0); // set amplitude + carrier.freq(carrierBaseFreq); // set frequency + carrier.start(); // start oscillating + + // try changing the type to 'square', 'sine' or 'triangle' + modulator = new p5.Oscillator('sawtooth'); + modulator.start(); + + // add the modulator's output to modulate the carrier's frequency + modulator.disconnect(); + carrier.freq(modulator); + + // create an FFT to analyze the audio + analyzer = new p5.FFT(); + + // fade carrier in/out on mouseover / touch start + toggleAudio(cnv); + } + + function draw() { + background(30); + + // map mouseY to modulator freq between a maximum and minimum frequency + let modFreq = map(mouseY, height, 0, modMinFreq, modMaxFreq); + modulator.freq(modFreq); + + // change the amplitude of the modulator + // negative amp reverses the sawtooth waveform, and sounds percussive + // + let modDepth = map(mouseX, 0, width, modMinDepth, modMaxDepth); + modulator.amp(modDepth); + + // analyze the waveform + waveform = analyzer.waveform(); + + // draw the shape of the waveform + stroke(255); + strokeWeight(10); + beginShape(); + for (let i = 0; i < waveform.length; i++) { + let x = map(i, 0, waveform.length, 0, width); + let y = map(waveform[i], -1, 1, -height / 2, height / 2); + vertex(x, y + height / 2); + } + endShape(); + + strokeWeight(1); + // add a note about what's happening + text('Modulator Frequency: ' + modFreq.toFixed(3) + ' Hz', 20, 20); + text( + 'Modulator Amplitude (Modulation Depth): ' + modDepth.toFixed(3), + 20, + 40 + ); + text( + 'Carrier Frequency (pre-modulation): ' + carrierBaseFreq + ' Hz', + width / 2, + 20 + ); + } + + // helper function to toggle sound + function toggleAudio(cnv) { + cnv.mouseOver(function() { + carrier.amp(1.0, 0.01); + }); + cnv.touchStarted(function() { + carrier.amp(1.0, 0.01); + }); + cnv.mouseOut(function() { + carrier.amp(0.0, 1.0); + }); + } +title: Frequency Modulation +arialabel: >- + White sound waves on black background change as the user moves their mouse. + Labels of modulator frequency and amplitude change as the user moves their + mouse too. There is also a label of carrier frequency at 220 Hz +description: >- +

Frequency Modulation is a powerful form of synthesis. + + In its simplest form, FM involves two oscillators, referred + + to as the carrier and the modulator. As the modulator's waveform oscillates + + between some minimum and maximum amplitude value, that momentary value + + is added to ("modulates") the frequency of the carrier.

+ +

The carrier is typically set to oscillate at an audible frequency + + that we perceive as a pitch—in this case, it is a sine wave oscilaltor at + 220Hz, + + equivalent to an "A3" note. The carrier is connected to master output by + default + + (this is the case for all p5.Oscillators).

+ +

We will disconnect the modulator from master output, + + and instead connect to the frequency of the carrier: + + carrier.freq(modulator). This adds the output amplitude of the + + modulator to the frequency of the carrier.

+ +

+ + Modulation Depth describes how much the carrier frequency will + modulate. + + It is based on the amplitude of the modulator. + + The modulator produces a continuous stream of amplitude values that we will + add + + to the carrier frequency. An amplitude of zero means silence, so the + modulation will + + have no effect. An amplitude of 1.0 scales the range of output values + + between +1.0 and -1.0. That is the standard range for sound that gets sent to + + your speakers, but in FM we are instead sending the modulator's output to the + carrier frequency, + + where we'd barely notice the +1Hz / -1Hz modulation. + + So we will typically increase the amplitude ("depth") of the modulator to + numbers much higher than what + + we might send to our speakers.

+ +

Modulation Frequency is the speed of modulation. When the modulation + frequency is lower + + than 20Hz, we stop hearing its frequency as pitch, and start to hear it as a + beating rhythm. + + For example, try 7.5Hz at a depth of 20 to mimic the "vibrato" effect of an + operatic vocalist. + + The term for this is Low Frequency Oscillator, or LFO. Modulators set to + higher frequencies can + + also produce interesting effects, especially when the frequency has a harmonic + relationship + + to the carrier signal. For example, listen to what happens when the + modulator's frequency is + + half or twice that of the carrier. This is the basis for FM Synthesis, + developed by John Chowning + + in the 1960s, which came to revolutionize synthesis in the 1980s and is often + used to synthesize + + brass and bell-like sounds. + + +

In this example,

+ + - MouseX controls the modulation depth (the amplitude of the modulator) from + -150 to 150. + + When the modulator's amplitude is set to 0 (in the middle), notice how the + modulation + + has no effect. The greater (the absolute value of) the number, the greater the + effect. + + If the modulator waveform is symetrical like a square [], sine + ~ + + or triangle /\, the negative amplitude will be the same as + positive amplitude. + + But in this example, the modulator is an asymetrical sawtooth wave, shaped + like this /. + + When we multiply it by a negative number, it goes backwards like this \. To + best + + observe the difference, try lowering the frequency. + +

+ +

- MouseY controls the frequency of the modulator from 0 to 112 Hz. + + Try comparing modulation frequencies below the audible range (which starts + around 20hz), + + and above it, especially in a harmonic relationship to the carrier frequency + (which is 220hz, so + + try half that, 1/3, 1/4 etc...). + + +

You will need to include the + + p5.sound library + + for this example to work in your own project.

+--- + + +# Example diff --git a/src/content/examples/en/33_Sound/22_AmplitudeModulation.mdx b/src/content/examples/en/33_Sound/22_AmplitudeModulation.mdx new file mode 100644 index 0000000000..a6843edfd2 --- /dev/null +++ b/src/content/examples/en/33_Sound/22_AmplitudeModulation.mdx @@ -0,0 +1,106 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: | + + let carrier; // this is the oscillator we will hear + let modulator; // this oscillator will modulate the amplitude of the carrier + let fft; // we'll visualize the waveform + + function setup() { + createCanvas(800, 400); + noFill(); + background(30); // alpha + + carrier = new p5.Oscillator(); // connects to master output by default + carrier.freq(340); + carrier.amp(0); + // carrier's amp is 0 by default, giving our modulator total control + + carrier.start(); + + modulator = new p5.Oscillator('triangle'); + modulator.disconnect(); // disconnect the modulator from master output + modulator.freq(5); + modulator.amp(1); + modulator.start(); + + // Modulate the carrier's amplitude with the modulator + // Optionally, we can scale the signal. + carrier.amp(modulator.scale(-1, 1, 1, -1)); + + // create an fft to analyze the audio + fft = new p5.FFT(); + } + + function draw() { + background(30, 30, 30, 100); // alpha + + // map mouseY to moodulator freq between 0 and 20hz + let modFreq = map(mouseY, 0, height, 20, 0); + modulator.freq(modFreq); + + let modAmp = map(mouseX, 0, width, 0, 1); + modulator.amp(modAmp, 0.01); // fade time of 0.1 for smooth fading + + // analyze the waveform + waveform = fft.waveform(); + + // draw the shape of the waveform + drawWaveform(); + + drawText(modFreq, modAmp); + } + + function drawWaveform() { + stroke(240); + strokeWeight(4); + beginShape(); + for (let i = 0; i < waveform.length; i++) { + let x = map(i, 0, waveform.length, 0, width); + let y = map(waveform[i], -1, 1, -height / 2, height / 2); + vertex(x, y + height / 2); + } + endShape(); + } + + function drawText(modFreq, modAmp) { + strokeWeight(1); + text('Modulator Frequency: ' + modFreq.toFixed(3) + ' Hz', 20, 20); + text('Modulator Amplitude: ' + modAmp.toFixed(3), 20, 40); + } +title: Amplitude Modulation +arialabel: >- + White sound waves on black background change as the user moves their mouse. + Labels of modulator frequency and amplitude change as the user moves their + mouse too +description: |- +

Amplitude Modulation involves two oscillators, referred + to as the carrier and the modulator, where the modulator controls + the carrier's amplitude.

+ +

The carrier is typically set at an audible frequency (i.e. 440 Hz) + and connected to master output by default. The carrier.amp is + set to zero because we will have the modulator control its amplitude.

+ +

The modulator is disconnected from master output. Instead, it is connected + to the amplitude of the Carrier, like this: carrier.amp(modulator).

+ +

In this example...

+

- MouseX controls the amplitude of the modulator + from 0 to 1. When the modulator's amplitude is set to 0, the + amplitude modulation has no effect.

+ +

- MouseY controls the frequency of the modulator from 0 to 20hz. + This range is lower frequencies than humans can hear, and we perceive the + modulation as a rhythm. This range can simulate effects such as Tremolo. + Ring Modulation is a type of Amplitude Modulation where the original + carrier signal is not present, and often involves modulation at a faster + frequency.

+ +

You will need to include the + p5.sound library + for this example to work in your own project.

+--- + + +# Example diff --git a/src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js b/src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js new file mode 100644 index 0000000000..84aafb4f07 --- /dev/null +++ b/src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js @@ -0,0 +1,55 @@ + + +// Position Variables +let x = 0; +let y = 0; + +// Speed - Velocity +let vx = 0; +let vy = 0; + +// Acceleration +let ax = 0; +let ay = 0; + +let vMultiplier = 0.007; +let bMultiplier = 0.6; + +function setup() { + createCanvas(displayWidth, displayHeight); + fill(0); +} + +function draw() { + background(255); + ballMove(); + ellipse(x, y, 30, 30); +} + +function ballMove() { + ax = accelerationX; + ay = accelerationY; + + vx = vx + ay; + vy = vy + ax; + y = y + vy * vMultiplier; + x = x + vx * vMultiplier; + + // Bounce when touch the edge of the canvas + if (x < 0) { + x = 0; + vx = -vx * bMultiplier; + } + if (y < 0) { + y = 0; + vy = -vy * bMultiplier; + } + if (x > width - 20) { + x = width - 20; + vx = -vx * bMultiplier; + } + if (y > height - 20) { + y = height - 20; + vy = -vy * bMultiplier; + } +} diff --git a/src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.mdx b/src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.mdx new file mode 100644 index 0000000000..6839e0ddae --- /dev/null +++ b/src/content/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.mdx @@ -0,0 +1,6 @@ +--- +title: Acceleration Ball Bounce +--- + + +Move an ellipse around based on accelerationX and accelerationY values, and bounces when touch the edge of the canvas. diff --git a/src/content/examples/en/35_Mobile/01_Simple_Draw.js b/src/content/examples/en/35_Mobile/01_Simple_Draw.js new file mode 100644 index 0000000000..238cb509a3 --- /dev/null +++ b/src/content/examples/en/35_Mobile/01_Simple_Draw.js @@ -0,0 +1,12 @@ + + +function setup() { + createCanvas(displayWidth, displayHeight); + strokeWeight(10); + stroke(0); +} + +function touchMoved() { + line(mouseX, mouseY, pmouseX, pmouseY); + return false; +} diff --git a/src/content/examples/en/35_Mobile/01_Simple_Draw.mdx b/src/content/examples/en/35_Mobile/01_Simple_Draw.mdx new file mode 100644 index 0000000000..eb66b5e4eb --- /dev/null +++ b/src/content/examples/en/35_Mobile/01_Simple_Draw.mdx @@ -0,0 +1,6 @@ +--- +title: Simple Draw +--- + + +Touch to draw on the screen using mouseX, mouseY, pmouseX, and pmouseY values. diff --git a/src/content/examples/en/35_Mobile/02_Acceleration_Color.js b/src/content/examples/en/35_Mobile/02_Acceleration_Color.js new file mode 100644 index 0000000000..bd21cab105 --- /dev/null +++ b/src/content/examples/en/35_Mobile/02_Acceleration_Color.js @@ -0,0 +1,21 @@ + + +let r, g, b; + +function setup() { + createCanvas(displayWidth, displayHeight); + r = random(50, 255); + g = random(0, 200); + b = random(50, 255); +} + +function draw() { + background(r, g, b); + console.log('draw'); +} + +function deviceMoved() { + r = map(accelerationX, -90, 90, 100, 175); + g = map(accelerationY, -90, 90, 100, 200); + b = map(accelerationZ, -90, 90, 100, 200); +} diff --git a/src/content/examples/en/35_Mobile/02_Acceleration_Color.mdx b/src/content/examples/en/35_Mobile/02_Acceleration_Color.mdx new file mode 100644 index 0000000000..a374370086 --- /dev/null +++ b/src/content/examples/en/35_Mobile/02_Acceleration_Color.mdx @@ -0,0 +1,6 @@ +--- +title: Acceleration Color +--- + + +Use deviceMoved() to detect when the device is rotated. The background RGB color values are mapped to accelerationX, accelerationY, and accelerationZ values. diff --git a/src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.js b/src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.js new file mode 100644 index 0000000000..b9900fa53c --- /dev/null +++ b/src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.js @@ -0,0 +1,110 @@ + + +let balls = []; + +let threshold = 30; +let accChangeX = 0; +let accChangeY = 0; +let accChangeT = 0; + +function setup() { + createCanvas(displayWidth, displayHeight); + + for (let i = 0; i < 20; i++) { + balls.push(new Ball()); + } +} + +function draw() { + background(0); + + for (let i = 0; i < balls.length; i++) { + balls[i].move(); + balls[i].display(); + } + + checkForShake(); +} + +function checkForShake() { + // Calculate total change in accelerationX and accelerationY + accChangeX = abs(accelerationX - pAccelerationX); + accChangeY = abs(accelerationY - pAccelerationY); + accChangeT = accChangeX + accChangeY; + // If shake + if (accChangeT >= threshold) { + for (let i = 0; i < balls.length; i++) { + balls[i].shake(); + balls[i].turn(); + } + } + // If not shake + else { + for (let i = 0; i < balls.length; i++) { + balls[i].stopShake(); + balls[i].turn(); + balls[i].move(); + } + } +} + +// Ball class +class Ball { + constructor() { + this.x = random(width); + this.y = random(height); + this.diameter = random(10, 30); + this.xspeed = random(-2, 2); + this.yspeed = random(-2, 2); + this.oxspeed = this.xspeed; + this.oyspeed = this.yspeed; + this.direction = 0.7; + } + + move() { + this.x += this.xspeed * this.direction; + this.y += this.yspeed * this.direction; + } + + // Bounce when touch the edge of the canvas + turn() { + if (this.x < 0) { + this.x = 0; + this.direction = -this.direction; + } else if (this.y < 0) { + this.y = 0; + this.direction = -this.direction; + } else if (this.x > width - 20) { + this.x = width - 20; + this.direction = -this.direction; + } else if (this.y > height - 20) { + this.y = height - 20; + this.direction = -this.direction; + } + } + + // Add to xspeed and yspeed based on + // the change in accelerationX value + shake() { + this.xspeed += random(5, accChangeX / 3); + this.yspeed += random(5, accChangeX / 3); + } + + // Gradually slows down + stopShake() { + if (this.xspeed > this.oxspeed) { + this.xspeed -= 0.6; + } else { + this.xspeed = this.oxspeed; + } + if (this.yspeed > this.oyspeed) { + this.yspeed -= 0.6; + } else { + this.yspeed = this.oyspeed; + } + } + + display() { + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} diff --git a/src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.mdx b/src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.mdx new file mode 100644 index 0000000000..ac8de3e8fc --- /dev/null +++ b/src/content/examples/en/35_Mobile/03_Shake_Ball_Bounce.mdx @@ -0,0 +1,7 @@ +--- +title: Shake Ball Bounce +--- + + +Create a Ball class, instantiate multiple objects, move it around the screen, and bounce when touch the edge of the canvas. +Detect shake event based on total change in accelerationX and accelerationY and speed up or slow down objects based on detection. diff --git a/src/content/examples/en/35_Mobile/04_Tilted_3D_Box.js b/src/content/examples/en/35_Mobile/04_Tilted_3D_Box.js new file mode 100644 index 0000000000..60ee9365c6 --- /dev/null +++ b/src/content/examples/en/35_Mobile/04_Tilted_3D_Box.js @@ -0,0 +1,12 @@ + +function setup() { + createCanvas(displayWidth, displayHeight, WEBGL); +} + +function draw() { + background(250); + normalMaterial(); + rotateX(accelerationX * 0.01); + rotateY(accelerationY * 0.01); + box(100, 100, 100); +} diff --git a/src/content/examples/en/35_Mobile/04_Tilted_3D_Box.mdx b/src/content/examples/en/35_Mobile/04_Tilted_3D_Box.mdx new file mode 100644 index 0000000000..c008fe7419 --- /dev/null +++ b/src/content/examples/en/35_Mobile/04_Tilted_3D_Box.mdx @@ -0,0 +1,6 @@ +--- +title: Tilted 3D Box +--- + + +Use mobile to tilt a box diff --git a/src/content/examples/en/90_Hello_P5/01_shapes.js b/src/content/examples/en/90_Hello_P5/01_shapes.js new file mode 100644 index 0000000000..b635ce2ffd --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/01_shapes.js @@ -0,0 +1,25 @@ + +function setup() { + // Create the canvas + createCanvas(720, 400); + background(200); + + // Set colors + fill(204, 101, 192, 127); + stroke(127, 63, 120); + + // A rectangle + rect(40, 120, 120, 40); + // An ellipse + ellipse(240, 240, 80, 80); + // A triangle + triangle(300, 100, 320, 100, 310, 80); + + // A design for a simple flower + translate(580, 200); + noStroke(); + for (let i = 0; i < 10; i ++) { + ellipse(0, 30, 20, 80); + rotate(PI/5); + } +} diff --git a/src/content/examples/en/90_Hello_P5/01_shapes.mdx b/src/content/examples/en/90_Hello_P5/01_shapes.mdx new file mode 100644 index 0000000000..56f52974d4 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/01_shapes.mdx @@ -0,0 +1,9 @@ +--- +title: Simple Shapes +arialabel: >- + Grey canvas with 4 pink shapes: a circle, a rectangle, a triangle, and a + flower +--- + + +This examples includes a circle, square, triangle, and a flower. diff --git a/src/content/examples/en/90_Hello_P5/02_interactivity.js b/src/content/examples/en/90_Hello_P5/02_interactivity.js new file mode 100644 index 0000000000..a2c07670e4 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/02_interactivity.js @@ -0,0 +1,33 @@ + + +// for red, green, and blue color values +let r, g, b; + +function setup() { + createCanvas(720, 400); + // Pick colors randomly + r = random(255); + g = random(255); + b = random(255); +} + +function draw() { + background(127); + // Draw a circle + strokeWeight(2); + stroke(r, g, b); + fill(r, g, b, 127); + ellipse(360, 200, 200, 200); +} + +// When the user clicks the mouse +function mousePressed() { + // Check if mouse is inside the circle + let d = dist(mouseX, mouseY, 360, 200); + if (d < 100) { + // Pick new random color values + r = random(255); + g = random(255); + b = random(255); + } +} diff --git a/src/content/examples/en/90_Hello_P5/02_interactivity.mdx b/src/content/examples/en/90_Hello_P5/02_interactivity.mdx new file mode 100644 index 0000000000..e6c6220b1e --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/02_interactivity.mdx @@ -0,0 +1,9 @@ +--- +title: Interactivity 1 +arialabel: >- + Dark grey background with a colored circle in the middle that changes color + when clicked ons +--- + + +The circle changes color when you click on it. diff --git a/src/content/examples/en/90_Hello_P5/03_interactivity.js b/src/content/examples/en/90_Hello_P5/03_interactivity.js new file mode 100644 index 0000000000..50866c0388 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/03_interactivity.js @@ -0,0 +1,22 @@ + + +// A HTML range slider +let slider; + +function setup() { + createCanvas(720, 400); + // hue, saturation, and brightness + colorMode(HSB, 255); + // slider has a range between 0 and 255 with a starting value of 127 + slider = createSlider(0, 255, 127); +} + +function draw() { + background(127); + strokeWeight(2); + + // Set the hue according to the slider + stroke(slider.value(), 255, 255); + fill(slider.value(), 255, 255, 127); + ellipse(360, 200, 200, 200); +} \ No newline at end of file diff --git a/src/content/examples/en/90_Hello_P5/03_interactivity.mdx b/src/content/examples/en/90_Hello_P5/03_interactivity.mdx new file mode 100644 index 0000000000..35a73e42c6 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/03_interactivity.mdx @@ -0,0 +1,9 @@ +--- +title: Interactivity 2 +arialabel: >- + Dark grey background with a colored circle in the middle that changes color as + the user drags a slider on the bottom +--- + + +The circle changes color when you move the slider. diff --git a/src/content/examples/en/90_Hello_P5/04_animate.js b/src/content/examples/en/90_Hello_P5/04_animate.js new file mode 100644 index 0000000000..eb77f0abd6 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/04_animate.js @@ -0,0 +1,30 @@ + +// Where is the circle +let x, y; + +function setup() { + createCanvas(720, 400); + // Starts in the middle + x = width / 2; + y = height; +} + +function draw() { + background(200); + + // Draw a circle + stroke(50); + fill(100); + ellipse(x, y, 24, 24); + + // Jiggling randomly on the horizontal axis + x = x + random(-1, 1); + // Moving up at a constant speed + y = y - 1; + + // Reset to the bottom + if (y < 0) { + y = height; + } +} + diff --git a/src/content/examples/en/90_Hello_P5/04_animate.mdx b/src/content/examples/en/90_Hello_P5/04_animate.mdx new file mode 100644 index 0000000000..a1d2ae17b6 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/04_animate.mdx @@ -0,0 +1,9 @@ +--- +title: Animation +arialabel: >- + Light grey background with a dark grey circle that is traveling up from the + middle of the bottom of the screen as it moves slightly side-to-side +--- + + +The circle moves. diff --git a/src/content/examples/en/90_Hello_P5/04_flocking.mdx b/src/content/examples/en/90_Hello_P5/04_flocking.mdx new file mode 100644 index 0000000000..95c9519cba --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/04_flocking.mdx @@ -0,0 +1,198 @@ +--- +layout: '@layouts/reference/ExampleLayout.astro' +code: |+ + + let boids = []; + + function setup() { + createCanvas(720, 400); + + // Add an initial set of boids into the system + for (let i = 0; i < 100; i++) { + boids[i] = new Boid(random(width), random(height)); + } + } + + function draw() { + background(51); + // Run all the boids + for (let i = 0; i < boids.length; i++) { + boids[i].run(boids); + } + } + + // Boid class + // Methods for Separation, Cohesion, Alignment added + class Boid { + constructor(x, y) { + this.acceleration = createVector(0, 0); + this.velocity = p5.Vector.random2D(); + this.position = createVector(x, y); + this.r = 3.0; + this.maxspeed = 3; // Maximum speed + this.maxforce = 0.05; // Maximum steering force + } + + run(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); + } + + // Forces go into acceleration + applyForce(force) { + this.acceleration.add(force); + } + + // We accumulate a new acceleration each time based on three rules + flock(boids) { + let sep = this.separate(boids); // Separation + let ali = this.align(boids); // Alignment + let coh = this.cohesion(boids); // Cohesion + // Arbitrarily weight these forces + sep.mult(2.5); + ali.mult(1.0); + coh.mult(1.0); + // Add the force vectors to acceleration + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); + } + + // Method to update location + update() { + // Update velocity + this.velocity.add(this.acceleration); + // Limit speed + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // Reset acceleration to 0 each cycle + this.acceleration.mult(0); + } + + // A method that calculates and applies a steering force towards a target + // STEER = DESIRED MINUS VELOCITY + seek(target) { + let desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target + // Normalize desired and scale to maximum speed + desired.normalize(); + desired.mult(this.maxspeed); + // Steering = Desired minus Velocity + let steer = p5.Vector.sub(desired, this.velocity); + steer.limit(this.maxforce); // Limit to maximum steering force + return steer; + } + + // Draw boid as a circle + render() { + fill(127, 127); + stroke(200); + ellipse(this.position.x, this.position.y, 16, 16); + } + + // Wraparound + borders() { + if (this.position.x < -this.r) this.position.x = width + this.r; + if (this.position.y < -this.r) this.position.y = height + this.r; + if (this.position.x > width + this.r) this.position.x = -this.r; + if (this.position.y > height + this.r) this.position.y = -this.r; + } + + // Separation + // Method checks for nearby boids and steers away + separate(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // For every boid in the system, check if it's too close + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) + if ((d > 0) && (d < desiredseparation)) { + // Calculate vector pointing away from neighbor + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // Weight by distance + steer.add(diff); + count++; // Keep track of how many + } + } + // Average -- divide by how many + if (count > 0) { + steer.div(count); + } + + // As long as the vector is greater than 0 + if (steer.mag() > 0) { + // Implement Reynolds: Steering = Desired - Velocity + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; + } + + // Alignment + // For every nearby boid in the system, calculate the average velocity + align(boids) { + let neighbordist = 50; + let sum = createVector(0, 0); + let count = 0; + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + if ((d > 0) && (d < neighbordist)) { + sum.add(boids[i].velocity); + count++; + } + } + if (count > 0) { + sum.div(count); + sum.normalize(); + sum.mult(this.maxspeed); + let steer = p5.Vector.sub(sum, this.velocity); + steer.limit(this.maxforce); + return steer; + } else { + return createVector(0, 0); + } + } + + // Cohesion + // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location + cohesion(boids) { + let neighbordist = 50; + let sum = createVector(0, 0); // Start with empty vector to accumulate all locations + let count = 0; + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + if ((d > 0) && (d < neighbordist)) { + sum.add(boids[i].position); // Add location + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // Steer towards the location + } else { + return createVector(0, 0); + } + } + } + +title: Flocking +arialabel: >- + Light grey circles on a dark grey background that travel across the screen in + flocks or groups +description: >- + Demonstration of Craig Reynolds' + "Flocking" behavior.
+ + (Rules: Cohesion, Separation, Alignment.)
+ + From natureofcode.com. +--- + + +# Example diff --git a/src/content/examples/en/90_Hello_P5/05_weather.js b/src/content/examples/en/90_Hello_P5/05_weather.js new file mode 100644 index 0000000000..322824b776 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/05_weather.js @@ -0,0 +1,67 @@ + + +// A wind direction vector +let wind; +// Circle position +let position; + +function setup() { + createCanvas(720, 200); + // Request the data from metaweather.com + let url = 'https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/2459115/'; + loadJSON(url,gotWeather); + // Circle starts in the middle + position = createVector(width/2, height/2); + // wind starts as (0,0) + wind = createVector(); +} + +function draw() { + background(200); + + // This section draws an arrow pointing in the direction of wind + push(); + translate(32, height - 32); + // Rotate by the wind's angle + rotate(wind.heading() + PI/2); + noStroke(); + fill(255); + ellipse(0, 0, 48, 48); + + stroke(45, 123, 182); + strokeWeight(3); + line(0, -16, 0, 16); + + noStroke(); + fill(45, 123, 182); + triangle(0, -18, -6, -10, 6, -10); + pop(); + + // Move in the wind's direction + position.add(wind); + + stroke(0); + fill(51); + ellipse(position.x, position.y, 16, 16); + + if (position.x > width) position.x = 0; + if (position.x < 0) position.x = width; + if (position.y > height) position.y = 0; + if (position.y < 0) position.y = height; +} + +function gotWeather(weather) { + let weather_today = weather.consolidated_weather[0] + // Get the angle (convert to radians) + let angle = radians(Number(weather_today.wind_direction)); + // Get the wind speed + let windmag = Number(weather_today.wind_speed); + + // Display as HTML elements + let temperatureDiv = createDiv(floor(weather_today.the_temp) + '°C'); + let windDiv = createDiv("WIND " + windmag + " MPH"); + + // Make a vector + wind = p5.Vector.fromAngle(angle); +} + diff --git a/src/content/examples/en/90_Hello_P5/05_weather.mdx b/src/content/examples/en/90_Hello_P5/05_weather.mdx new file mode 100644 index 0000000000..0e1e6c0602 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/05_weather.mdx @@ -0,0 +1,11 @@ +--- +title: Weather +arialabel: >- + Uses weather from Metweather website to control a blue arrow and grey circle + on the screen. The blue arrow is in a white circle on the bottom left corner + and points in the direction of the wind. The small dark grey circle is on a + grey background and moves in the window’s direction +--- + + +This example grabs JSON weather data from www.metaweather.com. diff --git a/src/content/examples/en/90_Hello_P5/06_drawing.js b/src/content/examples/en/90_Hello_P5/06_drawing.js new file mode 100644 index 0000000000..76c12e0cbd --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/06_drawing.js @@ -0,0 +1,129 @@ + + +// All the paths +let paths = []; +// Are we painting? +let painting = false; +// How long until the next circle +let next = 0; +// Where are we now and where were we? +let current; +let previous; + +function setup() { + createCanvas(720, 400); + current = createVector(0,0); + previous = createVector(0,0); +}; + +function draw() { + background(200); + + // If it's time for a new point + if (millis() > next && painting) { + + // Grab mouse position + current.x = mouseX; + current.y = mouseY; + + // New particle's force is based on mouse movement + let force = p5.Vector.sub(current, previous); + force.mult(0.05); + + // Add new particle + paths[paths.length - 1].add(current, force); + + // Schedule next circle + next = millis() + random(100); + + // Store mouse values + previous.x = current.x; + previous.y = current.y; + } + + // Draw all paths + for( let i = 0; i < paths.length; i++) { + paths[i].update(); + paths[i].display(); + } +} + +// Start it up +function mousePressed() { + next = 0; + painting = true; + previous.x = mouseX; + previous.y = mouseY; + paths.push(new Path()); +} + +// Stop +function mouseReleased() { + painting = false; +} + +// A Path is a list of particles +class Path { + constructor() { + this.particles = []; + this.hue = random(100); + } + + add(position, force) { + // Add a new particle with a position, force, and hue + this.particles.push(new Particle(position, force, this.hue)); + } + + // Display plath + update() { + for (let i = 0; i < this.particles.length; i++) { + this.particles[i].update(); + } + } + + // Display plath + display() { + // Loop through backwards + for (let i = this.particles.length - 1; i >= 0; i--) { + // If we shold remove it + if (this.particles[i].lifespan <= 0) { + this.particles.splice(i, 1); + // Otherwise, display it + } else { + this.particles[i].display(this.particles[i+1]); + } + } + + } +} + +// Particles along the path +class Particle { + constructor(position, force, hue) { + this.position = createVector(position.x, position.y); + this.velocity = createVector(force.x, force.y); + this.drag = 0.95; + this.lifespan = 255; + } + + update() { + // Move it + this.position.add(this.velocity); + // Slow it down + this.velocity.mult(this.drag); + // Fade it out + this.lifespan--; + } + + // Draw particle and connect it with a line + // Draw a line to another + display(other) { + stroke(0, this.lifespan); + fill(0, this.lifespan/2); + ellipse(this.position.x,this.position.y, 8, 8); + // If we need to draw a line + if (other) { + line(this.position.x, this.position.y, other.position.x, other.position.y); + } + } +} diff --git a/src/content/examples/en/90_Hello_P5/06_drawing.mdx b/src/content/examples/en/90_Hello_P5/06_drawing.mdx new file mode 100644 index 0000000000..3c7097a4af --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/06_drawing.mdx @@ -0,0 +1,10 @@ +--- +title: Drawing +arialabel: >- + When the user clicks and drags on the light grey background, the user draws a + pattern of dark grey circles connected by dark grey lines which also + disappears after a bit. +--- + + +Generative painting program. diff --git a/src/content/examples/en/90_Hello_P5/07_song.js b/src/content/examples/en/90_Hello_P5/07_song.js new file mode 100644 index 0000000000..da5bf1360f --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/07_song.js @@ -0,0 +1,112 @@ + +// The midi notes of a scale +let notes = [ 60, 62, 64, 65, 67, 69, 71]; + +// For automatically playing the song +let index = 0; +let song = [ + { note: 4, duration: 400, display: "D" }, + { note: 0, duration: 200, display: "G" }, + { note: 1, duration: 200, display: "A" }, + { note: 2, duration: 200, display: "B" }, + { note: 3, duration: 200, display: "C" }, + { note: 4, duration: 400, display: "D" }, + { note: 0, duration: 400, display: "G" }, + { note: 0, duration: 400, display: "G" } +]; +let trigger = 0; +let autoplay = false; +let osc; + +function setup() { + createCanvas(720, 400); + let div = createDiv("Click to play notes or ") + div.id("instructions"); + let button = createButton("play song automatically."); + button.parent("instructions"); + // Trigger automatically playing + button.mousePressed(function() { + if (!autoplay) { + index = 0; + autoplay = true; + } + }); + + // A triangle oscillator + osc = new p5.TriOsc(); + // Start silent + osc.start(); + osc.amp(0); +} + +// A function to play a note +function playNote(note, duration) { + osc.freq(midiToFreq(note)); + // Fade it in + osc.fade(0.5,0.2); + + // If we sest a duration, fade it out + if (duration) { + setTimeout(function() { + osc.fade(0,0.2); + }, duration-50); + } +} + +function draw() { + + // If we are autoplaying and it's time for the next note + if (autoplay && millis() > trigger){ + playNote(notes[song[index].note], song[index].duration); + trigger = millis() + song[index].duration; + // Move to the next note + index ++; + // We're at the end, stop autoplaying. + } else if (index >= song.length) { + autoplay = false; + } + + + // Draw a keyboard + + // The width for each key + let w = width / notes.length; + for (let i = 0; i < notes.length; i++) { + let x = i * w; + // If the mouse is over the key + if (mouseX > x && mouseX < x + w && mouseY < height) { + // If we're clicking + if (mouseIsPressed) { + fill(100,255,200); + // Or just rolling over + } else { + fill(127); + } + } else { + fill(200); + } + + // Or if we're playing the song, let's highlight it too + if (autoplay && i === song[index-1].note) { + fill(100,255,200); + } + + // Draw the key + rect(x, 0, w-1, height-1); + } + +} + +// When we click +function mousePressed(event) { + if(event.button == 0 && event.clientX < width && event.clientY < height) { + // Map mouse to the key index + let key = floor(map(mouseX, 0, width, 0, notes.length)); + playNote(notes[key]); + } +} + +// Fade it out when we release +function mouseReleased() { + osc.fade(0,0.5); +} diff --git a/src/content/examples/en/90_Hello_P5/07_song.mdx b/src/content/examples/en/90_Hello_P5/07_song.mdx new file mode 100644 index 0000000000..072a1ea455 --- /dev/null +++ b/src/content/examples/en/90_Hello_P5/07_song.mdx @@ -0,0 +1,13 @@ +--- +title: Song +arialabel: >- + Grey background divided into 7 vertical rectangles. When the user hovers, the + rectangle turns dark grey. When the user clicks, each rectangle turns cyan and + plays a different note. +--- + + +Play a song. +You will need to include the +p5.sound +library for this example to work in your own project. diff --git a/src/scripts/builders/reference.ts b/src/scripts/builders/reference.ts index b765aa43f3..d5445c19e0 100644 --- a/src/scripts/builders/reference.ts +++ b/src/scripts/builders/reference.ts @@ -2,7 +2,7 @@ import fs from "fs/promises"; import matter from "gray-matter"; import { remark } from "remark"; import remarkMDX from "remark-mdx"; -import { parseLibrary } from "../parsers/reference"; +import { parseLibraryReference } from "../parsers/reference"; import type { ReferenceClassDefinition, ReferenceClassItem, @@ -28,7 +28,7 @@ const modulePathTree = { modules: {}, classes: {} } as ReferenceModulePathTree; /* Main function to build the reference docs, runs automatically with Node execution */ export const buildReference = async () => { // Gets the JSON output from parsing - const parsedOutput = await parseLibrary(); + const parsedOutput = await parseLibraryReference(); if (!parsedOutput) { console.error("Unable to build reference docs to error in parsing!"); return; diff --git a/src/scripts/parsers/reference.ts b/src/scripts/parsers/reference.ts index c2d9766816..b8c5c92417 100644 --- a/src/scripts/parsers/reference.ts +++ b/src/scripts/parsers/reference.ts @@ -7,16 +7,16 @@ import type { ParsedLibraryReference } from "../../../types/parsers.interface"; // Derive the directory name (__dirname equivalent) in ES Module scope const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Local directory to clone the p5.js library -const localPath = path.join(__dirname, "in", "p5.js"); +const inputPath = path.join(__dirname, "in", "p5.js"); // Local path to save the YUIDoc output -const yuidocOutputPath = path.join(__dirname, "out", "data.json"); +const outputPath = path.join(__dirname, "out", "data.json"); /** * Main function to clone the p5.js library and save the YUIDoc output to a file */ -export const parseLibrary = +export const parseLibraryReference = async (): Promise => { - await cloneLibraryRepo(localPath); + await cloneLibraryRepo(inputPath); await saveYuidocOutput(); return getYuidocOutput(); }; @@ -26,7 +26,7 @@ export const parseLibrary = * returns the parsed YUIDoc output */ const getYuidocOutput = async (): Promise => { - const outputFilePath = path.join(yuidocOutputPath, "data.json"); + const outputFilePath = path.join(outputPath, "data.json"); const output = await readFile(outputFilePath); if (output) { try { @@ -45,7 +45,7 @@ export const saveYuidocOutput = async () => { console.log("Running YUIDoc command and capturing output..."); try { await new Promise((resolve, reject) => { - exec(`yuidoc -p --outdir ${yuidocOutputPath}`, (error, stdout) => { + exec(`yuidoc -p --outdir ${outputPath}`, (error, stdout) => { if (error) { console.error(`Error running YUIDoc command: ${error}`); reject(error); diff --git a/src/scripts/utils.ts b/src/scripts/utils.ts index c1a3e2bbdd..b88a2818c3 100644 --- a/src/scripts/utils.ts +++ b/src/scripts/utils.ts @@ -113,6 +113,33 @@ export const readFile = async (filePath: string) => { } }; +/** + * Get all the file paths in a directory and its subdirectories + * @param directory Top-level directory to search for files + * @returns string[] an array of all the file paths in the directory and its subdirectories + */ +export const getAllFiles = async (directory: string) => { + const files: string[] = []; + + // Function to recursively read the directory and its subdirectories + const readDirectory = async (dir: string) => { + const entries = await fs.readdir(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + await readDirectory(fullPath); + } else { + files.push(fullPath); + } + } + }; + + await readDirectory(directory); + return files; +}; + /** * The preprocessor.js file in the library repo has an absolute path to the parameterData.json file. * This function modifies the absolute path to a relative path.