diff --git a/dist/assets/css/all.css b/dist/assets/css/all.css new file mode 100644 index 0000000000..59bca3d6de --- /dev/null +++ b/dist/assets/css/all.css @@ -0,0 +1,4 @@ +/*! normalize.css v1.1.0 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}button,html,input,select,textarea{font-family:sans-serif}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:courier new,monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:after,q:before{content:"";content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ol,nav ul{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure,form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0} +;code[class*=language-],pre[class*=language-],textarea{color:#222;font-family:Inconsolata,Consolas,Monaco,Andale Mono,monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;font-size:1em!important}pre[class*=language-]{position:relative;padding:.5em 1em;margin:.5em 0 0 -.5em;border-left:.5em solid #afafaf;background-color:#fff;background-image:-webkit-linear-gradient(transparent 50%,rgba(69,142,209,.06) 0);background-image:-o-linear-gradient(transparent 50%,rgba(69,142,209,.06) 50%);background-image:-webkit-gradient(linear,left top,left bottom,color-stop(50%,transparent),color-stop(50%,rgba(69,142,209,.06)));background-image:linear-gradient(transparent 50%,rgba(69,142,209,.06) 0);-webkit-background-size:2.9em 2.9em;background-size:2.9em 2.9em;-webkit-background-origin:content-box;background-origin:content-box;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{margin-bottom:1em}:not(pre)>code[class*=language-]{position:relative;padding:.2em;border-radius:.3em;color:#333;border:1px solid rgba(0,0,0,.1)}:not(pre)>code[class*=language-]:after,pre[class*=language-]:after{right:.75em;left:auto}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#a0a0a0}.token.punctuation{color:#666}.token.boolean,.token.constant,.token.function-name,.token.number,.token.property,.token.symbol,.token.tag{color:#dc3787}.token.attr-name,.token.builtin,.token.function,.token.selector,.token.string{color:#00a1d3}.token.entity,.token.operator,.token.url,.token.variable{color:#a67f59;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.class-name,.token.keyword{color:#704f21}.token.important,.token.regex{color:#e90}.language-css .token.string,.style .token.string{color:#a67f59;background:hsla(0,0%,100%,.5)}.token.important{font-weight:400}.token.entity{cursor:help}.namespace{opacity:.7}@media screen and (max-width:767px){pre[class*=language-]:after,pre[class*=language-]:before{bottom:14px;-webkit-box-shadow:none;box-shadow:none}}.token.cr:before,.token.lf:before,.token.tab:not(:empty):before{color:#e0d7d1}pre.line-numbers{padding-left:3.8em;counter-reset:linenumber}pre.line-numbers,pre.line-numbers>code{position:relative}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right} +;button,html,input,select{color:#222}textarea{line-height:1.45em;padding:.5em 1em;border:none}body{font-size:1em;line-height:1.4}::-moz-selection{background:#b3d4fc;text-shadow:none}::selection{background:#b3d4fc;text-shadow:none}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}img{vertical-align:middle}img.med_left{width:300px;float:left}img.med_right{width:300px;float:right}img.small_left{width:200px;float:left}img.smaller_left{width:140px;float:left}img.small_right{width:200px;float:right}img.smaller_right{width:140px;float:right}img.small_center{width:200px;margin-left:250px}img.small{width:160px}img.med{width:400px}img.med_center{width:400px;margin-left:150px}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}.tagline{display:none}#home-page .home{pointer-events:none}#home-page .home a{pointer-events:all}#lockup>a{position:relative;display:block;width:200px;height:90px}#logo_image{position:absolute;top:0}#menu,#menu.top_menu{list-style:none;font-family:Montserrat,sans-serif;width:100%;margin:0 0 1em;padding:0;height:100%;font-size:1.3em}#menu.top_menu li{display:inline}#home-sketch{position:absolute;top:0;left:0;z-index:-2}@media screen and (max-width:780px){.sidebar-menu{clear:both;max-height:0;-webkit-transition:max-height .4s ease-out;-o-transition:max-height .4s ease-out;transition:max-height .4s ease-out;overflow:hidden}.sidebar-menu-nav-element{width:91vw}.sidebar-menu a{display:block;text-align:center;padding-bottom:.11em;border-bottom:.11em dashed transparent}.sidebar-menu-icon{top:2rem;cursor:pointer;float:right;padding:28px 20px;position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin-bottom:5rem}.sidebar-menu-icon .sidebar-nav-icon{background:#ed225d;display:block;height:2px;position:relative;-webkit-transition:background .4s ease-out;-o-transition:background .4s ease-out;transition:background .4s ease-out;width:18px}.sidebar-menu-icon .sidebar-nav-icon:after,.sidebar-menu-icon .sidebar-nav-icon:before{background:#ed225d;content:"";display:block;height:100%;position:absolute;-webkit-transition:all .4s ease-out;-o-transition:all .4s ease-out;transition:all .4s ease-out;width:100%}.sidebar-menu-icon .sidebar-nav-icon:before{top:5px}.sidebar-menu-icon .sidebar-nav-icon:after{top:-5px}.sidebar-menu-btn{display:none}.sidebar-menu-btn:checked~.sidebar-menu{max-height:475px}.sidebar-menu-btn:checked~.sidebar-menu-icon .sidebar-nav-icon{background:transparent}.sidebar-menu-btn:checked~.sidebar-menu-icon .sidebar-nav-icon:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);top:0}.sidebar-menu-btn:checked~.sidebar-menu-icon .sidebar-nav-icon:after{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);top:0}}.sidebar-menu-btn{display:none}#home-sketch-frame{position:fixed;width:100%;height:100%;left:0;top:0;z-index:-2;overflow:hidden;pointer-events:all;border:0}#credits{position:fixed;bottom:0;left:0;z-index:2;padding:1em;font-size:.7em}#skip-to-content{position:absolute;left:0;top:40px;z-index:5;background-color:#ed225d;color:#fff;width:auto;height:50px;border:none;outline-style:none;text-align:center;font-size:25px;padding:5px;opacity:0}#skip-to-content:focus{opacity:1}.button_box{padding:.4em .6em;margin:.5em 0;font-family:Montserrat,sans-serif;display:inline-block}.button_box,.download_box{border:1px solid #ed225d;color:#333}.download_box{padding:.4em;margin:0 1.75em 0 0;width:18.65em;float:left;height:7.45em;position:relative}.button_box:hover,.download_box:hover{border:1px solid #ed225d;background:#ed225d;color:#fff}.download_box.half_box{width:10.83em;margin-right:1.75em;float:left}.download_box.half_box.last_box{margin-right:0}.download_box .download_name{font-size:1em;margin:0;padding-bottom:.3em;border-bottom:.09em dashed #ed225d;line-height:1.2;font-family:Montserrat,sans-serif;display:block}.download_box:hover .download_name{-webkit-text-stroke-width:0;border-bottom-color:#fff}.download_box p{font-size:.65em;margin:0;position:absolute;bottom:1em}.download_box svg{height:.65em;width:.65em;position:absolute;bottom:3.5em}.download_box:hover svg{fill:#fff}.download_box h4+p{display:block}#download-page .link_group{width:100%;margin-bottom:3em}.download_box{margin-top:1em}.support div.download_box{margin-top:1em;margin-bottom:1em}#download-page .support p{font-size:.8em;position:static;margin-top:.3em}#slideshow{margin:1em 0}#slideshow p{font-size:.8em;color:#ababab;line-height:1.2em;margin-top:.5em}.extra{color:#fff;position:absolute;bottom:.65em;right:.9em;font-weight:700;-ms-transform:rotate(-12deg);-webkit-transform:rotate(-12deg);-o-transform:rotate(-12deg);transform:rotate(-12deg);font-size:.8em}#get-started-page .edit_space{position:relative;-webkit-box-ordinal-group:4;-webkit-order:3;-ms-flex-order:3;order:3;margin-bottom:4.8125em}#get-started-page .edit_space .copy_button{color:#2d7bb6;border-color:rgba(45,123,182,.25);float:right;margin:1.5em 0 1.5em .5em;background:hsla(0,0%,100%,.7);position:absolute;z-index:2;left:31.33em;top:-1.5em}@media (max-width:780px){#get-started-page .edit_space .copy_button{left:6.44em}}@media (max-width:600px){#get-started-page .edit_space .copy_button{left:5.91em}}#examples-page .column{margin-bottom:2em}#reference-page main h1{float:left}.reference-group h2{font-size:1.5em}.reference-group h3{font-size:1em;font-family:Montserrat,sans-serif;margin-top:.5em}div.reference-group{display:inline-block}div.reference-subgroups{margin:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}div.reference-subgroup{width:11em;margin-bottom:1em}#reference-page .params table p{display:inline;font-size:inherit}#reference-page .param-optional{color:#afafaf}#item{width:100%}#item h2{margin:.777em 0 0;font-size:1.444em;font-weight:inherit;font-family:Inconsolata,consolas,monospace;color:#00a1d3}#item h3{font-size:1.33em;margin:1em 0 0}#item ul{margin-top:.5em}#item li{margin-bottom:1em}.description{clear:both;display:block;width:100%}.syntax pre{width:100%}.item-wrapper,.list-wrapper{float:left;outline:none}.paramname{display:inline-block;min-width:25%;margin-right:1%;font-size:1.2em}.paramtype p{display:inline;font-size:1em}.paramtype{font-size:1.2em;width:73%;vertical-align:top}#library-page .group-name,.paramtype{display:inline-block}#library-page .group-name:hover{color:#ed225d}.example div{position:relative}.example-content .example_code{position:relative;left:1em;padding-top:0;margin-top:1rem;border:none;width:30.5em;max-width:100%}.example-content .example_code.norender{left:0;margin-left:0}.example-content .edit_space{position:absolute;top:0;left:0;margin-top:-.5em;width:100%;pointer-events:none}.example-content .edit_space *{pointer-events:auto}.example-content .edit_space ul{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse;position:relative;pointer-events:none}.example-content .edit_space ul li button{font-family:Montserrat,sans-serif;font-size:1em;color:#ccc;border:1px solid hsla(0,0%,78.4%,.15);background:transparent;outline:none;margin-top:.25em}.example-content .edit_space ul li button:hover,.example_container.editing ul li button{color:#2d7bb6;border-color:rgba(45,123,182,.25)}.example-content .edit_space .edit_area{position:absolute;top:.5em;left:120px;width:30.5em;display:none;font-family:monospace;padding:1.5em .5em .5em;font-size:15pt}.display_button{margin-bottom:2em;font-family:Montserrat,sans-serif;font-size:1em;color:#2d7bb6;border:1px solid rgba(45,123,182,.25);background:transparent;outline:none}.example-content .example_container{width:36em;max-width:100%;border-top:.09em dashed #333;padding-top:.5em;margin-top:2em;min-height:120px;height:-webkit-calc(110% + 20px);height:calc(110% + 20px);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}.example-content .example_container:first-of-type{margin-top:1em}@media (max-width:600px){.example-content .example_code{margin-top:.2rem;left:.5rem}.example-content .example_container{width:100%;min-height:220px;height:-webkit-calc(110% + 120px);height:calc(110% + 120px);display:block}.example-content .edit_space .edit_area{top:-webkit-calc(120px + 1em);top:calc(120px + 1em);left:0;width:100%;padding:.5em}.example_container button{top:124px}.description{margin-top:3rem}.edit_button{left:0}.reset_button{left:2.58em}.copy_button{left:5.91em}}form{pointer-events:all}#search_button{background:url(../img/search.png) 100% no-repeat}#search input[type=search],#search input[type=text]{border:1px solid hsla(0,0%,78.4%,.5);font-family:Montserrat,sans-serif;font-size:2.25em;width:9.75em}#search .twitter-typeahead .tt-hint,#search ::-webkit-input-placeholder{color:#ccc}:-moz-placeholder,:-ms-input-placeholder,::-moz-placeholder{color:#ccc}#search input[type=text]:focus{color:#2d7bb6;outline-color:#2d7bb6;outline-width:1px;outline-style:solid}#search .twitter-typeahead .tt-dropdown-menu{background-color:#fff}#search .twitter-typeahead .tt-suggestion.tt-cursor{color:#333;background-color:#eee}#search .twitter-typeahead .tt-suggestion p{margin:0}#search .twitter-typeahead .tt-suggestion p .small{font-size:12px;color:#666}#search{float:right}#search .twitter-typeahead .tt-dropdown-menu{border:1px solid rgba(0,0,0,.2);padding:.5em;max-height:200px;overflow-y:auto;font-size:1em;line-height:1.4em}#search .twitter-typeahead .tt-suggestion{padding:3px 20px;line-height:24px;cursor:pointer}#search .twitter-typeahead .empty-message{padding:8px 20px 1px;font-size:14px;line-height:24px}#search_button{float:right}a.code.core{color:#333}a.code.addon{color:#704f21}#contribute-item{font-size:.75em;text-align:left;display:inline-block;width:320px;height:250px;float:left;border:1px solid #ed225d;margin:0 25px 25px 0;position:relative}.contribute-item-container{position:absolute;z-index:20;margin:0;padding:10px}.container{height:100px;position:relative;background:#fff;margin-top:1.5em}#infoi,#navi{width:100%;height:100%;position:absolute;top:0;left:0}#infoi{z-index:10}h3.contribute-title{font-size:1.33em;margin:0 0 27px;padding-bottom:.3em;border-bottom:.09em dashed #ed225d}.label{position:relative}.label .nounderline img{margin:.5em 0 0}.label h3{color:#fff;position:absolute;top:0;margin:1em}.label:hover h3{color:#ed225d}h3{font-size:1.33em;margin:1em 0 0}.bullet-list{padding:0 0 0 40px;list-style:disc}#libraries-page .label h3{background-color:#000;padding:0 5px}#learn-page .label .nounderline img{height:-webkit-fit-content;height:-moz-fit-content;height:fit-content}#learn-page .info{display:inline-block}#exampleDisplay,#exampleEditor,#exampleFrame{width:36em;border:none}#exampleDisplay{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-flow:column;-ms-flex-flow:column;flex-flow:column}#popupExampleFrame{position:fixed;top:0;left:0;right:0;bottom:0;z-index:1000;border:none}#exampleDisplay button{color:#2d7bb6;border-color:rgba(45,123,182,.25);float:right;margin:.5em 0 0 .5em;background:hsla(0,0%,100%,.7);position:absolute;left:0;z-index:2}#exampleDisplay .edit_button{left:25.42em;top:-2.5em}#exampleDisplay .reset_button{left:28em;top:-2.5em}#exampleDisplay .copy_button{left:31.33em;top:-2.5em}#exampleDisplay button:hover{background:#fff}#exampleDisplay .edit_space{position:relative;-webkit-box-ordinal-group:4;-webkit-order:3;-ms-flex-order:3;order:3}#exampleDisplay #exampleFrame{height:22em;-webkit-box-ordinal-group:3;-webkit-order:2;-ms-flex-order:2;order:2}#exampleDisplay #exampleEditor{height:500em;width:710px;overflow:hidden;margin-top:.5em;color:#222;font-family:Inconsolata,consolas,monospace;font-size:1em;background-color:#fff;line-height:1em;-webkit-box-ordinal-group:5;-webkit-order:4;-ms-flex-order:4;order:4}#exampleDisplay #exampleEditor .ace_gutter-cell{background-image:none;padding-left:10px;overflow:hidden;background-color:#afafaf}#exampleDisplay #exampleEditor .ace_gutter-cell.ace_info{background-color:#d7e5f5}#exampleDisplay #exampleEditor .ace_gutter-cell.ace_warning{background-color:gold;color:#fff}#exampleDisplay #exampleEditor .ace_gutter-cell.ace_error{background-color:tomato;color:#fff}#exampleDisplay #exampleEditor .ace_numeric,#exampleDisplay #exampleEditor .ace_tag{color:#dc3787}#exampleDisplay #exampleEditor .ace_attribute-name,#exampleDisplay #exampleEditor .ace_class,#exampleDisplay #exampleEditor .ace_type{color:#704f21}#exampleDisplay #exampleEditor .ace_function,#exampleDisplay #exampleEditor .ace_keyword,#exampleDisplay #exampleEditor .ace_support{color:#00a1d3}#exampleDisplay #exampleEditor .ace_comment{color:#a0a0a0}#exampleDisplay #exampleEditor .ace_string{color:#a67f59}#exampleDisplay #exampleEditor .ace_operator{color:#333}#exampleDisplay #exampleEditor .ace_regexp{color:#e90}#exampleDisplay #exampleEditor .ace-gutter,#exampleDisplay #exampleEditor .ace-gutter-layer{color:#333}#exampleDisplay #exampleEditor .ace_folding-enabled{width:10px!important;color:#333}.attribution{background-color:#eee;font-size:15px;padding:10px;margin:30px 0}#featuring{margin-bottom:1em}#showcase-page .showcase-intro h1{font:italic 900 14.5vw Montserrat,sans-serif;color:#ed225d;text-align:left;text-transform:uppercase}#showcase-page .showcase-intro p{font:400 1.4rem Montserrat,sans-serif;line-height:1.5em}#showcase-page .project-page h2,#showcase-page .showcase-featured h2{font:italic 900 2rem Montserrat,sans-serif;color:#ed225d;letter-spacing:.05rem}#showcase-page ul.left-column,#showcase-page ul.links,#showcase-page ul.project-tags,#showcase-page ul.right-column{list-style:none}#showcase-page img[alt]{font-size:.9rem}#showcase-page .showcase-featured{margin-top:15%}#showcase-page .showcase-featured h3.title{font:italic 900 1rem Montserrat,sans-serif}#showcase-page .showcase-featured p.credit{font:500 1rem Montserrat,sans-serif}#showcase-page .showcase-featured p.description{font-size:1em;margin-bottom:.5rem}#showcase-page .nominate{margin-top:1.5em;display:inline-block}#showcase-page .nominate a,#showcase-page .nominate a:visited{padding:.4em .5em;position:relative;top:0;left:0;border:2px solid #ed225d;-webkit-box-shadow:4px 4px 0 #ed225d;box-shadow:4px 4px 0 #ed225d;font:1.5rem Montserrat,sans-serif;color:#ed225d;letter-spacing:.02rem;-webkit-transition:all .3s;-o-transition:all .3s;transition:all .3s}@media (max-width:500px){#showcase-page .nominate a,#showcase-page .nominate a:visited{padding:.4em .3em;font:1.3rem Montserrat,sans-serif}}#showcase-page .nominate a:hover{top:4px;left:4px;-webkit-box-shadow:none;box-shadow:none}#showcase-page .showcase-featured a,#showcase-page .showcase-featured a:visited{font-size:1.2rem;color:#ed225d;letter-spacing:.02rem;line-height:1.5}#showcase-page .showcase-featured a:after{content:" →"}#showcase-page .showcase-featured a.tag:after{content:""}#showcase-page .showcase-featured .no-arrow-link:after{content:" "}#showcase-page .showcase-featured .no-arrow-link:hover{text-decoration:none;padding:none;border:none}.project-info{margin-top:1em}ul.project-tags a{line-height:0;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;font-size:.5em;margin:0}h3.title{margin-top:3em}#showcase-page ul.project-tags li{margin:5px;display:inline-block}h2.featuring{margin-top:0}#showcase-page a.tag{display:inline-block;padding:6px 14px;background-color:#ffe8e8;border-radius:27px;font:.7rem Montserrat,sans-serif;color:#333}#showcase-page ul.project-tags li{margin:0}#showcase-page{margin-top:3em}#showcase-page .project-page h2{line-height:1.4}@media (min-width:720px){#showcase-page .showcase-intro h1{font:italic 900 6.35vw Montserrat,sans-serif}#showcase-page .showcase-intro p{line-height:1.75em;font-size:1em}#showcase-page .project-metadata{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex}#showcase-page .project-resources{margin-left:3rem}#showcase-page .project-a{width:90%;float:right;display:inline-block;clear:both}#showcase-page .half-image{width:48%}}#showcase-page .project-metadata{margin-top:3%}#showcase-page .project-metadata section h3{color:#ed225d;font:700 italic 1rem Montserrat,sans-serif}#showcase-page .project-resources ul.links{font:500 .7rem Montserrat,sans-serif;letter-spacing:.01rem;line-height:1.5;margin:.5rem 0}#showcase-page .project-credit{font:italic 700 1.25rem Montserrat,sans-serif}#showcase-page .project-credit p{margin:.5rem 0}#showcase-page .creator-from,#showcase-page .note{font-size:.7rem}#showcase-page .qa-group{margin-bottom:2em}#showcase-page .project-q{margin-left:0;display:inline-block;clear:both;font:900 1.2rem Montserrat,sans-serif;line-height:1.5}#showcase-page code{font-size:1.1rem}#teach-page .case-list a:hover{border-bottom:none}#teach-page .heading{font:400 1.4rem Montserrat,sans-serif;color:#000;line-height:1.2em;padding-bottom:.4em;border-bottom:4px dotted #ed225d}#teach-page h3.title{margin-top:3em}#teach-page .search-filter{display:inline}#teach-page .search-filter label{display:inline-block;font:italic 900 1rem Montserrat,sans-serif;padding:6px 12px;text-align:left;white-space:nowrap;color:#ed225d;margin-bottom:.6em;margin-top:1.2em;border:1px solid #ed225d;cursor:pointer}#teach-page .search-filter label:hover{color:#fff;background-color:#ed225d}#teach-page .search-filter input[type=checkbox]{display:absolute;position:absolute;opacity:0}#teach-page ul.filters p.filter-title{font:400 .83rem Montserrat,sans-serif;color:#ed225d;height:50px;padding-top:20px;background:none;background-color:none;-webkit-box-shadow:none;box-shadow:none;display:inline-block;border:none;clear:both}#teach-page ul.filters li{display:inline;list-style:none;width:100%}#teach-page ul.filters li label{display:inline-block;border-radius:25px;font:200 .7rem Montserrat,sans-serif;color:#000;white-space:nowrap;margin:3px 0;-webkit-transition:.2s;-o-transition:.2s;transition:.2s;background:#fafafa;padding:6px 12px;cursor:pointer}#teach-page ul.filters li label:before{display:inline-block;padding:2px}#teach-page ul.filters li label:hover{color:#ed225d;background:#ffe8e8}#teach-page ul.filters li input[type=checkbox]:checked+label{color:#fff;background:#ed225d}#teach-page ul.filters li input[type=checkbox]{display:absolute;position:absolute;opacity:0}#teach-page ul.filters li.clear{display:block;clear:both}#teach-page .filter-panel{background-color:#fff;max-height:0;overflow:hidden;-webkit-transition:max-height .2s ease-out;-o-transition:max-height .2s ease-out;transition:max-height .2s ease-out;margin-bottom:.8em;padding:0 0 .4em}#teach-page .filter-panel p{margin:0;color:#333;font-size:.83em;height:50px;padding-top:20px;-webkit-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out}#teach-page .teach-intro p{font:400 1.2rem Times,sans-serif;line-height:1.5em}#teach-page .modal-title{margin-left:1em;margin-right:1em;font:400 1rem Montserrat,sans-serif;color:#ed225d;line-height:1.2em}#teach-page ul.cases li.clear{display:block;clear:both;margin-top:1em;margin-bottom:1.2em}#teach-page img{margin-bottom:1.4em}#teach-page img[alt]{font:.6rem Montserrat,sans-serif;color:#bababa}#teach-page .close{position:relative;color:#ffc7c7;float:right;font-size:40px;font-weight:700;margin-right:.4em;margin-top:.4em;cursor:pointer}#teach-page .close:hover,.close:focus{color:#ed225d;text-decoration:none;cursor:pointer}#teach-page .case label{margin:2px;padding:5px 8px;display:inline-block;border-radius:25px;font:.7rem Montserrat,sans-serif;color:#aaa;white-space:nowrap;color:#fff;background:#ed225d}#teach-page .modal-body::-webkit-scrollbar{width:5px;height:5px;border-radius:10px}#teach-page .modal-body::-webkit-scrollbar-track{background:#f1f1f1}#teach-page .modal-body::-webkit-scrollbar-thumb{background:#ffe8e8}#teach-page .case{margin-left:2em;margin-right:2em}#teach-page .case span{color:#ed225d;font:900 1.4rem Montserrat,sans-serif}#teach-page .case p.lead-name{font:900 Italic 1.2rem Montserrat,sans-serif;color:#ed225d;line-height:1.4em;border-bottom:1.4em}#teach-page .case .speech{position:relative;font:200 Italic .8rem Montserrat,sans-serif;color:#000;background:#ffe8e8;padding:.5em 1.2em;border-radius:.4em;border-bottom:none;margin-bottom:2em;margin-top:1em}#teach-page .case .speech:after{content:"";position:absolute;top:0;left:8%;width:0;height:0;border:10px solid transparent;border-bottom-color:#ffe8e8;border-top:0;margin-left:-10px;margin-top:-10px}#teach-page .case p.subtitle{font:400 1rem Montserrat,sans-serif;color:#ed225d}#teach-page .case p,#teach-page .case p.subtitle{line-height:1.4em;border-bottom:.1em dashed rgba(237,34,93,.15)}#teach-page .case p{font:400 1rem Times,sans-serif;color:#000}#teach-page .modal-footer,#teach-page .modal-header{margin-bottom:.8em}#teach-page .modal-body:-webkit-scrollbar{display:none}#teach-page .modal{display:none;position:fixed;z-index:100;width:100%;height:100%;top:0;left:0;right:0;overflow:auto;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;background-color:rgba(255,232,232,.5)}#teach-page .modal-content{position:fixed;background:#fff;top:2%;left:2%;right:2%;bottom:2%;margin:auto;border:1.2px solid #ffe8e8;max-width:740px;-webkit-box-shadow:10px 100px 30px -17px rgba(237,34,93,.5);box-shadow:10px 100px 30px -17px rgba(237,34,93,.5);-webkit-box-shadow:10px 100px 20px -17px rgba(237,34,93,.5);box-shadow:10px 100px 20px -17px rgba(237,34,93,.5);-webkit-box-shadow:10px 20px 10px -17px rgba(237,34,93,.5);box-shadow:10px 20px 10px -17px rgba(237,34,93,.5)}#teach-page .modal-body{margin:auto;height:85%;width:95%;overflow-y:auto}#teach-page .results-wrapper{width:100%;outline:none;background:#fff}#teach-page .results-wrapper ul li.case-list a.myBtn{overflow:hidden;text-overflow:ellipsis}#teach-page .case-list{margin-bottom:.8em;padding-bottom:.4em;font:400 1rem Times,sans-serif;line-height:1.2em;border-bottom:.1em dashed #ffe8e8}*,:after,:before{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}html{font-size:1.25em}body{margin:0;background-color:#fff;font-family:Times;font-weight:400;line-height:1.45;color:#333}p{font-size:1.2em;margin:.5em 0}.freeze{overflow:hidden}#menu li a:focus:active,#menu li a:focus:hover,#menu li a:link,#menu li a:visited{color:#ed225d;background:transparent;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}a:link,a:visited{color:#2d7bb6;text-decoration:none}#reference a:hover,a:active,a:hover{color:#ed225d;text-decoration:none;padding-bottom:.11em;border-bottom:.11em dashed #ed225d;-webkit-transition:border-bottom 30ms linear;-o-transition:border-bottom 30ms linear;transition:border-bottom 30ms linear}a.nounderline:hover{border:none}a.here{color:#ed225d;text-decoration:none;padding-bottom:.1em;border-bottom:transparent;border-bottom-color:#ed225d}.highlight{background-color:rgba(237,34,93,.15)}.container>div:first-of-type{margin-top:2em}h1,h2,h3,h4,h5{margin:1.414em 0 .5em;font-weight:inherit;line-height:1.2;font-family:Montserrat,sans-serif}h1{font-size:2.25em;margin:0}h2{font-size:1.5em;margin:1em 0 0}.code{font-family:Inconsolata,consolas,monospace}#backlink{margin:1.2em .444em 0 0;font-family:Montserrat,sans-serif;float:right}#backlink a{color:#afafaf}#backlink a:hover{color:#ed225d;border-bottom:none}#promo,#promo:visited{width:100%;background:#98fb98;margin:0;text-align:center;padding:.4em 0;background:#74ffb7;background:-webkit-radial-gradient(circle,#74ffb7 0,#8afff2 100%);background:-o-radial-gradient(circle,#74ffb7 0,#8afff2 100%);background:radial-gradient(circle,#74ffb7 0,#8afff2 100%);font-family:Montserrat,sans-serif;color:#ed225d!important}#promo:hover{background:#ed225d;color:#fff!important}#promo-link{margin:0!important;padding:0}#family a:link,#family a:visited{margin:.4em}#family a:active,#family a:hover{margin:.4em;border:none}#family{position:absolute;z-index:9999;top:0;left:0;width:100%;overflow:none;margin:0;border-bottom:1px solid rgba(51,51,51,.5);-webkit-box-shadow:0 0 10px #333;box-shadow:0 0 10px #333;background-color:hsla(0,0%,100%,.85)}#processing-sites{margin:.375em 0}#processing-sites li{list-style:none;display:inline-block;margin:0}#processing-sites li:first-child{margin-left:2em}#processing-sites li:last-child{float:right;margin-right:2em}.code-snippet{margin:0 0 0 1em;width:90%;clear:both}.column-span{margin:0 0 0 1em;padding:0;float:left;max-width:100%}.method_description p{margin-top:0}main{padding:0}.spacer{clear:both}ul{margin:0;padding:0;list-style:none}ol{font-size:1.2em}li{margin:0;padding:0}ul.list_view{margin:.5em 0 0 1em;padding:0;list-style:disc;list-style-position:outside;font-size:1.2em}ol ul.list_view{font-size:1em}ul.inside{margin:0 0 0 2em;padding:0;list-style:disc;list-style-position:inside}.image-row img{width:48%;height:14.3%}.image-row img+img{float:right;margin-right:0;margin-bottom:.25em}img,main div img{margin:.5em .5em 0 0;width:100%}p+img{margin-top:0}.video{width:100%}#lockup{position:absolute;top:-5.75em;left:1.25em;height:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#lockup object{margin:0;padding:0;border:none}#lockup a:focus{outline:0}.logo{padding:0;border:none;margin:0 0 .4em;height:4.5em;width:9.75em}#lockup p{color:#ed225d;font-size:.7em;font-family:Montserrat,sans-serif;margin:.5em 0 0 8.5em}#lockup a:link{border:transparent;height:4.5em;width:9.75em}.caption{margin-bottom:2.5em}.caption p,.caption span{text-align:right;font-size:.7em;font-family:Montserrat,sans-serif;padding-top:.25em}footer{clear:both;border-top:.1em dashed #ed225d;margin:2em 0}.videoWrapper{position:relative;padding-bottom:56.25%;height:0;margin-top:.5em}.videoWrapper iframe{position:absolute;top:0;left:0;width:100%;height:100%}.ir{background-color:transparent;border:0;overflow:hidden;*text-indent:-9999px}.ir:before{content:"";display:block;width:0;height:150%}.hidden{display:none!important;visibility:hidden}.sr-only{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only.focusable:active,.sr-only.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.clearfix{*zoom:1}#notMobile-message{display:none;-webkit-box-ordinal-group:2;-webkit-order:1;-ms-flex-order:1;order:1}#asterisk-design-element,#isMobile-displayButton,.separator-design-element{display:none}.pointerevents #asterisk-design-element,.pointerevents .separator-design-element{pointer-events:none;display:inline-block}@media (min-width:780px){.container{width:49em!important;margin:11.5em auto}main{width:36em;padding:0!important}footer{width:48em}}@media (min-width:780px){.container{margin:11.5em auto;width:100%;padding:.8em 0 0;height:auto;min-height:100%}#home-page{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:row;-ms-flex-wrap:row;flex-wrap:row}main{padding:0 1em 0 0}#family,.small,footer,small{font-size:.7em}footer{clear:both}#i18n-btn{position:absolute;top:4em;right:1em}#i18n-btn a,#menu{font-family:Montserrat,sans-serif}#menu{list-style:none;margin:0 .75em 0 -1.85em;width:7.3em;height:100%;border-top:transparent;border-bottom:transparent;padding:0;font-size:.83em;z-index:100;position:relative;top:0}#menu li{float:none;margin:0 0 1em;text-align:right}#menu li:nth-child(11){margin-top:3em;padding-top:.5em}.left-column{width:48%;float:left;margin-bottom:40px}.right-column{width:48%;float:right;margin-right:0;margin-bottom:.25em}.narrow-left-column{width:32%;float:left}.wide-right-column{width:64%;float:right;margin-right:0;margin-bottom:.25em}.book{font-size:.7em}.column_0,.column_1,.column_2{float:left;width:11.333em}.column_0,.column_1{margin-right:1em}#collection-list-nav{width:100%;clear:both;border-bottom:1px dashed rgba(0,0,0,.2)}#collection-list-categories{font-family:Montserrat,sans-serif;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;margin:1em 0 1.5em}#collection-list-categories ul{-webkit-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1}#collection-list{margin:0}.group-name.first{margin-top:0!important}.column.group-name{margin-bottom:1em}#library-page .group-name{margin:2em 0 .5em}#library-page .column{margin-top:1em}#list{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-bottom:1em}}@media (max-width:780px){.tagline{display:none!important}#family{display:none}#i18n-btn{position:absolute;top:.5em;right:.7em;z-index:10}#search{float:left;margin-bottom:1em}#search,#search input[type=text]{width:100%}#search input[type=search],#search input[type=text]{font-size:1.5em}#lockup{position:absolute;top:2em;left:1em}.column-span{margin:0;padding:0 1em;float:left}#menu,#menu.top_menu{margin:6em 0 .5em;font-size:1.3em}#menu li{display:inline-block}#menu li:last-child a:after{content:""}#menu li a:after{content:","}#contribute-item:first-child{margin-left:0}.download_box{width:96%}.download_box.half_box{width:46%;margin-right:4%;float:left}#etc_list{font-size:1.2em;margin-top:1em}#asterisk-design-element,.separator-design-element{display:none!important;pointer-events:none}pre[class*=language-]{padding:.5em;width:100%}code{word-wrap:break-word;word-break:break-all}#credits{position:relative!important;z-index:2;margin-top:-7em;padding:0 2em 3em 1em;font-size:.5em;float:right;width:100%;text-align:right}#credits,#home-sketch-frame{display:none}#exampleDisplay,#exampleDisplay #exampleEditor,#exampleFrame{width:100%}#exampleDisplay .edit_button{left:-.58em}#exampleDisplay .reset_button{left:3em}#exampleDisplay .copy_button{left:6.44em}#exampleEditor{margin-top:3em}.small,footer,small{font-size:.5em}.paramtype{width:96%}}@media (max-width:400px){#i18n{margin-top:.75em!important}body{margin-top:-.75em!important}}iframe{border:none;width:100%}.iframe-container{overflow:hidden;position:relative}.iframe-container iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.cnv_div{display:-webkit-inline-box;display:-webkit-inline-flex;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}.cnv_div>*{width:100px;height:auto}#i18n-buttons{margin:0;background:#fff}#i18n-buttons li{list-style:none;display:inline-block;margin-left:.5em}#i18n-btn a{border:none;outline:none;font-size:.7em;color:#696969;z-index:5}#i18n-btn a:hover{color:#ed225d}#i18n-btn a.disabled{color:#ed225d;cursor:default}#asterisk-design-element{position:fixed;z-index:-1;opacity:.6;pointer-events:none}.separator-design-element{width:.33em;height:.33em;margin:0 .09em .18em;display:inline-block;overflow:hidden;text-indent:-100%;background:transparent url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCI+PHBhdGggZD0iTTE2LjkgMTAuM2w4LjUtMi42IDEuNyA1LjItOC41IDIuOSA1LjMgNy41LTQuNCAzLjItNS42LTcuMy01LjQgNy4xTDQuMiAyM2w1LjMtNy4yLTguNi0zLjIgMS43LTUuMiA4LjYgMi44VjEuNEgxN3Y4Ljl6IiBmaWxsPSIjZWQyMjVkIiBzdHJva2U9IiNlZDIyNWQiLz48L3N2Zz4=");-webkit-background-size:.33em .33em;background-size:.33em}#home-page #asterisk-design-element{bottom:-8%;right:20%;height:12em;width:12em;opacity:1}#examples-page #asterisk-design-element,#learn-page #asterisk-design-element,#other-content-types-page #asterisk-design-element{bottom:-14%;left:-20%;height:25em;width:25em;-webkit-transform:rotate(-1deg);-ms-transform:rotate(-1deg);-o-transform:rotate(-1deg);transform:rotate(-1deg)}#books-page #asterisk-design-element,#libraries-page #asterisk-design-element{bottom:-19%;right:-16%;height:28em;width:28em;-webkit-transform:rotate(2deg);-ms-transform:rotate(2deg);-o-transform:rotate(2deg);transform:rotate(2deg)}#community-page #asterisk-design-element,#get-started-page #asterisk-design-element{top:10%;right:-20%;height:30em;width:30em;-webkit-transform:rotate(2deg);-ms-transform:rotate(2deg);-o-transform:rotate(2deg);transform:rotate(2deg)}#download-page #asterisk-design-element,#reference-page #asterisk-design-element{top:7%;left:1%;height:10em;width:10em;-webkit-transform:rotate(-21deg);-ms-transform:rotate(-21deg);-o-transform:rotate(-21deg);transform:rotate(-21deg)}.email-octopus-email-address{color:#ed225d;text-decoration:none;padding-bottom:.11em;outline:none;border:none;border-bottom:.11em dashed #ed225d;-webkit-transition:border-bottom 30ms linear;-o-transition:border-bottom 30ms linear;transition:border-bottom 30ms linear;width:13em}.email-octopus-form-row-hp{position:absolute;left:-5000px}.email-octopus-form-row button{border:1px solid #ed225d;color:#ed225d;padding:.4em .6em;margin:1em 0 0;font-family:Montserrat,sans-serif;display:block}.email-octopus-form-row button:hover{background-color:#ed225d;color:#fff}.email-octopus-email-address::-webkit-input-placeholder{color:#ababab}.email-octopus-email-address:-moz-placeholder,.email-octopus-email-address::-moz-placeholder{color:#ababab}.email-octopus-email-address:-ms-input-placeholder{color:#ababab}@media (min-width:720px){.email-octopus-email-address{width:16em}.email-octopus-form-row button{margin:0 0 0 .5em;display:inline}} +/*# sourceMappingURL=maps/all.css.map */ \ No newline at end of file diff --git a/dist/assets/css/maps/all.css.map b/dist/assets/css/maps/all.css.map new file mode 100644 index 0000000000..d3dc28567d --- /dev/null +++ b/dist/assets/css/maps/all.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../all.css"],"names":[],"mappings":"AAAA,4DAA4D,AAU5D,sFAYI,aAAe,CAClB,AAMD,mBAGI,qBAAsB,CACtB,eAAiB,CACjB,MAAS,CACZ,AAOD,sBACI,aAAc,AACd,QAAU,CACb,AAOD,SACI,YAAc,CACjB,AAaD,KACI,eAAgB,AAChB,8BAA+B,AAC/B,yBAA2B,CAC9B,AAOD,kCAKI,sBAAwB,CAC3B,AAkBD,QACI,mBAAqB,CACxB,AAMD,iBAEI,SAAW,CACd,AAYD,GACI,cAAe,AACf,cAAiB,CACpB,AAED,GAEI,cAAiB,CACpB,AAED,GACI,iBAAkB,AAClB,YAAc,CACjB,AAED,GACI,cAAe,AACf,eAAiB,CACpB,AAED,GACI,gBAAkB,AAClB,eAAiB,CACpB,AAED,GACI,gBAAkB,AAClB,eAAiB,CACpB,AAMD,YACI,wBAA0B,CAC7B,AAMD,SAEI,eAAkB,CACrB,AAED,WACI,eAAiB,CACpB,AAMD,IACI,iBAAmB,CACtB,AAOD,GACI,4BAA6B,AAC7B,+BAAwB,AAAxB,uBAAwB,AACxB,QAAU,CACb,AAMD,KACI,gBAAiB,AACjB,UAAY,CACf,AAMD,MAEI,YAAc,CACjB,AAMD,kBAII,4BAA8B,CAC9B,kCAAuC,AACvC,aAAe,CAClB,AAMD,IACI,gBAAiB,AACjB,qBAAsB,AACtB,oBAAsB,CACzB,AAMD,EACI,WAAa,CAChB,AAMD,iBAEI,WAAY,AACZ,YAAc,CACjB,AAMD,MACI,aAAe,CAClB,AAMD,QAEI,cAAe,AACf,cAAe,AACf,kBAAmB,AACnB,uBAAyB,CAC5B,AAED,IACI,SAAY,CACf,AAED,IACI,aAAgB,CACnB,AAUD,cAII,YAAc,CACjB,AAED,GACI,iBAAmB,CACtB,AAMD,WAGI,kBAAoB,CACvB,AAMD,cAEI,gBAAiB,AACjB,qBAAuB,CAC1B,AAWD,IACI,SAAU,AACV,8BAAgC,CACnC,AAMD,eACI,eAAiB,CACpB,AAsBD,YACI,QAAU,CACb,AAMD,SACI,wBAA0B,AAC1B,aAAc,AACd,0BAA+B,CAClC,AAQD,OACI,SAAU,AACV,UAAW,AACX,mBAAoB,CACpB,gBAAmB,CACtB,AASD,6BAII,eAAgB,AAChB,SAAU,AACV,wBAAyB,CACzB,qBAAwB,CAC3B,AAOD,aAEI,kBAAoB,CACvB,AASD,cAEI,mBAAqB,CACxB,AAYD,oEAII,0BAA2B,AAC3B,eAAgB,CAChB,gBAAmB,CACtB,AAMD,sCAEI,cAAgB,CACnB,AASD,uCAEI,8BAAuB,AAAvB,2BAAuB,AAAvB,sBAAuB,AACvB,UAAW,CACX,YAAc,CACd,UAAa,CAChB,AAQD,mBACI,6BAA8B,AAC9B,4BAA6B,AAC7B,+BAAgC,AAChC,sBAAwB,CAC3B,AAOD,+FAEI,uBAAyB,CAC5B,AAMD,iDAEI,SAAU,AACV,SAAW,CACd,AAOD,SACI,cAAe,AACf,kBAAoB,CACvB,AAUD,MACI,yBAA0B,AAC1B,gBAAkB,CACrB;CAAA,AAWD,sDAGE,WAAY,AACZ,8DAKc,AACd,cAAe,AACf,gBAAiB,AACjB,gBAAiB,AACjB,oBAAqB,AACrB,kBAAmB,AACnB,gBAAiB,AACjB,cAAe,AACf,WAAY,AACZ,qBAAsB,AACtB,kBAAmB,AACnB,iBAAkB,AAClB,aAAc,AACd,uBAA0B,CAC3B,AAGD,sBACE,kBAAkB,AAClB,iBAAqB,AACrB,sBAAyB,AACzB,+BAAiC,AACjC,sBAAuB,AAEvB,iFAAyF,AAGzF,8EAAoF,AACpF,gIAAiF,AAAjF,yEAAiF,AACjF,oCAA6B,AAA7B,4BAA6B,AAC7B,sCAA8B,AAA9B,8BAA8B,AAE9B,aAAc,CAIf,AAMD,uDAEE,iBAAmB,CACpB,AAGD,iCACE,kBAAkB,AAClB,aAAc,AAKd,mBAAqB,AACrB,WAAY,AACZ,+BAAqC,CACtC,AAGD,mEAEE,YAAc,AACd,SAAW,CACZ,AAGD,8EAKE,aAAe,CAChB,AAED,mBACE,UAAY,CACb,AAED,2GAOE,aAAe,CAChB,AAED,8EAKE,aAAe,CAChB,AAED,yDAIE,cAAe,AACf,6BAAqC,CACtC,AAED,iEAIE,aAAe,CAChB,AAED,8BAEE,UAAY,CACb,AACD,iDAEE,cAAe,AACf,6BAAqC,CACtC,AAED,iBACE,eAAoB,CACrB,AAED,cACE,WAAa,CACd,AAED,WACE,UAAY,CACb,AAED,oCACE,yDAEE,YAAY,AACZ,wBAAwB,AAExB,eAAgB,CACjB,CAEF,AAGD,gEAGE,aAAe,CAChB,AAED,iBAEE,mBAAoB,AACpB,wBAA0B,CAC3B,AAED,uCALE,iBAAmB,CAOpB,AAED,iCACE,kBAAmB,AACnB,oBAAqB,AACrB,MAAO,AACP,eAAgB,AAChB,YAAa,AACb,UAAW,AACX,oBAAqB,AACrB,4BAA6B,AAE7B,yBAA0B,AAC1B,sBAAuB,AACvB,qBAAsB,AACtB,gBAAkB,CAEnB,AAED,wBACE,oBAAqB,AACrB,cAAe,AACf,4BAA8B,CAC/B,AAED,+BACE,4BAA6B,AAC7B,WAAY,AACZ,cAAe,AACf,mBAAqB,AACrB,gBAAkB,CACnB;CAAA,AAaD,yBAIE,UAAY,CACb,AAED,SACE,mBAAoB,AACpB,iBAA6B,AAC7B,WAAa,CACd,AAED,KACE,cAAe,AACf,eAAiB,CAClB,AAQD,iBACE,mBAAoB,AACpB,gBAAkB,CACnB,AAED,YACE,mBAAoB,AACpB,gBAAkB,CACnB,AAMD,GACE,cAAe,AACf,WAAY,AACZ,SAAU,AACV,0BAA2B,AAC3B,aAAc,AACd,SAAW,CACZ,AAMD,IACE,qBAAuB,CACxB,AAED,aACE,YAAa,AACb,UAAY,CACb,AAED,cACE,YAAa,AACb,WAAa,CACd,AAED,eACE,YAAa,AACb,UAAY,CACb,AAED,iBACE,YAAa,AACb,UAAY,CACb,AAED,gBACE,YAAa,AACb,WAAa,CACd,AAED,kBACE,YAAa,AACb,WAAa,CACd,AAED,iBACE,YAAa,AACb,iBAAmB,CACpB,AAED,UACE,WAAa,CACd,AAED,QACE,WAAa,CACd,AAED,eACE,YAAa,AACb,iBAAmB,CACpB,AAMD,SACE,SAAU,AACV,SAAU,AACV,SAAW,CACZ,AAMD,SACE,eAAiB,CAClB,AAOD,SACE,YAAc,CACf,AAED,iBACE,mBAAqB,CACtB,AAED,mBACE,kBAAoB,CACrB,AAED,UACE,kBAAmB,AACnB,cAAe,AACf,YAAa,AACb,WAAa,CACd,AAED,YACE,kBAAmB,AACnB,KAAO,CACR,AAED,qBAEE,gBAAiB,AACjB,kCAAsC,AACtC,WAAY,AACZ,eAAkB,AAClB,UAAW,AACX,YAAa,AACb,eAAiB,CAClB,AAED,kBACE,cAAgB,CACjB,AAED,aACE,kBAAmB,AACnB,MAAO,AACP,OAAQ,AACR,UAAY,CACb,AAID,oCACE,cACE,WAAY,AACZ,aAAc,AACd,2CAAqC,AAArC,sCAAqC,AAArC,mCAAqC,AACrC,eAAiB,CAClB,AAED,0BACE,UAAY,CACb,AAED,gBACE,cAAe,AACf,kBAAmB,AACnB,qBAAuB,AACvB,sCAAyC,CAC1C,AAED,mBACE,SAAU,AACV,eAAgB,AAChB,YAAa,AACb,kBAAmB,AACnB,kBAAmB,AACnB,yBAAkB,AAAlB,sBAAkB,AAAlB,qBAAkB,AAAlB,iBAAkB,AAClB,kBAAoB,CACrB,AAED,qCACE,mBAAoB,AACpB,cAAe,AACf,WAAY,AACZ,kBAAmB,AACnB,2CAAqC,AAArC,sCAAqC,AAArC,mCAAqC,AACrC,UAAY,CACb,AAED,uFAEE,mBAAoB,AACpB,WAAY,AACZ,cAAe,AACf,YAAa,AACb,kBAAmB,AACnB,oCAA8B,AAA9B,+BAA8B,AAA9B,4BAA8B,AAC9B,UAAY,CACb,AAED,4CACE,OAAS,CACV,AAED,2CACE,QAAU,CACX,AAED,kBACE,YAAc,CACf,AAED,wCACE,gBAAkB,CACnB,AAED,+DACE,sBAAwB,CACzB,AAED,sEACE,iCAA0B,AAA1B,6BAA0B,AAA1B,4BAA0B,AAA1B,yBAA0B,AAC1B,KAAO,CACR,AAED,qEACE,gCAAyB,AAAzB,4BAAyB,AAAzB,2BAAyB,AAAzB,wBAAyB,AACzB,KAAO,CACR,CACF,AAED,kBACE,YAAc,CACf,AAID,mBACE,eAAgB,AAChB,WAAY,AACZ,YAAa,AACb,OAAQ,AACR,MAAO,AACP,WAAY,AACZ,gBAAiB,AACjB,mBAAoB,AACpB,QAAU,CACX,AAED,SACE,eAAgB,AAChB,SAAU,AACV,OAAQ,AACR,UAAW,AACX,YAAa,AACb,cAAiB,CAClB,AAED,iBACE,kBAAmB,AACnB,OAAU,AACV,SAAU,AACV,UAAW,AACX,yBAA0B,AAC1B,WAAa,AACb,WAAY,AACZ,YAAa,AACb,YAAa,AACb,mBAAoB,AACpB,kBAAmB,AACnB,eAAgB,AAChB,YAAa,AACb,SAAW,CACZ,AAED,uBACE,SAAW,CACZ,AAQD,YAEE,kBAAqB,AACrB,cAAgB,AAEhB,kCAAsC,AACtC,oBAAsB,CACvB,AAED,0BARE,yBAA0B,AAG1B,UAAY,CAcb,AATD,cAEE,aAAe,AACf,oBAAqB,AACrB,cAAe,AACf,WAAY,AAEZ,cAAe,AACf,iBAAmB,CACpB,AAED,sCAEE,yBAA0B,AAC1B,mBAAoB,AACpB,UAAe,CAChB,AAED,uBACE,cAAe,AACf,oBAAqB,AACrB,UAAY,CACb,AAED,gCACE,cAAgB,CACjB,AAED,6BACE,cAAe,AACf,SAAU,AACV,oBAAsB,AAEtB,mCAA6B,AAC7B,gBAAiB,AACjB,kCAAsC,AACtC,aAAe,CAChB,AAED,mCACE,4BAA6B,AAC7B,wBAA0B,CAC3B,AAED,gBACE,gBAAkB,AAClB,SAAU,AACV,kBAAmB,AACnB,UAAY,CACb,AAED,kBACE,aAAe,AACf,YAAc,AACd,kBAAmB,AACnB,YAAc,CACf,AAED,wBACE,SAAY,CACb,AAED,mBACE,aAAe,CAChB,AAED,2BACE,WAAY,AACZ,iBAAmB,CACpB,AAED,cACE,cAAgB,CACjB,AAED,0BACE,eAAgB,AAChB,iBAAmB,CACpB,AAED,0BACE,eAAiB,AACjB,gBAAiB,AACjB,eAAkB,CACnB,AAED,WACE,YAAc,CACf,AAED,aACE,eAAiB,AACjB,cAAe,AACf,kBAAmB,AACnB,eAAkB,CACnB,AAED,OACE,WAAa,AACb,kBAAmB,AACnB,aAAe,AACf,WAAa,AACb,gBAAkB,AAClB,6BAA8B,AAC9B,iCAAkC,AAClC,4BAA0B,AAA1B,yBAA0B,AAC1B,cAAiB,CAClB,AAOD,8BACE,kBAAmB,AACnB,4BAAS,AAAT,gBAAS,AAAT,iBAAS,AAAT,QAAS,AACT,sBAAwB,CACzB,AACD,2CACE,cAAe,AACf,kCAAuC,AACvC,YAAa,AACb,0BAA4B,AAC5B,8BAAqC,AACrC,kBAAmB,AACnB,UAAW,AACX,aAAc,AACd,UAAY,CACb,AAED,yBACE,2CACE,WAAa,CACd,CACF,AACD,yBACE,2CACE,WAAa,CACd,CACF,AAOD,uBACE,iBAAmB,CACpB,AAQD,wBACE,UAAY,CACb,AAED,oBACE,eAAiB,CAClB,AAED,oBACE,cAAe,AACf,kCAAsC,AACtC,eAAkB,CACnB,AAED,oBACE,oBAAsB,CACvB,AAED,wBACE,SAAU,AACV,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,aAAc,AACd,8BAAoB,AAApB,6BAAoB,AAApB,2BAAoB,AAApB,uBAAoB,AAApB,mBAAoB,AACpB,uBAAgB,AAAhB,mBAAgB,AAAhB,cAAgB,CACjB,AACD,uBACE,WAAY,AACZ,iBAAmB,CACpB,AAED,gCASE,eAAgB,AAChB,iBAAmB,CACpB,AAED,gCACE,aAAe,CAChB,AAED,MACE,UAAY,CACb,AAED,SACE,kBAAsB,AACtB,kBAAmB,AACnB,oBAAqB,AACrB,2CAAgD,AAChD,aAAe,CAChB,AAED,SACE,iBAAkB,AAClB,cAAkB,CACnB,AAED,SACE,eAAkB,CACnB,AAED,SACE,iBAAmB,CACpB,AAED,aACE,WAAY,AACZ,cAAe,AACf,UAAY,CACb,AAED,YACE,UAAY,CACb,AAED,4BAEE,WAAY,AACZ,YAAc,CACf,AAED,WACE,qBAAsB,AACtB,cAAe,AACf,gBAAiB,AACjB,eAAiB,CAClB,AAED,aACE,eAAgB,AAChB,aAAe,CAChB,AAED,WAEE,gBAAiB,AACjB,UAAW,AACX,kBAAoB,CACrB,AAED,qCANE,oBAAsB,CAQvB,AAED,gCACE,aAAe,CAChB,AAID,aACE,iBAAmB,CACpB,AAED,+BACE,kBAAmB,AACnB,SAAU,AACV,cAAe,AACf,gBAAiB,AACjB,YAAa,AACb,aAAc,AACd,cAAgB,CACjB,AAED,wCACE,OAAU,AACV,aAAe,CAChB,AAED,6BACE,kBAAmB,AACnB,MAAO,AACP,OAAQ,AACR,iBAAmB,AACnB,WAAY,AACZ,mBAAqB,CACtB,AAED,+BACE,mBAAqB,CACtB,AAED,gCACE,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,aAAc,AACd,8BAA4B,AAA5B,8BAA4B,AAA5B,mCAA4B,AAA5B,+BAA4B,AAA5B,2BAA4B,AAC5B,kBAAmB,AACnB,mBAAqB,CACtB,AAED,0CACE,kCAAsC,AACtC,cAAe,AACf,WAAY,AACZ,sCAA4C,AAC5C,uBAAwB,AACxB,aAAc,AACd,gBAAmB,CACpB,AAED,wFAEE,cAAe,AACf,iCAAuC,CACxC,AAED,wCACE,kBAAmB,AACnB,SAAW,AACX,WAAY,AACZ,aAAc,AAEd,aAAc,AACd,sBAAuB,AACvB,wBAAiC,AACjC,cAAgB,CACjB,AAED,gBACE,kBAAmB,AACnB,kCAAsC,AACtC,cAAe,AACf,cAAe,AACf,sCAA2C,AAC3C,uBAAwB,AACxB,YAAc,CACf,AAED,oCACE,WAAY,AACZ,eAAgB,AAEhB,6BAAuB,AACvB,iBAAmB,AACnB,eAAgB,AAChB,iBAAkB,AAClB,iCAAgC,AAAhC,yBAAgC,AAChC,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,YAAc,CACf,AAED,kDACE,cAAgB,CACjB,AAGD,yBACE,+BACE,iBAAmB,AACnB,UAAa,CACd,AAED,oCACE,WAAY,AACZ,iBAAkB,AAClB,kCAAiC,AAAjC,0BAAiC,AACjC,aAAe,CAChB,AAED,wCACE,8BAAuB,AAAvB,sBAAuB,AACvB,OAAQ,AACR,WAAY,AACZ,YAAe,CAChB,AAED,0BACE,SAAW,CACZ,AAED,aACE,eAAiB,CAClB,AAED,aACE,MAAQ,CACT,AAED,cACE,WAAa,CACd,AAED,aACE,WAAa,CACd,CACF,AAED,KACE,kBAAoB,CACrB,AAED,eACE,gDAAkD,CACnD,AAED,oDAEE,qCAA2C,AAC3C,kCAAsC,AACtC,iBAAkB,AAClB,YAAc,CACf,AAED,wEAEE,UAAY,CACb,AAED,4DAGE,UAAY,CACb,AAED,+BACE,cAAe,AACf,sBAAuB,AACvB,kBAAmB,AACnB,mBAAqB,CACtB,AAED,6CACE,qBAAuB,CAKxB,AAED,oDACE,WAAY,AACZ,qBAAuB,CACxB,AAED,4CACE,QAAU,CACX,AAED,mDACE,eAAgB,AAChB,UAAY,CACb,AAED,QACE,WAAa,CACd,AAED,6CACE,gCAAqC,AACrC,aAAe,AACf,iBAAkB,AAClB,gBAAiB,AACjB,cAAe,AACf,iBAAmB,CACpB,AAED,0CACE,iBAAkB,AAClB,iBAAkB,AAClB,cAAgB,CACjB,AAED,0CACE,qBAA2B,AAC3B,eAAgB,AAChB,gBAAkB,CACnB,AAED,eACE,WAAa,CACd,AAED,YACE,UAAY,CACb,AAED,aACE,aAAe,CAChB,AAcD,iBACE,gBAAkB,AAClB,gBAAiB,AACjB,qBAAsB,AACtB,YAAa,AACb,aAAc,AACd,WAAY,AACZ,yBAA0B,AAC1B,qBAAsB,AACtB,iBAAmB,CACpB,AAED,2BACE,kBAAmB,AACnB,WAAY,AACZ,SAAU,AACV,YAAc,CACf,AAED,WAEE,aAAc,AACd,kBAAmB,AACnB,gBAAkB,AAClB,gBAAkB,CACnB,AAED,aAEE,WAAY,AACZ,YAAa,AACb,kBAAmB,AACnB,MAAO,AACP,MAAQ,CACT,AAED,OACE,UAAY,CACb,AAED,oBACE,iBAAkB,AAClB,gBAAmB,AACnB,oBAAsB,AAEtB,kCAA6B,CAC9B,AAQD,OACE,iBAAmB,CACpB,AAED,wBACE,eAAoB,CACrB,AAED,UACE,WAAa,AACb,kBAAmB,AACnB,MAAO,AACP,UAAY,CACb,AAED,gBACE,aAAe,CAChB,AAED,GACE,iBAAkB,AAClB,cAAkB,CACnB,AAED,aACE,mBAAoB,AACpB,eAAiB,CAClB,AAED,0BACE,sBAAwB,AACxB,aAAgB,CACjB,AAED,oCACE,2BAAoB,AAApB,wBAAoB,AAApB,kBAAoB,CACrB,AAED,kBACE,oBAAsB,CACvB,AAED,6CAGE,WAAY,AACZ,WAAa,CACd,AAED,gBACE,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,aAAc,AACd,4BAAkB,AAAlB,6BAAkB,AAAlB,yBAAkB,AAAlB,qBAAkB,AAAlB,gBAAkB,CACnB,AAED,mBACE,eAAgB,AAChB,MAAO,AACP,OAAQ,AACR,QAAS,AACT,SAAU,AACV,aAAc,AACd,WAAa,CACd,AAED,uBACE,cAAe,AACf,kCAAuC,AACvC,YAAa,AACb,qBAAwB,AACxB,8BAAqC,AACrC,kBAAmB,AACnB,OAAQ,AACR,SAAW,CACZ,AAED,6BACE,aAAc,AACd,UAAY,CACb,AAED,8BACE,UAAW,AACX,UAAY,CACb,AAED,6BACE,aAAc,AACd,UAAY,CACb,AAED,6BACE,eAAiB,CAClB,AAED,4BACE,kBAAmB,AACnB,4BAAS,AAAT,gBAAS,AAAT,iBAAS,AAAT,OAAS,CACV,AAED,8BACE,YAAa,AACb,4BAAS,AAAT,gBAAS,AAAT,iBAAS,AAAT,OAAS,CACV,AAED,+BACE,aAAc,AACd,YAAa,AACb,gBAAiB,AACjB,gBAAkB,AAClB,WAAY,AACZ,2CAAgD,AAChD,cAAe,AACf,sBAAuB,AACvB,gBAAiB,AACjB,4BAAS,AAAT,gBAAS,AAAT,iBAAS,AAAT,OAAS,CACV,AAED,gDACE,sBAAuB,AACvB,kBAAmB,AACnB,gBAAiB,AACjB,wBAA0B,CAC3B,AAED,yDACE,wBAA0B,CAC3B,AAED,4DACE,sBAA0B,AAC1B,UAAe,CAChB,AAED,0DACE,wBAA0B,AAC1B,UAAe,CAChB,AAMD,oFAEE,aAAe,CAEhB,AAKD,sIAGE,aAAe,CAEhB,AAKD,qIAGE,aAAe,CAEhB,AAKD,4CACE,aAAe,CAEhB,AAKD,2CACE,aAAe,CAEhB,AAED,6CACE,UAAY,CACb,AAID,2CACE,UAAY,CAEb,AAMD,4FACE,UAAY,CACb,AAED,oDACE,qBAAuB,AACvB,UAAY,CACb,AAED,aACE,sBAAuB,AACvB,eAAgB,AAChB,aAAc,AACd,aAA0B,CAC3B,AAOD,WACE,iBAAmB,CACpB,AAED,kCACE,6CAAiD,AACjD,cAAe,AACf,gBAAiB,AACjB,wBAA0B,CAC3B,AAED,iCACE,sCAA0C,AAC1C,iBAAmB,CACpB,AAED,qEAEE,2CAA+C,AAC/C,cAAe,AACf,qBAAwB,CACzB,AAED,oHAIE,eAAiB,CAClB,AAED,wBACE,eAAkB,CACnB,AAED,kCACE,cAAgB,CACjB,AAED,2CACE,0CAA+C,CAChD,AAED,2CACE,mCAAwC,CACzC,AAED,gDACE,cAAe,AACf,mBAAsB,CACvB,AAED,yBACE,iBAAkB,AAClB,oBAAsB,CACvB,AAED,8DAEE,kBAAqB,AACrB,kBAAmB,AACnB,MAAS,AACT,OAAU,AACV,yBAA0B,AAC1B,qCAA8B,AAA9B,6BAA8B,AAE9B,kCAAsC,AACtC,cAAe,AACf,sBAAwB,AACxB,2BAAqB,AAArB,sBAAqB,AAArB,kBAAqB,CACtB,AAED,yBACE,8DAEE,kBAAqB,AACrB,iCAAsC,CACvC,CACF,AAED,iCACE,QAAS,AACT,SAAU,AACV,wBAAiB,AAAjB,eAAiB,CAClB,AAED,gFAEE,iBAAkB,AAClB,cAAe,AACf,sBAAwB,AACxB,eAAiB,CAClB,AAED,0CACE,YAAc,CACf,AACD,8CACE,UAAY,CACb,AACD,uDACE,WAAa,CACd,AAED,uDACE,qBAAsB,AACtB,aAAc,AACd,WAAa,CACd,AAED,cACE,cAAgB,CACjB,AAED,kBACE,cAAe,AACf,oBAAqB,AACrB,qBAAsB,AACtB,oBAAc,AAAd,aAAc,AACd,uBAAwB,AACxB,mBAAgB,AAAhB,eAAgB,AAChB,eAAiB,AACjB,QAAY,CACb,AACD,SACE,cAAgB,CACjB,AACD,kCACE,WAAY,AACZ,oBAAsB,CACvB,AACD,aACE,YAAgB,CACjB,AACD,qBACE,qBAAsB,AACtB,iBAAkB,AAClB,yBAA0B,AAC1B,mBAAoB,AACpB,iCAAsC,AACtC,UAAY,CACb,AACD,kCACE,QAAY,CACb,AAqBD,eACE,cAAgB,CACjB,AAED,gCACE,eAAiB,CAClB,AAED,yBAME,kCACE,4CAAiD,CAClD,AAED,iCACE,mBAAoB,AACpB,aAAe,CAChB,AAED,iCACE,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,YAAc,CACf,AAED,kCACE,gBAAkB,CACnB,AAED,0BACE,UAAW,AACX,YAAa,AACb,qBAAsB,AACtB,UAAY,CACb,AAED,2BACE,SAAW,CACZ,CACF,AAED,iCACE,aAAe,CAChB,AAED,4CACE,cAAe,AACf,0CAAgD,CACjD,AAED,2CACE,qCAA0C,AAC1C,sBAAwB,AACxB,gBAAiB,AACjB,cAAiB,CAClB,AAED,+BACE,6CAAmD,CACpD,AAED,iCACE,cAAiB,CAClB,AAMD,kDACE,eAAkB,CACnB,AAED,yBACE,iBAAmB,CACpB,AAED,0BACE,cAAgB,AAChB,qBAAsB,AACtB,WAAY,AAKZ,sCAA0C,AAC1C,eAAiB,CAClB,AAED,oBACE,gBAAkB,CACnB,AAOD,+BACE,kBAAoB,CACrB,AAED,qBACE,sCAA0C,AAC1C,WAAa,AACb,kBAAmB,AACnB,oBAAqB,AACrB,gCAAkC,CACnC,AAED,qBACE,cAAgB,CACjB,AAID,2BACE,cAAgB,CACjB,AAED,iCACE,qBAAsB,AACtB,2CAA+C,AAC/C,iBAAkB,AAClB,gBAAiB,AACjB,mBAAoB,AACpB,cAAe,AAEf,mBAAoB,AACpB,iBAAkB,AAClB,yBAA0B,AAM1B,cAAgB,CAHjB,AAOD,uCACE,WAAa,AACb,wBAA0B,CAC3B,AAGD,gDACE,iBAAkB,AAKlB,kBAAmB,AACnB,SAAW,CALZ,AASD,sCACE,sCAA2C,AAC3C,cAAe,AACf,YAAa,AACb,iBAAiB,AACjB,gBAAiB,AACjB,sBAAuB,AACvB,wBAAiB,AAAjB,gBAAiB,AACjB,qBAAsB,AACtB,YAAa,AACb,UAAY,CAEb,AAKD,0BACE,eAAgB,AAChB,gBAAiB,AACjB,UAAY,CACb,AAED,gCACI,qBAAsB,AACtB,mBAAoB,AACpB,qCAA0C,AAM1C,WAAa,AACb,mBAAoB,AACpB,aAAgB,AAChB,uBAAgB,AAAhB,kBAAgB,AAAhB,eAAgB,AAChB,mBAAoB,AAIpB,iBAAkB,AAClB,cAAgB,CAJnB,AAOD,uCACI,qBAAsB,AACtB,WAAyB,CAC5B,AAED,sCACI,cAAe,AACf,kBAAoB,CAGtB,AAEF,6DACI,WAAa,AACb,kBAAoB,CAEvB,AAED,+CACE,iBAAkB,AAClB,kBAAmB,AACnB,SAAW,CACZ,AAGD,gCACE,cAAe,AACf,UAAY,CAEb,AAKD,0BAEE,sBAAwB,AACxB,aAAc,AACd,gBAAiB,AACjB,2CAAqC,AAArC,sCAAqC,AAArC,mCAAqC,AACrC,mBAAqB,AACrB,gBAAqB,CAEtB,AAID,4BACE,SAAU,AACV,WAAY,AACZ,gBAAiB,AACjB,YAAa,AACb,iBAAiB,AACjB,uCAAiC,AAAjC,kCAAiC,AAAjC,8BAAiC,CAClC,AAID,2BACE,iCAAqC,AACrC,iBAAmB,CACpB,AAKD,yBAEE,gBAAiB,AACjB,iBAAkB,AAElB,oCAAwC,AACxC,cAAe,AACf,iBAAmB,CAEpB,AAED,8BACE,cAAe,AACf,WAAY,AACZ,eAAgB,AAChB,mBAAqB,CACtB,AAGD,gBACE,mBAAqB,CACtB,AAED,qBACE,iCAAsC,AACtC,aAAe,CAEhB,AAED,mBACE,kBAAmB,AACnB,cAAe,AACf,YAAa,AACb,eAAgB,AAChB,gBAAkB,AAClB,kBAAmB,AACnB,gBAAiB,AACjB,cAAe,CAChB,AAED,sCACE,cAAe,AACf,qBAAsB,AACtB,cAAgB,CACjB,AAED,wBAGE,WAAgB,AAChB,gBAAiB,AACjB,qBAAsB,AACtB,mBAAoB,AACpB,iCAAsC,AACtC,WAAe,AACf,mBAAoB,AACpB,WAAa,AACb,kBAAoB,CACrB,AAID,2CAEE,UAAW,AACX,WAAY,AACZ,kBAAoB,CACrB,AAED,iDACE,kBAAoB,CACrB,AAED,iDACE,kBAAoB,CACrB,AAID,kBACE,gBAAiB,AACjB,gBAAiB,CAClB,AAED,uBACE,cAAe,AACf,qCAA0C,CAC3C,AAGD,8BACE,6CAAiD,AACjD,cAAe,AACf,kBAAmB,AACnB,mBAAqB,CACtB,AAED,0BAEE,kBAAmB,AACnB,4CAAgD,AAChD,WAAa,AACb,mBAAoB,AACpB,mBAAqB,AACrB,mBAAoB,AACpB,mBAAoB,AACpB,kBAAmB,AACnB,cAAgB,CAGjB,AAED,gCACE,WAAY,AACZ,kBAAmB,AACnB,MAAO,AACP,QAAS,AACT,QAAS,AACT,SAAU,AAEV,8BAA6B,AAA7B,4BAA6B,AAC7B,aAAc,AACd,kBAAmB,AACnB,gBAAkB,CACnB,AAED,6BAEE,oCAAwC,AACxC,aAAe,CAGhB,AAED,iDAJE,kBAAmB,AACnB,6CAAoD,CAUrD,AAPD,oBACE,+BAAmC,AACnC,UAAa,CAKd,AAQD,oDAEE,kBAAqB,CACtB,AAOD,0CACE,YAAc,CACf,AAGD,mBACE,aAAc,AACd,eAAgB,AAChB,YAAa,AACb,WAAY,AACZ,YAAa,AACb,MAAM,AACN,OAAO,AACP,QAAQ,AACR,cAAe,AACf,8BAAuB,AAAvB,2BAAuB,AAAvB,sBAAuB,AACvB,qCAA2C,CAE5C,AAED,2BACE,eAAgB,AAChB,gBAAkB,AAClB,OAAQ,AACR,QAAS,AACT,SAAU,AACV,UAAW,AACX,YAAa,AACb,2BAA4B,AAC5B,gBAAiB,AACjB,4DAAyD,AAAzD,oDAAyD,AACzD,4DAAyD,AAAzD,oDAAyD,AACzD,2DAAwD,AAAxD,kDAAwD,CACzD,AAED,wBAEE,YAAa,AACb,WAAY,AACZ,UAAW,AACX,eAAiB,CAElB,AAED,6BACE,WAAY,AACZ,aAAc,AACd,eAAkB,CAYnB,AAED,qDAEE,gBAAiB,AACjB,sBAAwB,CAEzB,AAED,uBAEE,mBAAqB,AACrB,oBAAqB,AAErB,+BAAqC,AACrC,kBAAmB,AAEnB,iCAAoC,CAErC,AAQD,iBAGE,2BAA4B,AAC5B,8BAA+B,AAC/B,qBAAuB,CACxB,AAED,KACE,gBAAkB,CACnB,AAED,KACE,SAAU,AACV,sBAAuB,AACvB,kBAAqB,AACrB,gBAAiB,AACjB,iBAAkB,AAClB,UAAY,CACb,AAED,EACE,gBAAiB,AACjB,aAAgB,CACjB,AAED,QACE,eAAiB,CAClB,AAID,kFAIE,cAAe,AAKf,uBAAwB,AACxB,2BAA4B,AAC5B,yBAA0B,AAE1B,sBAAuB,AACvB,qBAAsB,AACtB,gBAAkB,CACnB,AAID,iBAEE,cAAe,AACf,oBAAsB,CAEvB,AAED,oCAGE,cAAe,AACf,qBAAsB,AACtB,qBAAuB,AAEvB,mCAA6B,AAC7B,6CAAsC,AAAtC,wCAAsC,AAAtC,oCAAsC,CACvC,AAED,oBACE,WAAa,CACd,AAED,OACE,cAAe,AACf,qBAAsB,AACtB,oBAAsB,AACtB,0BAA2B,AAC3B,2BAA6B,CAC9B,AAED,WACE,oCAA0C,CAC3C,AAED,6BACE,cAAgB,CACjB,AAED,eAKE,sBAA0B,AAC1B,oBAAqB,AACrB,gBAAiB,AACjB,iCAAsC,CACvC,AAED,GACE,iBAAkB,AAElB,QAAU,CACX,AAED,GACE,gBAAiB,AAEjB,cAAkB,CACnB,AAED,MACE,0CAAgD,CACjD,AAED,UACE,wBAA0B,AAC1B,kCAAsC,AACtC,WAAa,CACd,AAED,YACE,aAAe,CAChB,AAED,kBACE,cAAe,AACf,kBAAoB,CACrB,AAQD,sBAEE,WAAY,AACZ,mBAAsB,AAEtB,SAAU,AACV,kBAAmB,AACnB,eAAiB,AACjB,mBAA+B,AAC/B,kEAIE,AAJF,6DAIE,AAJF,0DAIE,AACF,kCAAsC,AACtC,uBAA0B,CAC3B,AAED,aACE,mBAAoB,AACpB,oBAAwB,CACzB,AAED,YACE,mBAAqB,AACrB,SAAW,CACZ,AAED,iCAEE,WAAc,CACf,AAED,iCAEE,YAAc,AACd,WAAa,CACd,AAED,QACE,kBAAmB,AACnB,aAAc,AACd,MAAO,AACP,OAAQ,AAER,WAAY,AAGZ,cAAe,AACf,SAAU,AACV,0CAA2C,AAC3C,iCAAsC,AAEtC,yBAA8B,AAC9B,oCAA4C,CAE7C,AAED,kBACE,eAAkB,CACnB,AAED,qBACE,gBAAiB,AACjB,qBAAsB,AACtB,QAAU,CACX,AAED,iCACE,eAAiB,CAClB,AAED,gCACE,YAAa,AACb,gBAAkB,CACnB,AAED,cACE,iBAAkB,AAClB,UAAW,AACX,UAAY,CACb,AAED,aACE,iBAAkB,AAClB,UAAW,AACX,WAAY,AACZ,cAAgB,CACjB,AAED,sBACE,YAAc,CACf,AAED,KACE,SAAW,CACZ,AAED,QACE,UAAY,CACb,AAED,GACE,SAAU,AACV,UAAW,AACX,eAAiB,CAClB,AAED,GACE,eAAiB,CAClB,AAED,GACE,SAAU,AACV,SAAW,CACZ,AAED,aACE,oBAAsB,AACtB,UAAW,AACX,gBAAiB,AACjB,4BAA6B,AAC7B,eAAiB,CAClB,AAED,gBACE,aAAe,CAChB,AAED,UACE,iBAAkB,AAClB,UAAW,AACX,gBAAiB,AACjB,0BAA4B,CAC7B,AAED,eACE,UAAW,AACX,YAAc,CACf,AAED,mBACE,YAAa,AACb,eAAgB,AAChB,mBAAsB,CACvB,AAED,iBAEE,qBAAwB,AACxB,UAAY,CACb,AAED,MACE,YAAc,CACf,AAED,OACE,UAAY,CACb,AAED,QACE,kBAAmB,AACnB,YAAa,AACb,YAAa,AACb,SAAY,AACZ,2BAA4B,AAC5B,yBAA0B,AAE1B,sBAAuB,AACvB,qBAAsB,AACtB,gBAAkB,CACnB,AAED,eACE,SAAU,AACV,UAAW,AACX,WAAa,CACd,AAED,gBACE,SAAW,CACZ,AAED,MAEE,UAAW,AACX,YAAa,AACb,gBAAqB,AACrB,aAAc,AACd,YAAc,CACf,AAED,UACE,cAAe,AACf,eAAiB,AACjB,kCAAsC,AACtC,qBAAwB,CACzB,AAED,eACE,mBAAoB,AACpB,aAAc,AACd,YAAc,CACf,AAED,SACE,mBAAqB,CACtB,AAED,yBAEE,iBAAkB,AAClB,eAAiB,AACjB,kCAAsC,AACtC,iBAAoB,CACrB,AAED,OACE,WAAY,AAEZ,+BAA0B,AAC1B,YAAc,CACf,AAED,cACE,kBAAmB,AACnB,sBAAuB,AACvB,SAAU,AACV,eAAkB,CACnB,AACD,qBACE,kBAAmB,AACnB,MAAO,AACP,OAAQ,AACR,WAAY,AACZ,WAAa,CACd,AAUD,IACE,6BAA8B,AAC9B,SAAU,AACV,gBAAiB,CAEjB,mBAAsB,CACvB,AAED,WACE,WAAY,AACZ,cAAe,AACf,QAAS,AACT,WAAa,CACd,AAMD,QACE,uBAAyB,AACzB,iBAAmB,CACpB,AAMD,SACE,SAAU,AACV,mBAAoB,AACpB,WAAY,AACZ,YAAa,AACb,gBAAiB,AACjB,UAAW,AACX,kBAAmB,AACnB,SAAW,CACZ,AAOD,mDAEE,UAAW,AACX,YAAa,AACb,SAAU,AACV,iBAAkB,AAClB,gBAAiB,AACjB,UAAY,CACb,AAMD,WACE,iBAAmB,CACpB,AAcD,iCAEE,YAAa,AAEb,aAAe,CAEhB,AAED,gBACE,UAAY,CACb,AAOD,WACE,MAAS,CACV,AAMD,mBACE,aAAc,AACd,4BAAS,AAAT,gBAAS,AAAT,iBAAS,AAAT,OAAS,CACV,AAMD,2EAEE,YAAc,CACf,AAED,iFAEE,oBAAqB,AACrB,oBAAsB,CACvB,AAED,yBACE,WACE,qBAAuB,AACvB,kBAAoB,CACrB,AACD,KACE,WAAY,AACZ,mBAAsB,CACvB,AACD,OACE,UAAY,CACb,CACF,AAED,yBACE,WACE,mBAAoB,AACpB,WAAY,AACZ,iBAAqB,AACrB,YAAa,AACb,eAAiB,CAClB,AACD,WACE,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,aAAc,AACd,sBAAe,AAAf,kBAAe,AAAf,aAAe,CAChB,AACD,KACE,iBAAmB,CACpB,AACD,4BAIE,cAAiB,CAClB,AACD,OACE,UAAY,CAEb,AACD,UACE,kBAAmB,AACnB,QAAW,AACX,SAAW,CACZ,AAID,kBAFE,iCAAsC,CAiBvC,AAfD,MACE,gBAAiB,AAEjB,yBAA2B,AAE3B,YAAa,AACb,YAAa,AAEb,uBAAwB,AACxB,0BAA2B,AAC3B,UAAW,AACX,gBAAkB,AAClB,YAAa,AACb,kBAAmB,AACnB,KAAO,CACR,AACD,SACE,WAAY,AACZ,eAAkB,AAClB,gBAAkB,CACnB,AASD,uBACE,eAAgB,AAChB,gBAAmB,CAEpB,AACD,aACE,UAAW,AACX,WAAY,AACZ,kBAAoB,CACrB,AACD,cACE,UAAW,AACX,YAAa,AACb,eAAgB,AAChB,mBAAsB,CACvB,AACD,oBACE,UAAW,AACX,UAAY,CACb,AACD,mBACE,UAAW,AACX,YAAa,AACb,eAAgB,AAChB,mBAAsB,CACvB,AACD,MACE,cAAiB,CAClB,AACD,8BAGE,WAAY,AACZ,cAAgB,CACjB,AACD,oBAEE,gBAAkB,CACnB,AACD,qBACE,WAAY,AACZ,WAAY,AACZ,uCAA6C,CAC9C,AAED,4BACE,kCAAsC,AACtC,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,aAAc,AACd,8BAAoB,AAApB,6BAAoB,AAApB,2BAAoB,AAApB,uBAAoB,AAApB,mBAAoB,AACpB,kBAAsB,CACvB,AACD,+BACE,mBAAQ,AAAR,eAAQ,AAAR,WAAQ,AAAR,MAAQ,CACT,AACD,iBACE,QAAU,CACX,AACD,kBACE,sBAAyB,CAC1B,AACD,mBACE,iBAAmB,CACpB,AAED,0BACE,iBAAsB,CACvB,AACD,sBACE,cAAgB,CACjB,AACD,MACE,oBAAc,AAAd,qBAAc,AAAd,oBAAc,AAAd,aAAc,AACd,8BAAoB,AAApB,6BAAoB,AAApB,2BAAoB,AAApB,uBAAoB,AAApB,mBAAoB,AACpB,uBAAgB,AAAhB,mBAAgB,AAAhB,eAAgB,AAChB,iBAAmB,CACpB,CACF,AAED,yBACE,SACE,sBAAyB,CAC1B,AAED,QACE,YAAc,CACf,AAED,UACE,kBAAmB,AACnB,SAAW,AACX,WAAa,AACb,UAAY,CACb,AAED,QAEE,WAAY,AACZ,iBAAmB,CACpB,AAED,iCALE,UAAY,CAOb,AAED,oDAEE,eAAiB,CAClB,AAED,QACE,kBAAmB,AACnB,QAAS,AACT,QAAU,CACX,AACD,aACE,SAAS,AACT,cAAe,AACf,UAAY,CACb,AACD,qBAEE,kBAAsB,AACtB,eAAiB,CAClB,AACD,SACE,oBAAsB,CACvB,AAED,4BACE,UAAY,CACb,AAED,iBACE,WAAa,CACd,AAED,6BACE,aAAiB,CAClB,AACD,cACE,SAAW,CACZ,AACD,uBACE,UAAW,AACX,gBAAiB,AACjB,UAAY,CACb,AACD,UACE,gBAAiB,AACjB,cAAgB,CACjB,AACD,mDAEE,uBAAyB,AACzB,mBAAqB,CACtB,AACD,sBACE,aAAqB,AACrB,UAAY,CACb,AAED,KACE,qBAAsB,AACtB,oBAAsB,CACvB,AACD,SACE,4BAA8B,AAC9B,UAAW,AACX,gBAAiB,AACjB,sBAAuB,AACvB,eAAiB,AACjB,YAAa,AACb,WAAY,AACZ,gBAAkB,CAGnB,AACD,4BAHE,YAAc,CAMf,AACD,6DAGE,UAAY,CACb,AACD,6BACE,WAAc,CACf,AACD,8BACE,QAAU,CACX,AACD,6BACE,WAAa,CACd,AACD,eACE,cAAgB,CACjB,AACD,oBAGE,cAAiB,CAClB,AACD,WACE,SAAW,CACZ,CACF,AAED,yBACE,MACE,0BAA8B,CAC/B,AACD,KACE,2BAA+B,CAChC,CACF,AAED,OACE,YAAa,AACb,UAAY,CACb,AAED,kBACE,gBAAiB,AACjB,iBAAmB,CACpB,AAED,yBACE,SAAU,AACV,YAAa,AACb,OAAQ,AACR,kBAAmB,AACnB,MAAO,AACP,UAAY,CACb,AAED,SAIE,2BAAqB,AAArB,4BAAqB,AAArB,2BAAqB,AAArB,oBAAqB,AACrB,4BAAuB,AAAvB,6BAAuB,AAAvB,8BAAuB,AAAvB,0BAAuB,AAAvB,qBAAuB,CACxB,AAED,WACE,YAAa,AACb,WAAa,CACd,AAQD,cACE,SAAU,AACV,eAAkB,CACnB,AAED,iBACE,gBAAiB,AACjB,qBAAsB,AACtB,gBAAmB,CACpB,AAED,YACE,YAAa,AACb,aAAc,AACd,eAAiB,AACjB,cAAe,AACf,SAAW,CACZ,AAED,kBACE,aAAe,CAChB,AAED,qBACE,cAAe,AACf,cAAgB,CACjB,AAUD,yBACE,eAAgB,AAChB,WAAY,AACZ,WAAa,AACb,mBAAqB,CACtB,AAID,0BACE,YAAc,AACd,aAAe,AACf,qBAA+B,AAC/B,qBAAsB,AACtB,gBAAiB,AACjB,kBAAmB,AACnB,6WACoY,AACpY,oCAAwB,AAAxB,qBAAwB,CACzB,AAED,oCACE,WAAY,AACZ,UAAW,AACX,YAAa,AACb,WAAY,AACZ,SAAW,CACZ,AAED,gIAGE,YAAa,AACb,UAAW,AACX,YAAa,AACb,WAAY,AACZ,gCAAiC,AAEjC,4BAA6B,AAC7B,2BAA4B,AAC5B,uBAAyB,CAC1B,AAED,8EAEE,YAAa,AACb,WAAY,AACZ,YAAa,AACb,WAAY,AACZ,+BAAgC,AAEhC,2BAA4B,AAC5B,0BAA2B,AAC3B,sBAAwB,CACzB,AAED,oFAEE,QAAS,AACT,WAAY,AACZ,YAAa,AACb,WAAY,AACZ,+BAAgC,AAEhC,2BAA4B,AAC5B,0BAA2B,AAC3B,sBAAwB,CACzB,AAED,iFAEE,OAAQ,AACR,QAAS,AACT,YAAa,AACb,WAAY,AACZ,iCAAkC,AAElC,6BAA8B,AAC9B,4BAA6B,AAC7B,wBAA0B,CAC3B,AAED,6BACE,cAAe,AACf,qBAAsB,AACtB,qBAAuB,AACvB,aAAc,AAGd,YAA6B,AAA7B,mCAA6B,AAC7B,6CAAsC,AAAtC,wCAAsC,AAAtC,qCAAsC,AACtC,UAAY,CACb,AAED,2BACE,kBAAmB,AACnB,YAAc,CACf,AAED,+BACE,yBAA0B,AAC1B,cAAe,AACf,kBAAqB,AACrB,eAAkB,AAClB,kCAAsC,AACtC,aAAe,CAChB,AAED,qCACE,yBAA0B,AAC1B,UAAa,CACd,AAED,wDACE,aAAe,CAChB,AAID,6FACE,aAAe,CAChB,AACD,mDACE,aAAe,CAChB,AAED,yBACE,6BACE,UAAY,CACb,AAED,+BAEE,kBAAmB,AACnB,cAAgB,CACjB,CACF","file":"../all.css","sourcesContent":["/*! normalize.css v1.1.0 | MIT License | git.io/normalize */\r\n\r\n/* ==========================================================================\r\n HTML5 display definitions\r\n ========================================================================== */\r\n\r\n/**\r\n * Correct `block` display not defined in IE 6/7/8/9 and Firefox 3.\r\n */\r\n\r\narticle,\r\naside,\r\ndetails,\r\nfigcaption,\r\nfigure,\r\nfooter,\r\nheader,\r\nhgroup,\r\nmain,\r\nnav,\r\nsection,\r\nsummary {\r\n display: block;\r\n}\r\n\r\n/**\r\n * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.\r\n */\r\n\r\naudio,\r\ncanvas,\r\nvideo {\r\n display: inline-block;\r\n *display: inline;\r\n *zoom: 1;\r\n}\r\n\r\n/**\r\n * Prevent modern browsers from displaying `audio` without controls.\r\n * Remove excess height in iOS 5 devices.\r\n */\r\n\r\naudio:not([controls]) {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n/**\r\n * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.\r\n * Known issue: no IE 6 support.\r\n */\r\n\r\n[hidden] {\r\n display: none;\r\n}\r\n\r\n/* ==========================================================================\r\n Base\r\n ========================================================================== */\r\n\r\n/**\r\n * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using\r\n * `em` units.\r\n * 2. Prevent iOS text size adjust after orientation change, without disabling\r\n * user zoom.\r\n */\r\n\r\nhtml {\r\n font-size: 100%; /* 1 */\r\n -webkit-text-size-adjust: 100%; /* 2 */\r\n -ms-text-size-adjust: 100%; /* 2 */\r\n}\r\n\r\n/**\r\n * Address `font-family` inconsistency between `textarea` and other form\r\n * elements.\r\n */\r\n\r\nhtml,\r\nbutton,\r\ninput,\r\nselect,\r\ntextarea {\r\n font-family: sans-serif;\r\n}\r\n\r\n/**\r\n * Address margins handled incorrectly in IE 6/7.\r\n */\r\n\r\nbody {\r\n margin: 0;\r\n}\r\n\r\n/* ==========================================================================\r\n Links\r\n ========================================================================== */\r\n\r\n/**\r\n * Address `outline` inconsistency between Chrome and other browsers.\r\n */\r\n\r\na:focus {\r\n outline: thin dotted;\r\n}\r\n\r\n/**\r\n * Improve readability when focused and also mouse hovered in all browsers.\r\n */\r\n\r\na:active,\r\na:hover {\r\n outline: 0;\r\n}\r\n\r\n/* ==========================================================================\r\n Typography\r\n ========================================================================== */\r\n\r\n/**\r\n * Address font sizes and margins set differently in IE 6/7.\r\n * Address font sizes within `section` and `article` in Firefox 4+, Safari 5,\r\n * and Chrome.\r\n */\r\n\r\nh1 {\r\n font-size: 2em;\r\n margin: 0.67em 0;\r\n}\r\n\r\nh2 {\r\n font-size: 1.5em;\r\n margin: 0.83em 0;\r\n}\r\n\r\nh3 {\r\n font-size: 1.17em;\r\n margin: 1em 0;\r\n}\r\n\r\nh4 {\r\n font-size: 1em;\r\n margin: 1.33em 0;\r\n}\r\n\r\nh5 {\r\n font-size: 0.83em;\r\n margin: 1.67em 0;\r\n}\r\n\r\nh6 {\r\n font-size: 0.67em;\r\n margin: 2.33em 0;\r\n}\r\n\r\n/**\r\n * Address styling not present in IE 7/8/9, Safari 5, and Chrome.\r\n */\r\n\r\nabbr[title] {\r\n border-bottom: 1px dotted;\r\n}\r\n\r\n/**\r\n * Address style set to `bolder` in Firefox 3+, Safari 4/5, and Chrome.\r\n */\r\n\r\nb,\r\nstrong {\r\n font-weight: bold;\r\n}\r\n\r\nblockquote {\r\n margin: 1em 40px;\r\n}\r\n\r\n/**\r\n * Address styling not present in Safari 5 and Chrome.\r\n */\r\n\r\ndfn {\r\n font-style: italic;\r\n}\r\n\r\n/**\r\n * Address differences between Firefox and other browsers.\r\n * Known issue: no IE 6/7 normalization.\r\n */\r\n\r\nhr {\r\n -moz-box-sizing: content-box;\r\n box-sizing: content-box;\r\n height: 0;\r\n}\r\n\r\n/**\r\n * Address styling not present in IE 6/7/8/9.\r\n */\r\n\r\nmark {\r\n background: #ff0;\r\n color: #000;\r\n}\r\n\r\n/**\r\n * Address margins set differently in IE 6/7.\r\n */\r\n\r\np,\r\npre {\r\n margin: 1em 0;\r\n}\r\n\r\n/**\r\n * Correct font family set oddly in IE 6, Safari 4/5, and Chrome.\r\n */\r\n\r\ncode,\r\nkbd,\r\npre,\r\nsamp {\r\n font-family: monospace, serif;\r\n _font-family: 'courier new', monospace;\r\n font-size: 1em;\r\n}\r\n\r\n/**\r\n * Improve readability of pre-formatted text in all browsers.\r\n */\r\n\r\npre {\r\n white-space: pre;\r\n white-space: pre-wrap;\r\n word-wrap: break-word;\r\n}\r\n\r\n/**\r\n * Address CSS quotes not supported in IE 6/7.\r\n */\r\n\r\nq {\r\n quotes: none;\r\n}\r\n\r\n/**\r\n * Address `quotes` property not supported in Safari 4.\r\n */\r\n\r\nq:before,\r\nq:after {\r\n content: '';\r\n content: none;\r\n}\r\n\r\n/**\r\n * Address inconsistent and variable font size in all browsers.\r\n */\r\n\r\nsmall {\r\n font-size: 80%;\r\n}\r\n\r\n/**\r\n * Prevent `sub` and `sup` affecting `line-height` in all browsers.\r\n */\r\n\r\nsub,\r\nsup {\r\n font-size: 75%;\r\n line-height: 0;\r\n position: relative;\r\n vertical-align: baseline;\r\n}\r\n\r\nsup {\r\n top: -0.5em;\r\n}\r\n\r\nsub {\r\n bottom: -0.25em;\r\n}\r\n\r\n/* ==========================================================================\r\n Lists\r\n ========================================================================== */\r\n\r\n/**\r\n * Address margins set differently in IE 6/7.\r\n */\r\n\r\ndl,\r\nmenu,\r\nol,\r\nul {\r\n margin: 1em 0;\r\n}\r\n\r\ndd {\r\n margin: 0 0 0 40px;\r\n}\r\n\r\n/**\r\n * Address paddings set differently in IE 6/7.\r\n */\r\n\r\nmenu,\r\nol,\r\nul {\r\n padding: 0 0 0 40px;\r\n}\r\n\r\n/**\r\n * Correct list images handled incorrectly in IE 7.\r\n */\r\n\r\nnav ul,\r\nnav ol {\r\n list-style: none;\r\n list-style-image: none;\r\n}\r\n\r\n/* ==========================================================================\r\n Embedded content\r\n ========================================================================== */\r\n\r\n/**\r\n * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.\r\n * 2. Improve image quality when scaled in IE 7.\r\n */\r\n\r\nimg {\r\n border: 0; /* 1 */\r\n -ms-interpolation-mode: bicubic; /* 2 */\r\n}\r\n\r\n/**\r\n * Correct overflow displayed oddly in IE 9.\r\n */\r\n\r\nsvg:not(:root) {\r\n overflow: hidden;\r\n}\r\n\r\n/* ==========================================================================\r\n Figures\r\n ========================================================================== */\r\n\r\n/**\r\n * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.\r\n */\r\n\r\nfigure {\r\n margin: 0;\r\n}\r\n\r\n/* ==========================================================================\r\n Forms\r\n ========================================================================== */\r\n\r\n/**\r\n * Correct margin displayed oddly in IE 6/7.\r\n */\r\n\r\nform {\r\n margin: 0;\r\n}\r\n\r\n/**\r\n * Define consistent border, margin, and padding.\r\n */\r\n\r\nfieldset {\r\n border: 1px solid #c0c0c0;\r\n margin: 0 2px;\r\n padding: 0.35em 0.625em 0.75em;\r\n}\r\n\r\n/**\r\n * 1. Correct color not being inherited in IE 6/7/8/9.\r\n * 2. Correct text not wrapping in Firefox 3.\r\n * 3. Correct alignment displayed oddly in IE 6/7.\r\n */\r\n\r\nlegend {\r\n border: 0; /* 1 */\r\n padding: 0;\r\n white-space: normal; /* 2 */\r\n *margin-left: -7px; /* 3 */\r\n}\r\n\r\n/**\r\n * 1. Correct font size not being inherited in all browsers.\r\n * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,\r\n * and Chrome.\r\n * 3. Improve appearance and consistency in all browsers.\r\n */\r\n\r\nbutton,\r\ninput,\r\nselect,\r\ntextarea {\r\n font-size: 100%; /* 1 */\r\n margin: 0; /* 2 */\r\n vertical-align: baseline; /* 3 */\r\n *vertical-align: middle; /* 3 */\r\n}\r\n\r\n/**\r\n * Address Firefox 3+ setting `line-height` on `input` using `!important` in\r\n * the UA stylesheet.\r\n */\r\n\r\nbutton,\r\ninput {\r\n line-height: normal;\r\n}\r\n\r\n/**\r\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\r\n * All other form control elements do not inherit `text-transform` values.\r\n * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.\r\n * Correct `select` style inheritance in Firefox 4+ and Opera.\r\n */\r\n\r\nbutton,\r\nselect {\r\n text-transform: none;\r\n}\r\n\r\n/**\r\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\r\n * and `video` controls.\r\n * 2. Correct inability to style clickable `input` types in iOS.\r\n * 3. Improve usability and consistency of cursor style between image-type\r\n * `input` and others.\r\n * 4. Remove inner spacing in IE 7 without affecting normal text inputs.\r\n * Known issue: inner spacing remains in IE 6.\r\n */\r\n\r\nbutton,\r\nhtml input[type=\"button\"], /* 1 */\r\ninput[type=\"reset\"],\r\ninput[type=\"submit\"] {\r\n -webkit-appearance: button; /* 2 */\r\n cursor: pointer; /* 3 */\r\n *overflow: visible; /* 4 */\r\n}\r\n\r\n/**\r\n * Re-set default cursor for disabled elements.\r\n */\r\n\r\nbutton[disabled],\r\nhtml input[disabled] {\r\n cursor: default;\r\n}\r\n\r\n/**\r\n * 1. Address box sizing set to content-box in IE 8/9.\r\n * 2. Remove excess padding in IE 8/9.\r\n * 3. Remove excess padding in IE 7.\r\n * Known issue: excess padding remains in IE 6.\r\n */\r\n\r\ninput[type=\"checkbox\"],\r\ninput[type=\"radio\"] {\r\n box-sizing: border-box; /* 1 */\r\n padding: 0; /* 2 */\r\n *height: 13px; /* 3 */\r\n *width: 13px; /* 3 */\r\n}\r\n\r\n/**\r\n * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.\r\n * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome\r\n * (include `-moz` to future-proof).\r\n */\r\n\r\ninput[type=\"search\"] {\r\n -webkit-appearance: textfield; /* 1 */\r\n -moz-box-sizing: content-box;\r\n -webkit-box-sizing: content-box; /* 2 */\r\n box-sizing: content-box;\r\n}\r\n\r\n/**\r\n * Remove inner padding and search cancel button in Safari 5 and Chrome\r\n * on OS X.\r\n */\r\n\r\ninput[type=\"search\"]::-webkit-search-cancel-button,\r\ninput[type=\"search\"]::-webkit-search-decoration {\r\n -webkit-appearance: none;\r\n}\r\n\r\n/**\r\n * Remove inner padding and border in Firefox 3+.\r\n */\r\n\r\nbutton::-moz-focus-inner,\r\ninput::-moz-focus-inner {\r\n border: 0;\r\n padding: 0;\r\n}\r\n\r\n/**\r\n * 1. Remove default vertical scrollbar in IE 6/7/8/9.\r\n * 2. Improve readability and alignment in all browsers.\r\n */\r\n\r\ntextarea {\r\n overflow: auto; /* 1 */\r\n vertical-align: top; /* 2 */\r\n}\r\n\r\n/* ==========================================================================\r\n Tables\r\n ========================================================================== */\r\n\r\n/**\r\n * Remove most spacing between table cells.\r\n */\r\n\r\ntable {\r\n border-collapse: collapse;\r\n border-spacing: 0;\r\n}\r\n;/* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+css-extras+clike+javascript+java&plugins=line-numbers */\r\n\r\n/*\r\n\r\n * p5.js highlighting based on the prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML\r\n * Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics);\r\n * @author Tim Shedor\r\n\r\n*/\r\n\r\ncode[class*=\"language-\"],\r\npre[class*=\"language-\"],\r\ntextarea {\r\n color: #222;\r\n font-family:\r\n 'Inconsolata',\r\n Consolas,\r\n Monaco,\r\n 'Andale Mono',\r\n monospace;\r\n direction: ltr;\r\n text-align: left;\r\n white-space: pre;\r\n word-spacing: normal;\r\n word-break: normal;\r\n -moz-tab-size: 4;\r\n -o-tab-size: 4;\r\n tab-size: 4;\r\n -webkit-hyphens: none;\r\n -moz-hyphens: none;\r\n -ms-hyphens: none;\r\n hyphens: none;\r\n font-size: 1em !important;\r\n}\r\n\r\n/* Code blocks */\r\npre[class*=\"language-\"] {\r\n position:relative;\r\n padding: 0.5em 1.0em;\r\n margin: 0.5em 0 0 -0.5em;\r\n border-left: 0.5em solid #AFAFAF; /* coy og blue 10px solid 358ccb */\r\n background-color: #fff; /* coy og white #fdfdfd */\r\n /* lines */\r\n background-image: -webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.06) 50%);\r\n background-image: -moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.06) 50%);\r\n background-image: -ms-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.06) 50%);\r\n background-image: -o-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.06) 50%);\r\n background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.06) 50%);\r\n background-size: 2.9em 2.9em; /* adjusts height of alternating lines */\r\n background-origin:content-box;\r\n /* set overflow to just let the code roll */\r\n overflow:auto;\r\n /* or uncomment this to let an inner vertical scroll be triggered,\r\n but be generous as to when\r\n max-height:36em; */\r\n}\r\n\r\ncode[class*=\"language\"] {\r\n}\r\n\r\n\r\n:not(pre) > code[class*=\"language-\"],\r\npre[class*=\"language-\"] {\r\n margin-bottom: 1em;\r\n}\r\n\r\n/* Inline code */\r\n:not(pre) > code[class*=\"language-\"] {\r\n position:relative;\r\n padding: .2em;\r\n -webkit-border-radius: 0.3em;\r\n -moz-border-radius: 0.3em;\r\n -ms-border-radius: 0.3em;\r\n -o-border-radius: 0.3em;\r\n border-radius: 0.3em;\r\n color: #333;\r\n border: 1px solid rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n\r\n:not(pre) > code[class*=\"language-\"]:after,\r\npre[class*=\"language-\"]:after {\r\n right: 0.75em;\r\n left: auto;\r\n}\r\n\r\n/* code colors */\r\n.token.comment,\r\n.token.block-comment,\r\n.token.prolog,\r\n.token.doctype,\r\n.token.cdata {\r\n color: #A0A0A0; /* light gray */ /* 727272 898189 919191 A0A0A0 AFAFAF BEBEBE coy og: #7D8B99; */\r\n}\r\n\r\n.token.punctuation {\r\n color: #666; /* darker gray */ /* og coy 5F6364 */\r\n}\r\n\r\n.token.property,\r\n.token.tag,\r\n.token.boolean,\r\n.token.number,\r\n.token.function-name,\r\n.token.constant,\r\n.token.symbol {\r\n color: #DC3787; /* not p5 pink, but related */ /* og coy c92c2c a reddish color */\r\n}\r\n\r\n.token.selector,\r\n.token.attr-name,\r\n.token.string,\r\n.token.function,\r\n.token.builtin {\r\n color: #00A1D3; /* blue */ /* 877923 */ /* og coy 2f9c0a - green */\r\n}\r\n\r\n.token.operator,\r\n.token.entity,\r\n.token.url,\r\n.token.variable {\r\n color: #a67f59; /* og coy a67f59 a light brown */\r\n background: rgba(255, 255, 255, 0.5);\r\n}\r\n\r\n.token.atrule,\r\n.token.attr-value,\r\n.token.keyword,\r\n.token.class-name {\r\n color: #704F21; /* 9F944F brown */ /* og coy #1990b8 blue */\r\n}\r\n\r\n.token.regex,\r\n.token.important {\r\n color: #e90; /* og coy e90 orange */\r\n}\r\n.language-css .token.string,\r\n.style .token.string {\r\n color: #a67f59; /* og coy a67f59 a light brown */\r\n background: rgba(255, 255, 255, 0.5);\r\n}\r\n\r\n.token.important {\r\n font-weight: normal;\r\n}\r\n\r\n.token.entity {\r\n cursor: help;\r\n}\r\n\r\n.namespace {\r\n opacity: .7;\r\n}\r\n\r\n@media screen and (max-width:767px){\r\n pre[class*=\"language-\"]:before,\r\n pre[class*=\"language-\"]:after {\r\n bottom:14px;\r\n -webkit-box-shadow:none;\r\n -moz-box-shadow:none;\r\n box-shadow:none;\r\n }\r\n\r\n}\r\n\r\n/* Plugin styles */\r\n.token.tab:not(:empty):before,\r\n.token.cr:before,\r\n.token.lf:before {\r\n color: #e0d7d1; /* og coy very light brown */\r\n}\r\n\r\npre.line-numbers {\r\n position: relative;\r\n padding-left: 3.8em;\r\n counter-reset: linenumber;\r\n}\r\n\r\npre.line-numbers > code {\r\n position: relative;\r\n}\r\n\r\n.line-numbers .line-numbers-rows {\r\n position: absolute;\r\n pointer-events: none;\r\n top: 0;\r\n font-size: 100%;\r\n left: -3.8em;\r\n width: 3em; /* works for line-numbers below 1000 lines */\r\n letter-spacing: -1px;\r\n border-right: 1px solid #999;\r\n\r\n -webkit-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n\r\n}\r\n\r\n.line-numbers-rows > span {\r\n pointer-events: none;\r\n display: block;\r\n counter-increment: linenumber;\r\n}\r\n\r\n.line-numbers-rows > span:before {\r\n content: counter(linenumber);\r\n color: #999;\r\n display: block;\r\n padding-right: 0.8em;\r\n text-align: right;\r\n}\r\n;/*\r\n * HTML5 Boilerplate\r\n *\r\n * What follows is the result of much research on cross-browser styling.\r\n * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,\r\n * Kroc Camen, and the H5BP dev community and team.\r\n */\r\n\r\n/* ==========================================================================\r\n Base styles: opinionated defaults\r\n ========================================================================== */\r\n\r\nhtml,\r\nbutton,\r\ninput,\r\nselect {\r\n color: #222;\r\n}\r\n\r\ntextarea {\r\n line-height: 1.45em;\r\n padding: 0.5em 1em 0.5em 1em;\r\n border: none;\r\n}\r\n\r\nbody {\r\n font-size: 1em;\r\n line-height: 1.4;\r\n}\r\n\r\n/*\r\n * Remove text-shadow in selection highlight: h5bp.com/i\r\n * These selection rule sets have to be separate.\r\n * Customize the background color to match your design.\r\n */\r\n\r\n::-moz-selection {\r\n background: #b3d4fc;\r\n text-shadow: none;\r\n}\r\n\r\n::selection {\r\n background: #b3d4fc;\r\n text-shadow: none;\r\n}\r\n\r\n/*\r\n * A better looking default horizontal rule\r\n */\r\n\r\nhr {\r\n display: block;\r\n height: 1px;\r\n border: 0;\r\n border-top: 1px solid #ccc;\r\n margin: 1em 0;\r\n padding: 0;\r\n}\r\n\r\n/*\r\n * Remove the gap between images and the bottom of their containers: h5bp.com/i/440\r\n */\r\n\r\nimg {\r\n vertical-align: middle;\r\n}\r\n\r\nimg.med_left {\r\n width: 300px;\r\n float: left;\r\n}\r\n\r\nimg.med_right {\r\n width: 300px;\r\n float: right;\r\n}\r\n\r\nimg.small_left {\r\n width: 200px;\r\n float: left;\r\n}\r\n\r\nimg.smaller_left {\r\n width: 140px;\r\n float: left;\r\n}\r\n\r\nimg.small_right {\r\n width: 200px;\r\n float: right;\r\n}\r\n\r\nimg.smaller_right {\r\n width: 140px;\r\n float: right;\r\n}\r\n\r\nimg.small_center {\r\n width: 200px;\r\n margin-left: 250px;\r\n}\r\n\r\nimg.small {\r\n width: 160px;\r\n}\r\n\r\nimg.med {\r\n width: 400px;\r\n}\r\n\r\nimg.med_center {\r\n width: 400px;\r\n margin-left: 150px;\r\n}\r\n\r\n/*\r\n * Remove default fieldset styles.\r\n */\r\n\r\nfieldset {\r\n border: 0;\r\n margin: 0;\r\n padding: 0;\r\n}\r\n\r\n/*\r\n * Allow only vertical resizing of textareas.\r\n */\r\n\r\ntextarea {\r\n resize: vertical;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n HOMEPAGE\r\n //////////////////////////////////////////////////\r\n*/\r\n.tagline {\r\n display: none;\r\n}\r\n\r\n#home-page .home {\r\n pointer-events: none;\r\n}\r\n\r\n#home-page .home a {\r\n pointer-events: all;\r\n}\r\n\r\n#lockup > a {\r\n position: relative;\r\n display: block;\r\n width: 200px;\r\n height: 90px;\r\n}\r\n\r\n#logo_image {\r\n position: absolute;\r\n top: 0;\r\n}\r\n\r\n#menu.top_menu,\r\n#menu {\r\n list-style: none;\r\n font-family: 'Montserrat', sans-serif;\r\n width: 100%;\r\n margin: 0 0 1em 0;\r\n padding: 0;\r\n height: 100%;\r\n font-size: 1.3em;\r\n}\r\n\r\n#menu.top_menu li {\r\n display: inline;\r\n}\r\n\r\n#home-sketch {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n z-index: -2;\r\n}\r\n\r\n/* <======== Styling for responsive menu bar ========> */\r\n\r\n@media screen and (max-width: 780px) {\r\n .sidebar-menu {\r\n clear: both;\r\n max-height: 0;\r\n transition: max-height 0.4s ease-out;\r\n overflow: hidden;\r\n }\r\n\r\n .sidebar-menu-nav-element {\r\n width: 91vw;\r\n }\r\n\r\n .sidebar-menu a {\r\n display: block;\r\n text-align: center;\r\n padding-bottom: 0.11em;\r\n border-bottom: 0.11em dashed transparent;\r\n }\r\n\r\n .sidebar-menu-icon {\r\n top: 2rem;\r\n cursor: pointer;\r\n float: right;\r\n padding: 28px 20px;\r\n position: relative;\r\n user-select: none;\r\n margin-bottom: 5rem;\r\n }\r\n\r\n .sidebar-menu-icon .sidebar-nav-icon {\r\n background: #ed225d;\r\n display: block;\r\n height: 2px;\r\n position: relative;\r\n transition: background 0.4s ease-out;\r\n width: 18px;\r\n }\r\n\r\n .sidebar-menu-icon .sidebar-nav-icon:before,\r\n .sidebar-menu-icon .sidebar-nav-icon:after {\r\n background: #ed225d;\r\n content: '';\r\n display: block;\r\n height: 100%;\r\n position: absolute;\r\n transition: all 0.4s ease-out;\r\n width: 100%;\r\n }\r\n\r\n .sidebar-menu-icon .sidebar-nav-icon:before {\r\n top: 5px;\r\n }\r\n\r\n .sidebar-menu-icon .sidebar-nav-icon:after {\r\n top: -5px;\r\n }\r\n\r\n .sidebar-menu-btn {\r\n display: none;\r\n }\r\n\r\n .sidebar-menu-btn:checked ~ .sidebar-menu {\r\n max-height: 475px;\r\n }\r\n\r\n .sidebar-menu-btn:checked ~ .sidebar-menu-icon .sidebar-nav-icon {\r\n background: transparent;\r\n }\r\n\r\n .sidebar-menu-btn:checked ~ .sidebar-menu-icon .sidebar-nav-icon:before {\r\n transform: rotate(-45deg);\r\n top: 0;\r\n }\r\n\r\n .sidebar-menu-btn:checked ~ .sidebar-menu-icon .sidebar-nav-icon:after {\r\n transform: rotate(45deg);\r\n top: 0;\r\n }\r\n}\r\n\r\n.sidebar-menu-btn {\r\n display: none;\r\n}\r\n\r\n/* <=================================================> */\r\n\r\n#home-sketch-frame {\r\n position: fixed;\r\n width: 100%;\r\n height: 100%;\r\n left: 0;\r\n top: 0;\r\n z-index: -2;\r\n overflow: hidden;\r\n pointer-events: all;\r\n border: 0;\r\n}\r\n\r\n#credits {\r\n position: fixed;\r\n bottom: 0;\r\n left: 0;\r\n z-index: 2;\r\n padding: 1em;\r\n font-size: 0.7em;\r\n}\r\n\r\n#skip-to-content {\r\n position: absolute;\r\n left: 0px;\r\n top: 40px;\r\n z-index: 5;\r\n background-color: #ed225d;\r\n color: white;\r\n width: auto;\r\n height: 50px;\r\n border: none;\r\n outline-style: none;\r\n text-align: center;\r\n font-size: 25px;\r\n padding: 5px;\r\n opacity: 0;\r\n}\r\n\r\n#skip-to-content:focus {\r\n opacity: 1;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n DOWNLOAD PAGE\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n.button_box {\r\n border: 1px solid #ed225d;\r\n padding: 0.4em 0.6em;\r\n margin: 0.5em 0;\r\n color: #333;\r\n font-family: 'Montserrat', sans-serif;\r\n display: inline-block;\r\n}\r\n\r\n.download_box {\r\n border: 1px solid #ed225d;\r\n padding: 0.4em;\r\n margin: 0 1.75em 0 0;\r\n width: 18.65em;\r\n float: left;\r\n color: #333;\r\n height: 7.45em;\r\n position: relative;\r\n}\r\n\r\n.download_box:hover,\r\n.button_box:hover {\r\n border: 1px solid #ed225d;\r\n background: #ed225d;\r\n color: #ffffff;\r\n}\r\n\r\n.download_box.half_box {\r\n width: 10.83em;\r\n margin-right: 1.75em;\r\n float: left;\r\n}\r\n\r\n.download_box.half_box.last_box {\r\n margin-right: 0;\r\n}\r\n\r\n.download_box .download_name {\r\n font-size: 1em;\r\n margin: 0;\r\n padding-bottom: 0.3em;\r\n border-bottom: 0.09em dashed;\r\n border-bottom-color: #ed225d;\r\n line-height: 1.2;\r\n font-family: 'Montserrat', sans-serif;\r\n display: block;\r\n}\r\n\r\n.download_box:hover .download_name {\r\n -webkit-text-stroke-width: 0;\r\n border-bottom-color: #fff;\r\n}\r\n\r\n.download_box p {\r\n font-size: 0.65em;\r\n margin: 0;\r\n position: absolute;\r\n bottom: 1em;\r\n}\r\n\r\n.download_box svg {\r\n height: 0.65em;\r\n width: 0.65em;\r\n position: absolute;\r\n bottom: 3.5em;\r\n}\r\n\r\n.download_box:hover svg {\r\n fill: white;\r\n}\r\n\r\n.download_box h4 + p {\r\n display: block;\r\n}\r\n\r\n#download-page .link_group {\r\n width: 100%;\r\n margin-bottom: 3em;\r\n}\r\n\r\n.download_box {\r\n margin-top: 1em;\r\n}\r\n\r\n.support div.download_box {\r\n margin-top: 1em;\r\n margin-bottom: 1em;\r\n}\r\n\r\n#download-page .support p {\r\n font-size: 0.8em;\r\n position: static;\r\n margin-top: 0.3em;\r\n}\r\n\r\n#slideshow {\r\n margin: 1em 0;\r\n}\r\n\r\n#slideshow p {\r\n font-size: 0.8em;\r\n color: #ababab;\r\n line-height: 1.2em;\r\n margin-top: 0.5em;\r\n}\r\n\r\n.extra {\r\n color: white;\r\n position: absolute;\r\n bottom: 0.65em;\r\n right: 0.9em;\r\n font-weight: bold;\r\n -ms-transform: rotate(-12deg);\r\n -webkit-transform: rotate(-12deg);\r\n transform: rotate(-12deg);\r\n font-size: 0.8em;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n GET STARTED\r\n //////////////////////////////////////////////////\r\n*/\r\n#get-started-page .edit_space {\r\n position: relative;\r\n order: 3;\r\n margin-bottom: 4.8125em;\r\n}\r\n#get-started-page .edit_space .copy_button{\r\n color: #2d7bb6;\r\n border-color: rgba(45, 123, 182, 0.25);\r\n float: right;\r\n margin: 1.5em 0 1.5em 0.5em;\r\n background: rgba(255, 255, 255, 0.7);\r\n position: absolute;\r\n z-index: 2;\r\n left: 31.33em;\r\n top: -1.5em;\r\n}\r\n/* To make get-started-page responsive */\r\n@media (max-width: 780px) {\r\n #get-started-page .edit_space .copy_button{\r\n left: 6.44em;\r\n }\r\n}\r\n@media (max-width: 600px) {\r\n #get-started-page .edit_space .copy_button{\r\n left: 5.91em;\r\n }\r\n}\r\n/*\r\n //////////////////////////////////////////////////\r\n EXAMPLES\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n#examples-page .column {\r\n margin-bottom: 2em;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n REFERENCE\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n#reference-page main h1 {\r\n float: left;\r\n}\r\n\r\n.reference-group h2 {\r\n font-size: 1.5em;\r\n}\r\n\r\n.reference-group h3 {\r\n font-size: 1em;\r\n font-family: 'Montserrat', sans-serif;\r\n margin-top: 0.5em;\r\n}\r\n\r\ndiv.reference-group {\r\n display: inline-block;\r\n}\r\n\r\ndiv.reference-subgroups {\r\n margin: 0;\r\n display: flex;\r\n flex-direction: row;\r\n flex-wrap: wrap;\r\n}\r\ndiv.reference-subgroup {\r\n width: 11em;\r\n margin-bottom: 1em;\r\n}\r\n\r\n#reference-page .params table p {\r\n /* Recently-added support for Markdown means that every parameter\r\n * description is wrapped in a paragraph element. (Previously, they weren't\r\n * wrapped in any kind of element.)\r\n *\r\n * We may eventually want to display paragraphs as blocks, so that we\r\n * can have lengthy descriptions for parameters, but for now we'll\r\n * keep our pre-existing behavior and essentially make paragraphs\r\n * \"invisible\" by rendering them inline. */\r\n display: inline;\r\n font-size: inherit;\r\n}\r\n\r\n#reference-page .param-optional {\r\n color: #afafaf;\r\n}\r\n\r\n#item {\r\n width: 100%;\r\n}\r\n\r\n#item h2 {\r\n margin: 0.777em 0 0 0;\r\n font-size: 1.444em;\r\n font-weight: inherit;\r\n font-family: 'Inconsolata', consolas, monospace;\r\n color: #00a1d3;\r\n}\r\n\r\n#item h3 {\r\n font-size: 1.33em;\r\n margin: 1em 0 0 0;\r\n}\r\n\r\n#item ul {\r\n margin-top: 0.5em;\r\n}\r\n\r\n#item li {\r\n margin-bottom: 1em;\r\n}\r\n\r\n.description {\r\n clear: both;\r\n display: block;\r\n width: 100%;\r\n}\r\n\r\n.syntax pre {\r\n width: 100%;\r\n}\r\n\r\n.item-wrapper,\r\n.list-wrapper {\r\n float: left;\r\n outline: none;\r\n}\r\n\r\n.paramname {\r\n display: inline-block;\r\n min-width: 25%;\r\n margin-right: 1%;\r\n font-size: 1.2em;\r\n}\r\n\r\n.paramtype p {\r\n display: inline;\r\n font-size: 1em;\r\n}\r\n\r\n.paramtype {\r\n display: inline-block;\r\n font-size: 1.2em;\r\n width: 73%;\r\n vertical-align: top;\r\n}\r\n\r\n#library-page .group-name {\r\n display: inline-block;\r\n}\r\n\r\n#library-page .group-name:hover {\r\n color: #ed225d;\r\n}\r\n\r\n/* EXAMPLES IN REF */\r\n\r\n.example div {\r\n position: relative;\r\n}\r\n\r\n.example-content .example_code {\r\n position: relative;\r\n left: 1em;\r\n padding-top: 0;\r\n margin-top: 1rem;\r\n border: none;\r\n width: 30.5em;\r\n max-width: 100%;\r\n}\r\n\r\n.example-content .example_code.norender {\r\n left: 0px;\r\n margin-left: 0;\r\n}\r\n\r\n.example-content .edit_space {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n margin-top: -0.5em;\r\n width: 100%;\r\n pointer-events: none;\r\n}\r\n\r\n.example-content .edit_space * {\r\n pointer-events: auto;\r\n}\r\n\r\n.example-content .edit_space ul {\r\n display: flex;\r\n flex-direction: row-reverse;\r\n position: relative;\r\n pointer-events: none;\r\n}\r\n\r\n.example-content .edit_space ul li button {\r\n font-family: 'Montserrat', sans-serif;\r\n font-size: 1em;\r\n color: #ccc;\r\n border: 1px solid rgba(200, 200, 200, 0.15);\r\n background: transparent;\r\n outline: none;\r\n margin-top: 0.25em;\r\n}\r\n\r\n.example-content .edit_space ul li button:hover,\r\n.example_container.editing ul li button {\r\n color: #2d7bb6;\r\n border-color: rgba(45, 123, 182, 0.25);\r\n}\r\n\r\n.example-content .edit_space .edit_area {\r\n position: absolute;\r\n top: 0.5em;\r\n left: 120px;\r\n width: 30.5em;\r\n padding-top: 1.5rem;\r\n display: none;\r\n font-family: monospace;\r\n padding: 1.5em 0.5em 0.5em 0.5em;\r\n font-size: 15pt;\r\n}\r\n\r\n.display_button {\r\n margin-bottom: 2em;\r\n font-family: 'Montserrat', sans-serif;\r\n font-size: 1em;\r\n color: #2d7bb6;\r\n border: 1px solid rgba(45, 123, 182, 0.25);\r\n background: transparent;\r\n outline: none;\r\n}\r\n\r\n.example-content .example_container {\r\n width: 36em;\r\n max-width: 100%;\r\n border-top: 0.09em dashed;\r\n border-top-color: #333;\r\n padding-top: 0.5em;\r\n margin-top: 2em;\r\n min-height: 120px;\r\n height: calc(100% * 1.1 + 20px);\r\n display: flex;\r\n}\r\n\r\n.example-content .example_container:first-of-type {\r\n margin-top: 1em;\r\n}\r\n\r\n/*to make ref example responsive*/\r\n@media (max-width: 600px) {\r\n .example-content .example_code {\r\n margin-top: 0.2rem;\r\n left: 0.5rem;\r\n }\r\n\r\n .example-content .example_container {\r\n width: 100%;\r\n min-height: 220px;\r\n height: calc(100% * 1.1 + 120px);\r\n display: block;\r\n }\r\n\r\n .example-content .edit_space .edit_area {\r\n top: calc(120px + 1em);\r\n left: 0;\r\n width: 100%;\r\n padding: 0.5em;\r\n }\r\n\r\n .example_container button {\r\n top: 124px;\r\n }\r\n\r\n .description {\r\n margin-top: 3rem;\r\n }\r\n\r\n .edit_button {\r\n left: 0;\r\n }\r\n\r\n .reset_button {\r\n left: 2.58em;\r\n }\r\n\r\n .copy_button {\r\n left: 5.91em;\r\n }\r\n}\r\n\r\nform {\r\n pointer-events: all;\r\n}\r\n\r\n#search_button {\r\n background: url(../img/search.png) 100% no-repeat;\r\n}\r\n\r\n#search input[type='text'],\r\n#search input[type='search'] {\r\n border: 1px solid rgba(200, 200, 200, 0.5);\r\n font-family: 'Montserrat', sans-serif;\r\n font-size: 2.25em;\r\n width: 9.75em;\r\n}\r\n\r\n#search ::-webkit-input-placeholder,\r\n#search .twitter-typeahead .tt-hint {\r\n color: #ccc;\r\n}\r\n\r\n:-moz-placeholder,\r\n::-moz-placeholder,\r\n:-ms-input-placeholder {\r\n color: #ccc;\r\n}\r\n\r\n#search input[type='text']:focus {\r\n color: #2d7bb6;\r\n outline-color: #2d7bb6;\r\n outline-width: 1px;\r\n outline-style: solid;\r\n}\r\n\r\n#search .twitter-typeahead .tt-dropdown-menu {\r\n background-color: #fff;\r\n border: 1px solid rgba(0, 0, 0, 0.2);\r\n overflow-y: auto;\r\n font-size: 1em;\r\n line-height: 1.4em;\r\n}\r\n\r\n#search .twitter-typeahead .tt-suggestion.tt-cursor {\r\n color: #333;\r\n background-color: #eee;\r\n}\r\n\r\n#search .twitter-typeahead .tt-suggestion p {\r\n margin: 0;\r\n}\r\n\r\n#search .twitter-typeahead .tt-suggestion p .small {\r\n font-size: 12px;\r\n color: #666;\r\n}\r\n\r\n#search {\r\n float: right;\r\n}\r\n\r\n#search .twitter-typeahead .tt-dropdown-menu {\r\n border: 1px solid rgba(0, 0, 0, 0.2);\r\n padding: 0.5em;\r\n max-height: 200px;\r\n overflow-y: auto;\r\n font-size: 1em;\r\n line-height: 1.4em;\r\n}\r\n\r\n#search .twitter-typeahead .tt-suggestion {\r\n padding: 3px 20px;\r\n line-height: 24px;\r\n cursor: pointer;\r\n}\r\n\r\n#search .twitter-typeahead .empty-message {\r\n padding: 8px 20px 1px 20px;\r\n font-size: 14px;\r\n line-height: 24px;\r\n}\r\n\r\n#search_button {\r\n float: right;\r\n}\r\n\r\na.code.core {\r\n color: #333;\r\n}\r\n\r\na.code.addon {\r\n color: #704f21;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n CONTRIBUTORS FORM\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n Contributors\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n#contribute-item {\r\n font-size: 0.75em;\r\n text-align: left;\r\n display: inline-block;\r\n width: 320px;\r\n height: 250px;\r\n float: left;\r\n border: 1px solid #ed225d;\r\n margin: 0 25px 25px 0;\r\n position: relative;\r\n}\r\n\r\n.contribute-item-container {\r\n position: absolute;\r\n z-index: 20;\r\n margin: 0;\r\n padding: 10px;\r\n}\r\n\r\n.container {\r\n /* width: 100px;*/\r\n height: 100px;\r\n position: relative;\r\n background: white;\r\n margin-top: 1.5em; /* temp promo */\r\n}\r\n\r\n#navi,\r\n#infoi {\r\n width: 100%;\r\n height: 100%;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n}\r\n\r\n#infoi {\r\n z-index: 10;\r\n}\r\n\r\nh3.contribute-title {\r\n font-size: 1.33em;\r\n margin: 0 0 27px 0;\r\n padding-bottom: 0.3em;\r\n border-bottom: 0.09em dashed;\r\n border-bottom-color: #ed225d;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n LIBRARIES / LEARN\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n.label {\r\n position: relative;\r\n}\r\n\r\n.label .nounderline img {\r\n margin: 0.5em 0 0 0;\r\n}\r\n\r\n.label h3 {\r\n color: white;\r\n position: absolute;\r\n top: 0;\r\n margin: 1em;\r\n}\r\n\r\n.label:hover h3 {\r\n color: #ed225d;\r\n}\r\n\r\nh3 {\r\n font-size: 1.33em;\r\n margin: 1em 0 0 0;\r\n}\r\n\r\n.bullet-list {\r\n padding: 0 0 0 40px;\r\n list-style: disc;\r\n}\r\n\r\n#libraries-page .label h3{\r\n background-color: black;\r\n padding:0px 5px;\r\n}\r\n\r\n#learn-page .label .nounderline img {\r\n height: fit-content;\r\n}\r\n\r\n#learn-page .info {\r\n display: inline-block;\r\n}\r\n\r\n#exampleDisplay,\r\n#exampleFrame,\r\n#exampleEditor {\r\n width: 36em;\r\n border: none;\r\n}\r\n\r\n#exampleDisplay {\r\n display: flex;\r\n flex-flow: column;\r\n}\r\n\r\n#popupExampleFrame {\r\n position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n z-index: 1000;\r\n border: none;\r\n}\r\n\r\n#exampleDisplay button {\r\n color: #2d7bb6;\r\n border-color: rgba(45, 123, 182, 0.25);\r\n float: right;\r\n margin: 0.5em 0 0 0.5em;\r\n background: rgba(255, 255, 255, 0.7);\r\n position: absolute;\r\n left: 0;\r\n z-index: 2;\r\n}\r\n\r\n#exampleDisplay .edit_button {\r\n left: 25.42em;\r\n top: -2.5em;\r\n}\r\n\r\n#exampleDisplay .reset_button {\r\n left: 28em;\r\n top: -2.5em;\r\n}\r\n\r\n#exampleDisplay .copy_button {\r\n left: 31.33em;\r\n top: -2.5em;\r\n}\r\n\r\n#exampleDisplay button:hover {\r\n background: #fff;\r\n}\r\n\r\n#exampleDisplay .edit_space {\r\n position: relative;\r\n order: 3;\r\n}\r\n\r\n#exampleDisplay #exampleFrame {\r\n height: 22em;\r\n order: 2;\r\n}\r\n\r\n#exampleDisplay #exampleEditor {\r\n height: 500em;\r\n width: 710px;\r\n overflow: hidden;\r\n margin-top: 0.5em;\r\n color: #222;\r\n font-family: 'Inconsolata', consolas, monospace;\r\n font-size: 1em;\r\n background-color: #fff;\r\n line-height: 1em;\r\n order: 4;\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace_gutter-cell {\r\n background-image: none;\r\n padding-left: 10px;\r\n overflow: hidden;\r\n background-color: #afafaf;\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace_gutter-cell.ace_info {\r\n background-color: #d7e5f5;\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace_gutter-cell.ace_warning {\r\n background-color: #ffd700;\r\n color: #ffffff;\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace_gutter-cell.ace_error {\r\n background-color: #ff6347;\r\n color: #ffffff;\r\n}\r\n\r\n/* property, tag, boolean,\r\n number, function-name, constant,\r\n symbol */\r\n\r\n#exampleDisplay #exampleEditor .ace_numeric,\r\n#exampleDisplay #exampleEditor .ace_tag {\r\n color: #dc3787;\r\n /* not p5 pink, but related */\r\n}\r\n\r\n/* atrule, attr-value, keyword,\r\n class-name */\r\n\r\n#exampleDisplay #exampleEditor .ace_type,\r\n#exampleDisplay #exampleEditor .ace_class,\r\n#exampleDisplay #exampleEditor .ace_attribute-name {\r\n color: #704f21;\r\n /* darker brown */\r\n}\r\n\r\n/* selector, attr-name,\r\nfunction, builtin */\r\n\r\n#exampleDisplay #exampleEditor .ace_function,\r\n#exampleDisplay #exampleEditor .ace_keyword,\r\n#exampleDisplay #exampleEditor .ace_support {\r\n color: #00a1d3;\r\n /* not p5 blue, but related */\r\n}\r\n\r\n/* comment, block-comment, prolog,\r\n doctype, cdata */\r\n\r\n#exampleDisplay #exampleEditor .ace_comment {\r\n color: #a0a0a0;\r\n /* light gray */\r\n}\r\n\r\n/* operator, entity, url,\r\nvariable */\r\n\r\n#exampleDisplay #exampleEditor .ace_string {\r\n color: #a67f59;\r\n /* og coy a67f59 a light brown */\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace_operator {\r\n color: #333;\r\n}\r\n\r\n/* regex, important */\r\n\r\n#exampleDisplay #exampleEditor .ace_regexp {\r\n color: #e90;\r\n /* og coy e90 orange */\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace-gutter {\r\n color: #333;\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace-gutter-layer {\r\n color: #333;\r\n}\r\n\r\n#exampleDisplay #exampleEditor .ace_folding-enabled {\r\n width: 10px !important;\r\n color: #333;\r\n}\r\n\r\n.attribution {\r\n background-color: #eee;\r\n font-size: 15px;\r\n padding: 10px;\r\n margin: 30px 0px 30px 0px;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n SHOWCASE\r\n //////////////////////////////////////////////////\r\n*/\r\n#featuring {\r\n margin-bottom: 1em;\r\n}\r\n\r\n#showcase-page .showcase-intro h1 {\r\n font: italic 900 14.5vw 'Montserrat', sans-serif;\r\n color: #ed225d;\r\n text-align: left;\r\n text-transform: uppercase;\r\n}\r\n\r\n#showcase-page .showcase-intro p {\r\n font: 400 1.4rem 'Montserrat', sans-serif;\r\n line-height: 1.5em;\r\n}\r\n\r\n#showcase-page .showcase-featured h2,\r\n#showcase-page .project-page h2 {\r\n font: italic 900 2rem 'Montserrat', sans-serif;\r\n color: #ed225d;\r\n letter-spacing: 0.05rem;\r\n}\r\n\r\n#showcase-page ul.left-column,\r\n#showcase-page ul.right-column,\r\n#showcase-page ul.project-tags,\r\n#showcase-page ul.links {\r\n list-style: none;\r\n}\r\n\r\n#showcase-page img[alt] {\r\n font-size: 0.9rem;\r\n}\r\n\r\n#showcase-page .showcase-featured {\r\n margin-top: 15%;\r\n}\r\n\r\n#showcase-page .showcase-featured h3.title {\r\n font: italic 900 1rem 'Montserrat', sans-serif;\r\n}\r\n\r\n#showcase-page .showcase-featured p.credit {\r\n font: 500 1rem 'Montserrat', sans-serif;\r\n}\r\n\r\n#showcase-page .showcase-featured p.description {\r\n font-size: 1em;\r\n margin-bottom: 0.5rem;\r\n}\r\n\r\n#showcase-page .nominate {\r\n margin-top: 1.5em;\r\n display: inline-block;\r\n}\r\n\r\n#showcase-page .nominate a,\r\n#showcase-page .nominate a:visited {\r\n padding: 0.4em 0.5em;\r\n position: relative;\r\n top: 0px;\r\n left: 0px;\r\n border: solid #ed225d 2px;\r\n box-shadow: 4px 4px 0 #ed225d;\r\n\r\n font: 1.5rem 'Montserrat', sans-serif;\r\n color: #ed225d;\r\n letter-spacing: 0.02rem;\r\n transition: all 0.3s;\r\n}\r\n\r\n@media (max-width: 500px) {\r\n #showcase-page .nominate a,\r\n #showcase-page .nominate a:visited {\r\n padding: 0.4em 0.3em;\r\n font: 1.3rem 'Montserrat', sans-serif;\r\n }\r\n}\r\n\r\n#showcase-page .nominate a:hover {\r\n top: 4px;\r\n left: 4px;\r\n box-shadow: none;\r\n}\r\n\r\n#showcase-page .showcase-featured a,\r\n#showcase-page .showcase-featured a:visited {\r\n font-size: 1.2rem;\r\n color: #ed225d;\r\n letter-spacing: 0.02rem;\r\n line-height: 1.5;\r\n}\r\n\r\n#showcase-page .showcase-featured a::after {\r\n content: ' →';\r\n}\r\n#showcase-page .showcase-featured a.tag::after {\r\n content: '';\r\n}\r\n#showcase-page .showcase-featured .no-arrow-link::after {\r\n content: ' ';\r\n}\r\n\r\n#showcase-page .showcase-featured .no-arrow-link:hover {\r\n text-decoration: none;\r\n padding: none;\r\n border: none;\r\n}\r\n\r\n.project-info {\r\n margin-top: 1em;\r\n}\r\n\r\nul.project-tags a {\r\n line-height: 0;\r\n display: -webkit-box;\r\n display: -webkit-flex;\r\n display: flex;\r\n -webkit-flex-wrap: wrap;\r\n flex-wrap: wrap;\r\n font-size: 0.5em;\r\n margin: 0px;\r\n}\r\nh3.title {\r\n margin-top: 3em;\r\n}\r\n#showcase-page ul.project-tags li {\r\n margin: 5px;\r\n display: inline-block;\r\n}\r\nh2.featuring {\r\n margin-top: 0px;\r\n}\r\n#showcase-page a.tag {\r\n display: inline-block;\r\n padding: 6px 14px;\r\n background-color: #ffe8e8;\r\n border-radius: 27px;\r\n font: 0.7rem 'Montserrat', sans-serif;\r\n color: #333;\r\n}\r\n#showcase-page ul.project-tags li {\r\n margin: 0px;\r\n}\r\n/*\r\n //////////////////////////////////////////////////\r\n SHOWCASE - FEATURED PROJECT PAGE\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n/* Link style for mobile and tablet screens (no :hover state) */\r\n/*\r\n@media (max-width: 991.98px){\r\n #showcase-page .project-page a, #showcase-page .project-page a:visited {\r\n color:#ED225D;\r\n text-decoration: none;\r\n padding-bottom: 0.11em;\r\n border-bottom: 0.11em dashed;\r\n border-bottom-color: #ED225D;\r\n transition: border-bottom 30ms linear;\r\n }\r\n}\r\n*/\r\n\r\n#showcase-page{\r\n margin-top: 3em;\r\n}\r\n\r\n#showcase-page .project-page h2 {\r\n line-height: 1.4;\r\n}\r\n\r\n@media (min-width: 720px) {\r\n /* for desktop/tablet:\r\n * - two columns, one each for resources & authors\r\n * - indent answer paragraphs in q & a\r\n */\r\n\r\n #showcase-page .showcase-intro h1 {\r\n font: italic 900 6.35vw 'Montserrat', sans-serif;\r\n }\r\n\r\n #showcase-page .showcase-intro p {\r\n line-height: 1.75em;\r\n font-size: 1em;\r\n }\r\n\r\n #showcase-page .project-metadata {\r\n display: flex;\r\n }\r\n\r\n #showcase-page .project-resources {\r\n margin-left: 3rem;\r\n }\r\n\r\n #showcase-page .project-a {\r\n width: 90%;\r\n float: right;\r\n display: inline-block;\r\n clear: both;\r\n }\r\n\r\n #showcase-page .half-image {\r\n width: 48%;\r\n }\r\n}\r\n\r\n#showcase-page .project-metadata {\r\n margin-top: 3%;\r\n}\r\n\r\n#showcase-page .project-metadata section h3 {\r\n color: #ed225d;\r\n font: bold italic 1rem 'Montserrat', sans-serif;\r\n}\r\n\r\n#showcase-page .project-resources ul.links {\r\n font: 500 0.7rem 'Montserrat', sans-serif;\r\n letter-spacing: 0.01rem;\r\n line-height: 1.5;\r\n margin: 0.5rem 0;\r\n}\r\n\r\n#showcase-page .project-credit {\r\n font: italic bold 1.25rem 'Montserrat', sans-serif;\r\n}\r\n\r\n#showcase-page .project-credit p {\r\n margin: 0.5rem 0;\r\n}\r\n\r\n#showcase-page .note {\r\n font-size: 0.7rem;\r\n}\r\n\r\n#showcase-page .creator-from {\r\n font-size: 0.7rem;\r\n}\r\n\r\n#showcase-page .qa-group{\r\n margin-bottom: 2em;\r\n}\r\n\r\n#showcase-page .project-q {\r\n margin-left: 0%;\r\n display: inline-block;\r\n clear: both;\r\n /*\r\n font-size: 1.2rem;\r\n font-weight: 900;\r\n */\r\n font: 900 1.2rem 'Montserrat', sans-serif;\r\n line-height: 1.5;\r\n}\r\n\r\n#showcase-page code {\r\n font-size: 1.1rem;\r\n}\r\n\r\n\r\n/* ==========================================================================\r\n Teach Page\r\n ========================================================================== */\r\n\r\n#teach-page .case-list a:hover {\r\n border-bottom: none;\r\n}\r\n\r\n#teach-page .heading {\r\n font: 400 1.4rem \"Montserrat\", sans-serif;\r\n color: black;\r\n line-height: 1.2em;\r\n padding-bottom: .4em;\r\n border-bottom: 4px dotted #ed225d;\r\n}\r\n\r\n#teach-page h3.title{\r\n margin-top: 3em;\r\n}\r\n\r\n/*search-filter label*/\r\n\r\n#teach-page .search-filter {\r\n display: inline;\r\n}\r\n\r\n#teach-page .search-filter label {\r\n display: inline-block;\r\n font: italic 900 1rem \"Montserrat\", sans-serif;\r\n padding: 6px 12px;\r\n text-align: left;\r\n white-space: nowrap;\r\n color: #ed225d;\r\n /*transition: .2s; */\r\n margin-bottom: .6em;\r\n margin-top: 1.2em;\r\n border: 1px solid #ed225d;\r\n\r\n\r\n}\r\n\r\n#teach-page .search-filter label {\r\n cursor: pointer;\r\n}\r\n\r\n\r\n#teach-page .search-filter label:hover {\r\n color: white;\r\n background-color: #ed225d;\r\n}\r\n\r\n\r\n#teach-page .search-filter input[type=\"checkbox\"] {\r\n display: absolute;\r\n}\r\n\r\n\r\n#teach-page .search-filter input[type=\"checkbox\"] {\r\n position: absolute;\r\n opacity: 0;\r\n}\r\n\r\n\r\n#teach-page ul.filters p.filter-title {\r\n font: 400 0.83rem \"Montserrat\", sans-serif;\r\n color: #ed225d;\r\n height: 50px;\r\n padding-top:20px;\r\n background: none;\r\n background-color: none;\r\n box-shadow: none;\r\n display: inline-block;\r\n border: none;\r\n clear: both;\r\n\r\n}\r\n\r\n\r\n\r\n\r\n#teach-page ul.filters li {\r\n display: inline;\r\n list-style: none;\r\n width: 100%;\r\n}\r\n\r\n#teach-page ul.filters li label {\r\n display: inline-block;\r\n border-radius: 25px;\r\n font: 200 0.7rem \"Montserrat\", sans-serif;\r\n /*font-style: normal;\r\n font-variant: normal;\r\n text-rendering: auto;\r\n -webkit-font-smoothing: antialiased;*/\r\n\r\n color: black;\r\n white-space: nowrap;\r\n margin: 3px 0px;\r\n transition: .2s;\r\n background: #fafafa;\r\n}\r\n\r\n#teach-page ul.filters li label {\r\n padding: 6px 12px;\r\n cursor: pointer;\r\n}\r\n\r\n#teach-page ul.filters li label::before {\r\n display: inline-block;\r\n padding: 2px 2px 2px 2px; /*padding among labels*/\r\n}\r\n\r\n#teach-page ul.filters li label:hover {\r\n color: #ed225d;\r\n background: #ffe8e8;\r\n /*transform: translateY(2px);*/\r\n\r\n }\r\n\r\n#teach-page ul.filters li input[type=\"checkbox\"]:checked + label {\r\n color: white;\r\n background: #ed225d;\r\n\r\n}\r\n\r\n#teach-page ul.filters li input[type=\"checkbox\"] {\r\n display: absolute;\r\n position: absolute;\r\n opacity: 0;\r\n}\r\n\r\n\r\n#teach-page ul.filters li.clear{\r\n display: block;\r\n clear: both;\r\n\r\n}\r\n\r\n\r\n/*Filter Panel*/\r\n\r\n#teach-page .filter-panel {\r\n padding: 0px;\r\n background-color: white;\r\n max-height: 0;\r\n overflow: hidden;\r\n transition: max-height 0.2s ease-out;\r\n margin-bottom: 0.8em;\r\n padding-bottom: .4em;\r\n\r\n}\r\n\r\n\r\n\r\n#teach-page .filter-panel p {\r\n margin: 0;\r\n color: #333;\r\n font-size: .83em;\r\n height: 50px;\r\n padding-top:20px;\r\n transition: all 0.5s ease-in-out;\r\n}\r\n\r\n\r\n /*p5 workshop and class title*/\r\n#teach-page .teach-intro p {\r\n font: 400 1.2rem \"Times\", sans-serif;\r\n line-height: 1.5em;\r\n}\r\n\r\n\r\n/*modal box*/\r\n\r\n#teach-page .modal-title{\r\n\r\n margin-left: 1em;\r\n margin-right: 1em;\r\n\r\n font: 400 1rem \"Montserrat\", sans-serif;\r\n color: #ed225d;\r\n line-height: 1.2em;\r\n\r\n}\r\n\r\n#teach-page ul.cases li.clear{\r\n display: block;\r\n clear: both;\r\n margin-top: 1em;\r\n margin-bottom: 1.2em;\r\n}\r\n\r\n\r\n#teach-page img{\r\n margin-bottom: 1.4em;\r\n}\r\n\r\n#teach-page img[alt]{\r\n font: 0.6rem \"Montserrat\", sans-serif;\r\n color: #bababa;\r\n\r\n}\r\n\r\n#teach-page .close {\r\n position: relative;\r\n color: #ffc7c7;\r\n float: right;\r\n font-size: 40px;\r\n font-weight: bold;\r\n margin-right: .4em;\r\n margin-top: .4em;\r\n cursor:pointer;\r\n}\r\n\r\n#teach-page .close:hover, .close:focus {\r\n color: #ed225d;\r\n text-decoration: none;\r\n cursor: pointer;\r\n}\r\n\r\n#teach-page .case label{\r\n margin-left: 1em;\r\n margin-right: 1em;\r\n margin: 2px 2px;\r\n padding: 5px 8px;\r\n display: inline-block;\r\n border-radius: 25px;\r\n font: 0.7rem \"Montserrat\", sans-serif;\r\n color: #aaaaaa;\r\n white-space: nowrap;\r\n color: white;\r\n background: #ed225d;\r\n}\r\n\r\n/*modal scrollbar*/\r\n\r\n#teach-page .modal-body::-webkit-scrollbar {\r\n\r\n width: 5px;\r\n height: 5px;\r\n border-radius: 10px;\r\n}\r\n\r\n#teach-page .modal-body::-webkit-scrollbar-track {\r\n background: #f1f1f1;\r\n}\r\n\r\n#teach-page .modal-body::-webkit-scrollbar-thumb {\r\n background: #ffe8e8;\r\n}\r\n\r\n/*modal contents*/\r\n\r\n#teach-page .case{\r\n margin-left: 2em;\r\n margin-right:2em;\r\n}\r\n\r\n#teach-page .case span {\r\n color: #ed225d;\r\n font: 900 1.4rem \"Montserrat\", sans-serif;\r\n}\r\n\r\n\r\n#teach-page .case p.lead-name{\r\n font: 900 Italic 1.2rem \"Montserrat\", sans-serif;\r\n color: #ed225d;\r\n line-height: 1.4em;\r\n border-bottom: 1.4em;\r\n}\r\n\r\n#teach-page .case .speech{\r\n\r\n position: relative;\r\n font: 200 Italic .8rem \"Montserrat\", sans-serif;\r\n color: black; /*#aaaaaa; */\r\n background: #ffe8e8;\r\n padding: 0.5em 1.2em;\r\n border-radius: .4em;\r\n border-bottom: none;\r\n margin-bottom: 2em;\r\n margin-top: 1em;\r\n\r\n\r\n}\r\n\r\n#teach-page .case .speech::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: 8%;\r\n width: 0;\r\n height: 0;\r\n border: 10px solid transparent;\r\n border-bottom-color: #ffe8e8;\r\n border-top: 0;\r\n margin-left: -10px;\r\n margin-top: -10px;\r\n}\r\n\r\n#teach-page .case p.subtitle{\r\n\r\n font: 400 1rem \"Montserrat\", sans-serif;\r\n color: #ed225d;\r\n line-height: 1.4em;\r\n border-bottom: 0.1em dashed rgba(237, 34, 93, 0.15);\r\n}\r\n\r\n#teach-page .case p{\r\n font: 400 1rem \"Times\", sans-serif;\r\n color: black;\r\n line-height: 1.4em;\r\n\r\n border-bottom: 0.1em dashed rgba(237, 34, 93, 0.15);\r\n\r\n}\r\n\r\n#teach-page .modal-header{\r\n\r\n margin-bottom: 0.8em;\r\n}\r\n\r\n\r\n#teach-page .modal-footer{\r\n\r\n margin-bottom: 0.8em;\r\n}\r\n\r\n/*#teach-page .modal-body p{\r\n border-bottom: 0.1em dashed rgba(237, 34, 93, 0.15);\r\n\r\n}*/\r\n\r\n#teach-page .modal-body:-webkit-scrollbar{\r\n display: none;\r\n}\r\n\r\n\r\n#teach-page .modal {\r\n display: none; /* Hidden by default */\r\n position: fixed; /* Stay in place */\r\n z-index: 100;\r\n width: 100%;\r\n height: 100%;\r\n top:0;\r\n left:0;\r\n right:0;\r\n overflow: auto;\r\n box-sizing: border-box;\r\n background-color: rgba(255, 232, 232, 0.5); /* Fallback color */\r\n\r\n}\r\n\r\n#teach-page .modal-content{\r\n position: fixed;\r\n background: white;\r\n top: 2%;\r\n left: 2%;\r\n right: 2%;\r\n bottom: 2%;\r\n margin: auto; /*keep centered*/\r\n border: 1.2px solid #ffe8e8;\r\n max-width: 740px;\r\n box-shadow: 10px 100px 30px -17px rgba(237, 34, 93, 0.5);\r\n box-shadow: 10px 100px 20px -17px rgba(237, 34, 93, 0.5);\r\n box-shadow: 10px 20px 10px -17px rgba(237, 34, 93, 0.5);\r\n}\r\n\r\n#teach-page .modal-body{\r\n\r\n margin: auto;\r\n height: 85%;\r\n width: 95%;\r\n overflow-y: auto;\r\n\r\n}\r\n\r\n#teach-page .results-wrapper{\r\n width: 100%;\r\n outline: none;\r\n background: white;\r\n /*background: white;\r\n background: #fafafa;*/\r\n /*border: solid white 1px;*/\r\n /*background: -webkit-linear-gradient(to bottom, white, #fafafa);\r\n background: linear-gradient(to bottom, white, #fafafa);*/\r\n /*border: 1px solid #ffe8e8;*/\r\n /*box-shadow: 10px 100px 30px -17px rgba(237, 34, 93, 0.5);\r\n box-shadow: 10px 100px 20px -17px rgba(255, 232, 232, 0.5);\r\n box-shadow: 10px 20px 10px -17px rgba(237, 34, 93, 0.5);*/\r\n\r\n\r\n}\r\n\r\n#teach-page .results-wrapper ul li.case-list a.myBtn {\r\n\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n\r\n}\r\n\r\n#teach-page .case-list{\r\n\r\n margin-bottom: 0.8em;\r\n padding-bottom: .4em;\r\n\r\n font: 400 1.0rem \"Times\", sans-serif;\r\n line-height: 1.2em;\r\n\r\n border-bottom: 0.1em dashed #ffe8e8;\r\n\r\n}\r\n\r\n/* ==========================================================================\r\n Author's custom styles\r\n ========================================================================== */\r\n\r\n/* apply a natural box layout model to all elements */\r\n\r\n*,\r\n*:before,\r\n*:after {\r\n -moz-box-sizing: border-box;\r\n -webkit-box-sizing: border-box;\r\n box-sizing: border-box;\r\n}\r\n\r\nhtml {\r\n font-size: 1.25em;\r\n}\r\n\r\nbody {\r\n margin: 0;\r\n background-color: #fff;\r\n font-family: 'Times';\r\n font-weight: 400;\r\n line-height: 1.45;\r\n color: #333;\r\n}\r\n\r\np {\r\n font-size: 1.2em;\r\n margin: 0.5em 0;\r\n}\r\n\r\n.freeze {\r\n overflow: hidden;\r\n}\r\n\r\n/* menu links */\r\n\r\n#menu li a:link,\r\n#menu li a:visited,\r\n#menu li a:focus:active,\r\n#menu li a:focus:hover {\r\n color: #ed225d;\r\n /* gray #333;\r\n og p5 pink #ED225D;\r\n blue #2D7BB6 (a lighter Processing blue — it's our take on it) */\r\n /*outline: none !important; keep on for accessibility */\r\n background: transparent;\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n/* body links */\r\n\r\na:link,\r\na:visited {\r\n color: #2d7bb6;\r\n text-decoration: none;\r\n /*outline: none !important; keep on for accessibility */\r\n}\r\n\r\na:active,\r\na:hover,\r\n#reference a:hover {\r\n color: #ed225d;\r\n text-decoration: none;\r\n padding-bottom: 0.11em;\r\n border-bottom: 0.11em dashed;\r\n border-bottom-color: #ed225d;\r\n transition: border-bottom 30ms linear;\r\n}\r\n\r\na.nounderline:hover {\r\n border: none;\r\n}\r\n\r\na.here {\r\n color: #ed225d;\r\n text-decoration: none;\r\n padding-bottom: 0.1em;\r\n border-bottom: transparent;\r\n border-bottom-color: #ed225d;\r\n}\r\n\r\n.highlight {\r\n background-color: rgba(237, 34, 93, 0.15);\r\n}\r\n\r\n.container > div:first-of-type {\r\n margin-top: 2em;\r\n}\r\n\r\nh1,\r\nh2,\r\nh3,\r\nh4,\r\nh5 {\r\n margin: 1.414em 0 0.5em 0;\r\n font-weight: inherit;\r\n line-height: 1.2;\r\n font-family: 'Montserrat', sans-serif;\r\n}\r\n\r\nh1 {\r\n font-size: 2.25em;\r\n /* 2.369em */\r\n margin: 0;\r\n}\r\n\r\nh2 {\r\n font-size: 1.5em;\r\n /* 1.777em */\r\n margin: 1em 0 0 0;\r\n}\r\n\r\n.code {\r\n font-family: 'Inconsolata', consolas, monospace;\r\n}\r\n\r\n#backlink {\r\n margin: 1.2em 0.444em 0 0;\r\n font-family: 'Montserrat', sans-serif;\r\n float: right;\r\n}\r\n\r\n#backlink a {\r\n color: #afafaf;\r\n}\r\n\r\n#backlink a:hover {\r\n color: #ed225d;\r\n border-bottom: none;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n HEADER\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n#promo,\r\n#promo:visited {\r\n width: 100%;\r\n background: palegreen;\r\n padding: 0;\r\n margin: 0;\r\n text-align: center;\r\n padding: 0.4em 0;\r\n background: rgb(116, 255, 183);\r\n background: radial-gradient(\r\n circle,\r\n rgba(116, 255, 183, 1) 0%,\r\n rgba(138, 255, 242, 1) 100%\r\n );\r\n font-family: 'Montserrat', sans-serif;\r\n color: #ed225d !important;\r\n}\r\n\r\n#promo:hover {\r\n background: #ed225d;\r\n color: white !important;\r\n}\r\n\r\n#promo-link {\r\n margin: 0 !important;\r\n padding: 0;\r\n}\r\n\r\n#family a:link,\r\n#family a:visited {\r\n margin: 0.4em;\r\n}\r\n\r\n#family a:hover,\r\n#family a:active {\r\n margin: 0.4em;\r\n border: none;\r\n}\r\n\r\n#family {\r\n position: absolute;\r\n z-index: 9999;\r\n top: 0;\r\n left: 0;\r\n /*padding: 0.5em 2em;*/\r\n width: 100%;\r\n /* 96, 100% if fixed*/\r\n border-bottom: 1px solid;\r\n overflow: none;\r\n margin: 0;\r\n border-bottom-color: rgba(51, 51, 51, 0.5);\r\n -webkit-box-shadow: 0px 0px 10px #333;\r\n -moz-box-shadow: 0px 0px 10px #333;\r\n box-shadow: 0px 0px 10px #333;\r\n background-color: rgba(255, 255, 255, 0.85);\r\n /* */\r\n}\r\n\r\n#processing-sites {\r\n margin: 0.375em 0;\r\n}\r\n\r\n#processing-sites li {\r\n list-style: none;\r\n display: inline-block;\r\n margin: 0;\r\n}\r\n\r\n#processing-sites li:first-child {\r\n margin-left: 2em;\r\n}\r\n\r\n#processing-sites li:last-child {\r\n float: right;\r\n margin-right: 2em;\r\n}\r\n\r\n.code-snippet {\r\n margin: 0 0 0 1em;\r\n width: 90%;\r\n clear: both;\r\n}\r\n\r\n.column-span {\r\n margin: 0 0 0 1em;\r\n padding: 0;\r\n float: left;\r\n max-width: 100%;\r\n}\r\n\r\n.method_description p {\r\n margin-top: 0;\r\n}\r\n\r\nmain {\r\n padding: 0;\r\n}\r\n\r\n.spacer {\r\n clear: both;\r\n}\r\n\r\nul {\r\n margin: 0;\r\n padding: 0;\r\n list-style: none;\r\n}\r\n\r\nol {\r\n font-size: 1.2em;\r\n}\r\n\r\nli {\r\n margin: 0;\r\n padding: 0;\r\n}\r\n\r\nul.list_view {\r\n margin: 0.5em 0 0 1em;\r\n padding: 0;\r\n list-style: disc;\r\n list-style-position: outside;\r\n font-size: 1.2em;\r\n}\r\n\r\nol ul.list_view {\r\n font-size: 1em;\r\n}\r\n\r\nul.inside {\r\n margin: 0 0 0 2em;\r\n padding: 0;\r\n list-style: disc;\r\n list-style-position: inside;\r\n}\r\n\r\n.image-row img {\r\n width: 48%;\r\n height: 14.3%;\r\n}\r\n\r\n.image-row img + img {\r\n float: right;\r\n margin-right: 0;\r\n margin-bottom: 0.25em;\r\n}\r\n\r\nimg,\r\nmain div img {\r\n margin: 0.5em 0.5em 0 0;\r\n width: 100%;\r\n}\r\n\r\np + img {\r\n margin-top: 0;\r\n}\r\n\r\n.video {\r\n width: 100%;\r\n}\r\n\r\n#lockup {\r\n position: absolute;\r\n top: -5.75em;\r\n left: 1.25em;\r\n height: 0px;\r\n -webkit-touch-callout: none;\r\n -webkit-user-select: none;\r\n -khtml-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n\r\n#lockup object {\r\n margin: 0;\r\n padding: 0;\r\n border: none;\r\n}\r\n\r\n#lockup a:focus {\r\n outline: 0;\r\n}\r\n\r\n.logo {\r\n margin: 0;\r\n padding: 0;\r\n border: none;\r\n margin-bottom: 0.4em;\r\n height: 4.5em;\r\n width: 9.75em;\r\n}\r\n\r\n#lockup p {\r\n color: #ed225d;\r\n font-size: 0.7em;\r\n font-family: 'Montserrat', sans-serif;\r\n margin: 0.5em 0 0 8.5em;\r\n}\r\n\r\n#lockup a:link {\r\n border: transparent;\r\n height: 4.5em;\r\n width: 9.75em;\r\n}\r\n\r\n.caption {\r\n margin-bottom: 2.5em;\r\n}\r\n\r\n.caption span,\r\n.caption p {\r\n text-align: right;\r\n font-size: 0.7em;\r\n font-family: 'Montserrat', sans-serif;\r\n padding-top: 0.25em;\r\n}\r\n\r\nfooter {\r\n clear: both;\r\n border-top: 0.1em dashed;\r\n border-top-color: #ed225d;\r\n margin: 2em 0;\r\n}\r\n\r\n.videoWrapper {\r\n position: relative;\r\n padding-bottom: 56.25%; /* 16:9 */\r\n height: 0;\r\n margin-top: 0.5em;\r\n}\r\n.videoWrapper iframe {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n width: 100%;\r\n height: 100%;\r\n}\r\n\r\n/* ==========================================================================\r\n Helper classes\r\n ========================================================================== */\r\n\r\n/*\r\n * Image replacement\r\n */\r\n\r\n.ir {\r\n background-color: transparent;\r\n border: 0;\r\n overflow: hidden;\r\n /* IE 6/7 fallback */\r\n *text-indent: -9999px;\r\n}\r\n\r\n.ir:before {\r\n content: '';\r\n display: block;\r\n width: 0;\r\n height: 150%;\r\n}\r\n\r\n/*\r\n * Hide from both screenreaders and browsers: h5bp.com/u\r\n */\r\n\r\n.hidden {\r\n display: none !important;\r\n visibility: hidden;\r\n}\r\n\r\n/*\r\n * Hide only visually, but have it available for screenreaders: h5bp.com/v\r\n */\r\n\r\n.sr-only {\r\n border: 0;\r\n clip: rect(0 0 0 0);\r\n height: 1px;\r\n margin: -1px;\r\n overflow: hidden;\r\n padding: 0;\r\n position: absolute;\r\n width: 1px;\r\n}\r\n\r\n/*\r\n * Extends the .visuallyhidden class to allow the element to be focusable\r\n * when navigated to via the keyboard: h5bp.com/p\r\n */\r\n\r\n.sr-only.focusable:active,\r\n.sr-only.focusable:focus {\r\n clip: auto;\r\n height: auto;\r\n margin: 0;\r\n overflow: visible;\r\n position: static;\r\n width: auto;\r\n}\r\n\r\n/*\r\n * Hide visually and from screenreaders, but maintain layout\r\n */\r\n\r\n.invisible {\r\n visibility: hidden;\r\n}\r\n\r\n/*\r\n * Clearfix: contain floats\r\n *\r\n * For modern browsers\r\n * 1. The space content is one way to avoid an Opera bug when the\r\n * `contenteditable` attribute is included anywhere else in the document.\r\n * Otherwise it causes space to appear at the top and bottom of elements\r\n * that receive the `clearfix` class.\r\n * 2. The use of `table` rather than `block` is only necessary if using\r\n * `:before` to contain the top-margins of child elements.\r\n */\r\n\r\n.clearfix:before,\r\n.clearfix:after {\r\n content: ' ';\r\n /* 1 */\r\n display: table;\r\n /* 2 */\r\n}\r\n\r\n.clearfix:after {\r\n clear: both;\r\n}\r\n\r\n/*\r\n * For IE 6/7 only\r\n * Include this rule to trigger hasLayout and contain floats.\r\n */\r\n\r\n.clearfix {\r\n *zoom: 1;\r\n}\r\n\r\n/* ==========================================================================\r\n Responsive design\r\n ========================================================================== */\r\n\r\n#notMobile-message {\r\n display: none;\r\n order: 1;\r\n}\r\n\r\n#isMobile-displayButton {\r\n display: none;\r\n}\r\n\r\n#asterisk-design-element,\r\n.separator-design-element {\r\n display: none;\r\n}\r\n\r\n.pointerevents #asterisk-design-element,\r\n.pointerevents .separator-design-element {\r\n pointer-events: none;\r\n display: inline-block;\r\n}\r\n\r\n@media (min-width: 780px) {\r\n .container {\r\n width: 49em !important;\r\n margin: 11.5em auto; /* temp promo, 10.0em */\r\n }\r\n main {\r\n width: 36em;\r\n padding: 0 !important;\r\n }\r\n footer {\r\n width: 48em;\r\n }\r\n}\r\n\r\n@media (min-width: 780px) {\r\n .container {\r\n margin: 11.5em auto; /* temp promo, 10.0em */\r\n width: 100%;\r\n padding: 0.8em 0 0 0;\r\n height: auto;\r\n min-height: 100%;\r\n }\r\n #home-page {\r\n display: flex;\r\n flex-wrap: row;\r\n }\r\n main {\r\n padding: 0 1em 0 0;\r\n }\r\n small,\r\n .small,\r\n footer,\r\n #family {\r\n font-size: 0.7em;\r\n }\r\n footer {\r\n clear: both;\r\n /*margin: 4em 0 2em -.75em;*/\r\n }\r\n #i18n-btn {\r\n position: absolute;\r\n top: 4.0em; /* temp promo, 2.5em */\r\n right: 1em;\r\n }\r\n #i18n-btn a {\r\n font-family: 'Montserrat', sans-serif;\r\n }\r\n #menu {\r\n list-style: none;\r\n font-family: 'Montserrat', sans-serif;\r\n margin: 0 0.75em 0 -1.85em;\r\n /* margin-right: 0.75em; */\r\n width: 7.3em;\r\n height: 100%;\r\n /*float:left;*/\r\n border-top: transparent;\r\n border-bottom: transparent;\r\n padding: 0;\r\n font-size: 0.83em;\r\n z-index: 100;\r\n position: relative;\r\n top: 0;\r\n }\r\n #menu li {\r\n float: none;\r\n margin: 0 0 1em 0;\r\n text-align: right;\r\n }\r\n /* #menu li:last-child {\r\n margin: 0;\r\n } */\r\n /* #menu .other-link::after {\r\n content:\"\\2192\";\r\n margin-right: -0.98em;\r\n content:\" »\";\r\n } */\r\n #menu li:nth-child(11) {\r\n margin-top: 3em;\r\n padding-top: 0.5em;\r\n /*border-top: 0.06em solid rgba(51,51,51,0.25);*/\r\n }\r\n .left-column {\r\n width: 48%;\r\n float: left;\r\n margin-bottom: 40px;\r\n }\r\n .right-column {\r\n width: 48%;\r\n float: right;\r\n margin-right: 0;\r\n margin-bottom: 0.25em;\r\n }\r\n .narrow-left-column {\r\n width: 32%;\r\n float: left;\r\n }\r\n .wide-right-column {\r\n width: 64%;\r\n float: right;\r\n margin-right: 0;\r\n margin-bottom: 0.25em;\r\n }\r\n .book {\r\n font-size: 0.7em;\r\n }\r\n .column_0,\r\n .column_1,\r\n .column_2 {\r\n float: left;\r\n width: 11.333em;\r\n }\r\n .column_0,\r\n .column_1 {\r\n margin-right: 1em;\r\n }\r\n #collection-list-nav {\r\n width: 100%;\r\n clear: both;\r\n border-bottom: 1px dashed rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n #collection-list-categories {\r\n font-family: 'Montserrat', sans-serif;\r\n display: flex;\r\n flex-direction: row;\r\n margin: 1em 0 1.5em 0;\r\n }\r\n #collection-list-categories ul {\r\n flex: 1;\r\n }\r\n #collection-list {\r\n margin: 0;\r\n }\r\n .group-name.first {\r\n margin-top: 0 !important;\r\n }\r\n .column.group-name {\r\n margin-bottom: 1em;\r\n }\r\n\r\n #library-page .group-name {\r\n margin: 2em 0 0.5em 0;\r\n }\r\n #library-page .column {\r\n margin-top: 1em;\r\n }\r\n #list {\r\n display: flex;\r\n flex-direction: row;\r\n flex-wrap: wrap;\r\n margin-bottom: 1em;\r\n }\r\n}\r\n\r\n@media (max-width: 780px) {\r\n .tagline {\r\n display: none !important;\r\n }\r\n\r\n #family {\r\n display: none;\r\n }\r\n\r\n #i18n-btn {\r\n position: absolute;\r\n top: 0.5em;\r\n right: 0.7em;\r\n z-index: 10;\r\n }\r\n\r\n #search {\r\n width: 100%;\r\n float: left;\r\n margin-bottom: 1em;\r\n }\r\n\r\n #search input[type='text'] {\r\n width: 100%;\r\n }\r\n\r\n #search input[type='text'],\r\n #search input[type='search'] {\r\n font-size: 1.5em;\r\n }\r\n\r\n #lockup {\r\n position: absolute;\r\n top: 2em;\r\n left: 1em;\r\n }\r\n .column-span {\r\n margin:0;\r\n padding: 0 1em;\r\n float: left;\r\n }\r\n #menu.top_menu,\r\n #menu {\r\n margin: 6em 0 0.5em 0;\r\n font-size: 1.3em;\r\n }\r\n #menu li {\r\n display: inline-block;\r\n }\r\n\r\n #menu li:nth-last-child(1) a::after {\r\n content: '';\r\n }\r\n\r\n #menu li a::after {\r\n content: ',';\r\n }\r\n\r\n #contribute-item:first-child {\r\n margin-left: 0px;\r\n }\r\n .download_box {\r\n width: 96%;\r\n }\r\n .download_box.half_box {\r\n width: 46%;\r\n margin-right: 4%;\r\n float: left;\r\n }\r\n #etc_list {\r\n font-size: 1.2em;\r\n margin-top: 1em;\r\n }\r\n #asterisk-design-element,\r\n .separator-design-element {\r\n display: none !important;\r\n pointer-events: none;\r\n }\r\n pre[class*='language-'] {\r\n padding: 0.5em 0.5em;\r\n width: 100%;\r\n }\r\n\r\n code {\r\n word-wrap: break-word;\r\n word-break: break-all;\r\n }\r\n #credits {\r\n position: relative !important;\r\n z-index: 2;\r\n margin-top: -7em;\r\n padding: 0 2em 3em 1em;\r\n font-size: 0.5em;\r\n float: right;\r\n width: 100%;\r\n text-align: right;\r\n display: none;\r\n /* HIDDEN SKETCH */\r\n }\r\n #home-sketch-frame {\r\n display: none;\r\n /* HIDDEN SKETCH */\r\n }\r\n #exampleDisplay,\r\n #exampleFrame,\r\n #exampleDisplay #exampleEditor {\r\n width: 100%;\r\n }\r\n #exampleDisplay .edit_button {\r\n left: -0.58em;\r\n }\r\n #exampleDisplay .reset_button {\r\n left: 3em;\r\n }\r\n #exampleDisplay .copy_button {\r\n left: 6.44em;\r\n }\r\n #exampleEditor {\r\n margin-top: 3em;\r\n }\r\n small,\r\n .small,\r\n footer {\r\n font-size: 0.5em;\r\n }\r\n .paramtype {\r\n width: 96%;\r\n }\r\n}\r\n\r\n@media (max-width: 400px) {\r\n #i18n {\r\n margin-top: 0.75em !important;\r\n }\r\n body {\r\n margin-top: -0.75em !important;\r\n }\r\n}\r\n\r\niframe {\r\n border: none;\r\n width: 100%;\r\n}\r\n\r\n.iframe-container {\r\n overflow: hidden;\r\n position: relative;\r\n}\r\n\r\n.iframe-container iframe {\r\n border: 0;\r\n height: 100%;\r\n left: 0;\r\n position: absolute;\r\n top: 0;\r\n width: 100%;\r\n}\r\n\r\n.cnv_div {\r\n /* This ensures that all canvases and additional html elements (if any) from\r\n * the example code snippets are only 100px wide rather than covering the\r\n * entire page, which potentially obscures the example code. */\r\n display: inline-flex;\r\n flex-direction: column;\r\n}\r\n\r\n.cnv_div > * {\r\n width: 100px;\r\n height: auto;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n LANGUAGE BUTTONS\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n#i18n-buttons {\r\n margin: 0;\r\n background: white;\r\n}\r\n\r\n#i18n-buttons li {\r\n list-style: none;\r\n display: inline-block;\r\n margin-left: 0.5em;\r\n}\r\n\r\n#i18n-btn a {\r\n border: none;\r\n outline: none;\r\n font-size: 0.7em;\r\n color: #696969;\r\n z-index: 5;\r\n}\r\n\r\n#i18n-btn a:hover {\r\n color: #ed225d;\r\n}\r\n\r\n#i18n-btn a.disabled {\r\n color: #ed225d;\r\n cursor: default;\r\n}\r\n\r\n/*\r\n //////////////////////////////////////////////////\r\n ASTERISKS\r\n //////////////////////////////////////////////////\r\n*/\r\n\r\n/* constants for the asterisk */\r\n\r\n#asterisk-design-element {\r\n position: fixed;\r\n z-index: -1;\r\n opacity: 0.6;\r\n pointer-events: none;\r\n}\r\n\r\n/* variations for asterisks on pages */\r\n\r\n.separator-design-element {\r\n width: 0.33em;\r\n height: 0.33em;\r\n margin: 0 0.09em 0.18em 0.09em;\r\n display: inline-block;\r\n overflow: hidden;\r\n text-indent: -100%;\r\n background: transparent\r\n url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyOCIgaGVpZ2h0PSIyOCIgdmlld0JveD0iMCAwIDI4IDI4Ij48cGF0aCBkPSJNMTYuOSAxMC4zbDguNS0yLjYgMS43IDUuMiAtOC41IDIuOSA1LjMgNy41IC00LjQgMy4yIC01LjYtNy4zTDguNSAyNi4zbC00LjMtMy4zIDUuMy03LjJMMC45IDEyLjZsMS43LTUuMiA4LjYgMi44VjEuNGg1LjhWMTAuM3oiIHN0eWxlPSJmaWxsOiNFRDIyNUQ7c3Ryb2tlOiNFRDIyNUQiLz48L3N2Zz4=');\r\n background-size: 0.33em;\r\n}\r\n\r\n#home-page #asterisk-design-element {\r\n bottom: -8%;\r\n right: 20%;\r\n height: 12em;\r\n width: 12em;\r\n opacity: 1;\r\n}\r\n\r\n#learn-page #asterisk-design-element,\r\n#examples-page #asterisk-design-element,\r\n#other-content-types-page #asterisk-design-element {\r\n bottom: -14%;\r\n left: -20%;\r\n height: 25em;\r\n width: 25em;\r\n -webkit-transform: rotate(-1deg);\r\n -moz-transform: rotate(-1deg);\r\n -ms-transform: rotate(-1deg);\r\n -o-transform: rotate(-1deg);\r\n transform: rotate(-1deg);\r\n}\r\n\r\n#libraries-page #asterisk-design-element,\r\n#books-page #asterisk-design-element {\r\n bottom: -19%;\r\n right: -16%;\r\n height: 28em;\r\n width: 28em;\r\n -webkit-transform: rotate(2deg);\r\n -moz-transform: rotate(2deg);\r\n -ms-transform: rotate(2deg);\r\n -o-transform: rotate(2deg);\r\n transform: rotate(2deg);\r\n}\r\n\r\n#get-started-page #asterisk-design-element,\r\n#community-page #asterisk-design-element {\r\n top: 10%;\r\n right: -20%;\r\n height: 30em;\r\n width: 30em;\r\n -webkit-transform: rotate(2deg);\r\n -moz-transform: rotate(2deg);\r\n -ms-transform: rotate(2deg);\r\n -o-transform: rotate(2deg);\r\n transform: rotate(2deg);\r\n}\r\n\r\n#reference-page #asterisk-design-element,\r\n#download-page #asterisk-design-element {\r\n top: 7%;\r\n left: 1%;\r\n height: 10em;\r\n width: 10em;\r\n -webkit-transform: rotate(-21deg);\r\n -moz-transform: rotate(-21deg);\r\n -ms-transform: rotate(-21deg);\r\n -o-transform: rotate(-21deg);\r\n transform: rotate(-21deg);\r\n}\r\n\r\n.email-octopus-email-address {\r\n color: #ed225d;\r\n text-decoration: none;\r\n padding-bottom: 0.11em;\r\n outline: none;\r\n border: none;\r\n border-bottom: 0.11em dashed;\r\n border-bottom-color: #ed225d;\r\n transition: border-bottom 30ms linear;\r\n width: 13em;\r\n}\r\n\r\n.email-octopus-form-row-hp {\r\n position: absolute;\r\n left: -5000px;\r\n}\r\n\r\n.email-octopus-form-row button {\r\n border: 1px solid #ed225d;\r\n color: #ed225d;\r\n padding: 0.4em 0.6em;\r\n margin: 1em 0 0 0;\r\n font-family: 'Montserrat', sans-serif;\r\n display: block;\r\n}\r\n\r\n.email-octopus-form-row button:hover {\r\n background-color: #ed225d;\r\n color: white;\r\n}\r\n\r\n.email-octopus-email-address::-webkit-input-placeholder {\r\n color: #ababab;\r\n}\r\n.email-octopus-email-address::-moz-placeholder {\r\n color: #ababab;\r\n}\r\n.email-octopus-email-address:-moz-placeholder {\r\n color: #ababab;\r\n}\r\n.email-octopus-email-address:-ms-input-placeholder {\r\n color: #ababab;\r\n}\r\n\r\n@media (min-width: 720px) {\r\n .email-octopus-email-address {\r\n width: 16em;\r\n }\r\n\r\n .email-octopus-form-row button {\r\n margin: 0;\r\n margin-left: 0.5em;\r\n display: inline;\r\n }\r\n}\r\n"]} \ No newline at end of file diff --git a/dist/assets/examples/assets/360video_256crop_v2.mp4 b/dist/assets/examples/assets/360video_256crop_v2.mp4 new file mode 100644 index 0000000000..e64ba0d13c Binary files /dev/null and b/dist/assets/examples/assets/360video_256crop_v2.mp4 differ diff --git a/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_01.mp3 b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_01.mp3 new file mode 100644 index 0000000000..9653a67bb6 Binary files /dev/null and b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_01.mp3 differ diff --git a/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_01.ogg b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_01.ogg new file mode 100644 index 0000000000..ddb329fc15 Binary files /dev/null and b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_01.ogg differ diff --git a/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_02.mp3 b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_02.mp3 new file mode 100644 index 0000000000..b113049905 Binary files /dev/null and b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_02.mp3 differ diff --git a/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_02.ogg b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_02.ogg new file mode 100644 index 0000000000..77d530a2df Binary files /dev/null and b/dist/assets/examples/assets/Damscray_-_Dancing_Tiger_02.ogg differ diff --git a/dist/assets/examples/assets/Damscray_DancingTiger.mp3 b/dist/assets/examples/assets/Damscray_DancingTiger.mp3 new file mode 100644 index 0000000000..b113049905 Binary files /dev/null and b/dist/assets/examples/assets/Damscray_DancingTiger.mp3 differ diff --git a/dist/assets/examples/assets/Damscray_DancingTiger.ogg b/dist/assets/examples/assets/Damscray_DancingTiger.ogg new file mode 100644 index 0000000000..77d530a2df Binary files /dev/null and b/dist/assets/examples/assets/Damscray_DancingTiger.ogg differ diff --git a/dist/assets/examples/assets/LeagueGothic-Regular.otf b/dist/assets/examples/assets/LeagueGothic-Regular.otf new file mode 100644 index 0000000000..6cd753faf8 Binary files /dev/null and b/dist/assets/examples/assets/LeagueGothic-Regular.otf differ diff --git a/dist/assets/examples/assets/SourceSansPro-Regular.otf b/dist/assets/examples/assets/SourceSansPro-Regular.otf new file mode 100644 index 0000000000..38941ae72f Binary files /dev/null and b/dist/assets/examples/assets/SourceSansPro-Regular.otf differ diff --git a/dist/assets/examples/assets/basic.frag b/dist/assets/examples/assets/basic.frag new file mode 100644 index 0000000000..e6bc05d861 --- /dev/null +++ b/dist/assets/examples/assets/basic.frag @@ -0,0 +1,22 @@ +// casey conchinha - @kcconch ( https://github.com/kcconch ) +// louise lessel - @louiselessel ( https://github.com/louiselessel ) +// more p5.js + shader examples: https://itp-xstory.github.io/p5js-shaders/ +// this is a modification of a shader by adam ferriss +// https://github.com/aferriss/p5jsShaderExamples/tree/gh-pages/2_texture-coordinates/2-1_basic + +precision mediump float; + +// this is the same variable we declared in the vertex shader +// we need to declare it here too! +varying vec2 vTexCoord; + +void main() { + + // copy the vTexCoord + // vTexCoord is a value that goes from 0.0 - 1.0 depending on the pixels location + // we can use it to access every pixel on the screen + vec2 coord = vTexCoord; + + // x values for red, y values for green, both for blue + gl_FragColor = vec4(coord.x, coord.y, (coord.x+coord.y), 1.0 ); +} diff --git a/dist/assets/examples/assets/basic.vert b/dist/assets/examples/assets/basic.vert new file mode 100644 index 0000000000..df069583a8 --- /dev/null +++ b/dist/assets/examples/assets/basic.vert @@ -0,0 +1,26 @@ +// vert file and comments from adam ferriss +// https://github.com/aferriss/p5jsShaderExamples + +// our vertex data +attribute vec3 aPosition; + +// our texcoordinates +attribute vec2 aTexCoord; + +// this is a variable that will be shared with the fragment shader +// we will assign the attribute texcoords to the varying texcoords to move them from the vert shader to the frag shader +// it can be called whatever you want but often people prefiv it with 'v' to indicate that it is a varying +varying vec2 vTexCoord; + +void main() { + + // copy the texture coordinates + vTexCoord = aTexCoord; + + // copy the position data into a vec4, using 1.0 as the w component + vec4 positionVec4 = vec4(aPosition, 1.0); + positionVec4.xy = positionVec4.xy * 2.0 - 1.0; + + // send the vertex information on to the fragment shader + gl_Position = positionVec4; +} diff --git a/dist/assets/examples/assets/beat.mp3 b/dist/assets/examples/assets/beat.mp3 new file mode 100644 index 0000000000..3e5802604c Binary files /dev/null and b/dist/assets/examples/assets/beat.mp3 differ diff --git a/dist/assets/examples/assets/beat.ogg b/dist/assets/examples/assets/beat.ogg new file mode 100644 index 0000000000..c13f86a41f Binary files /dev/null and b/dist/assets/examples/assets/beat.ogg differ diff --git a/dist/assets/examples/assets/beatbox.mp3 b/dist/assets/examples/assets/beatbox.mp3 new file mode 100644 index 0000000000..23fb92eb71 Binary files /dev/null and b/dist/assets/examples/assets/beatbox.mp3 differ diff --git a/dist/assets/examples/assets/beatbox.ogg b/dist/assets/examples/assets/beatbox.ogg new file mode 100644 index 0000000000..b2593a6340 Binary files /dev/null and b/dist/assets/examples/assets/beatbox.ogg differ diff --git a/dist/assets/examples/assets/brush.png b/dist/assets/examples/assets/brush.png new file mode 100644 index 0000000000..f3390e3501 Binary files /dev/null and b/dist/assets/examples/assets/brush.png differ diff --git a/dist/assets/examples/assets/bubbles.csv b/dist/assets/examples/assets/bubbles.csv new file mode 100644 index 0000000000..88ac4c1b72 --- /dev/null +++ b/dist/assets/examples/assets/bubbles.csv @@ -0,0 +1,5 @@ +x,y,diameter,name +160,103,43.19838,Happy +372,137,52.42526,Sad +273,235,61.14072,Joyous +121,179,44.758068,Melancholy \ No newline at end of file diff --git a/dist/assets/examples/assets/bubbles.json b/dist/assets/examples/assets/bubbles.json new file mode 100644 index 0000000000..173b118dd4 --- /dev/null +++ b/dist/assets/examples/assets/bubbles.json @@ -0,0 +1,20 @@ +{ + "bubbles": [ + { + "position": { + "x": 160, + "y": 103 + }, + "diameter": 43.19838, + "label": "Happy" + }, + { + "position": { + "x": 372, + "y": 137 + }, + "diameter": 52.42526, + "label": "Sad" + } + ] +} diff --git a/dist/assets/examples/assets/bx-spring.mp3 b/dist/assets/examples/assets/bx-spring.mp3 new file mode 100644 index 0000000000..4a955ab7fa Binary files /dev/null and b/dist/assets/examples/assets/bx-spring.mp3 differ diff --git a/dist/assets/examples/assets/bx-spring.ogg b/dist/assets/examples/assets/bx-spring.ogg new file mode 100644 index 0000000000..b01abee927 Binary files /dev/null and b/dist/assets/examples/assets/bx-spring.ogg differ diff --git a/dist/assets/examples/assets/cat.jpg b/dist/assets/examples/assets/cat.jpg new file mode 100644 index 0000000000..6fd0221988 Binary files /dev/null and b/dist/assets/examples/assets/cat.jpg differ diff --git a/dist/assets/examples/assets/concrete-tunnel.mp3 b/dist/assets/examples/assets/concrete-tunnel.mp3 new file mode 100644 index 0000000000..1bfbd4f8f8 Binary files /dev/null and b/dist/assets/examples/assets/concrete-tunnel.mp3 differ diff --git a/dist/assets/examples/assets/concrete-tunnel.ogg b/dist/assets/examples/assets/concrete-tunnel.ogg new file mode 100644 index 0000000000..be5f66b72c Binary files /dev/null and b/dist/assets/examples/assets/concrete-tunnel.ogg differ diff --git a/dist/assets/examples/assets/doorbell.mp3 b/dist/assets/examples/assets/doorbell.mp3 new file mode 100644 index 0000000000..44b6367916 Binary files /dev/null and b/dist/assets/examples/assets/doorbell.mp3 differ diff --git a/dist/assets/examples/assets/doorbell.ogg b/dist/assets/examples/assets/doorbell.ogg new file mode 100644 index 0000000000..e816288c97 Binary files /dev/null and b/dist/assets/examples/assets/doorbell.ogg differ diff --git a/dist/assets/examples/assets/drum.mp3 b/dist/assets/examples/assets/drum.mp3 new file mode 100644 index 0000000000..9cd8727617 Binary files /dev/null and b/dist/assets/examples/assets/drum.mp3 differ diff --git a/dist/assets/examples/assets/drum.ogg b/dist/assets/examples/assets/drum.ogg new file mode 100644 index 0000000000..5061a1b319 Binary files /dev/null and b/dist/assets/examples/assets/drum.ogg differ diff --git a/dist/assets/examples/assets/fingers.mov b/dist/assets/examples/assets/fingers.mov new file mode 100644 index 0000000000..a9cbbbe3ea Binary files /dev/null and b/dist/assets/examples/assets/fingers.mov differ diff --git a/dist/assets/examples/assets/fingers.webm b/dist/assets/examples/assets/fingers.webm new file mode 100644 index 0000000000..8fb81cfd15 Binary files /dev/null and b/dist/assets/examples/assets/fingers.webm differ diff --git a/dist/assets/examples/assets/large-dark-plate.mp3 b/dist/assets/examples/assets/large-dark-plate.mp3 new file mode 100644 index 0000000000..b9a15cbed7 Binary files /dev/null and b/dist/assets/examples/assets/large-dark-plate.mp3 differ diff --git a/dist/assets/examples/assets/large-dark-plate.ogg b/dist/assets/examples/assets/large-dark-plate.ogg new file mode 100644 index 0000000000..40115377e5 Binary files /dev/null and b/dist/assets/examples/assets/large-dark-plate.ogg differ diff --git a/dist/assets/examples/assets/lucky_dragons_-_power_melody.mp3 b/dist/assets/examples/assets/lucky_dragons_-_power_melody.mp3 new file mode 100644 index 0000000000..c54c70c01a Binary files /dev/null and b/dist/assets/examples/assets/lucky_dragons_-_power_melody.mp3 differ diff --git a/dist/assets/examples/assets/lucky_dragons_-_power_melody.ogg b/dist/assets/examples/assets/lucky_dragons_-_power_melody.ogg new file mode 100644 index 0000000000..1e5b9e7abc Binary files /dev/null and b/dist/assets/examples/assets/lucky_dragons_-_power_melody.ogg differ diff --git a/dist/assets/examples/assets/mask.png b/dist/assets/examples/assets/mask.png new file mode 100644 index 0000000000..a6737489b9 Binary files /dev/null and b/dist/assets/examples/assets/mask.png differ diff --git a/dist/assets/examples/assets/moonwalk.jpg b/dist/assets/examples/assets/moonwalk.jpg new file mode 100644 index 0000000000..36cc6c060e Binary files /dev/null and b/dist/assets/examples/assets/moonwalk.jpg differ diff --git a/dist/assets/examples/assets/parrot-bw.png b/dist/assets/examples/assets/parrot-bw.png new file mode 100644 index 0000000000..cbc6a868d1 Binary files /dev/null and b/dist/assets/examples/assets/parrot-bw.png differ diff --git a/dist/assets/examples/assets/parrot-color.png b/dist/assets/examples/assets/parrot-color.png new file mode 100644 index 0000000000..5addae8d3a Binary files /dev/null and b/dist/assets/examples/assets/parrot-color.png differ diff --git a/dist/assets/examples/assets/particle_texture.png b/dist/assets/examples/assets/particle_texture.png new file mode 100644 index 0000000000..0852c88e1d Binary files /dev/null and b/dist/assets/examples/assets/particle_texture.png differ diff --git a/dist/assets/examples/assets/rover.png b/dist/assets/examples/assets/rover.png new file mode 100644 index 0000000000..a597279130 Binary files /dev/null and b/dist/assets/examples/assets/rover.png differ diff --git a/dist/assets/examples/assets/rover_wide.jpg b/dist/assets/examples/assets/rover_wide.jpg new file mode 100644 index 0000000000..793781a3be Binary files /dev/null and b/dist/assets/examples/assets/rover_wide.jpg differ diff --git a/dist/assets/examples/assets/small-plate.mp3 b/dist/assets/examples/assets/small-plate.mp3 new file mode 100644 index 0000000000..656e154a5f Binary files /dev/null and b/dist/assets/examples/assets/small-plate.mp3 differ diff --git a/dist/assets/examples/assets/small-plate.ogg b/dist/assets/examples/assets/small-plate.ogg new file mode 100644 index 0000000000..7b70d3349d Binary files /dev/null and b/dist/assets/examples/assets/small-plate.ogg differ diff --git a/dist/assets/examples/assets/texture.frag b/dist/assets/examples/assets/texture.frag new file mode 100644 index 0000000000..c74ce3f42f --- /dev/null +++ b/dist/assets/examples/assets/texture.frag @@ -0,0 +1,84 @@ +// casey conchinha - @kcconch ( https://github.com/kcconch ) +// louise lessel - @louiselessel ( https://github.com/louiselessel ) +// more p5.js + shader examples: https://itp-xstory.github.io/p5js-shaders/ +// rotate/tile functions from example by patricio gonzalez vivo +// @patriciogv ( patriciogonzalezvivo.com ) + +#ifdef GL_ES +precision mediump float; +#endif + +#define PI 3.14159265358979323846 + +uniform vec2 resolution; +uniform float time; +uniform vec2 mouse; + +vec2 rotate2D (vec2 _st, float _angle) { + _st -= 0.5; + _st = mat2(cos(_angle),-sin(_angle), + sin(_angle),cos(_angle)) * _st; + _st += 0.5; + return _st; +} + +vec2 tile (vec2 _st, float _zoom) { + _st *= _zoom; + return fract(_st); +} + +vec2 rotateTilePattern(vec2 _st){ + + // Scale the coordinate system by 2x2 + _st *= 2.0; + + // Give each cell an index number + // according to its position + float index = 0.0; + index += step(1., mod(_st.x,2.0)); + index += step(1., mod(_st.y,2.0))*2.0; + + // | + // 2 | 3 + // | + //-------------- + // | + // 0 | 1 + // | + + // Make each cell between 0.0 - 1.0 + _st = fract(_st); + + // Rotate each cell according to the index + if(index == 1.0){ + // Rotate cell 1 by 90 degrees + _st = rotate2D(_st,PI*0.5); + } else if(index == 2.0){ + // Rotate cell 2 by -90 degrees + _st = rotate2D(_st,PI*-0.5); + } else if(index == 3.0){ + // Rotate cell 3 by 180 degrees + _st = rotate2D(_st,PI); + } + + return _st; +} + +float concentricCircles(in vec2 st, in vec2 radius, in float res, in float scale) { + float dist = distance(st,radius); + float pct = floor(dist*res)/scale; + return pct; +} + +void main (void) { + vec2 st = gl_FragCoord.xy/resolution.xy; + vec2 mst = gl_FragCoord.xy/mouse.xy; + float mdist= distance(vec2(1.0,1.0), mst); + + float dist = distance(st,vec2(sin(time/10.0),cos(time/10.0))); + st = tile(st,10.0); + + st = rotate2D(st,dist/(mdist/5.0)*PI*2.0); + + gl_FragColor = vec4(vec3(concentricCircles(st, vec2(0.0,0.0), 5.0, 5.0),concentricCircles(st, vec2(0.0,0.0), 10.0, 10.0),concentricCircles(st, vec2(0.0,0.0), 20.0, 10.0)),1.0); +} diff --git a/dist/assets/examples/assets/texture.vert b/dist/assets/examples/assets/texture.vert new file mode 100644 index 0000000000..5dd95c9b31 --- /dev/null +++ b/dist/assets/examples/assets/texture.vert @@ -0,0 +1,15 @@ +// vert file and comments from adam ferriss +// https://github.com/aferriss/p5jsShaderExamples + +// our vertex data +attribute vec3 aPosition; + +void main() { + + // copy the position data into a vec4, using 1.0 as the w component + vec4 positionVec4 = vec4(aPosition, 1.0); + positionVec4.xy = positionVec4.xy * 2.0 - 1.0; + + // send the vertex information on to the fragment shader + gl_Position = positionVec4; +} diff --git a/dist/assets/examples/assets/uniforms.frag b/dist/assets/examples/assets/uniforms.frag new file mode 100644 index 0000000000..bf2ad1bc5d --- /dev/null +++ b/dist/assets/examples/assets/uniforms.frag @@ -0,0 +1,77 @@ +// casey conchinha - @kcconch ( https://github.com/kcconch ) +// louise lessel - @louiselessel ( https://github.com/louiselessel ) +// more p5.js + shader examples: https://itp-xstory.github.io/p5js-shaders/ +// this is a modification of a shader by adam ferriss +// https://github.com/aferriss/p5jsShaderExamples/tree/gh-pages/5_shapes/5-3_polygon + +precision mediump float; + +// these are known as preprocessor directive +// essentially we are just declaring some variables that wont change +// you can think of them just like const variables + +#define PI 3.14159265359 +#define TWO_PI 6.28318530718 + +// we need the sketch resolution to perform some calculations +uniform vec2 resolution; +uniform float time; +uniform float mouse; + +// this is a function that turns an rgb value that goes from 0 - 255 into 0.0 - 1.0 +vec3 rgb(float r, float g, float b){ + return vec3(r / 255.0, g / 255.0, b / 255.0); +} + +vec4 poly(float x, float y, float size, float sides, float rotation, vec3 col){ + // get our coordinates + vec2 coord = gl_FragCoord.xy; + + // move the coordinates to where we want to draw the shape + vec2 pos = vec2(x,y) - coord; + + // calculate the angle of a pixel relative to our position + float angle = atan( pos.x, pos.y) + PI + rotation; + + // calculate the size of our shape + float radius = TWO_PI / sides; + + // this is the function that controls our shapes appearance + // i pulled it from the book of shaders shapes page https://thebookofshaders.com/07/ + // essentially what we are doing here is computing a circle with length(pos) and manipulating it's shape with the cos() function + // this technique is really powerful and can be used to create all sorts of different shapes + // for instance, try changing cos() to sin() + float d = cos(floor(0.5 + angle / radius) * radius - angle) * length(pos); + + // restrict our shape to black and white and set it's size + // we use the smoothstep function to get a nice soft edge + d = 1.0 - smoothstep(size*0.5, size*0.5+1.0, d); + + // return the color with the shape as the alpha channel + return vec4(col, d); +} + + +void main() { + + vec2 center = resolution * 1.0; // draw the shape at the center of the screen + float size = resolution.y * 0.5; // make the shape a quarter of the screen height + float sides = mod(floor(mouse), 7.0) + 3.0; // slowly increase the sides, when it reaches 10 sides, go back down to 3 + float rotation = time; // rotation is in radians, but for time it doesnt really matter + + // lets make our shape in the center of the screen. We have to subtract half of it's width and height just like in p5 + float x = center.x ; + float y = center.y ; + + // a color for the shape + vec3 grn = rgb(200.0, 240.0, 200.0); + + // call our shape function with poly(x, y, sz, sides, rotation, color); + vec4 poly = poly(center.x , center.y, size, sides, rotation, grn); + + // mix the polygon with the opposite of the green color according to the shapes alpha + poly.rgb = mix(1.0 - grn, poly.rgb, poly.a); + + // render to screen + gl_FragColor = vec4(poly.rgb, 1.0); +} diff --git a/dist/assets/examples/assets/uniforms.vert b/dist/assets/examples/assets/uniforms.vert new file mode 100644 index 0000000000..568a87edd2 --- /dev/null +++ b/dist/assets/examples/assets/uniforms.vert @@ -0,0 +1,19 @@ +// vert file and comments from adam ferriss +// https://github.com/aferriss/p5jsShaderExamples + +attribute vec3 aPosition; +attribute vec2 aTexCoord; + +void main() { + + // copy the position data into a vec4, using 1.0 as the w component + vec4 positionVec4 = vec4(aPosition, 1.0); + + // scale the rect by two, and move it to the center of the screen + // if we don't do this, it will appear with its bottom left corner in the center of the sketch + // try commenting this line out to see what happens + positionVec4.xy = positionVec4.xy * 2.0 - 1.0; + + // send the vertex information on to the fragment shader + gl_Position = positionVec4; +} diff --git a/dist/assets/examples/assets/webcam.frag b/dist/assets/examples/assets/webcam.frag new file mode 100644 index 0000000000..ada0949d9a --- /dev/null +++ b/dist/assets/examples/assets/webcam.frag @@ -0,0 +1,34 @@ +// casey conchinha - @kcconch ( https://github.com/kcconch ) +// louise lessel - @louiselessel ( https://github.com/louiselessel ) +// more p5.js + shader examples: https://itp-xstory.github.io/p5js-shaders/ + +precision mediump float; + +// grab texcoords from vert shader +varying vec2 vTexCoord; + +// our texture coming from p5 +uniform sampler2D tex0; + + +void main() { + vec2 uv = vTexCoord; + + // the texture is loaded upside down and backwards by default so lets flip it + uv.y = 1.0 - uv.y; + + vec4 tex = texture2D(tex0, uv); + + float gray = (tex.r + tex.g + tex.b) / 3.0; + + float res = 20.0; + float scl = res / (10.0); + + float threshR = (fract(floor(tex.r*res)/scl)*scl) * gray ; + float threshG = (fract(floor(tex.g*res)/scl)*scl) * gray ; + float threshB = (fract(floor(tex.b*res)/scl)*scl) * gray ; + vec3 thresh = vec3(threshR, threshG, threshB); + + // render the output + gl_FragColor = vec4(thresh, 1.0); +} diff --git a/dist/assets/examples/assets/webcam.vert b/dist/assets/examples/assets/webcam.vert new file mode 100644 index 0000000000..c04d96c34a --- /dev/null +++ b/dist/assets/examples/assets/webcam.vert @@ -0,0 +1,21 @@ +// vert file and comments from adam ferriss +// https://github.com/aferriss/p5jsShaderExamples + +// our vertex data +attribute vec3 aPosition; +attribute vec2 aTexCoord; + +// lets get texcoords just for fun! +varying vec2 vTexCoord; + +void main() { + // copy the texcoords + vTexCoord = aTexCoord; + + // copy the position data into a vec4, using 1.0 as the w component + vec4 positionVec4 = vec4(aPosition, 1.0); + positionVec4.xy = positionVec4.xy * 2.0 - 1.0; + + // send the vertex information on to the fragment shader + gl_Position = positionVec4; +} diff --git a/dist/assets/examples/en/00_Structure/00_Statements_and_Comments.js b/dist/assets/examples/en/00_Structure/00_Statements_and_Comments.js new file mode 100644 index 0000000000..8b8d81e5b1 --- /dev/null +++ b/dist/assets/examples/en/00_Structure/00_Statements_and_Comments.js @@ -0,0 +1,20 @@ +/* + * @name Comments and Statements + * @arialabel Mustard yellow background + * @description Statements are the elements that make up programs. The ";" (semi-colon) symbol is used to end statements. It is called the "statement terminator". Comments are used for making notes to help people better understand programs. A comment begins with two forward slashes ("//"). (ported from https://processing.org/examples/statementscomments.html) + */ +// The createCanvas function is a statement that tells the computer +// how large to make the window. +// Each function statement has zero or more parameters. +// Parameters are data passed into the function +// and are used as values for telling the computer what to do. +function setup() { + createCanvas(710, 400); +} + +// The background function is a statement that tells the computer +// which color (or gray value) to make the background of the display window +function draw() { + background(204, 153, 0); +} + diff --git a/dist/assets/examples/en/00_Structure/01_Coordinates.js b/dist/assets/examples/en/00_Structure/01_Coordinates.js new file mode 100644 index 0000000000..76e304461d --- /dev/null +++ b/dist/assets/examples/en/00_Structure/01_Coordinates.js @@ -0,0 +1,40 @@ +/* + * @name 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 + * @description 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]. + */ +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/dist/assets/examples/en/00_Structure/02_Width_and_Height.js b/dist/assets/examples/en/00_Structure/02_Width_and_Height.js new file mode 100644 index 0000000000..a80a682a4b --- /dev/null +++ b/dist/assets/examples/en/00_Structure/02_Width_and_Height.js @@ -0,0 +1,21 @@ +/* + * @name 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 + * @description The 'width' and 'height' variables contain the + * width and height of the display window as defined in the createCanvas() + * function. + */ +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/dist/assets/examples/en/00_Structure/03_Setup_and_Draw.js b/dist/assets/examples/en/00_Structure/03_Setup_and_Draw.js new file mode 100644 index 0000000000..ec48063635 --- /dev/null +++ b/dist/assets/examples/en/00_Structure/03_Setup_and_Draw.js @@ -0,0 +1,28 @@ +/* + * @name Setup and Draw + * @arialabel Animated horizontal white line on a black background that moves from the bottom to the top of the screen + * @description The code inside the draw() function runs continuously from top + * to bottom until the program is stopped. + */ +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/dist/assets/examples/en/00_Structure/04_No_Loop.js b/dist/assets/examples/en/00_Structure/04_No_Loop.js new file mode 100644 index 0000000000..48e0095d7e --- /dev/null +++ b/dist/assets/examples/en/00_Structure/04_No_Loop.js @@ -0,0 +1,31 @@ +/* + * @name No Loop + * @arialabel Horizontal white line across the middle of a black background + * @description The noLoop() function causes draw() to only execute once. + * Without calling noLoop(), the code inside draw() is run continually. + */ +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/dist/assets/examples/en/00_Structure/05_Loop.js b/dist/assets/examples/en/00_Structure/05_Loop.js new file mode 100644 index 0000000000..a624d8520f --- /dev/null +++ b/dist/assets/examples/en/00_Structure/05_Loop.js @@ -0,0 +1,27 @@ +/* + * @name 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 + * @description The code inside the draw() function runs continuously from top + * to bottom until the program is stopped. + */ +let y = 100; + +// 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); +} +// 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/dist/assets/examples/en/00_Structure/06_Redraw.js b/dist/assets/examples/en/00_Structure/06_Redraw.js new file mode 100644 index 0000000000..6a05360b92 --- /dev/null +++ b/dist/assets/examples/en/00_Structure/06_Redraw.js @@ -0,0 +1,34 @@ +/* + * @name Redraw + * @arialabel Horizontal white line across a black background that moves higher on the screen with each mouse click + * @description The redraw() function makes draw() execute once. In this example, + * draw() is executed once every time the mouse is clicked. + */ + +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/dist/assets/examples/en/00_Structure/07_Functions.js b/dist/assets/examples/en/00_Structure/07_Functions.js new file mode 100644 index 0000000000..648915c01d --- /dev/null +++ b/dist/assets/examples/en/00_Structure/07_Functions.js @@ -0,0 +1,29 @@ +/* + *@name 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. + *@description 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. + */ + +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/dist/assets/examples/en/00_Structure/08_Recursion.js b/dist/assets/examples/en/00_Structure/08_Recursion.js new file mode 100644 index 0000000000..4f0b211912 --- /dev/null +++ b/dist/assets/examples/en/00_Structure/08_Recursion.js @@ -0,0 +1,36 @@ +/* + *@name 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. + *@description 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. + */ + +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/dist/assets/examples/en/00_Structure/09_Create_Graphics.js b/dist/assets/examples/en/00_Structure/09_Create_Graphics.js new file mode 100644 index 0000000000..a786f0c06c --- /dev/null +++ b/dist/assets/examples/en/00_Structure/09_Create_Graphics.js @@ -0,0 +1,30 @@ +/* + * @name 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. + * @description 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. + */ + +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/dist/assets/examples/en/01_Form/00_Points_and_Lines.js b/dist/assets/examples/en/01_Form/00_Points_and_Lines.js new file mode 100644 index 0000000000..4aeb06e69f --- /dev/null +++ b/dist/assets/examples/en/01_Form/00_Points_and_Lines.js @@ -0,0 +1,37 @@ +/* + * @name Points and Lines + * @arialabel White outline of a square on a black background + * @description 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'. + */ +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/dist/assets/examples/en/01_Form/01_Shape_Primitives.js b/dist/assets/examples/en/01_Form/01_Shape_Primitives.js new file mode 100644 index 0000000000..b7726f42ca --- /dev/null +++ b/dist/assets/examples/en/01_Form/01_Shape_Primitives.js @@ -0,0 +1,32 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/01_Form/02_Pie_Chart.js b/dist/assets/examples/en/01_Form/02_Pie_Chart.js new file mode 100644 index 0000000000..b95d3b6b43 --- /dev/null +++ b/dist/assets/examples/en/01_Form/02_Pie_Chart.js @@ -0,0 +1,35 @@ +/* + * @name Pie Chart + * @arialabel Pie chart on a grey background with the different slices of the pie chart in various shades of grey + * @description Uses the arc() function to generate a pie chart from the data + * stored in an array. + */ +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/dist/assets/examples/en/01_Form/03_Regular_Polygon.js b/dist/assets/examples/en/01_Form/03_Regular_Polygon.js new file mode 100644 index 0000000000..d84740c2fd --- /dev/null +++ b/dist/assets/examples/en/01_Form/03_Regular_Polygon.js @@ -0,0 +1,44 @@ +/* + * @name Regular Polygon + * @arialabel Three white shapes with black outlines on a grey background rotating. From left to right, a triangle, icosagon, and a heptagon + * @description 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. + */ +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/dist/assets/examples/en/01_Form/04_Star.js b/dist/assets/examples/en/01_Form/04_Star.js new file mode 100644 index 0000000000..e8dbb998c2 --- /dev/null +++ b/dist/assets/examples/en/01_Form/04_Star.js @@ -0,0 +1,47 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/01_Form/05_Triangle_Strip.js b/dist/assets/examples/en/01_Form/05_Triangle_Strip.js new file mode 100644 index 0000000000..be5a1d2807 --- /dev/null +++ b/dist/assets/examples/en/01_Form/05_Triangle_Strip.js @@ -0,0 +1,39 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/01_Form/06_Bezier.js b/dist/assets/examples/en/01_Form/06_Bezier.js new file mode 100644 index 0000000000..cef3778da3 --- /dev/null +++ b/dist/assets/examples/en/01_Form/06_Bezier.js @@ -0,0 +1,29 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/01_Form/07_3D_Primitives.js b/dist/assets/examples/en/01_Form/07_3D_Primitives.js new file mode 100644 index 0000000000..89a93fc57f --- /dev/null +++ b/dist/assets/examples/en/01_Form/07_3D_Primitives.js @@ -0,0 +1,31 @@ +/* + * @name 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 + * @frame 720,400 (optional) + * @description 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. + */ +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/dist/assets/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js b/dist/assets/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js new file mode 100644 index 0000000000..dcbf6dfd29 --- /dev/null +++ b/dist/assets/examples/en/01_Form/08_Trig_Wheels_and_Pie_Chart.js @@ -0,0 +1,89 @@ +/* + * @name Trig Wheels and Pie Chart + * @arialabel Two circles on a white background. One circle has slices of various colors. One circle is comprised of rectangles spiraled into a circle shape in a rainbow gradient + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create +a trig color wheel and a visualization of a population age data as a +pie chart.
+ Functions are +created for the canvas setup, trig color wheel, drawslice, and pie +chart. The size of the slices are determined as well as their color +range. The pie chart is separated by definitive color per value +whereas the trig color wheel has a fixed slice amount with a range +color fill. +*/ + +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/dist/assets/examples/en/02_Data/00_Variables.js b/dist/assets/examples/en/02_Data/00_Variables.js new file mode 100644 index 0000000000..95b750da04 --- /dev/null +++ b/dist/assets/examples/en/02_Data/00_Variables.js @@ -0,0 +1,38 @@ +/* + * @name Variables + * @arialabel Black background with three sets of grey lines that form rectangles. + * @description Variables are used for storing values. In this example, change + * the values of variables to affect the composition. + */ +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/dist/assets/examples/en/02_Data/01_True_and_False.js b/dist/assets/examples/en/02_Data/01_True_and_False.js new file mode 100644 index 0000000000..d86f218d15 --- /dev/null +++ b/dist/assets/examples/en/02_Data/01_True_and_False.js @@ -0,0 +1,32 @@ +/* + * @name True and False + * @arialabel Black background with vertical white lines on the left half and horizontal white lines on the right half + * @description 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. + */ +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/dist/assets/examples/en/02_Data/03_Variable_Scope.js b/dist/assets/examples/en/02_Data/03_Variable_Scope.js new file mode 100644 index 0000000000..a58724046a --- /dev/null +++ b/dist/assets/examples/en/02_Data/03_Variable_Scope.js @@ -0,0 +1,49 @@ +/* + * @name Variable Scope + * @arialabel Black background with vertical white lines condensed on the left side + * @description 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. + */ +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/dist/assets/examples/en/02_Data/04_Numbers.js b/dist/assets/examples/en/02_Data/04_Numbers.js new file mode 100644 index 0000000000..b786a524b5 --- /dev/null +++ b/dist/assets/examples/en/02_Data/04_Numbers.js @@ -0,0 +1,32 @@ +/* + * @name 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. + * @frame 720,400 + * @description 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. + */ +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/dist/assets/examples/en/03_Arrays/00_Array.js b/dist/assets/examples/en/03_Arrays/00_Array.js new file mode 100644 index 0000000000..0c245ea30f --- /dev/null +++ b/dist/assets/examples/en/03_Arrays/00_Array.js @@ -0,0 +1,45 @@ +/* + * @name Array + * @arialabel Vertical lines are graphed across a white background to visualize the values of a cosine curve + * @description 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. + */ +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/dist/assets/examples/en/03_Arrays/01_Array_2d.js b/dist/assets/examples/en/03_Arrays/01_Array_2d.js new file mode 100644 index 0000000000..82f04efe9a --- /dev/null +++ b/dist/assets/examples/en/03_Arrays/01_Array_2d.js @@ -0,0 +1,39 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/03_Arrays/02_Array_Objects.js b/dist/assets/examples/en/03_Arrays/02_Array_Objects.js new file mode 100644 index 0000000000..cae5bc765e --- /dev/null +++ b/dist/assets/examples/en/03_Arrays/02_Array_Objects.js @@ -0,0 +1,72 @@ +/* + * @name 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 + * @description Demonstrates the syntax for creating an array of custom objects. + */ + +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/dist/assets/examples/en/03_Arrays/03_Walk_Over_2dArray.js b/dist/assets/examples/en/03_Arrays/03_Walk_Over_2dArray.js new file mode 100644 index 0000000000..b8e6d5431d --- /dev/null +++ b/dist/assets/examples/en/03_Arrays/03_Walk_Over_2dArray.js @@ -0,0 +1,86 @@ +/* + * @name Walk Over 2dArray + * @arialabel 20 phrases in black text are arranged on a black background with 4 phrases in a row, 5 rows total + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to display 2D array contents on the canvas +using regular for and for-of loops in multiple different ways.
+ A function is created for the canvas, the 2D + array (Friend Array) is initialized and walked over using nested + loops in different ways. Variables x and y are used to place the + array item on the canvas in the form of 2D array. + The final nested loop is used to initialize 2D + array (Fish Array) with random Integers (fish ages). +*/ + + +//"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/dist/assets/examples/en/04_Control/00_Iteration.js b/dist/assets/examples/en/04_Control/00_Iteration.js new file mode 100644 index 0000000000..6d51a4c860 --- /dev/null +++ b/dist/assets/examples/en/04_Control/00_Iteration.js @@ -0,0 +1,42 @@ +/* + * @name 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 + * @description Iteration with a "for" structure to construct repetitive forms. + */ +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/dist/assets/examples/en/04_Control/01_Embedded_Iteration.js b/dist/assets/examples/en/04_Control/01_Embedded_Iteration.js new file mode 100644 index 0000000000..ff7b852a8e --- /dev/null +++ b/dist/assets/examples/en/04_Control/01_Embedded_Iteration.js @@ -0,0 +1,22 @@ +/* + * @name 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 + * @description Embedding "for" structures allows repetition in two dimensions. + */ +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/dist/assets/examples/en/04_Control/02_Conditionals_1.js b/dist/assets/examples/en/04_Control/02_Conditionals_1.js new file mode 100644 index 0000000000..e3b6b582f1 --- /dev/null +++ b/dist/assets/examples/en/04_Control/02_Conditionals_1.js @@ -0,0 +1,27 @@ +/* + * @name Conditionals 1 + * @arialabel Pattern of alternating long and short lines + * @description 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. + */ +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/dist/assets/examples/en/04_Control/03_Conditionals_2.js b/dist/assets/examples/en/04_Control/03_Conditionals_2.js new file mode 100644 index 0000000000..a84c2ba04a --- /dev/null +++ b/dist/assets/examples/en/04_Control/03_Conditionals_2.js @@ -0,0 +1,29 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/04_Control/04_Logical_Operators.js b/dist/assets/examples/en/04_Control/04_Logical_Operators.js new file mode 100644 index 0000000000..7cc4decc76 --- /dev/null +++ b/dist/assets/examples/en/04_Control/04_Logical_Operators.js @@ -0,0 +1,43 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/04_Control/05_Logical_Operators_2.js b/dist/assets/examples/en/04_Control/05_Logical_Operators_2.js new file mode 100644 index 0000000000..17b32a83a6 --- /dev/null +++ b/dist/assets/examples/en/04_Control/05_Logical_Operators_2.js @@ -0,0 +1,92 @@ +/* + * @name Logical Operators 2 + * @arialabel Squares travel diagonally across the screen when a rectangle on the screen is pressed + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to create Xboxes with one global variable and create conditions with + boolean variables and boolean expressions by utilizing Boolean + operators ||, &&, and ! to do boundary checking.
+ Functions + are created for both the canvas set up as well as the creation of + the boxes. Background color is dependent on the location of the + boxes in the canvas space. When mouse button and key are pressed + simultaneously, the “where” text and box color changes to cyan, + but if the mouse button is clicked alone then the animation will + start. When q or Q are pressed the text “Did you type q or Q?” + will change to blue, else it will be purple. If the mouse is placed + within the orange box containing the text, “withinRect” then the + shape will turn pink. + */ + + +//1 coordinate for everything :) +let where = 0; //control boxes' positions + +function setup() { + createCanvas(400, 400); +} + +function draw() { + //similar to slide 4 use of OR, || + //to set bg color of canvas + if ((where < 0) || (where > height)) { + background("beige"); + } else { + background("chocolate"); + } + + //similar to slide 4 use of AND, && + //to set fill color of box & text + if (mouseIsPressed && keyIsPressed) { + fill("cyan"); + } else { + fill(255); + } + + //boxL + rect(where, where, 40); + + //boxR, pad x coordinate for size of box + rect(width - where - 40, where, 40); + + //Move the boxes + where = where + 1; + + //Show the value of where the boxes are + text("where is " + where, 150, 30); + + //testing not, ! and or, || operators + if (!(key === "q" || key === "Q")) { + fill("purple"); + } else { + fill("dodgerBlue"); + } + //Show the current key value + text("Did you type a q or Q? " + key, 150, 70); + + //*** Boundary checking *** + //Is the mouse within rect boundary? + //left, right, top, bottom + let withinRect = (mouseX >= 150) && + (mouseX <= 150 + 100) && + (mouseY >= 300) && + (mouseY <= 300 + 40); + //fill color based on value of withinRect + if (withinRect) { + fill("pink"); + } else { + fill("orange"); + } + //draw the rect + rect(150, 300, 100, 40); + //show withinRect value as label on rect + fill(0); + text("withinRect " + withinRect, 160, 320); +} + +//boxes restart +function mousePressed() { + //Reset boxes back up and above the canvas + where = -50; +} \ No newline at end of file diff --git a/dist/assets/examples/en/04_Control/06_Conditional_Shapes.js b/dist/assets/examples/en/04_Control/06_Conditional_Shapes.js new file mode 100644 index 0000000000..f3562640ee --- /dev/null +++ b/dist/assets/examples/en/04_Control/06_Conditional_Shapes.js @@ -0,0 +1,49 @@ +/* + * @name Conditional Shapes + * @arialabel The middle of the window is white and the user’s mouse draws red dots within it. The side edges of the window are beige and as the user’s mouse travels up and down the edges, orange squares with a red border are drawn up and down the center of the window + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to draw different shapes mid canvas depending on the mouse position.
+ Functions + are created for the main canvas set up with the markers on the left and + right hand sides. One is also created for the location of the mouse + regarding the canvas and the markers. If the mouse is within the + outer left hand beige rectangle, then the shape of circle is drawn + down the center of the canvas. If the mouse is within the outer right + hand beige rectangle, then the shape of square is drawn down the + center of the canvas. +*/ +function setup() { + createCanvas(400, 400); + strokeWeight(3); + //center squares to match circles + rectMode(CENTER); + + //draw rects to mark far sides + noStroke(); + fill("beige"); + rect(5, height / 2, 10, height); + rect(width - 5, height / 2, 10, height); + fill("orange"); + stroke("brown"); + + } + + function draw() { + point(mouseX, mouseY); + + //if (test) {doThis; } + //test: mouseX on far left of canvas + //doThis: draw a circle at mouseY + if (mouseX < 10) { + circle(width / 2, mouseY, 20); + } + + //test: mouseX on far right of canvas + //doThis: draw a square at mouseY + if (mouseX > width - 10) { + square(width / 2, mouseY, 20); + } + + } diff --git a/dist/assets/examples/en/05_Image/00_Load_and_Display_Image.js b/dist/assets/examples/en/05_Image/00_Load_and_Display_Image.js new file mode 100644 index 0000000000..2d4c70b8a8 --- /dev/null +++ b/dist/assets/examples/en/05_Image/00_Load_and_Display_Image.js @@ -0,0 +1,23 @@ +/* + * @name Load and Display Image + * @arialabel An astronaut on a planet with the same image in a smaller size in the bottom left quarter + * @description 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.

+ + */ +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/dist/assets/examples/en/05_Image/01_Background_Image.js b/dist/assets/examples/en/05_Image/01_Background_Image.js new file mode 100644 index 0000000000..32a6af747c --- /dev/null +++ b/dist/assets/examples/en/05_Image/01_Background_Image.js @@ -0,0 +1,32 @@ +/* + * @name Background Image + * @arialabel An astronaut on a planet with a horizontal yellow line traveling from the top to the bottom of the image + * @description 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.

+ */ +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/dist/assets/examples/en/05_Image/02_Transparency.js b/dist/assets/examples/en/05_Image/02_Transparency.js new file mode 100644 index 0000000000..8a12536041 --- /dev/null +++ b/dist/assets/examples/en/05_Image/02_Transparency.js @@ -0,0 +1,26 @@ +/* + * @name 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 + * @description 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.

+ */ +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/dist/assets/examples/en/05_Image/03_Alpha_Mask.js b/dist/assets/examples/en/05_Image/03_Alpha_Mask.js new file mode 100644 index 0000000000..477fc3bf89 --- /dev/null +++ b/dist/assets/examples/en/05_Image/03_Alpha_Mask.js @@ -0,0 +1,29 @@ +/* + * @name 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 horizontal direction of the user’s mouse. Both have a light blue gradient on the right side. + * @description 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.

+ */ +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/dist/assets/examples/en/05_Image/04_Create_Image.js b/dist/assets/examples/en/05_Image/04_Create_Image.js new file mode 100644 index 0000000000..cd2e0b9ec0 --- /dev/null +++ b/dist/assets/examples/en/05_Image/04_Create_Image.js @@ -0,0 +1,26 @@ +/* + * @name 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 + * @description The createImage() function provides a fresh buffer of pixels to + * play with. This example creates an image gradient. + */ +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/dist/assets/examples/en/05_Image/05_Pointillism.js b/dist/assets/examples/en/05_Image/05_Pointillism.js new file mode 100644 index 0000000000..22c60611c0 --- /dev/null +++ b/dist/assets/examples/en/05_Image/05_Pointillism.js @@ -0,0 +1,35 @@ +/* + * @name 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 + * @description 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.

+ */ +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/dist/assets/examples/en/05_Image/06_Blur.js b/dist/assets/examples/en/05_Image/06_Blur.js new file mode 100644 index 0000000000..f2992b49ba --- /dev/null +++ b/dist/assets/examples/en/05_Image/06_Blur.js @@ -0,0 +1,90 @@ +/* + * @name 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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/en/05_Image/07_EdgeDetection.js b/dist/assets/examples/en/05_Image/07_EdgeDetection.js new file mode 100644 index 0000000000..5a8fb552ae --- /dev/null +++ b/dist/assets/examples/en/05_Image/07_EdgeDetection.js @@ -0,0 +1,94 @@ +/* + * @name 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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/en/05_Image/08_Brightness.js b/dist/assets/examples/en/05_Image/08_Brightness.js new file mode 100644 index 0000000000..c3f5e66f28 --- /dev/null +++ b/dist/assets/examples/en/05_Image/08_Brightness.js @@ -0,0 +1,64 @@ +/* + * @name 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 + */ +// 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(); +} \ No newline at end of file diff --git a/dist/assets/examples/en/05_Image/09_Convolution.js b/dist/assets/examples/en/05_Image/09_Convolution.js new file mode 100644 index 0000000000..4b9af4343d --- /dev/null +++ b/dist/assets/examples/en/05_Image/09_Convolution.js @@ -0,0 +1,92 @@ +/* + * @name Convolution + * @arialabel An astronaut on a planet. As the user’s mouse moves, a square section increasing the sharpness of the image also moves + * @description 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.

+ */ + +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); +} \ No newline at end of file diff --git a/dist/assets/examples/en/05_Image/10_Copy_Method.js b/dist/assets/examples/en/05_Image/10_Copy_Method.js new file mode 100644 index 0000000000..eb9966e40e --- /dev/null +++ b/dist/assets/examples/en/05_Image/10_Copy_Method.js @@ -0,0 +1,21 @@ +/* + * @name 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 + * @frame 600,400 + * @description An example of how to simulate coloring image with the copy() method. + */ +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/dist/assets/examples/en/07_Color/00_Hue.js b/dist/assets/examples/en/07_Color/00_Hue.js new file mode 100644 index 0000000000..7ea8fc1cbc --- /dev/null +++ b/dist/assets/examples/en/07_Color/00_Hue.js @@ -0,0 +1,26 @@ +/* + * @name Hue + * @arialabel Vertical bars of color appear in a gradient pattern as the user drags their mouse across the screen + * @description Hue is the color reflected from or transmitted through an + * object and is typically referred to as the name of the color (red, blue, + * yellow, etc.) Move the cursor vertically over each bar to alter its hue. + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, height, height, height); + noStroke(); + background(0); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(mouseY, height, height); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/en/07_Color/01_Saturation.js b/dist/assets/examples/en/07_Color/01_Saturation.js new file mode 100644 index 0000000000..27ff14d3f8 --- /dev/null +++ b/dist/assets/examples/en/07_Color/01_Saturation.js @@ -0,0 +1,26 @@ +/* + * @name Saturation + * @arialabel Vertical bars of color appear in a gradient rainbow pattern as the user drags their mouse across the screen. The saturation of these bars change as the user’s mouse drags through + * @description 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. + * Move the cursor vertically over each bar to alter its saturation. + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, width, height, 100); + noStroke(); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(barX, mouseY, 66); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/en/07_Color/02_Brightness.js b/dist/assets/examples/en/07_Color/02_Brightness.js new file mode 100644 index 0000000000..e94eb2cd2e --- /dev/null +++ b/dist/assets/examples/en/07_Color/02_Brightness.js @@ -0,0 +1,47 @@ +/* + * @name Brightness + * @arialabel A black and white photograph of an astronaut on the moon covered by black. The mouse acts as a light and a circular area of the photograph is illuminated where the mouse hovers + * @description By Dan Shiffman. This program adjusts the brightness of a part + * of the image by calculating the distance of each pixel to the mouse. + *

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

+ */ +let img; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 200); + pixelDensity(1); + img.loadPixels(); + loadPixels(); +} + +function draw() { + 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]; + // Calculate an amount to change brightness based on proximity to the mouse + let maxdist = 50; + let d = dist(x, y, mouseX, mouseY); + let adjustbrightness = (255 * (maxdist - d)) / maxdist; + r += adjustbrightness; + // Constrain RGB to make sure they are within 0-255 color range + r = constrain(r, 0, 255); + // Make a new color and set pixel in the window + //color c = color(r, g, b); + let pixloc = (y * width + x) * 4; + pixels[pixloc] = r; + pixels[pixloc + 1] = r; + pixels[pixloc + 2] = r; + pixels[pixloc + 3] = 255; + } + } + updatePixels(); +} diff --git a/dist/assets/examples/en/07_Color/03_Color_Variables.js b/dist/assets/examples/en/07_Color/03_Color_Variables.js new file mode 100644 index 0000000000..5c211264dc --- /dev/null +++ b/dist/assets/examples/en/07_Color/03_Color_Variables.js @@ -0,0 +1,41 @@ +/* + * @name 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 + * @description (Homage to Albers.) This example creates variables for colors + * that may be referred to in the program by a name, rather than a number. + */ +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/dist/assets/examples/en/07_Color/04_Relativity.js b/dist/assets/examples/en/07_Color/04_Relativity.js new file mode 100644 index 0000000000..ebeaa83a33 --- /dev/null +++ b/dist/assets/examples/en/07_Color/04_Relativity.js @@ -0,0 +1,35 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/07_Color/05_Linear_Gradient.js b/dist/assets/examples/en/07_Color/05_Linear_Gradient.js new file mode 100644 index 0000000000..6e1b589d04 --- /dev/null +++ b/dist/assets/examples/en/07_Color/05_Linear_Gradient.js @@ -0,0 +1,53 @@ +/* + * @name 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 + * @description The lerpColor() function is useful for interpolating between + * two colors. + */ +// 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/dist/assets/examples/en/07_Color/06_Radial_Gradient.js b/dist/assets/examples/en/07_Color/06_Radial_Gradient.js new file mode 100644 index 0000000000..0882cb7ccb --- /dev/null +++ b/dist/assets/examples/en/07_Color/06_Radial_Gradient.js @@ -0,0 +1,34 @@ +/* + * @name 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 + * @description Draws a series of concentric circles to create a gradient + * from one color to another. + */ +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/dist/assets/examples/en/07_Color/07_Lerp_Color.js b/dist/assets/examples/en/07_Color/07_Lerp_Color.js new file mode 100644 index 0000000000..6bdf1d46eb --- /dev/null +++ b/dist/assets/examples/en/07_Color/07_Lerp_Color.js @@ -0,0 +1,50 @@ +/* + * @name Lerp Color + * @arialabel Four piles of triangles in random sizes: red, maroon, purple, and blue. The triangles move around within their pile to form different designs + * @description Loop random shapes, + * lerp color from red to blue. + */ +function setup() { + createCanvas(720, 400); + background(255); + noStroke(); +} + +function draw() { + background(255); + from = color(255, 0, 0, 0.2 * 255); + to = color(0, 0, 255, 0.2 * 255); + c1 = lerpColor(from, to, 0.33); + c2 = lerpColor(from, to, 0.66); + for (let i = 0; i < 15; i++) { + fill(from); + quad( + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height) + ); + fill(c1); + quad( + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height) + ); + fill(c2); + quad( + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height) + ); + fill(to); + quad( + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height) + ); + } + frameRate(5); +} diff --git a/dist/assets/examples/en/08_Math/00_incrementdecrement.js b/dist/assets/examples/en/08_Math/00_incrementdecrement.js new file mode 100644 index 0000000000..082922a048 --- /dev/null +++ b/dist/assets/examples/en/08_Math/00_incrementdecrement.js @@ -0,0 +1,43 @@ +/* + * @name 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 + * @description Writing "a++" is equivalent to "a = a + 1". + * Writing "a--" is equivalent to "a = a - 1". + */ +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/dist/assets/examples/en/08_Math/01_operatorprecedence.js b/dist/assets/examples/en/08_Math/01_operatorprecedence.js new file mode 100644 index 0000000000..c42516635f --- /dev/null +++ b/dist/assets/examples/en/08_Math/01_operatorprecedence.js @@ -0,0 +1,55 @@ +/* + * @name Operator Precedence + * @arialabel Grey background with two rectangles outlined in white on the left, and white vertical lines on the top and bottom + * @description 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. + */ +// 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/dist/assets/examples/en/08_Math/02_distance1d.js b/dist/assets/examples/en/08_Math/02_distance1d.js new file mode 100644 index 0000000000..0238a94c36 --- /dev/null +++ b/dist/assets/examples/en/08_Math/02_distance1d.js @@ -0,0 +1,66 @@ +/* + * @name 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 + * @description Move the mouse left and right to control + * the speed and direction of the moving shapes. + */ +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/dist/assets/examples/en/08_Math/03_distance2d.js b/dist/assets/examples/en/08_Math/03_distance2d.js new file mode 100644 index 0000000000..951edbd803 --- /dev/null +++ b/dist/assets/examples/en/08_Math/03_distance2d.js @@ -0,0 +1,26 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/08_Math/04_sine.js b/dist/assets/examples/en/08_Math/04_sine.js new file mode 100644 index 0000000000..3e8a4733d8 --- /dev/null +++ b/dist/assets/examples/en/08_Math/04_sine.js @@ -0,0 +1,28 @@ +/* + * @name Sine + * @arialabel Three yellow circles grow larger and smaller on a black background + * @description Smoothly scaling size with the sin() function. + */ +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/dist/assets/examples/en/08_Math/05_sincosine.js b/dist/assets/examples/en/08_Math/05_sincosine.js new file mode 100644 index 0000000000..9577d762d8 --- /dev/null +++ b/dist/assets/examples/en/08_Math/05_sincosine.js @@ -0,0 +1,44 @@ +/* + * @name Sine Cosine + * @arialabel Two blue and two yellow circles move side to side on each side of a white square + * @description 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. + */ +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/dist/assets/examples/en/08_Math/06_sinewave.js b/dist/assets/examples/en/08_Math/06_sinewave.js new file mode 100644 index 0000000000..728c16284f --- /dev/null +++ b/dist/assets/examples/en/08_Math/06_sinewave.js @@ -0,0 +1,49 @@ +/* + * @name Sine Wave + * @arialabel White circles line up to form a sine wave that moves across the black screen + * @description Render a simple sine wave. + * Original by Daniel Shiffman. + */ + +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/dist/assets/examples/en/08_Math/07_additivewave.js b/dist/assets/examples/en/08_Math/07_additivewave.js new file mode 100644 index 0000000000..0ab818066e --- /dev/null +++ b/dist/assets/examples/en/08_Math/07_additivewave.js @@ -0,0 +1,71 @@ +/* + * @name Additive Wave + * @arialabel Slightly opaque white circles line up to form waves that moves ross the black screen + * @description Create a more complex wave by adding two waves together. + * Original by Daniel Shiffman + */ +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/dist/assets/examples/en/08_Math/08_polartocartesian.js b/dist/assets/examples/en/08_Math/08_polartocartesian.js new file mode 100644 index 0000000000..6c2dff4b81 --- /dev/null +++ b/dist/assets/examples/en/08_Math/08_polartocartesian.js @@ -0,0 +1,45 @@ +/* + * @name PolarToCartesian + * @arialabel Grey circle travels faster and faster in a circle path on a black background + * @description Convert a polar coordinate (r,θ) + * to cartesian (x,y): x = r cos(θ), y = r sin(θ) + * Original by Daniel Shiffman. + */ +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/dist/assets/examples/en/08_Math/09_arctangent.js b/dist/assets/examples/en/08_Math/09_arctangent.js new file mode 100644 index 0000000000..83a135efe9 --- /dev/null +++ b/dist/assets/examples/en/08_Math/09_arctangent.js @@ -0,0 +1,46 @@ +/* + * @name 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. + */ +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(); + }; +} diff --git a/dist/assets/examples/en/08_Math/10_Interpolate.js b/dist/assets/examples/en/08_Math/10_Interpolate.js new file mode 100644 index 0000000000..e6b1c5c55b --- /dev/null +++ b/dist/assets/examples/en/08_Math/10_Interpolate.js @@ -0,0 +1,35 @@ +/* + * @name Linear Interpolation + * @arialabel White circle follows the user’s mouse around the screen + * @frame 720, 400 + * @description 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.. + */ + +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/dist/assets/examples/en/08_Math/11_doubleRandom.js b/dist/assets/examples/en/08_Math/11_doubleRandom.js new file mode 100644 index 0000000000..946d268673 --- /dev/null +++ b/dist/assets/examples/en/08_Math/11_doubleRandom.js @@ -0,0 +1,25 @@ +/* + * @name 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 + * @frame 720,400 (optional) + * @description Using two random() calls and the point() + * function to create an irregular sawtooth line. + * Original by by Ira Greenberg. + */ +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/dist/assets/examples/en/08_Math/12_random.js b/dist/assets/examples/en/08_Math/12_random.js new file mode 100644 index 0000000000..0d150abf10 --- /dev/null +++ b/dist/assets/examples/en/08_Math/12_random.js @@ -0,0 +1,20 @@ +/* + * @name Random + * @arialabel Various shades of grey bars change patterns randomly every half a second + * @description Random numbers create the basis of this image. + * Each time the program is loaded the result is different. + */ +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/dist/assets/examples/en/08_Math/13_noise1D.js b/dist/assets/examples/en/08_Math/13_noise1D.js new file mode 100644 index 0000000000..12d20b9a6b --- /dev/null +++ b/dist/assets/examples/en/08_Math/13_noise1D.js @@ -0,0 +1,32 @@ +/* + * @name Noise1D + * @arialabel White circle travels side to side based on perlin noise + * @description Using 1D Perlin Noise to assign location. + */ +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/dist/assets/examples/en/08_Math/14_noisewave.js b/dist/assets/examples/en/08_Math/14_noisewave.js new file mode 100644 index 0000000000..b953310739 --- /dev/null +++ b/dist/assets/examples/en/08_Math/14_noisewave.js @@ -0,0 +1,43 @@ +/* + * @name Noise Wave + * @arialabel Wave shapes are generated by perlin noise + * @description Using Perlin Noise to generate a wave-like pattern. + * Original by Daniel Shiffman. + */ +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/dist/assets/examples/en/08_Math/15_Noise2D.js b/dist/assets/examples/en/08_Math/15_Noise2D.js new file mode 100644 index 0000000000..be75543d2b --- /dev/null +++ b/dist/assets/examples/en/08_Math/15_Noise2D.js @@ -0,0 +1,43 @@ +/* + * @name Noise2D + * @arialabel Two gradient, perlin noises, one on the left and one on the right + * @frame 710,400 (optional) + * @description Create a 2D noise with different parameters. + * + */ + +let noiseVal; +let noiseScale = 0.02; + +function setup() { + createCanvas(640, 360); +} + +function draw() { + background(0); + // Draw the left half of image + for (let y = 0; y < height - 30; y++) { + for (let x = 0; x < width / 2; x++) { + // noiseDetail of the pixels octave count and falloff value + noiseDetail(2, 0.2); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // Draw the right half of image + for (let y = 0; y < height - 30; y++) { + for (let x = width / 2; x < width; x++) { + // noiseDetail of the pixels octave count and falloff value + noiseDetail(5, 0.5); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + //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 1 octaves and 0.7 falloff', 330, 350); +} diff --git a/dist/assets/examples/en/08_Math/16_Noise3D.js b/dist/assets/examples/en/08_Math/16_Noise3D.js new file mode 100644 index 0000000000..82ccbe67ea --- /dev/null +++ b/dist/assets/examples/en/08_Math/16_Noise3D.js @@ -0,0 +1,49 @@ +/* + * @name Noise3D + * @arialabel Gradient noise + * @frame 710,400 (optional) + * @description Using 3D noise to create simple animated texture. + */ + +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/dist/assets/examples/en/08_Math/17_Randomchords.js b/dist/assets/examples/en/08_Math/17_Randomchords.js new file mode 100644 index 0000000000..94c3de0a1d --- /dev/null +++ b/dist/assets/examples/en/08_Math/17_Randomchords.js @@ -0,0 +1,36 @@ +/* + * @name Random Chords + * @arialabel Random lines are drawn from one side of a circle to the other until it looks like a shaded sphere + * @description 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 + */ + +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/dist/assets/examples/en/08_Math/18_randomGaussian.js b/dist/assets/examples/en/08_Math/18_randomGaussian.js new file mode 100644 index 0000000000..144450623c --- /dev/null +++ b/dist/assets/examples/en/08_Math/18_randomGaussian.js @@ -0,0 +1,27 @@ +/* + * @name Random Gaussian + * @arialabel Translucent white circles are drawn in a line left and right multiple times until they overlap to form a white streak + * @frame 720,400 + * @description This sketch draws ellipses with x and y locations tied to a gaussian distribution of random numbers. + * (ported from https://processing.org/examples/randomgaussian.html) + */ + + 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 + } + diff --git a/dist/assets/examples/en/08_Math/19_Map.js b/dist/assets/examples/en/08_Math/19_Map.js new file mode 100644 index 0000000000..feeed43c2a --- /dev/null +++ b/dist/assets/examples/en/08_Math/19_Map.js @@ -0,0 +1,23 @@ +/* + * @name 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 + * @description 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. + */ +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/dist/assets/examples/en/08_Math/20_Graphing2DEquations.js b/dist/assets/examples/en/08_Math/20_Graphing2DEquations.js new file mode 100644 index 0000000000..1e22963abd --- /dev/null +++ b/dist/assets/examples/en/08_Math/20_Graphing2DEquations.js @@ -0,0 +1,53 @@ +/** + * @name 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 + * @frame 710, 400 + * @description Graphics the following equation: sin(n cos(r) + 5θ) where n is a function of horizontal mouse location. Original by Daniel Shiffman + */ +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/dist/assets/examples/en/08_Math/21_parametricEquation.js b/dist/assets/examples/en/08_Math/21_parametricEquation.js new file mode 100644 index 0000000000..d52dbfdc0a --- /dev/null +++ b/dist/assets/examples/en/08_Math/21_parametricEquation.js @@ -0,0 +1,45 @@ +/* + * @name Parametric Equations + * @arialabel Black vertical lines travel in a spiral pattern in a 3D space + * @description 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. + */ + +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/dist/assets/examples/en/09_Simulate/00_Forces.js b/dist/assets/examples/en/09_Simulate/00_Forces.js new file mode 100644 index 0000000000..224dbdaf27 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/00_Forces.js @@ -0,0 +1,149 @@ +/* + * @name 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 + * @description Demonstration of multiple force acting on bodies + * (natureofcode.com) + */ +// Demonstration of multiple force acting on +// bodies (Mover class) +// Bodies experience gravity continuously +// Bodies experience fluid resistance when in "water" + +// Five 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/dist/assets/examples/en/09_Simulate/01_ParticleSystem.js b/dist/assets/examples/en/09_Simulate/01_ParticleSystem.js new file mode 100644 index 0000000000..6cfe27a74a --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/01_ParticleSystem.js @@ -0,0 +1,70 @@ +/* + * @name Particle System + * @arialabel Light grey circles flowing out from a point like a sparkler + * @description This is a basic Particle System + * (natureofcode.com) + */ +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/dist/assets/examples/en/09_Simulate/02_Flocking.js b/dist/assets/examples/en/09_Simulate/02_Flocking.js new file mode 100644 index 0000000000..832b1d60f4 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/02_Flocking.js @@ -0,0 +1,230 @@ +/* + * @name Flocking + * @arialabel Groups of little grey triangles moving across a darker grey background + * @description 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. + */ + + +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/dist/assets/examples/en/09_Simulate/03_WolframCA.js b/dist/assets/examples/en/09_Simulate/03_WolframCA.js new file mode 100644 index 0000000000..15f5030d4e --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/03_WolframCA.js @@ -0,0 +1,74 @@ +/* + * @name 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 + * @description Simple demonstration of a Wolfram 1-dimensional cellular automata + * (natureofcode.com) + */ + +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/dist/assets/examples/en/09_Simulate/04_GameOfLife.js b/dist/assets/examples/en/09_Simulate/04_GameOfLife.js new file mode 100644 index 0000000000..166a4a18c1 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/04_GameOfLife.js @@ -0,0 +1,95 @@ +/* + * @name Game of Life + * @arialabel Grid of white squares on a black background with some squares flickering between white and black to generate random patterns + * @description A basic implementation of John Conway's Game of Life CA + * (natureofcode.com) + */ + +let w; +let columns; +let rows; +let board; +let next; + +function setup() { + 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/dist/assets/examples/en/09_Simulate/05_MultipleParticleSystems.js b/dist/assets/examples/en/09_Simulate/05_MultipleParticleSystems.js new file mode 100644 index 0000000000..9a84cf67dd --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/05_MultipleParticleSystems.js @@ -0,0 +1,139 @@ +/* + * @name 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. + */ +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(); +} diff --git a/dist/assets/examples/en/09_Simulate/06_Spirograph.js b/dist/assets/examples/en/09_Simulate/06_Spirograph.js new file mode 100644 index 0000000000..4d503a631a --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/06_Spirograph.js @@ -0,0 +1,74 @@ + +/* + * @name Spirograph + * @arialabel 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 + */ +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 + * Example created by R. Luke DuBois.
+ * https://en.wikipedia.org/wiki/L-system + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/en/09_Simulate/08_Spring.js b/dist/assets/examples/en/09_Simulate/08_Spring.js new file mode 100644 index 0000000000..e3d363a32a --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/08_Spring.js @@ -0,0 +1,93 @@ +/* + * @name 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. + * @frame 710, 400 + * @description Click, drag, and release the horizontal bar to start the spring. + */ +// 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/dist/assets/examples/en/09_Simulate/09_Springs.js b/dist/assets/examples/en/09_Simulate/09_Springs.js new file mode 100644 index 0000000000..17bb191922 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/09_Springs.js @@ -0,0 +1,148 @@ +/* + * @name 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 + * @frame 710,400 + * @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. + * (ported from https://processing.org/examples/springs.html) + */ +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; + } +}; \ No newline at end of file diff --git a/dist/assets/examples/en/09_Simulate/10_SoftBody.js b/dist/assets/examples/en/09_Simulate/10_SoftBody.js new file mode 100644 index 0000000000..32a9d665e3 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/10_SoftBody.js @@ -0,0 +1,111 @@ +/* + * @name 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(). + */ +// 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]; + } +} diff --git a/dist/assets/examples/en/09_Simulate/11_SmokeParticleSystem.js b/dist/assets/examples/en/09_Simulate/11_SmokeParticleSystem.js new file mode 100644 index 0000000000..e298313b34 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/11_SmokeParticleSystem.js @@ -0,0 +1,181 @@ +/* + * @name SmokeParticles + * @arialabel White circle gives off smoke on the middle of the bottom of the screen. The smoke blows in the direction of the user’s mouse as it moves side to side. There is a white arrow on the top that also points to the side where the user’s mouse is + * @description a port of Dan Shiffman's SmokeParticleSystem example originally + * for Processing. Creates smokey particles :p + */ + +// 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/dist/assets/examples/en/09_Simulate/12_BrownianMotion.js b/dist/assets/examples/en/09_Simulate/12_BrownianMotion.js new file mode 100644 index 0000000000..a9e0404a80 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/12_BrownianMotion.js @@ -0,0 +1,47 @@ +/* + * @name Brownian Motion + * @arialabel A continuous white line draws squiggles on a grey background + * @description Recording random movement as a continuous line. + * Port of original example from the Processing examples page. + */ + +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/dist/assets/examples/en/09_Simulate/13_Chain.js b/dist/assets/examples/en/09_Simulate/13_Chain.js new file mode 100644 index 0000000000..15988d2478 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/13_Chain.js @@ -0,0 +1,56 @@ +/* + * @name 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. + * Ported from the Processing Examples page. + */ +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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/en/09_Simulate/14_SnowflakeParticleSystem.js b/dist/assets/examples/en/09_Simulate/14_SnowflakeParticleSystem.js new file mode 100644 index 0000000000..ac3fc46f9a --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/14_SnowflakeParticleSystem.js @@ -0,0 +1,64 @@ +/* + * @name Snowflakes + * @arialabel White snowflakes fall in a random pattern from the top of a red background + * @description Particle system simulating the motion of falling snowflakes. + * Uses an array of objects to hold the snowflake particles. + * Contributed by Aatish Bhatia. + */ + +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/dist/assets/examples/en/09_Simulate/15_penrose_tiles.js b/dist/assets/examples/en/09_Simulate/15_penrose_tiles.js new file mode 100644 index 0000000000..c5b5cd0f3f --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/15_penrose_tiles.js @@ -0,0 +1,126 @@ +/* + * @name Penrose Tiles + * @arialabel A penrose tile pattern is created by white rhombi being drawn on a black background + * @frame 710,400 + * @description This is a port by David Blitz of the "Penrose Tile" example from processing.org/examples + */ + +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; iRecursive Tree Example for Processing. + */ +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/dist/assets/examples/en/09_Simulate/17_Mandelbrot.js b/dist/assets/examples/en/09_Simulate/17_Mandelbrot.js new file mode 100644 index 0000000000..dc7ae43320 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/17_Mandelbrot.js @@ -0,0 +1,87 @@ +/* + * @name 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 + * @description Simple rendering of the Mandelbrot set. + * Based on Daniel Shiffman's Mandelbrot Example for Processing. + */ + +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/dist/assets/examples/en/09_Simulate/18_Koch.js b/dist/assets/examples/en/09_Simulate/18_Koch.js new file mode 100644 index 0000000000..4d5c2ec3d1 --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/18_Koch.js @@ -0,0 +1,142 @@ +/* + * @name 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 + * @description Renders a simple fractal, the Koch snowflake. Each recursive level is drawn in sequence. + * By Daniel Shiffman + */ + +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/dist/assets/examples/en/09_Simulate/19_Bubblesort.js b/dist/assets/examples/en/09_Simulate/19_Bubblesort.js new file mode 100644 index 0000000000..89e1079ede --- /dev/null +++ b/dist/assets/examples/en/09_Simulate/19_Bubblesort.js @@ -0,0 +1,68 @@ +/* + * @name Bubble Sort + * @arialabel 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 + * @description 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. + */ + +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= 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); + +// +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 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
+ * 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
+ */ + +// 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)); +} \ No newline at end of file diff --git a/dist/assets/examples/en/10_Interaction/10_Tickle.js b/dist/assets/examples/en/10_Interaction/10_Tickle.js new file mode 100644 index 0000000000..a47d2bc4a0 --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/10_Tickle.js @@ -0,0 +1,49 @@ +/* + * @name 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 + * @description The word "tickle" jitters when the cursor hovers over. + * Sometimes, it can be tickled off the screen. + */ +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/dist/assets/examples/en/10_Interaction/11_WeightLine.js b/dist/assets/examples/en/10_Interaction/11_WeightLine.js new file mode 100644 index 0000000000..eb39963d8c --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/11_WeightLine.js @@ -0,0 +1,56 @@ +/* + * @name Weight Line + * @arialabel Light yellow background and the user’s mouse draws lines of various shades and thicknesses as it hovers over the background + * @frame 710,400 + * @description contributed by + Prof WM Harris, using the random function with events to color/weight a line
+ How to use the random function with events to color/ weight a line + dependent on mouse location, left mouse button clicks, character key types, and + random key releases.
+ Functions are created for both the canvas set up as well as the creation of + the line. Depending on the action taken by the user the line can + vary in width and color. Left mouse button clicks result in a color + change to blue, while the typing of any character key will change + the color to turquoise, each resulting in a variable stroke weight; + the width of the former will be between 0 – 1 while the width of + the latter will be 0 – 5. The release of any key will result in a + random hue, saturation, and brightness change to the line. + */ + + +function setup() { + createCanvas(400, 400); + background("beige"); + colorMode(HSB); + } + + function draw() { + //Line from prev pt to current pt + //of mouse position + line(mouseX, mouseY, pmouseX, pmouseY); + } + + //listen when we click the mouse + function mouseClicked() { + //weights 0 to 1 + stroke("slateBlue"); + strokeWeight(random()); + + //what if want weights 0 to .4? + //strokeWeight( random(.4) ); + } + + //listen when we release *any* key + function keyReleased() { + //color hue values between 20 and 145 + //saturation 0 to 100 + //brightness 80 to 100 + stroke(random(20, 145), random(100), random(80, 100)); + } + + //listen for only character keys + function keyTyped() { + //weights 0 to 5 + stroke("turquoise"); + strokeWeight(random(5)); + } \ No newline at end of file diff --git a/dist/assets/examples/en/10_Interaction/20_Follow1.js b/dist/assets/examples/en/10_Interaction/20_Follow1.js new file mode 100644 index 0000000000..ebce244abc --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/20_Follow1.js @@ -0,0 +1,38 @@ +/* + * @name 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. + * @frame 710,400 + * @description A line segment is pushed and pulled by the cursor. + * Based on code from Keith Peters. + */ +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/dist/assets/examples/en/10_Interaction/21_Follow2.js b/dist/assets/examples/en/10_Interaction/21_Follow2.js new file mode 100644 index 0000000000..6a25565488 --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/21_Follow2.js @@ -0,0 +1,40 @@ +/* + * @name 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 + * @frame 710,400 + * @description 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. + */ +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/dist/assets/examples/en/10_Interaction/22_Follow3.js b/dist/assets/examples/en/10_Interaction/22_Follow3.js new file mode 100644 index 0000000000..0057e748e6 --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/22_Follow3.js @@ -0,0 +1,48 @@ +/* + * @name Follow 3 + * @arialabel Long segmented snake shape follows the user’s mouse as it moves + * @frame 710,400 + * @description 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. + */ +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/dist/assets/examples/en/10_Interaction/23_snake.js b/dist/assets/examples/en/10_Interaction/23_snake.js new file mode 100644 index 0000000000..6a213d5eef --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/23_snake.js @@ -0,0 +1,173 @@ +/* + * @name Snake game + * @arialabel Snake game where a snake represented by a long white oval on a black background is controlled by the i,j,k,l keys. Users use these keys to move the snake to not hit the sides of the window and to eat a small white circle which represents food and allows the snake to grow. + * @description The famous snake game! Once you click run, click anywhere + * inside the black area, and control the snake using i j k and l. Don't let + * the snake hit itself or the wall!
+ * Example created by Prashant Gupta + */ + +// 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/dist/assets/examples/en/10_Interaction/24_Wavemaker.js b/dist/assets/examples/en/10_Interaction/24_Wavemaker.js new file mode 100644 index 0000000000..50d3d2061e --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/24_Wavemaker.js @@ -0,0 +1,38 @@ +/* + * @name 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 + * @description 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. + */ + +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/dist/assets/examples/en/10_Interaction/25_reach1.js b/dist/assets/examples/en/10_Interaction/25_reach1.js new file mode 100644 index 0000000000..36a039008b --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/25_reach1.js @@ -0,0 +1,58 @@ +/* + * @name 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. + * @frame 710,400 + * @description The arm follows the position of the mouse by calculating the + * angles with atan2(). Based on code from Keith Peters. + */ +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/dist/assets/examples/en/10_Interaction/26_reach2.js b/dist/assets/examples/en/10_Interaction/26_reach2.js new file mode 100644 index 0000000000..4143ef5c97 --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/26_reach2.js @@ -0,0 +1,66 @@ +/* + * @name 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 + * @frame 710,400 + * @description The arm follows the position of the mouse by calculating the + * angles with atan2(). Based on code from Keith Peters. + */ +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/dist/assets/examples/en/10_Interaction/27_reach3.js b/dist/assets/examples/en/10_Interaction/27_reach3.js new file mode 100644 index 0000000000..133b1479b9 --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/27_reach3.js @@ -0,0 +1,82 @@ +/* + * @name 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 + * @frame 710,400 + * @description The arm follows the position of the ball by calculating the + * angles with atan2(). Based on code from Keith Peters. + */ +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/dist/assets/examples/en/10_Interaction/28_ArduinoSensor.js b/dist/assets/examples/en/10_Interaction/28_ArduinoSensor.js new file mode 100644 index 0000000000..09cd07dfde --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/28_ArduinoSensor.js @@ -0,0 +1,37 @@ +/* + * @name Arduino sensor data via WebJack + * @description 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: + *
<script src="https://webjack.io/dist/webjack.js"></script>
+ *
<script src="https://jywarren.github.io/p5-webjack/lib.js"></script>
+ * + * 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. + */ + +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/dist/assets/examples/en/10_Interaction/29_kaleidoscope.js b/dist/assets/examples/en/10_Interaction/29_kaleidoscope.js new file mode 100644 index 0000000000..8eec6dcdc6 --- /dev/null +++ b/dist/assets/examples/en/10_Interaction/29_kaleidoscope.js @@ -0,0 +1,73 @@ +/* + * @name Kaleidoscope + * @arialabel User draws thick black lines on the grey background and it is mirrored 5 times in a circle like a kaleidoscope + * @description 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. Adjust the brush size with the help of the slider. The clear screen as it says clears the screen. The save button will download a .jpg file of the art that you have created. + */ +// 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/dist/assets/examples/en/11_Objects/01_Objects.js b/dist/assets/examples/en/11_Objects/01_Objects.js new file mode 100644 index 0000000000..d299c1ab88 --- /dev/null +++ b/dist/assets/examples/en/11_Objects/01_Objects.js @@ -0,0 +1,40 @@ +/* + * @name 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 + * @description 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. + */ + +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/dist/assets/examples/en/11_Objects/02_Multiple_Objects.js b/dist/assets/examples/en/11_Objects/02_Multiple_Objects.js new file mode 100644 index 0000000000..734a6aae3f --- /dev/null +++ b/dist/assets/examples/en/11_Objects/02_Multiple_Objects.js @@ -0,0 +1,51 @@ +/* + * @name 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 + * @description Create a Jitter class, instantiate multiple objects, + * and move it around the screen. + */ + +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/dist/assets/examples/en/11_Objects/03_Objects_Array.js b/dist/assets/examples/en/11_Objects/03_Objects_Array.js new file mode 100644 index 0000000000..c9a5dd335f --- /dev/null +++ b/dist/assets/examples/en/11_Objects/03_Objects_Array.js @@ -0,0 +1,43 @@ +/* + * @name 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 + * @description Create a Jitter class, instantiate an array of objects + * and move them around the screen. + */ + +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/dist/assets/examples/en/11_Objects/03_Objects_Optional_Arguments.js b/dist/assets/examples/en/11_Objects/03_Objects_Optional_Arguments.js new file mode 100644 index 0000000000..2adbd9a7b8 --- /dev/null +++ b/dist/assets/examples/en/11_Objects/03_Objects_Optional_Arguments.js @@ -0,0 +1,66 @@ +/* + * @name 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 + * @description 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. + */ + +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/dist/assets/examples/en/11_Objects/04_Inheritance.js b/dist/assets/examples/en/11_Objects/04_Inheritance.js new file mode 100644 index 0000000000..9e47eb9630 --- /dev/null +++ b/dist/assets/examples/en/11_Objects/04_Inheritance.js @@ -0,0 +1,71 @@ +/* @name Inheritance + * @arialabel Two white circles connected and spinning around each other anti-clockwise with a black line behind that is spinning clockwise + * @description A class can be defined using another class as a + * foundation. In object-oriented programming terminology, one class can + * inherit fields and methods from another. An object that inherits from + * another is called a subclass, and the object it inherits from is called + * a superclass. A subclass extends the superclass. + */ +let spots, arm; + +function setup() { +createCanvas(640, 360); +arm = new SpinArm(width/2, height/2, 0.01); +spots = new SpinSpots(width/2, height/2, -0.02, 90.0); +} + +function draw() { +background(204); +arm.update(); +arm.display(); +spots.update(); +spots.display(); +} + +class Spin { +constructor(x, y, s) { + this.x = x; + this.y = y; + this.speed = s; + this.angle = 0.0; +} + +update() { + this.angle += this.speed; +} +} + +class SpinArm extends Spin { +constructor(x, y, s) { + super(x, y, s) +} + +display() { + strokeWeight(1); + stroke(0); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + line(0, 0, 165, 0); + pop(); +} +} + +class SpinSpots extends Spin { +constructor(x, y, s, d) { + super(x, y, s) + this.dim = d; +} + +display() { + noStroke(); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + ellipse(-this.dim/2, 0, this.dim, this.dim); + ellipse(this.dim/2, 0, this.dim, this.dim); + pop(); +} +} diff --git a/dist/assets/examples/en/11_Objects/05_Composite_Objects.js b/dist/assets/examples/en/11_Objects/05_Composite_Objects.js new file mode 100644 index 0000000000..1fd5313ea9 --- /dev/null +++ b/dist/assets/examples/en/11_Objects/05_Composite_Objects.js @@ -0,0 +1,100 @@ +/* @name Composite Objects + * @arialabel Two white egg shapes that totter side to side. There is a grey circle within each egg that expands larger until it is off the screen + * @description An object can include several other objects. + * Creating such composite objects is a good way to use the principles + * of modularity and build higher levels of abstraction within a program. + */ +let er1, er2; + +function setup() { +createCanvas(640, 360); +er1 = new EggRing(width * 0.45, height * 0.5, 0.1, 120); +er2 = new EggRing(width * 0.65, height * 0.8, 0.05, 180); +} + +function draw() { +background(0); +er1.transmit(); +er2.transmit(); +} + +class Egg { +constructor(xpos, ypos, t, s) { + this.x = xpos; + this.y = ypos; + this.tilt = t; + this.scalar = s / 100.0; + this.angle = 0.0; +} + +wobble() { + this.tilt = cos(this.angle) / 8; + this.angle += 0.1; +} + +display() { + noStroke(); + fill(255); + push(); + translate(this.x, this.y); + rotate(this.tilt); + scale(this.scalar); + beginShape(); + vertex(0, -100); + bezierVertex(25, -100, 40, -65, 40, -40); + bezierVertex(40, -15, 25, 0, 0, 0); + bezierVertex(-25, 0, -40, -15, -40, -40); + bezierVertex(-40, -65, -25, -100, 0, -100); + endShape(); + pop(); +} +} + +class Ring { +start(xpos, ypos) { + this.x = xpos; + this.y = ypos; + this.on = true; + this.diameter = 1; +} + +grow() { + if (this.on == true) { + this.diameter += 0.5; + if (this.diameter > width * 2) { + this.diameter = 0.0; + } + } + } + +display() { + if (this.on == true) { + noFill(); + strokeWeight(4); + stroke(155, 153); + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} +} + +class EggRing { +constructor(x, y, t, sp) { + this.x = x; + this.y = y; + this.t = t; + this.sp = sp; + this.circle = new Ring(); + this.ovoid = new Egg(this.x, this.y, this.t, this.sp); + this.circle.start(this.x, this.y - this.sp/2); +} + +transmit() { + this.ovoid.wobble(); + this.ovoid.display(); + this.circle.grow(); + this.circle.display(); + if (circle.on == false) { + circle.on = true; + } +} +} diff --git a/dist/assets/examples/en/11_Objects/06_Car_Instances.js b/dist/assets/examples/en/11_Objects/06_Car_Instances.js new file mode 100644 index 0000000000..8e10eb089e --- /dev/null +++ b/dist/assets/examples/en/11_Objects/06_Car_Instances.js @@ -0,0 +1,83 @@ +/* + * @name Car Instances + * @arialabel Vertical pale sage background with three rectangles--blue, yellow, and grey--moving across the screen horizontally at different speeds + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create three instances of Car Class and +invoke class methods.
+ A function is created for the canvas setup, and +3 car instances are initialized with different colors and canvas +positions. The speed of each car is set by passing value to the +instance’s start method. A second function calls class methods to +display and move the cars. +*/ +class Car { + /* Constructor expects parameters for + fill color, x and y coordinates that + will be used to initialize class properties. + */ + constructor(cColor, x, y) { + this.color = cColor; + this.doors = 4; + this.isConvertible = false; + this.x = x; + this.y = y; + this.speed = 0; + } + + start(speed) { // method expects parameter! + this.speed = speed; + } + + display() { // method! + fill(this.color); + rect(this.x, this.y, 20, 10); + } + + move() { // method! + this.x += this.speed; + // Wrap x around boundaries + if (this.x < -20) { + this.x = width; + } else if (this.x > width) { + this.x = -20; + } + } +} //end class Car + +let rav4; +let charger; +let nova; + +function setup() { + createCanvas(200, 400); + /* Construct the 3 Cars */ + //constructor expects cColor, x, y + rav4 = new Car("silver", 100, 300); + charger = new Car("gold", 0, 200); + nova = new Car("blue", 200, 100); + nova.doors = 2; //update nova's doors property + + console.log("rav4", rav4); + console.log("charger", charger); + console.log("nova", nova); + + //call start methods of Car instances + //the start method expects a number for speed + rav4.start(2.3); + charger.start(-4); + nova.start(random(-1, 1)); +} + +function draw() { + background("beige"); + + //display and move all 3 Cars + rav4.display(); + charger.display(); + nova.display(); + + rav4.move(); + charger.move(); + nova.move(); +} diff --git a/dist/assets/examples/en/12_Lights/02_Directional.js b/dist/assets/examples/en/12_Lights/02_Directional.js new file mode 100644 index 0000000000..2b6a74bb7b --- /dev/null +++ b/dist/assets/examples/en/12_Lights/02_Directional.js @@ -0,0 +1,28 @@ +/* + * @name 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 + * @frame 710,400 + * @description 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. + */ +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/dist/assets/examples/en/12_Lights/05_Mixture.js b/dist/assets/examples/en/12_Lights/05_Mixture.js new file mode 100644 index 0000000000..70b3461a4f --- /dev/null +++ b/dist/assets/examples/en/12_Lights/05_Mixture.js @@ -0,0 +1,45 @@ +/* + * @name 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 + * @frame 710,400 (optional) + * @description Display a box with three different kinds of lights. + */ +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/dist/assets/examples/en/13_Motion/01_non_orthogonal_reflection.js b/dist/assets/examples/en/13_Motion/01_non_orthogonal_reflection.js new file mode 100644 index 0000000000..3f07f8e469 --- /dev/null +++ b/dist/assets/examples/en/13_Motion/01_non_orthogonal_reflection.js @@ -0,0 +1,111 @@ +/* + * @name 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 + * @frame 710,400 (optional) + * @description This is a port by David Blitz of the "Reflection 1" example from processing.org/examples + */ + +//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/dist/assets/examples/en/13_Motion/02_Linear_Motion.js b/dist/assets/examples/en/13_Motion/02_Linear_Motion.js new file mode 100644 index 0000000000..f76560d1de --- /dev/null +++ b/dist/assets/examples/en/13_Motion/02_Linear_Motion.js @@ -0,0 +1,25 @@ +/* + * @name Linear + * @arialabel Horizontal white line on a black background traveling from the bottom to the top of the screen parallel to the x axis + * @frame 720,400 + * @description 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. + */ + +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/dist/assets/examples/en/13_Motion/03_Bounce.js b/dist/assets/examples/en/13_Motion/03_Bounce.js new file mode 100644 index 0000000000..1267f8cfec --- /dev/null +++ b/dist/assets/examples/en/13_Motion/03_Bounce.js @@ -0,0 +1,45 @@ +/* + * @name Bounce + * @arialabel White circle moving on a grey background. When it hits the edge of the background window, it changes it’s direction + * @frame 720,400 + * @description When the shape hits the edge of the window, it reverses its direction. + */ + +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/dist/assets/examples/en/13_Motion/04_Bouncy_Bubbles.js b/dist/assets/examples/en/13_Motion/04_Bouncy_Bubbles.js new file mode 100644 index 0000000000..2dba410120 --- /dev/null +++ b/dist/assets/examples/en/13_Motion/04_Bouncy_Bubbles.js @@ -0,0 +1,96 @@ +/* + * @name 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 + * @frame 720,400 + * @description based on code from Keith Peters. Multiple-object collision.. + */ + +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/dist/assets/examples/en/13_Motion/05_Brownian.js b/dist/assets/examples/en/13_Motion/05_Brownian.js new file mode 100644 index 0000000000..0860f72479 --- /dev/null +++ b/dist/assets/examples/en/13_Motion/05_Brownian.js @@ -0,0 +1,53 @@ +/* + * @name Brownian Motion + * @arialabel A continuous white line draws squiggles on a grey background, forming a random pattern + * @description Recording random movement as a continuous line. + * (ported from https://processing.org/examples/brownian.html) + */ + +let num = 2000; +let range = 6; + +// global variable +let i; + +let ax = []; +let ay = []; + +function setup() +{ + createCanvas(640, 360); + for(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( 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( i=1; i -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/dist/assets/examples/en/13_Motion/07_Circle_Collision.js b/dist/assets/examples/en/13_Motion/07_Circle_Collision.js new file mode 100644 index 0000000000..3833e4210e --- /dev/null +++ b/dist/assets/examples/en/13_Motion/07_Circle_Collision.js @@ -0,0 +1,146 @@ +/* + * @name 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 + * @frame 710,400 (optional) + * @description This is a port of the "Circle Collision" example from processing.org/examples
This example uses vectors for better visualization of physical Quantity + */ +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]); + } +} diff --git a/dist/assets/examples/en/13_Motion/08_Moving_On_Curves.js b/dist/assets/examples/en/13_Motion/08_Moving_On_Curves.js new file mode 100644 index 0000000000..02c87c5c5f --- /dev/null +++ b/dist/assets/examples/en/13_Motion/08_Moving_On_Curves.js @@ -0,0 +1,48 @@ +/* + * @name 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 + * @frame 720,400 + * @description In this example, the circles moves along the curve y = x^4. + * Click the mouse to have it move to a new position. + */ + +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/dist/assets/examples/en/15_Instance_Mode/01_Instantiating.js b/dist/assets/examples/en/15_Instance_Mode/01_Instantiating.js new file mode 100644 index 0000000000..07163bdb99 --- /dev/null +++ b/dist/assets/examples/en/15_Instance_Mode/01_Instantiating.js @@ -0,0 +1,36 @@ +/* + * @name Instantiation + * @arialabel White square in the upper left quadrant on black background + * @description Create a p5 instance, which keeps all variables + * out of the global scope of your page. + */ +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/dist/assets/examples/en/15_Instance_Mode/02_Instance_Container.js b/dist/assets/examples/en/15_Instance_Mode/02_Instance_Container.js new file mode 100644 index 0000000000..9675fdeaaf --- /dev/null +++ b/dist/assets/examples/en/15_Instance_Mode/02_Instance_Container.js @@ -0,0 +1,94 @@ +/* + * @norender + * @name Instance Container + * @description Optionally, you can specify a default container for the canvas + * and any other elements to append to with a second argument. You can give the + * ID of an element in your html, or an html node itself. + * + * Here are three different options for selecting a container + * DOM element. All DOM elements (canvas, buttons, divs, etc) created by p5 + * will be attached to the DOM element specified as the second argument to the + * p5() call. + */ + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dist/assets/examples/en/16_Dom/03_Input_Button.js b/dist/assets/examples/en/16_Dom/03_Input_Button.js new file mode 100644 index 0000000000..f82a84d456 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/03_Input_Button.js @@ -0,0 +1,39 @@ +/* + * @name 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. + * @description Input text and click the button to see it affect the the canvas. + */ +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/dist/assets/examples/en/16_Dom/04_Slider.js b/dist/assets/examples/en/16_Dom/04_Slider.js new file mode 100644 index 0000000000..1628b88653 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/04_Slider.js @@ -0,0 +1,31 @@ +/* + * @name 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. + * @description Move the sliders to control the R, G, B values of the background. + */ +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/dist/assets/examples/en/16_Dom/07_Modify_DOM.js b/dist/assets/examples/en/16_Dom/07_Modify_DOM.js new file mode 100644 index 0000000000..40cd500b35 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/07_Modify_DOM.js @@ -0,0 +1,55 @@ +/* + * @name Modifying the DOM + * @arialabel Words in black font jittering on a white background + * @frame 710,300 + * @description Create DOM elements and modify their properties every time + * draw() is called. + */ +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/dist/assets/examples/en/16_Dom/08_Video.js b/dist/assets/examples/en/16_Dom/08_Video.js new file mode 100644 index 0000000000..2b39aeadc8 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/08_Video.js @@ -0,0 +1,30 @@ +/* + * @name Video + * @arialabel Video of fingers walking + * @frame 710,250 + * @description Load a video with multiple formats and toggle between playing + * and paused with a button press. + */ +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/dist/assets/examples/en/16_Dom/09_Video_Canvas.js b/dist/assets/examples/en/16_Dom/09_Video_Canvas.js new file mode 100644 index 0000000000..42f867fe31 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/09_Video_Canvas.js @@ -0,0 +1,28 @@ +/* + * @name Video Canvas + * @arialabel grey background with two identical videos playing. One in color and one in black and white. + * @description Load a video with multiple formats and draw it to the canvas. + * To run this example locally, you will need a running + * local server. + */ +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/dist/assets/examples/en/16_Dom/10_Video_Pixels.js b/dist/assets/examples/en/16_Dom/10_Video_Pixels.js new file mode 100644 index 0000000000..2d3b4681cb --- /dev/null +++ b/dist/assets/examples/en/16_Dom/10_Video_Pixels.js @@ -0,0 +1,33 @@ +/* + * @name 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 + * @frame 320,240 + * @description Load a video, manipulate its pixels and draw to canvas. + * To run this example locally, you will need a running + * local server. + */ +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/dist/assets/examples/en/16_Dom/11_Capture.js b/dist/assets/examples/en/16_Dom/11_Capture.js new file mode 100644 index 0000000000..8368132b19 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/11_Capture.js @@ -0,0 +1,23 @@ +/* + * @name Video Capture + * @arialabel Takes feed from the user’s computer camera and displays it in the window + * @frame 710,240 + * @description 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. + */ +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/dist/assets/examples/en/16_Dom/12_Drop.js b/dist/assets/examples/en/16_Dom/12_Drop.js new file mode 100644 index 0000000000..f2a515a333 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/12_Drop.js @@ -0,0 +1,34 @@ +/* + * @name Drop + * @arialabel Empty grey canvas that displays an image if it is dragged from the user’s computer to the grey canvas + * @description Drag an image file onto the canvas to see it displayed. + */ + +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/dist/assets/examples/en/16_Dom/13_DOM_Form_Elements.js b/dist/assets/examples/en/16_Dom/13_DOM_Form_Elements.js new file mode 100644 index 0000000000..a08ef5dc15 --- /dev/null +++ b/dist/assets/examples/en/16_Dom/13_DOM_Form_Elements.js @@ -0,0 +1,153 @@ +/* + * @name DOM Form Elements + * @arialabel Light yellow box with “checked” written with form elements such as checking boxes, sliders, and empty text input below + * @frame 600,400 + * @description contributed by + Prof WM Harris, How to use p5 DOM form elements to create a slider, +button, checkbox, radio group, select menu, and entry field.
+Functions are created that include: the canvas +setup, checkbox creation with text, text box with text that projects +typed text onto canvas, slider with button, three selections which +project a rectangle in different areas on the canvas depending on +selection, and a drop down menu with font change. +*/ + +/* global variables */ +//p5 DOM form elements +let slider1; +let button1; +let checkbox1; +let radio1; +let select1; +let entry1; + +function setup() { + createCanvas(200, 200); + background("beige"); + + checkbox1 = createCheckbox("Check me"); + + createP(); //spacer with

tag + + createSpan("What's your name? "); //label for entry1 + // createInput([value], [type]) + // type: "text" (default), "number", + // "date", "password", "email", etc. + entry1 = createInput(); + //If text in the entry field changes, call + //the entryCallback function. + entry1.changed(entryCallback); + + createP(); //spacer with

tag + + //createSlider(min, max, [value], [step]) + slider1 = createSlider(10, 200); + + button1 = createButton("Press me"); //, "pressed"); + //Assign callback fcn for button1 + //when user clicks mouse on it + button1.mouseClicked(button1Clicked); + + createP(); //spacer with

tag + + radio1 = createRadio(); + + //.option([value], [contentLabel]) + //If 1 param, it's both content AND + //value. Values treated as strings. + radio1.option(1, "cranberries"); + radio1.option(2, "almonds"); + radio1.option(3, "gouda"); + + radio1.value("1"); //set init value + + createP(); //spacer with

tag + + select1 = createSelect(); + //.option([contentValue],[value]) + //If 1 param, it's both content AND + //value. Values treated as strings. + select1.option("Sans-serif"); + select1.option("Serif"); + select1.option("Fantasy"); + //If changed, call select1Changed + select1.changed(select1Changed); +} + +function draw() { + //get value from slider 1 + let gray = slider1.value(); + fill(gray); + + //If mouse in corner, turn on checkbox1 + if ((mouseX < width / 3) && + (mouseY < height / 3)) { + checkbox1.checked(true); + } + //Is checkbox1 checked? Say so. + if (checkbox1.checked()) { + text("CHECKED", 20, 40); + } + + switch (radio1.value()) { + //radio value is always a string + case "1": + rect(0, 0, width, 50); + break; + case "2": + rect(0, 70, width, 50); + break; + case "3": + rect(0, 140, width, 50); + break; + } +} + +//callback fcn for button1 +function button1Clicked() { + //reset slider value to 200 + slider1.value(200); +} + + +//callback fcn for select1 +function select1Changed() { + switch (select1.value()) { + case "Sans-serif": + textFont("sans-serif"); + break; + case "Serif": + textFont("serif"); + break; + case "Fantasy": + textFont("fantasy"); + break; + } +} + +//callback function for entry1 +function entryCallback() { + for (let i = 0; i < 25; i++) { + text(entry1.value(), random(width), + random(height)); + } + +} + +function mouseClicked() { + console.log("button1?", button1.value()); + console.log("checkbox1?", checkbox1.value()); + //Update .value of either? No visible change + //to a button or checkbox + checkbox1.value("Check again"); + button1.value("clicked?"); +} + +function keyTyped() { + switch (key) { + case "r": + //move slider1 value to 100 + slider1.value(100); + break; + } +} \ No newline at end of file diff --git a/dist/assets/examples/en/17_Drawing/00_Continuous_Lines.js b/dist/assets/examples/en/17_Drawing/00_Continuous_Lines.js new file mode 100644 index 0000000000..564c8cab35 --- /dev/null +++ b/dist/assets/examples/en/17_Drawing/00_Continuous_Lines.js @@ -0,0 +1,16 @@ +/* + * @name Continuous Lines + * @arialabel Thin white line draws on a dark grey background as the user clicks and drags their mouse + * @description Click and drag the mouse to draw a line. + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + stroke(255); + if (mouseIsPressed === true) { + line(mouseX, mouseY, pmouseX, pmouseY); + } +} diff --git a/dist/assets/examples/en/17_Drawing/01_Pattern.js b/dist/assets/examples/en/17_Drawing/01_Pattern.js new file mode 100644 index 0000000000..5f32d33ae2 --- /dev/null +++ b/dist/assets/examples/en/17_Drawing/01_Pattern.js @@ -0,0 +1,28 @@ +/* + * @name 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 + * @description Move the cursor over the image to draw with a software tool + * which responds to the speed of the mouse. + */ +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/dist/assets/examples/en/17_Drawing/02_Pulses.js b/dist/assets/examples/en/17_Drawing/02_Pulses.js new file mode 100644 index 0000000000..2eec4a1736 --- /dev/null +++ b/dist/assets/examples/en/17_Drawing/02_Pulses.js @@ -0,0 +1,32 @@ +/* + * @name 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. + * @description 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. + */ +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/dist/assets/examples/en/18_Transform/00_Translate.js b/dist/assets/examples/en/18_Transform/00_Translate.js new file mode 100644 index 0000000000..dede423e77 --- /dev/null +++ b/dist/assets/examples/en/18_Transform/00_Translate.js @@ -0,0 +1,41 @@ +/* + * @name Translate + * @arialabel Two squares one white one black travel horizontally across a grey background. The black square moves faster than the white + * @description 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. + */ + +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/dist/assets/examples/en/18_Transform/01_Scale.js b/dist/assets/examples/en/18_Transform/01_Scale.js new file mode 100644 index 0000000000..2ddafda414 --- /dev/null +++ b/dist/assets/examples/en/18_Transform/01_Scale.js @@ -0,0 +1,47 @@ +/* + * @name Scale + * @arialabel Two squares one white and one black grow and shrink on a grey background + * @description 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. + */ + +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/dist/assets/examples/en/18_Transform/02_Rotate.js b/dist/assets/examples/en/18_Transform/02_Rotate.js new file mode 100644 index 0000000000..b6a465e67e --- /dev/null +++ b/dist/assets/examples/en/18_Transform/02_Rotate.js @@ -0,0 +1,44 @@ +/* + * @name Rotate + * @arialabel White square on a dark grey background rotates side to side + * @description 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. + */ + +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/dist/assets/examples/en/18_Transform/03_Arm.js b/dist/assets/examples/en/18_Transform/03_Arm.js new file mode 100644 index 0000000000..d6a282449d --- /dev/null +++ b/dist/assets/examples/en/18_Transform/03_Arm.js @@ -0,0 +1,50 @@ +/* + * @name 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 + * @description 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. + */ + +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/dist/assets/examples/en/19_Typography/00_Letters.js b/dist/assets/examples/en/19_Typography/00_Letters.js new file mode 100644 index 0000000000..acbfe5588f --- /dev/null +++ b/dist/assets/examples/en/19_Typography/00_Letters.js @@ -0,0 +1,65 @@ +/* + * @name Letters + * @arialabel Letters and characters on a grey background. All are white except the vowels are pink. + * @description 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. + */ +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/dist/assets/examples/en/19_Typography/01_Words.js b/dist/assets/examples/en/19_Typography/01_Words.js new file mode 100644 index 0000000000..8304e785dd --- /dev/null +++ b/dist/assets/examples/en/19_Typography/01_Words.js @@ -0,0 +1,60 @@ +/* + * @name 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 + * @description 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(). + */ +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/dist/assets/examples/en/19_Typography/02_Text_Rotation.js b/dist/assets/examples/en/19_Typography/02_Text_Rotation.js new file mode 100644 index 0000000000..69d49bec03 --- /dev/null +++ b/dist/assets/examples/en/19_Typography/02_Text_Rotation.js @@ -0,0 +1,63 @@ +/* + * @name 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. + * (ported from https://processing.org/examples/textrotation.html) + */ + +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); +} diff --git a/dist/assets/examples/en/20_3D/00_geometries.js b/dist/assets/examples/en/20_3D/00_geometries.js new file mode 100644 index 0000000000..09afb9a92e --- /dev/null +++ b/dist/assets/examples/en/20_3D/00_geometries.js @@ -0,0 +1,61 @@ +/* + * @name Geometries + * @arialabel Six 3D shapes in neon gradient rotating on a white background. Shapes include cube, cylinder, ring, pyramid, sphere, and a plane. + * @description There are six 3D primitives in p5 now. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + + translate(-240, -100, 0); + normalMaterial(); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + plane(70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(70, 70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cylinder(70, 70); + pop(); + + translate(-240 * 2, 200, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cone(70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + torus(70, 20); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + sphere(70); + pop(); +} diff --git a/dist/assets/examples/en/20_3D/01_sine_cosine_in_3D.js b/dist/assets/examples/en/20_3D/01_sine_cosine_in_3D.js new file mode 100644 index 0000000000..3eb4293d6c --- /dev/null +++ b/dist/assets/examples/en/20_3D/01_sine_cosine_in_3D.js @@ -0,0 +1,29 @@ +/* + * @name Sine Cosine in 3D + * @arialabel Geometric spheres moving in different spiral shapes in a 3D space + * @description Sine, cosine and push / pop could be applied in 3D as well. + */ +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/dist/assets/examples/en/20_3D/02_multiple_lights.js b/dist/assets/examples/en/20_3D/02_multiple_lights.js new file mode 100644 index 0000000000..7a9689965e --- /dev/null +++ b/dist/assets/examples/en/20_3D/02_multiple_lights.js @@ -0,0 +1,31 @@ +/* + * @name 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 + * @description All types of lights could be used in one sketch. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + ambientLight(50); + directionalLight(255, 0, 0, 0.25, 0.25, 0); + 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, 64); +} diff --git a/dist/assets/examples/en/20_3D/03_materials.js b/dist/assets/examples/en/20_3D/03_materials.js new file mode 100644 index 0000000000..c2c6e0bfca --- /dev/null +++ b/dist/assets/examples/en/20_3D/03_materials.js @@ -0,0 +1,66 @@ +/* + * @name 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. + * @description There are five types of materials supported. + * They respond to light differently. + * Move your mouse to change the light position. + */ +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/dist/assets/examples/en/20_3D/04_textures.js b/dist/assets/examples/en/20_3D/04_textures.js new file mode 100644 index 0000000000..87d08f2f57 --- /dev/null +++ b/dist/assets/examples/en/20_3D/04_textures.js @@ -0,0 +1,41 @@ +/* + * @name 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. + * @description Images and videos are supported for texture. + */ +// 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/dist/assets/examples/en/20_3D/05_ray_casting.js b/dist/assets/examples/en/20_3D/05_ray_casting.js new file mode 100644 index 0000000000..e3a2515ca5 --- /dev/null +++ b/dist/assets/examples/en/20_3D/05_ray_casting.js @@ -0,0 +1,101 @@ +/* + * @name 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. + */ +const objects = []; +let eyeZ; + +function setup() { + createCanvas(710, 400, WEBGL); + + eyeZ = height / 2 / tan((30 * PI) / 180); // 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); + } +} diff --git a/dist/assets/examples/en/20_3D/07_orbit_control.js b/dist/assets/examples/en/20_3D/07_orbit_control.js new file mode 100644 index 0000000000..7ae75b1650 --- /dev/null +++ b/dist/assets/examples/en/20_3D/07_orbit_control.js @@ -0,0 +1,37 @@ +/* + * @name 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. + * @description Orbit control allows you to drag and move around the world. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + let radius = width * 1.5; + + //drag to move the world. + orbitControl(); + + normalMaterial(); + translate(0, 0, -600); + 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/dist/assets/examples/en/20_3D/08_basic_shader.js b/dist/assets/examples/en/20_3D/08_basic_shader.js new file mode 100644 index 0000000000..bf531490d2 --- /dev/null +++ b/dist/assets/examples/en/20_3D/08_basic_shader.js @@ -0,0 +1,28 @@ +/* + * @name 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 + */ + +// 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); +} diff --git a/dist/assets/examples/en/20_3D/09_shader_as_a_texture.js b/dist/assets/examples/en/20_3D/09_shader_as_a_texture.js new file mode 100644 index 0000000000..ba67dd8e89 --- /dev/null +++ b/dist/assets/examples/en/20_3D/09_shader_as_a_texture.js @@ -0,0 +1,69 @@ +/* + * @name 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 + */ + + // 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); + } diff --git a/dist/assets/examples/en/20_3D/10_passing_shader_uniforms.js b/dist/assets/examples/en/20_3D/10_passing_shader_uniforms.js new file mode 100644 index 0000000000..c01ea5da83 --- /dev/null +++ b/dist/assets/examples/en/20_3D/10_passing_shader_uniforms.js @@ -0,0 +1,34 @@ +/* + * @name 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 + */ + + // 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(); + } + + function draw() { + // shader() sets the active shader with our shader + shader(theShader); + + // lets send the resolution, mouse, and time to our shader + // before sending mouse + time we modify the data so it's more easily usable by the shader + theShader.setUniform('resolution', [width, height]); + 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); + } diff --git a/dist/assets/examples/en/20_3D/11_shader_using_webcam.js b/dist/assets/examples/en/20_3D/11_shader_using_webcam.js new file mode 100644 index 0000000000..b54a51c9a4 --- /dev/null +++ b/dist/assets/examples/en/20_3D/11_shader_using_webcam.js @@ -0,0 +1,38 @@ +/* + * @name 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 + */ + + // 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); + } diff --git a/dist/assets/examples/en/21_Input/00_Clock.js b/dist/assets/examples/en/21_Input/00_Clock.js new file mode 100644 index 0000000000..c95fac761c --- /dev/null +++ b/dist/assets/examples/en/21_Input/00_Clock.js @@ -0,0 +1,63 @@ +/* + * @name Clock + * @arialabel Functioning pink clock on a grey background + * @description 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. + */ +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/dist/assets/examples/en/21_Input/01_Constrain.js b/dist/assets/examples/en/21_Input/01_Constrain.js new file mode 100644 index 0000000000..f2e4ace449 --- /dev/null +++ b/dist/assets/examples/en/21_Input/01_Constrain.js @@ -0,0 +1,37 @@ +/* + * @name Constrain + * @arialabel Pink rectangle on a grey background. A user uses their mouse to move a white circle within the pink rectangle + * @description Move the mouse across the screen to move + * the circle. The program constrains the circle to its box. + */ +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/dist/assets/examples/en/21_Input/02_Easing.js b/dist/assets/examples/en/21_Input/02_Easing.js new file mode 100644 index 0000000000..79d78921bc --- /dev/null +++ b/dist/assets/examples/en/21_Input/02_Easing.js @@ -0,0 +1,31 @@ +/* + * @name Easing + * @arialabel Pink background with a white circle that the user can move around by hovering over the circle + * @description 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. + */ +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/dist/assets/examples/en/21_Input/03_Keyboard.js b/dist/assets/examples/en/21_Input/03_Keyboard.js new file mode 100644 index 0000000000..450a7ffb44 --- /dev/null +++ b/dist/assets/examples/en/21_Input/03_Keyboard.js @@ -0,0 +1,39 @@ +/* + * @name Keyboard + * @arialabel Each letter on the keyboard draws a different color rectangle on the grey screen when pressed + * @description 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. + */ +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/dist/assets/examples/en/21_Input/04_Milliseconds.js b/dist/assets/examples/en/21_Input/04_Milliseconds.js new file mode 100644 index 0000000000..2076f3e112 --- /dev/null +++ b/dist/assets/examples/en/21_Input/04_Milliseconds.js @@ -0,0 +1,23 @@ +/* + * @name 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. (ported from https://processing.org/examples/milliseconds.html) + */ + +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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/en/21_Input/05_Mouse1D.js b/dist/assets/examples/en/21_Input/05_Mouse1D.js new file mode 100644 index 0000000000..412dc4c466 --- /dev/null +++ b/dist/assets/examples/en/21_Input/05_Mouse1D.js @@ -0,0 +1,25 @@ +/* + * @name 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. + * @description 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. + */ +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/dist/assets/examples/en/21_Input/06_Mouse2D.js b/dist/assets/examples/en/21_Input/06_Mouse2D.js new file mode 100644 index 0000000000..4998706a06 --- /dev/null +++ b/dist/assets/examples/en/21_Input/06_Mouse2D.js @@ -0,0 +1,21 @@ +/* + * @name 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 + * @description Moving the mouse changes the position and + * size of each box. + */ +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/dist/assets/examples/en/21_Input/07_Mouse_Functions.js b/dist/assets/examples/en/21_Input/07_Mouse_Functions.js new file mode 100644 index 0000000000..c2c5c4d2fb --- /dev/null +++ b/dist/assets/examples/en/21_Input/07_Mouse_Functions.js @@ -0,0 +1,67 @@ +/* + * @name 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. + * @description Click on the box and drag it across the screen. + */ +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/dist/assets/examples/en/21_Input/08_Mouse_Signals.js b/dist/assets/examples/en/21_Input/08_Mouse_Signals.js new file mode 100644 index 0000000000..2b61304295 --- /dev/null +++ b/dist/assets/examples/en/21_Input/08_Mouse_Signals.js @@ -0,0 +1,53 @@ +/* + * @name 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. + * @description 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". + */ +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/dist/assets/examples/en/21_Input/09_MouseIsPressed.js b/dist/assets/examples/en/21_Input/09_MouseIsPressed.js new file mode 100644 index 0000000000..bc0a51a843 --- /dev/null +++ b/dist/assets/examples/en/21_Input/09_MouseIsPressed.js @@ -0,0 +1,21 @@ +/* + * @name Mouse Press + * @arialabel User draws pink crosses on a grey background and can change the cross color to white by clicking the mouse. + * @description Move the mouse to position the shape. + * Press the mouse button to invert the color. + */ +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/dist/assets/examples/en/21_Input/10_Rollover.js b/dist/assets/examples/en/21_Input/10_Rollover.js new file mode 100644 index 0000000000..449bda1689 --- /dev/null +++ b/dist/assets/examples/en/21_Input/10_Rollover.js @@ -0,0 +1,80 @@ +/* + * @name 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 + */ +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; + } +} \ No newline at end of file diff --git a/dist/assets/examples/en/21_Input/11_Storing_Input.js b/dist/assets/examples/en/21_Input/11_Storing_Input.js new file mode 100644 index 0000000000..4e76fded22 --- /dev/null +++ b/dist/assets/examples/en/21_Input/11_Storing_Input.js @@ -0,0 +1,39 @@ +/* + * @name Storing Input + * @arialabel User draws white circles on a fuschia background. Circles fade in color as the next circle is drawn. + * @description 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. + */ +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/dist/assets/examples/en/22_Advanced_Data/00_Load_Saved_JSON.js b/dist/assets/examples/en/22_Advanced_Data/00_Load_Saved_JSON.js new file mode 100644 index 0000000000..7aab438794 --- /dev/null +++ b/dist/assets/examples/en/22_Advanced_Data/00_Load_Saved_JSON.js @@ -0,0 +1,105 @@ +/* + * @name 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 the 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. + */ + +// 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); +} diff --git a/dist/assets/examples/en/22_Advanced_Data/01_Load_Saved_Table.js b/dist/assets/examples/en/22_Advanced_Data/01_Load_Saved_Table.js new file mode 100644 index 0000000000..3cd098bd82 --- /dev/null +++ b/dist/assets/examples/en/22_Advanced_Data/01_Load_Saved_Table.js @@ -0,0 +1,111 @@ +/* + * @name 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 the web browsers differ in where they save files, we do not make use of + * + * Based on Daniel Shiffman's LoadSaveTable Example for Processing. + */ + +// 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); +} diff --git a/dist/assets/examples/en/33_Sound/00_Load_and_Play_Sound.js b/dist/assets/examples/en/33_Sound/00_Load_and_Play_Sound.js new file mode 100644 index 0000000000..93b5855ec8 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/00_Load_and_Play_Sound.js @@ -0,0 +1,26 @@ +/* + * @name 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. + */ +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); + } +} diff --git a/dist/assets/examples/en/33_Sound/01_Preload_Sound.js b/dist/assets/examples/en/33_Sound/01_Preload_Sound.js new file mode 100644 index 0000000000..ff8034c009 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/01_Preload_Sound.js @@ -0,0 +1,35 @@ +/* + * @name 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. + */ + +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); + } +} diff --git a/dist/assets/examples/en/33_Sound/02_soundFormats.js b/dist/assets/examples/en/33_Sound/02_soundFormats.js new file mode 100644 index 0000000000..536efe0506 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/02_soundFormats.js @@ -0,0 +1,55 @@ +/** + * @name soundFormats + * @arialabel On page load, a green screen plays music. When the user clicks on it, the screen turns red and stops playing music + * @description

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.

+ */ +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/dist/assets/examples/en/33_Sound/03_Play_Mode.js b/dist/assets/examples/en/33_Sound/03_Play_Mode.js new file mode 100644 index 0000000000..f011f6bec1 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/03_Play_Mode.js @@ -0,0 +1,43 @@ +/* + * @name Play Mode + * @arialabel Yellow screen plays music when user clicks on it + * @description + *

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.

+ */ +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/dist/assets/examples/en/33_Sound/04_Pan_SoundFile.js b/dist/assets/examples/en/33_Sound/04_Pan_SoundFile.js new file mode 100644 index 0000000000..e35f75a29c --- /dev/null +++ b/dist/assets/examples/en/33_Sound/04_Pan_SoundFile.js @@ -0,0 +1,35 @@ +/* + * @name 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 + * @description

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.

+ * + */ +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/dist/assets/examples/en/33_Sound/05_Sound_Effect.js b/dist/assets/examples/en/33_Sound/05_Sound_Effect.js new file mode 100644 index 0000000000..fd0cf56081 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/05_Sound_Effect.js @@ -0,0 +1,70 @@ +/* + * @name Sound Effect + * @arialabel Grey circle on a white screen that plays a doorbell sound when pressed on + * @description

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.

+ */ +// 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/dist/assets/examples/en/33_Sound/06_Manipulate_Sound.js b/dist/assets/examples/en/33_Sound/06_Manipulate_Sound.js new file mode 100644 index 0000000000..9ad41eb08e --- /dev/null +++ b/dist/assets/examples/en/33_Sound/06_Manipulate_Sound.js @@ -0,0 +1,50 @@ +/* + * @name 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 + * @description

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.

+ */ +// 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/dist/assets/examples/en/33_Sound/07_Amplitude_Analysis.js b/dist/assets/examples/en/33_Sound/07_Amplitude_Analysis.js new file mode 100644 index 0000000000..2b24248613 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/07_Amplitude_Analysis.js @@ -0,0 +1,51 @@ +/** + * @name 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.

+ */ +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); +} diff --git a/dist/assets/examples/en/33_Sound/08_Noise_Envelope.js b/dist/assets/examples/en/33_Sound/08_Noise_Envelope.js new file mode 100644 index 0000000000..4c4d89905f --- /dev/null +++ b/dist/assets/examples/en/33_Sound/08_Noise_Envelope.js @@ -0,0 +1,55 @@ +/** + * @name 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 + * @description

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.

+ */ +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/dist/assets/examples/en/33_Sound/09_Note_Envelope.js b/dist/assets/examples/en/33_Sound/09_Note_Envelope.js new file mode 100644 index 0000000000..844105a528 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/09_Note_Envelope.js @@ -0,0 +1,62 @@ +/** + * @name Note Envelope + * @arialabel Red bars rise on the screen based on the amplitude and the note played + * @description

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.

+ */ +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/dist/assets/examples/en/33_Sound/10_Oscillator_Waveform.js b/dist/assets/examples/en/33_Sound/10_Oscillator_Waveform.js new file mode 100644 index 0000000000..ccc4e8086d --- /dev/null +++ b/dist/assets/examples/en/33_Sound/10_Oscillator_Waveform.js @@ -0,0 +1,41 @@ +/* + * @name 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 + * @description

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.

+ */ +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/dist/assets/examples/en/33_Sound/11_Live_Input.js b/dist/assets/examples/en/33_Sound/11_Live_Input.js new file mode 100644 index 0000000000..091302632a --- /dev/null +++ b/dist/assets/examples/en/33_Sound/11_Live_Input.js @@ -0,0 +1,37 @@ +/** + * @name 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 + * @description

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.

+ */ +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/dist/assets/examples/en/33_Sound/12_FFT_Spectrum.js b/dist/assets/examples/en/33_Sound/12_FFT_Spectrum.js new file mode 100644 index 0000000000..46c7b05c6e --- /dev/null +++ b/dist/assets/examples/en/33_Sound/12_FFT_Spectrum.js @@ -0,0 +1,31 @@ +/** + * @name Frequency Spectrum + * @arialabel Audio waves are graphed on a grey screen based on the user’s audio input into their mic + * @description

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.

+ */ +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/dist/assets/examples/en/33_Sound/13_Mic_Threshold.js b/dist/assets/examples/en/33_Sound/13_Mic_Threshold.js new file mode 100644 index 0000000000..9cf48ef5f7 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/13_Mic_Threshold.js @@ -0,0 +1,50 @@ +/** + * @name 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 + * @description

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.

+ */ +// 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/dist/assets/examples/en/33_Sound/14_Filter_LowPass.js b/dist/assets/examples/en/33_Sound/14_Filter_LowPass.js new file mode 100644 index 0000000000..4eaadf5a10 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/14_Filter_LowPass.js @@ -0,0 +1,63 @@ +/** + * @name Filter LowPass + * @arialabel The lowpass filter changes intensity as the user’s mouse moves left and right on the screen + * @description 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.

+ */ +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/dist/assets/examples/en/33_Sound/15_Filter_BandPass.js b/dist/assets/examples/en/33_Sound/15_Filter_BandPass.js new file mode 100644 index 0000000000..35d10b146a --- /dev/null +++ b/dist/assets/examples/en/33_Sound/15_Filter_BandPass.js @@ -0,0 +1,52 @@ +/** + * @name Filter BandPass + * @arialabel The bandpass filter changes intensity as the user’s mouse moves left and right on the screen + * @description 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.

+ */ +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/dist/assets/examples/en/33_Sound/16_Delay.js b/dist/assets/examples/en/33_Sound/16_Delay.js new file mode 100644 index 0000000000..15e2336106 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/16_Delay.js @@ -0,0 +1,57 @@ +/** + * @name 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 + * @description + * 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.

+ */ + +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/dist/assets/examples/en/33_Sound/17_Reverb.js b/dist/assets/examples/en/33_Sound/17_Reverb.js new file mode 100644 index 0000000000..b8e297253f --- /dev/null +++ b/dist/assets/examples/en/33_Sound/17_Reverb.js @@ -0,0 +1,37 @@ +/** + * @name Reverb + * @arialabel When the user clicks on the black screen, sound with reverb is played + * @description 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.

+ */ +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/dist/assets/examples/en/33_Sound/18_Convolution_Reverb.js b/dist/assets/examples/en/33_Sound/18_Convolution_Reverb.js new file mode 100644 index 0000000000..2e40973ed2 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/18_Convolution_Reverb.js @@ -0,0 +1,88 @@ +/** + * @name 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

+ */ +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(); +} diff --git a/dist/assets/examples/en/33_Sound/19_Record_Save.js b/dist/assets/examples/en/33_Sound/19_Record_Save.js new file mode 100644 index 0000000000..a7d8af4a38 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/19_Record_Save.js @@ -0,0 +1,59 @@ +/** + * @name 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 + * @description 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.

+ */ +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/dist/assets/examples/en/33_Sound/21_FreqModulation.js b/dist/assets/examples/en/33_Sound/21_FreqModulation.js new file mode 100644 index 0000000000..bd128b7fc7 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/21_FreqModulation.js @@ -0,0 +1,149 @@ +/** + * @name 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.

+ */ + +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); + }); +} diff --git a/dist/assets/examples/en/33_Sound/22_AmplitudeModulation.js b/dist/assets/examples/en/33_Sound/22_AmplitudeModulation.js new file mode 100644 index 0000000000..e66ae8aa70 --- /dev/null +++ b/dist/assets/examples/en/33_Sound/22_AmplitudeModulation.js @@ -0,0 +1,96 @@ +/** + * @name 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.

+ */ +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); +} diff --git a/dist/assets/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js b/dist/assets/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js new file mode 100644 index 0000000000..0942148573 --- /dev/null +++ b/dist/assets/examples/en/35_Mobile/00_Acceleration_Ball_Bounce.js @@ -0,0 +1,58 @@ +/* + * @name Acceleration Ball Bounce + * @description Move an ellipse around based on accelerationX and accelerationY values, and bounces when touch the edge of the canvas. + */ + +// 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/dist/assets/examples/en/35_Mobile/01_Simple_Draw.js b/dist/assets/examples/en/35_Mobile/01_Simple_Draw.js new file mode 100644 index 0000000000..80cddb8562 --- /dev/null +++ b/dist/assets/examples/en/35_Mobile/01_Simple_Draw.js @@ -0,0 +1,15 @@ +/* + * @name Simple Draw + * @description Touch to draw on the screen using mouseX, mouseY, pmouseX, and pmouseY values. + */ + +function setup() { + createCanvas(displayWidth, displayHeight); + strokeWeight(10); + stroke(0); +} + +function touchMoved() { + line(mouseX, mouseY, pmouseX, pmouseY); + return false; +} diff --git a/dist/assets/examples/en/35_Mobile/02_Acceleration_Color.js b/dist/assets/examples/en/35_Mobile/02_Acceleration_Color.js new file mode 100644 index 0000000000..a7183d1def --- /dev/null +++ b/dist/assets/examples/en/35_Mobile/02_Acceleration_Color.js @@ -0,0 +1,24 @@ +/* + * @name Acceleration Color + * @description Use deviceMoved() to detect when the device is rotated. The background RGB color values are mapped to accelerationX, accelerationY, and accelerationZ values. + */ + +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/dist/assets/examples/en/35_Mobile/03_Shake_Ball_Bounce.js b/dist/assets/examples/en/35_Mobile/03_Shake_Ball_Bounce.js new file mode 100644 index 0000000000..5d2880dbe7 --- /dev/null +++ b/dist/assets/examples/en/35_Mobile/03_Shake_Ball_Bounce.js @@ -0,0 +1,114 @@ +/* + * @name Shake Ball Bounce + * @description 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. + */ + +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/dist/assets/examples/en/35_Mobile/04_Tilted_3D_Box.js b/dist/assets/examples/en/35_Mobile/04_Tilted_3D_Box.js new file mode 100644 index 0000000000..ea39b5414f --- /dev/null +++ b/dist/assets/examples/en/35_Mobile/04_Tilted_3D_Box.js @@ -0,0 +1,15 @@ +/* + * @name Tilted 3D Box + * @description Use mobile to tilt a box + */ +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/dist/assets/examples/en/90_Hello_P5/01_shapes.js b/dist/assets/examples/en/90_Hello_P5/01_shapes.js new file mode 100644 index 0000000000..122ac85697 --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/01_shapes.js @@ -0,0 +1,29 @@ +/* + * @name Simple Shapes + * @arialabel Grey canvas with 4 pink shapes: a circle, a rectangle, a triangle, and a flower + * @description This examples includes a circle, square, triangle, and a flower. + */ +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/dist/assets/examples/en/90_Hello_P5/02_interactivity.js b/dist/assets/examples/en/90_Hello_P5/02_interactivity.js new file mode 100644 index 0000000000..1b478af003 --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/02_interactivity.js @@ -0,0 +1,38 @@ +/* + * @name Interactivity 1 + * @arialabel Dark grey background with a colored circle in the middle that changes color when clicked ons + * @frame 720,425 + * @description The circle changes color when you click on it. + */ + +// 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/dist/assets/examples/en/90_Hello_P5/03_interactivity.js b/dist/assets/examples/en/90_Hello_P5/03_interactivity.js new file mode 100644 index 0000000000..86218e4b4d --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/03_interactivity.js @@ -0,0 +1,27 @@ +/* + * @name 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 + * @frame 720,425 + * @description The circle changes color when you move the slider. + */ + +// 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/dist/assets/examples/en/90_Hello_P5/04_animate.js b/dist/assets/examples/en/90_Hello_P5/04_animate.js new file mode 100644 index 0000000000..75ec783002 --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/04_animate.js @@ -0,0 +1,34 @@ +/* + * @name 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 + * @description The circle moves. + */ +// 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/dist/assets/examples/en/90_Hello_P5/04_flocking.js b/dist/assets/examples/en/90_Hello_P5/04_flocking.js new file mode 100644 index 0000000000..7e1ff4812f --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/04_flocking.js @@ -0,0 +1,186 @@ +/* + * @name 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. + */ +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); + } + } +} + diff --git a/dist/assets/examples/en/90_Hello_P5/05_weather.js b/dist/assets/examples/en/90_Hello_P5/05_weather.js new file mode 100644 index 0000000000..429d25ac65 --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/05_weather.js @@ -0,0 +1,72 @@ +/* + * @name 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 + * @frame 720,280 + * @description This example grabs JSON weather data from www.metaweather.com. +*/ + +// 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/dist/assets/examples/en/90_Hello_P5/06_drawing.js b/dist/assets/examples/en/90_Hello_P5/06_drawing.js new file mode 100644 index 0000000000..6ca6c97e50 --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/06_drawing.js @@ -0,0 +1,133 @@ +/* +* @name 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. +* @description Generative painting program. +*/ + +// 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/dist/assets/examples/en/90_Hello_P5/07_song.js b/dist/assets/examples/en/90_Hello_P5/07_song.js new file mode 100644 index 0000000000..a43e43363e --- /dev/null +++ b/dist/assets/examples/en/90_Hello_P5/07_song.js @@ -0,0 +1,120 @@ +/* + * @name 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. + * @frame 720, 430 + * @description Play a song. + * You will need to include the + * p5.sound + * library for this example to work in your own project. + */ +// 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/dist/assets/examples/es/00_Structure/00_Statements_and_Comments.js b/dist/assets/examples/es/00_Structure/00_Statements_and_Comments.js new file mode 100644 index 0000000000..8469f369b7 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/00_Statements_and_Comments.js @@ -0,0 +1,19 @@ +/* + * @name Comments and Statements + * @description Statements are the elements that make up programs. The ";" (semi-colon) symbol is used to end statements. It is called the "statement * terminator". Comments are used for making notes to help people better understand programs. A comment begins with two forward slashes ("//"). (ported from https://processing.org/examples/statementscomments.html) + */ +// The createCanvas function is a statement that tells the computer +// how large to make the window. +// Each function statement has zero or more parameters. +// Parameters are data passed into the function +// and are used as values for telling the computer what to do. +function setup() { + createCanvas(710, 400); +} + +// The background function is a statement that tells the computer +// which color (or gray value) to make the background of the display window +function draw() { + background(204, 153, 0); +} + diff --git a/dist/assets/examples/es/00_Structure/01_Coordinates.js b/dist/assets/examples/es/00_Structure/01_Coordinates.js new file mode 100644 index 0000000000..d38351aa8c --- /dev/null +++ b/dist/assets/examples/es/00_Structure/01_Coordinates.js @@ -0,0 +1,37 @@ +/* + * @name Coordenadas + * @description Todas las formas dibujadas en la pantalla tienen una posición que es + * especificada como una coordenada. Todas las coordenadas son medidas como una distancia desde el origen, usando el pixel como unidad de medida. + * El origen [0, 0] es la coordenada en la esquina superior izquierda de la ventana y la coordenada de la esquina inferior derecha es [ancho-1, altura-1]. + */ +function setup() { + // Definir lienzo de 720 pixeles de ancho y 400 pixeles de alto + createCanvas(720, 400); +} + +function draw() { + // Definir el color del fondo como negro + // y definir que las figuras sean pintadas sin relleno + background(0); + noFill(); + + // Los dos parámetros del método point() especifican coordenadas. + // El primer parámetro es la coordenada x y el segundo es la y. + stroke(255); + point(width * 0.5, height * 0.5); + point(width * 0.5, height * 0.25); + + // Las coordenadas se usan para dibujar figuras, no solo puntos. + // Los parámetros de las funciones son usados para múltiples + // propósitos. Por ejemplo, los dos primeros parámetros + // de line() especifican las coordenadas del primer extremo + //y los siguientes dos parámetros del segundo extremo. + stroke(0, 153, 255); + line(0, height * 0.33, width, height * 0.33); + + // Por defecto, los dos primeros parámetros de rect() son + // las coordenadas de la esquina superior izquierda y el + // segundo par son el ancho y el alto. + stroke(255, 153, 0); + rect(width * 0.25, height * 0.1, width * 0.5, height * 0.8); +} diff --git a/dist/assets/examples/es/00_Structure/02_Width_and_Height.js b/dist/assets/examples/es/00_Structure/02_Width_and_Height.js new file mode 100644 index 0000000000..02df6efe69 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/02_Width_and_Height.js @@ -0,0 +1,19 @@ +/* + * @name width y height + * @description Las variables 'width' (ancho) y 'height' (altura) contienen + * el ancho y la altura del lienzo, como fue definido en la función createCanvas(). + */ +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/dist/assets/examples/es/00_Structure/03_Setup_and_Draw.js b/dist/assets/examples/es/00_Structure/03_Setup_and_Draw.js new file mode 100644 index 0000000000..1c4b247351 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/03_Setup_and_Draw.js @@ -0,0 +1,28 @@ +/* + * @name Setup y Draw + * @description El código dentro de la función draw() corre continuamente de arriba + * a a bajo hasta que el programa es parado. + */ +let y = 100; + +// Las instrucciones dentro de la función setup() +// se ejecutan una vez, al principio del programa +function setup() { + // createCanvas() debe ser la primera instrucción + createCanvas(720, 400); + stroke(255); // Hacer que el color de trazado sea blanco + frameRate(30); +} + +// Las instrucciones en draw() son ejecutadas hasta que +// el programa es parado. Cada instrucción es ejecutada +// en orden y luego de que la última línea es leída, +// se vuelve a ejecutar draw() desde el principio +function draw() { + background(0); // Hacer que el color del fondo sea negro + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/es/00_Structure/04_No_Loop.js b/dist/assets/examples/es/00_Structure/04_No_Loop.js new file mode 100644 index 0000000000..4c56f21a70 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/04_No_Loop.js @@ -0,0 +1,30 @@ +/* + * @name No Loop + * @description La función noLoop() hace que draw() se ejecuta solo una vez. + * Sin ejecutar noLoop(), el código dentro de draw() es ejecutado continuamente. + */ +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; +} + +// Las instrucciones en draw() son ejecutadas hasta que +// el programa es parado. Cada instrucción es ejecutada +// en orden y luego de que la última línea es leída, +// se vuelve a ejecutar draw() desde el principio +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/dist/assets/examples/es/00_Structure/05_Loop.js b/dist/assets/examples/es/00_Structure/05_Loop.js new file mode 100644 index 0000000000..c8a3e298e9 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/05_Loop.js @@ -0,0 +1,26 @@ +/* + * @name Bucle + * @description El código dentro de la función draw() corre continuamente de arriba a abajo hasta que el prorgrama para. + */ +let y = 100; + +// Las instrucciones dentro de la función setup() +// se ejecutan una vez, cuando el programa empieza +function setup() { + createCanvas(720, 400); // El tamaño debe ser la primera instrucción + stroke(255); // Definir que el color del trazado sea blanco + frameRate(30); +} + +// Las instrucciones en draw() son ejecutadas hasta que +// el programa es parado. Cada instrucción es ejecutada +// en orden y luego de que la última línea es leída, +// se vuelve a ejecutar draw() desde el principio +function draw() { + background(0); // Definir que el color del fondo sea negro + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/es/00_Structure/06_Redraw.js b/dist/assets/examples/es/00_Structure/06_Redraw.js new file mode 100644 index 0000000000..0cb9bbbfe2 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/06_Redraw.js @@ -0,0 +1,33 @@ +/* + * @name Redraw + * @description La función redraw() hace que draw() se ejecute una vez. En este ejemplo, + * draw() se ejecutado una vez cada vez que el ratón hace click. + */ + +let y; + +// Las instrucciones dentro de la función setup() +// se ejecutan una vez, cuando el programa se inicia +function setup() { + createCanvas(720, 400); + stroke(255); + noLoop(); + y = height * 0.5; +} + +// Las instrucciones en draw() son ejecutadas hasta que +// el programa es parado. Cada instrucción es ejecutada +// en orden y luego de que la última línea es leída, +// se vuelve a ejecutar draw() desde el principio +function draw() { + background(0); + y = y - 4; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} + +function mousePressed() { + redraw(); +} diff --git a/dist/assets/examples/es/00_Structure/07_Functions.js b/dist/assets/examples/es/00_Structure/07_Functions.js new file mode 100644 index 0000000000..157494342e --- /dev/null +++ b/dist/assets/examples/es/00_Structure/07_Functions.js @@ -0,0 +1,28 @@ +/* + *@name Funciones + *@description La función drawTarget() hace fácil dibujar muchas dianas distintos. + * Cada llamada a drawTarget() especifica la posición, tamaño y número de + * anillos por cada diana. + */ + +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/dist/assets/examples/es/00_Structure/08_Recursion.js b/dist/assets/examples/es/00_Structure/08_Recursion.js new file mode 100644 index 0000000000..ce0befd0ee --- /dev/null +++ b/dist/assets/examples/es/00_Structure/08_Recursion.js @@ -0,0 +1,27 @@ +/* + *@name Recursión + *@description Una demonstración de recursión, que significa funciones llamándose a sí mismas. + * Fíjate cómo la función drawCircle() se llama a sí misma al final del bloque de código. + * Continúa haciéndolo hasta que la variable "level" es igual a 1. + */ + +function setup() { + createCanvas(720, 560); + noStroke(); + noLoop(); +} + +function draw() { + drawCircle(width / 2, 280, 6); +} + +function drawCircle(x, radius, level) { + const tt = (126 * level) / 4.0; + fill(tt); + ellipse(x, height / 2, radius * 2, radius * 2); + if (level > 1) { + level = level - 1; + drawCircle(x - radius / 2, radius / 2, level); + drawCircle(x + radius / 2, radius / 2, level); + } +} diff --git a/dist/assets/examples/es/00_Structure/09_Create_Graphics.js b/dist/assets/examples/es/00_Structure/09_Create_Graphics.js new file mode 100644 index 0000000000..88085349e2 --- /dev/null +++ b/dist/assets/examples/es/00_Structure/09_Create_Graphics.js @@ -0,0 +1,29 @@ +/* + * @name createGraphics + * @description Crea y retorna un nuevo objeto p5.Renderer. Usa esta + * clase si necesitas dibujar en un buffer gráfico fuera-de-pantalla. Los dos parámetros + * definen el ancho y la altura en pixeles. + */ + +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); + + //El buffer fuera de pantalla es dibujado en la pantalla con image() + image(pg, 150, 75); +} diff --git a/dist/assets/examples/es/01_Form/00_Points_and_Lines.js b/dist/assets/examples/es/01_Form/00_Points_and_Lines.js new file mode 100644 index 0000000000..4e5b1d64c8 --- /dev/null +++ b/dist/assets/examples/es/01_Form/00_Points_and_Lines.js @@ -0,0 +1,36 @@ +/* + * @name Puntos y líneas + * @description Puntos y líneas pueden ser usados para dibujar geometría básica. + * Cambia el valor de la variable 'd' para escalar la figura. Las cuatro + * variables definen las posiciones basadas en el valor de 'd'. + */ +function setup() { + let d = 70; + let p1 = d; + let p2 = p1 + d; + let p3 = p2 + d; + let p4 = p3 + d; + + // Define el lienzo de 720 pixeles de ancho y 400 de alto + createCanvas(720, 400); + background(0); + noSmooth(); + + translate(140, 0); + + // Dibuja una caja gris + stroke(153); + line(p3, p3, p2, p3); + line(p2, p3, p2, p2); + line(p2, p2, p3, p2); + line(p3, p2, p3, p3); + + // Dibuja puntos blancos + stroke(255); + point(p1, p1); + point(p1, p3); + point(p2, p4); + point(p3, p1); + point(p4, p2); + point(p4, p4); +} diff --git a/dist/assets/examples/es/01_Form/01_Shape_Primitives.js b/dist/assets/examples/es/01_Form/01_Shape_Primitives.js new file mode 100644 index 0000000000..dd3ebaedac --- /dev/null +++ b/dist/assets/examples/es/01_Form/01_Shape_Primitives.js @@ -0,0 +1,31 @@ +/* + * @name Figuras primitivas + * @description Las funciones primitivas de figuras básicas son triangle(), + * rect(), quad(), ellipse() y arc(). Rectángulos y cuadrados se construyen con rect() + * y círculos y elipses con ellipse(). Cada una de estas funciones requiere + * un número de parámetros para determinar la posición y tamaño de la figura. + */ +function setup() { + // Define un lienzo de 720 pixeles de ancho y 400 de alto + 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/dist/assets/examples/es/01_Form/02_Pie_Chart.js b/dist/assets/examples/es/01_Form/02_Pie_Chart.js new file mode 100644 index 0000000000..7b85112b04 --- /dev/null +++ b/dist/assets/examples/es/01_Form/02_Pie_Chart.js @@ -0,0 +1,33 @@ +/* + * @name Gráfico de sectores + * @description Usa la función arc() para generar un gráfico de sectores de los datos contenidos en un arreglo + */ +let angles = [30, 10, 45, 35, 60, 38, 75, 67]; + +function setup() { + createCanvas(720, 400); + noStroke(); + noLoop(); // Corre una vez y luego para. +} + +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/dist/assets/examples/es/01_Form/03_Regular_Polygon.js b/dist/assets/examples/es/01_Form/03_Regular_Polygon.js new file mode 100644 index 0000000000..9e8e34facf --- /dev/null +++ b/dist/assets/examples/es/01_Form/03_Regular_Polygon.js @@ -0,0 +1,43 @@ +/* + * @name Polígono regular + * @description ¿Cuál es tu favorito? ¿Pentágono? ¿Hexágono? ¿Heptágono? ¿No? + * ¿O el icoságono? La función polygon() creada para este ejemplo es + * capaz de dibujar cualquier polígono regular. Trata con distintos números en los paráemtros de + * la función polygon() dentro de draw() para explorar. + */ +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/dist/assets/examples/es/01_Form/04_Star.js b/dist/assets/examples/es/01_Form/04_Star.js new file mode 100644 index 0000000000..e63b1d93c8 --- /dev/null +++ b/dist/assets/examples/es/01_Form/04_Star.js @@ -0,0 +1,46 @@ +/* + * @name Estrella + * @description La función star() creada para este ejemplo es capaz de + * dibujar una gran grama de figuras. Prueba poniendo distintos números en los parámetros de + * la función star() dentro de draw() para explorar. + */ +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/dist/assets/examples/es/01_Form/05_Triangle_Strip.js b/dist/assets/examples/es/01_Form/05_Triangle_Strip.js new file mode 100644 index 0000000000..2a75c76898 --- /dev/null +++ b/dist/assets/examples/es/01_Form/05_Triangle_Strip.js @@ -0,0 +1,38 @@ +/* + * @name Tira de triángulos + * @description Ejemplo por Ira Greenberg. Genera un anillo cerrado usando la + * función vertex() y el modo beginShape(TRIANGLE_STRIP). Las variables outsideRadius + * e insideRadius controlan los radios externo e interno del anillo, respectivamente. + */ +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/dist/assets/examples/es/01_Form/06_Bezier.js b/dist/assets/examples/es/01_Form/06_Bezier.js new file mode 100644 index 0000000000..69be92268d --- /dev/null +++ b/dist/assets/examples/es/01_Form/06_Bezier.js @@ -0,0 +1,27 @@ +/* + * @name Bezier + * @description Los primeros dos parámetros de la función bezier() especifican + * el primer punto en la curva y los últimos dos parámetros especifican el último punto. + * Los parámetros de al medio definen los puntos de control que definen la figura de la curva. + */ +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/dist/assets/examples/es/01_Form/07_3D_Primitives.js b/dist/assets/examples/es/01_Form/07_3D_Primitives.js new file mode 100644 index 0000000000..5a0740519e --- /dev/null +++ b/dist/assets/examples/es/01_Form/07_3D_Primitives.js @@ -0,0 +1,30 @@ +/* + * @name Primitivas 3D + * @frame 720,400 (optional) + * @description Ubicar matemáticamente objetos 3D en un espacio sintétito. + * Las funciones box() y sphere() toman al menos un parámetro para especificar su + * tamaño. Estas figuras son posicionadas usando la función translate(). + */ +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/dist/assets/examples/es/01_Form/08_Trig_Wheels_and_Pie_Chart.js b/dist/assets/examples/es/01_Form/08_Trig_Wheels_and_Pie_Chart.js new file mode 100644 index 0000000000..20597a112e --- /dev/null +++ b/dist/assets/examples/es/01_Form/08_Trig_Wheels_and_Pie_Chart.js @@ -0,0 +1,88 @@ +/* + * @name Trig Wheels and Pie Chart + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create +a trig color wheel and a visualization of a population age data as a +pie chart.
+ Functions are +created for the canvas setup, trig color wheel, drawslice, and pie +chart. The size of the slices are determined as well as their color +range. The pie chart is separated by definitive color per value +whereas the trig color wheel has a fixed slice amount with a range +color fill. +*/ + +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/dist/assets/examples/es/02_Data/00_Variables.js b/dist/assets/examples/es/02_Data/00_Variables.js new file mode 100644 index 0000000000..5b4b2b4e1b --- /dev/null +++ b/dist/assets/examples/es/02_Data/00_Variables.js @@ -0,0 +1,37 @@ +/* + * @name Variables + * @description Las variables son usadas para almacenar valores. En este ejemplo, cambia + * los valores de las variables para cambiar la composición. + */ +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/dist/assets/examples/es/02_Data/01_True_and_False.js b/dist/assets/examples/es/02_Data/01_True_and_False.js new file mode 100644 index 0000000000..2cecea384c --- /dev/null +++ b/dist/assets/examples/es/02_Data/01_True_and_False.js @@ -0,0 +1,30 @@ +/* + * @name True y False + * @description Una variable de tipo Boolean tiene solo dos valores posibles: true (verdadero) o false (falso). + * Es común usar booleanos con instrucciones de control para determinar el flujo + * de un programa. En este ejemplo, cuando el valor booleano "x" es verdadero, se dibujan + * líneas negras verticales y cuando el valor booleano "x" es falso, se dibujan líneas grises horizontales. + */ +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) { + // Línea vertical + line(i, d, i, height - d); + } + + if (b === false) { + // Línea horizontal + line(middle, i - middle + d, width - d, i - middle + d); + } + } +} diff --git a/dist/assets/examples/es/02_Data/03_Variable_Scope.js b/dist/assets/examples/es/02_Data/03_Variable_Scope.js new file mode 100644 index 0000000000..3da8554047 --- /dev/null +++ b/dist/assets/examples/es/02_Data/03_Variable_Scope.js @@ -0,0 +1,48 @@ +/* + * @name Alcance de variabless + * @description Las variables tienen un alcance global o local. Por ejemplo, + * las variables declaradas dentro de las funciones setup() o draw() solamente pueden + * ser usadas dentro de esas funciones. Las variables globales, esto es, variables declaradas fuera de setup() y + * draw(), pueden ser usadas en cualquier parte del programa. Si una variable local + * es declarada con el mismo nombre que una variable global, el programa usará + * el valor local para hacer sus cálculos dentro de la función. + * Las variables son localizadas dentro de cada bloque, el espacio entre llaves { y }. + */ +let a = 80; // Crea una variable global "a" + +function setup() { + createCanvas(720, 400); + background(0); + stroke(255); + noLoop(); +} + +function draw() { + // Dibuja una línea usando la variable global "a" + line(a, 0, a, height); + + // Crea una nueva variable local "a" al for() + for (let a = 120; a < 200; a += 3) { + line(a, 0, a, height); + } + + // Llamada a la función drawAnotherLine() + drawAnotherLine(); + + // Llamada a la función drawYetAnotherLine() + drawYetAnotherLine(); +} + +function drawAnotherLine() { + // Crea una nueva variable local "a" de este método + let a = 320; + // Dibuja una línea usando la variable local "a" + line(a, 0, a, height); +} + +function drawYetAnotherLine() { + // Como no definimos una nueva variable local "a", + // esta línea se dibuja usando la variable global original + // "a" que tiene un valor de 20. + line(a + 3, 0, a + 3, height); +} diff --git a/dist/assets/examples/es/02_Data/04_Numbers.js b/dist/assets/examples/es/02_Data/04_Numbers.js new file mode 100644 index 0000000000..9ac71d676b --- /dev/null +++ b/dist/assets/examples/es/02_Data/04_Numbers.js @@ -0,0 +1,30 @@ +/* + * @name Números + * @frame 720,400 + * @description Los números pueden ser escritos con o sin decimales. Un número * entero (más comúnmente conocido como int por el inglés integer) es un + * número sin fracción decimal. Un número de punto flotante (conocido como float + * por el inglés floating-point number) es un número con fracción decimal. + */ +let a = 0; // Crea una variable global "a" de tipo Number +let b = 0; // Crea una variable global "b" de tipo Number + +function setup() { + createCanvas(720, 400); + stroke(255); +} + +function draw() { + background(0); + + a = a + 1; // Incrementar a con un int + b = b + 0.2; //Incrementar b con un 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/dist/assets/examples/es/03_Arrays/00_Array.js b/dist/assets/examples/es/03_Arrays/00_Array.js new file mode 100644 index 0000000000..cb374a5534 --- /dev/null +++ b/dist/assets/examples/es/03_Arrays/00_Array.js @@ -0,0 +1,44 @@ +/* + * @name Arreglo + * @description Un arreglo es una lista de datos. Cada dato en un arreglo + * es idenfiticado por un número de índice, representando su posición en + * el arreglo. Los arreglos son indexados en cero, lo que significa que + * el primer elemento en el arreglo es [0], el segundo es [1], y así. + * En este ejemplo, un arregllo llamado "coswav" es creado y + * llenado con valores de la función coseno. Estos datos son mostrados + * de tres maneras diferentes en pantalla. + */ +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/dist/assets/examples/es/03_Arrays/01_Array_2d.js b/dist/assets/examples/es/03_Arrays/01_Array_2d.js new file mode 100644 index 0000000000..144d3d9c81 --- /dev/null +++ b/dist/assets/examples/es/03_Arrays/01_Array_2d.js @@ -0,0 +1,39 @@ +/* + * @name Arreglo 2D + * @description Demuestra la sintaxis para crear un arreglo + de dos dimensiones (2D). + * Se accede a los valores en un arreglo 2D a través de dos valores de índice. + * Los arreglos 2D son útiles para almacenar imágenes. En este ejemplo, cada punto + * es coloreado en relación a su distancia del centro de la imagen. + */ +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] = []; // Crear un arreglo anidado + 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(); // Correr draw() una vez y luego parar +} + +function draw() { + background(0); + // Este loop anidado recorre los valores en los arreglos basado + // en la variable spacer, así que hay más valores en el arreglo + // que los que dibujamos. Cambia el valor de la variable spacer + // para cambiar la densidad de los puntos. + 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/dist/assets/examples/es/03_Arrays/02_Array_Objects.js b/dist/assets/examples/es/03_Arrays/02_Array_Objects.js new file mode 100644 index 0000000000..dd67e8e45b --- /dev/null +++ b/dist/assets/examples/es/03_Arrays/02_Array_Objects.js @@ -0,0 +1,71 @@ +/* + * @name Arreglo de objetos + * @description Demuestra la sintaxis para crear un arreglo de objetos definidos por el programador. + */ + +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; + } + + // Método personalizado para refrescar las 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; + } + } + + // Método personalizado para dibujar el objeto + 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/dist/assets/examples/es/03_Arrays/03_Walk_Over_2dArray.js b/dist/assets/examples/es/03_Arrays/03_Walk_Over_2dArray.js new file mode 100644 index 0000000000..e5577e7383 --- /dev/null +++ b/dist/assets/examples/es/03_Arrays/03_Walk_Over_2dArray.js @@ -0,0 +1,85 @@ +/* + * @name Walk Over 2dArray + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to display 2D array contents on the canvas +using regular for and for-of loops in multiple different ways.
+ A function is created for the canvas, the 2D + array (Friend Array) is initialized and walked over using nested + loops in different ways. Variables x and y are used to place the + array item on the canvas in the form of 2D array. + The final nested loop is used to initialize 2D + array (Fish Array) with random Integers (fish ages). +*/ + + +//"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/dist/assets/examples/es/04_Control/00_Iteration.js b/dist/assets/examples/es/04_Control/00_Iteration.js new file mode 100644 index 0000000000..39cb8ac76d --- /dev/null +++ b/dist/assets/examples/es/04_Control/00_Iteration.js @@ -0,0 +1,41 @@ +/* + * @name Iteración + * @description Iteración con una estructura "for" para construir figuras repetitivas. + */ +let y; +let num = 14; + +function setup() { + createCanvas(720, 360); + background(102); + noStroke(); + + // Dibujar barras blancas + fill(255); + y = 60; + for (let i = 0; i < num / 3; i++) { + rect(50, y, 475, 10); + y += 20; + } + + // Barras grises + 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; + } + + // Líneas delgadas + y = 45; + fill(0); + for (let i = 0; i < num - 1; i++) { + rect(120, y, 40, 1); + y += 20; + } +} diff --git a/dist/assets/examples/es/04_Control/01_Embedded_Iteration.js b/dist/assets/examples/es/04_Control/01_Embedded_Iteration.js new file mode 100644 index 0000000000..b1e58b0628 --- /dev/null +++ b/dist/assets/examples/es/04_Control/01_Embedded_Iteration.js @@ -0,0 +1,21 @@ +/* + * @name Iteración anidada + * @description Anidar estructuras "for" permite repetición en dos dimensiones. + */ +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/dist/assets/examples/es/04_Control/02_Conditionals_1.js b/dist/assets/examples/es/04_Control/02_Conditionals_1.js new file mode 100644 index 0000000000..f101596663 --- /dev/null +++ b/dist/assets/examples/es/04_Control/02_Conditionals_1.js @@ -0,0 +1,26 @@ +/* + * @name Condicionales 1 + * @description Las condiciones son como preguntas. + * Permiten que un programa decida ejecutar una acción + * si la respuesta a una pregunta es afirmativa o hacer otra + * acción si la respuesta a la pregunta es negativa. + * Las preguntas formuladas dentro de un programa son siempre + * instrucciones lógicas o relacionales. Por ejemplo, si la + * variable 'i' es igual a cero, entonces dibuja una línea. + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 10; i < width; i += 10) { + // Si 'i' divide a 20 sin resto, dibuja la primera línea + // en caso contrario, dibuja la segunda línea + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + } else { + stroke(153); + line(i, 20, i, 180); + } + } +} diff --git a/dist/assets/examples/es/04_Control/03_Conditionals_2.js b/dist/assets/examples/es/04_Control/03_Conditionals_2.js new file mode 100644 index 0000000000..b2324c682c --- /dev/null +++ b/dist/assets/examples/es/04_Control/03_Conditionals_2.js @@ -0,0 +1,29 @@ +/* + * @name Condicionales 2 + * @description Extendemos el lenguaje de los condicionales + * del ejemplo anterior añadiendo la palabra clave "else". + * Esto permite construir condicionales que preguntan + * dos o más preguntas en secuencia, cada una con una acción + * asociada. + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 2; i < width - 2; i += 4) { + // Si 'i' divide a 20 sin resto + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + // Si 'i' divide a 10 sin resto + } else if (i % 10 === 0) { + stroke(153); + line(i, 20, i, 180); + // Si ninguna de las condiciones anteriores es cierta, + // entonces dibuja esta línea + } else { + stroke(102); + line(i, height / 2, i, height - 20); + } + } +} diff --git a/dist/assets/examples/es/04_Control/04_Logical_Operators.js b/dist/assets/examples/es/04_Control/04_Logical_Operators.js new file mode 100644 index 0000000000..dd03f26d67 --- /dev/null +++ b/dist/assets/examples/es/04_Control/04_Logical_Operators.js @@ -0,0 +1,42 @@ +/* + * @name Operadores lógicos + * @description Los operadores lógicos AND (&&) y OR (||), (Y y Ó, respectivamente),son usados para + * combinar instrucciones relacionales simples en expresiones más complejas + * El operador NOT (!), NO, es usado para negar una declaración de carácter boolean. + */ +let test = false; + +function setup() { + createCanvas(720, 360); + background(126); + + for (let i = 5; i <= height; i += 5) { + // Y lógico + stroke(0); + if (i > 35 && i < 100) { + line(width / 4, i, width / 2, i); + test = false; + } + + // Ó lógico + stroke(76); + if (i <= 35 || i >= 100) { + line(width / 2, i, width, i); + test = true; + } + + // Probando si un valor boolean es "verdadero" + // La expresión "if(test)" es equivalente a "if(test == true)" + if (test) { + stroke(0); + point(width / 3, i); + } + + // Probando si un valor boolean es "falso" + // La expresión "if(!test)" es equivalente a "if(test == false)" + if (!test) { + stroke(255); + point(width / 4, i); + } + } +} diff --git a/dist/assets/examples/es/04_Control/05_Logical_Operators_2.js b/dist/assets/examples/es/04_Control/05_Logical_Operators_2.js new file mode 100644 index 0000000000..2684feb956 --- /dev/null +++ b/dist/assets/examples/es/04_Control/05_Logical_Operators_2.js @@ -0,0 +1,91 @@ +/* + * @name Logical Operators 2 + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to create Xboxes with one global variable and create conditions with + boolean variables and boolean expressions by utilizing Boolean + operators ||, &&, and ! to do boundary checking.
+ Functions + are created for both the canvas set up as well as the creation of + the boxes. Background color is dependent on the location of the + boxes in the canvas space. When mouse button and key are pressed + simultaneously, the “where” text and box color changes to cyan, + but if the mouse button is clicked alone then the animation will + start. When q or Q are pressed the text “Did you type q or Q?” + will change to blue, else it will be purple. If the mouse is placed + within the orange box containing the text, “withinRect” then the + shape will turn pink. + */ + + +//1 coordinate for everything :) +let where = 0; //control boxes' positions + +function setup() { + createCanvas(400, 400); +} + +function draw() { + //similar to slide 4 use of OR, || + //to set bg color of canvas + if ((where < 0) || (where > height)) { + background("beige"); + } else { + background("chocolate"); + } + + //similar to slide 4 use of AND, && + //to set fill color of box & text + if (mouseIsPressed && keyIsPressed) { + fill("cyan"); + } else { + fill(255); + } + + //boxL + rect(where, where, 40); + + //boxR, pad x coordinate for size of box + rect(width - where - 40, where, 40); + + //Move the boxes + where = where + 1; + + //Show the value of where the boxes are + text("where is " + where, 150, 30); + + //testing not, ! and or, || operators + if (!(key === "q" || key === "Q")) { + fill("purple"); + } else { + fill("dodgerBlue"); + } + //Show the current key value + text("Did you type a q or Q? " + key, 150, 70); + + //*** Boundary checking *** + //Is the mouse within rect boundary? + //left, right, top, bottom + let withinRect = (mouseX >= 150) && + (mouseX <= 150 + 100) && + (mouseY >= 300) && + (mouseY <= 300 + 40); + //fill color based on value of withinRect + if (withinRect) { + fill("pink"); + } else { + fill("orange"); + } + //draw the rect + rect(150, 300, 100, 40); + //show withinRect value as label on rect + fill(0); + text("withinRect " + withinRect, 160, 320); +} + +//boxes restart +function mousePressed() { + //Reset boxes back up and above the canvas + where = -50; +} \ No newline at end of file diff --git a/dist/assets/examples/es/04_Control/06_Conditional_Shapes.js b/dist/assets/examples/es/04_Control/06_Conditional_Shapes.js new file mode 100644 index 0000000000..8d544e9081 --- /dev/null +++ b/dist/assets/examples/es/04_Control/06_Conditional_Shapes.js @@ -0,0 +1,48 @@ +/* + * @name Conditional Shapes + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to draw different shapes mid canvas depending on the mouse position.
+ Functions + are created for the main canvas set up with the markers on the left and + right hand sides. One is also created for the location of the mouse + regarding the canvas and the markers. If the mouse is within the + outer left hand beige rectangle, then the shape of circle is drawn + down the center of the canvas. If the mouse is within the outer right + hand beige rectangle, then the shape of square is drawn down the + center of the canvas. +*/ +function setup() { + createCanvas(400, 400); + strokeWeight(3); + //center squares to match circles + rectMode(CENTER); + + //draw rects to mark far sides + noStroke(); + fill("beige"); + rect(5, height / 2, 10, height); + rect(width - 5, height / 2, 10, height); + fill("orange"); + stroke("brown"); + + } + + function draw() { + point(mouseX, mouseY); + + //if (test) {doThis; } + //test: mouseX on far left of canvas + //doThis: draw a circle at mouseY + if (mouseX < 10) { + circle(width / 2, mouseY, 20); + } + + //test: mouseX on far right of canvas + //doThis: draw a square at mouseY + if (mouseX > width - 10) { + square(width / 2, mouseY, 20); + } + + } diff --git a/dist/assets/examples/es/05_Image/00_Load_and_Display_Image.js b/dist/assets/examples/es/05_Image/00_Load_and_Display_Image.js new file mode 100644 index 0000000000..a7ef6fd310 --- /dev/null +++ b/dist/assets/examples/es/05_Image/00_Load_and_Display_Image.js @@ -0,0 +1,21 @@ +/* + * @name Cargar y mostrar imagen + * @description Las imágenes pueden ser cargadas y mostradas en la pantalla en su tamaño original o cualquier otro. + *

Para correr este ejemplo localmente, necesitarás un archivo de imagen + * y un + * servidor local.

corriendo. + */ + +let img; // Declarar variable 'img'. + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // Cargar la imagen +} + +function draw() { + // Muestra la imagen en su tamaño original en la posición (0,0) + image(img, 0, 0); + // Muestra la imagen en la posición (0, height/2) a la mitad del tamaño + image(img, 0, height / 2, img.width / 2, img.height / 2); +} diff --git a/dist/assets/examples/es/05_Image/01_Background_Image.js b/dist/assets/examples/es/05_Image/01_Background_Image.js new file mode 100644 index 0000000000..9d55cbd1f9 --- /dev/null +++ b/dist/assets/examples/es/05_Image/01_Background_Image.js @@ -0,0 +1,31 @@ +/* + * @name Imagen de fondo + * @description Este ejemplo presenta la manera más rápida de cargar una + * imagen de fondo. Para cargar una imagen como fondo, + * idebe tener el mismo ancho y altura que el programa. + *

Para correr este ejemplo localmente, necesitarás un archivo de imagen + * y un + * servidor local.

corriendo. + */ + +let bg; +let y = 0; + +function setup() { + // La imagen de fondo debe tener el mismo tamaño que el lienzo, según el método createCanvas(). + // En este programa, el tamaño de la imagen es de 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/dist/assets/examples/es/05_Image/02_Transparency.js b/dist/assets/examples/es/05_Image/02_Transparency.js new file mode 100644 index 0000000000..a0a191e6ad --- /dev/null +++ b/dist/assets/examples/es/05_Image/02_Transparency.js @@ -0,0 +1,24 @@ +/* + * @name Transparencia + * @description Mueve el cursor de izquierda a derecha a lo largo de la imagen para cambiar su + * posición. Este program superpone una imagen sobre otra, modificando el valor alpha de la imagen con la función tint(). + *

Para correr este ejemplo localmente, necesitarás un archivo de imagen + * y un + * servidor local.

corriendo. + */ +let img; +let offset = 0; +let easing = 0.05; + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // Cargar una imagen al programa +} + +function draw() { + image(img, 0, 0); // Mostrar al máximo de opacidad + let dx = mouseX - img.width / 2 - offset; + offset += dx * easing; + tint(255, 127); // Mostrar a media opacidad + image(img, offset, 0); +} diff --git a/dist/assets/examples/es/05_Image/03_Alpha_Mask.js b/dist/assets/examples/es/05_Image/03_Alpha_Mask.js new file mode 100644 index 0000000000..ed747c4428 --- /dev/null +++ b/dist/assets/examples/es/05_Image/03_Alpha_Mask.js @@ -0,0 +1,28 @@ +/* + * @name Alpha Mask + * @description 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. + *

Para correr este ejemplo localmente, necesitarás un archivo de imagen + * y un + * servidor local.

corriendo. + */ +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/dist/assets/examples/es/05_Image/04_Create_Image.js b/dist/assets/examples/es/05_Image/04_Create_Image.js new file mode 100644 index 0000000000..fca9f40817 --- /dev/null +++ b/dist/assets/examples/es/05_Image/04_Create_Image.js @@ -0,0 +1,25 @@ +/* + * @name Crear una imagen + * @description La función createImage() provee un buffer fresco de pixeles para experimentar. + * Este ejemplo crea un gradiente de imagen. + */ +let img; // Declarar 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/dist/assets/examples/es/05_Image/05_Pointillism.js b/dist/assets/examples/es/05_Image/05_Pointillism.js new file mode 100644 index 0000000000..64d29a6919 --- /dev/null +++ b/dist/assets/examples/es/05_Image/05_Pointillism.js @@ -0,0 +1,33 @@ +/* + * @name Puntillismo + * @description Por Dan Shiffman. La posición horizontal del ratón controla el tamaño de + * los puntos. Crea un efecto puntillista simple usando elipses coloreadas según los pixeles en una imagen. + *

Para correr este ejemplo localmente, necesitarás un archivo de imagen + * y un + * servidor local.

corriendo. + */ +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/dist/assets/examples/es/05_Image/06_Blur.js b/dist/assets/examples/es/05_Image/06_Blur.js new file mode 100644 index 0000000000..2374bc0345 --- /dev/null +++ b/dist/assets/examples/es/05_Image/06_Blur.js @@ -0,0 +1,89 @@ +/* + * @name Blur + * @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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/es/05_Image/07_EdgeDetection.js b/dist/assets/examples/es/05_Image/07_EdgeDetection.js new file mode 100644 index 0000000000..2c0509d44b --- /dev/null +++ b/dist/assets/examples/es/05_Image/07_EdgeDetection.js @@ -0,0 +1,93 @@ +/* + * @name Edge Detection + * @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 + */ +// 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); +} diff --git a/dist/assets/examples/es/05_Image/08_Brightness.js b/dist/assets/examples/es/05_Image/08_Brightness.js new file mode 100644 index 0000000000..3c58a98876 --- /dev/null +++ b/dist/assets/examples/es/05_Image/08_Brightness.js @@ -0,0 +1,63 @@ +/* + * @name Brightness + * @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 + */ +// 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(); +} \ No newline at end of file diff --git a/dist/assets/examples/es/05_Image/09_Convolution.js b/dist/assets/examples/es/05_Image/09_Convolution.js new file mode 100644 index 0000000000..eb953c6729 --- /dev/null +++ b/dist/assets/examples/es/05_Image/09_Convolution.js @@ -0,0 +1,91 @@ +/* + * @name Convolution + * @description 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.

+ */ + +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); +} \ No newline at end of file diff --git a/dist/assets/examples/es/05_Image/10_Copy_Method.js b/dist/assets/examples/es/05_Image/10_Copy_Method.js new file mode 100644 index 0000000000..8d7db11f81 --- /dev/null +++ b/dist/assets/examples/es/05_Image/10_Copy_Method.js @@ -0,0 +1,20 @@ +/* + * @name Método copy() + * @frame 600,400 + * @description Un ejemplo de cómo simular colorear una imagen con el método copy(). + */ +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/dist/assets/examples/es/07_Color/00_Hue.js b/dist/assets/examples/es/07_Color/00_Hue.js new file mode 100644 index 0000000000..7f017b3733 --- /dev/null +++ b/dist/assets/examples/es/07_Color/00_Hue.js @@ -0,0 +1,26 @@ +/* + * @name Tinte + * @description El tinte es el color reflejado o transmitidio + * a través de un objecto y es típicamente nombrado como + * el nombre del color (rojo, azul, amarillo, etc). + * Mueve el cursor verticalmente sobre cada barra para alterar su tinte. + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, height, height, height); + noStroke(); + background(0); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(mouseY, height, height); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/es/07_Color/01_Saturation.js b/dist/assets/examples/es/07_Color/01_Saturation.js new file mode 100644 index 0000000000..c7728a7978 --- /dev/null +++ b/dist/assets/examples/es/07_Color/01_Saturation.js @@ -0,0 +1,25 @@ +/* + * @name Saturación + * @description La saturación es la fuerza o pureza del color y + * representa la cantidad de gris en proporción al tinte. + * Un color "saturado" es puro y uno "insaturado" tiene un gran porcentaje de gris. + * Mueve el cursor verticalmente sobre cada barra para alterar su saturación. + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, width, height, 100); + noStroke(); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(barX, mouseY, 66); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/es/07_Color/02_Brightness.js b/dist/assets/examples/es/07_Color/02_Brightness.js new file mode 100644 index 0000000000..475142942a --- /dev/null +++ b/dist/assets/examples/es/07_Color/02_Brightness.js @@ -0,0 +1,46 @@ +/* + * @name Brillo + * @description Por Dan Shiffman. Este programa ajusta el brillo de una parte de + * la imagen, calculando la distancia de cada pixel al ratón. + *

Para correr este ejemplo localmente, necesitarás al menos un archivo de imagen + * y un servidor local corriendo.

+ */ +let img; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 200); + pixelDensity(1); + img.loadPixels(); + loadPixels(); +} + +function draw() { + for (let x = 0; x < img.width; x++) { + for (let y = 0; y < img.height; y++) { + // Calcular la posición 1D de una matriz 2D + let loc = (x + y * img.width) * 4; + // Obtener los valores R,G,B de una imagen + let r, g, b; + r = img.pixels[loc]; + // Calcular una cantidad a cambiar de brillo basado en la proximidad al ratón + let maxdist = 50; + let d = dist(x, y, mouseX, mouseY); + let adjustbrightness = (255 * (maxdist - d)) / maxdist; + r += adjustbrightness; + // Limitar RGB para asegurarse de estar dentro del rango 0-255 de color + r = constrain(r, 0, 255); + // Hacer un nuevo color y definir el pixel en la ventana + //color c = color(r, g, b); + let pixloc = (y * width + x) * 4; + pixels[pixloc] = r; + pixels[pixloc + 1] = r; + pixels[pixloc + 2] = r; + pixels[pixloc + 3] = 255; + } + } + updatePixels(); +} diff --git a/dist/assets/examples/es/07_Color/03_Color_Variables.js b/dist/assets/examples/es/07_Color/03_Color_Variables.js new file mode 100644 index 0000000000..f13cd859aa --- /dev/null +++ b/dist/assets/examples/es/07_Color/03_Color_Variables.js @@ -0,0 +1,40 @@ +/* + * @name Variables de color + * @description (Homenajen a Albers.) Este ejemplo crea variables de colores + * que pueden ser referenciadas en el programa por un nombre, en vez de un número. + */ +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); + + // Estas instrucciones son equivalentes a las de arriba. + // Los programadores pueden usar el formato que prefieran. + //color inside = #CC6600; + //color middle = #CC9900; + //color outside = #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/dist/assets/examples/es/07_Color/04_Relativity.js b/dist/assets/examples/es/07_Color/04_Relativity.js new file mode 100644 index 0000000000..64b6555506 --- /dev/null +++ b/dist/assets/examples/es/07_Color/04_Relativity.js @@ -0,0 +1,34 @@ +/* + * @name Relatividad + * @description Cada colores es percibido en relación a los otros colores. Las barras superiores e inferiores + * contienen los mismos componentes de color, pero con un distinto orden causa que + * los colores individuales aparezcan como distintos. + */ +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(); // Ejecutar draw() solo una vez +} + +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/dist/assets/examples/es/07_Color/05_Linear_Gradient.js b/dist/assets/examples/es/07_Color/05_Linear_Gradient.js new file mode 100644 index 0000000000..29fbefabf9 --- /dev/null +++ b/dist/assets/examples/es/07_Color/05_Linear_Gradient.js @@ -0,0 +1,52 @@ +/* + * @name Gradiente linear + * @description La función lerpColor() es útil para interpolar entre + * dos colores. + */ +// Constantes +const Y_AXIS = 1; +const X_AXIS = 2; +let b1, b2, c1, c2; + +function setup() { + createCanvas(710, 400); + + // Definir colores + b1 = color(255); + b2 = color(0); + c1 = color(204, 102, 0); + c2 = color(0, 102, 153); + + noLoop(); +} + +function draw() { + // Fondo + setGradient(0, 0, width / 2, height, b1, b2, X_AXIS); + setGradient(width / 2, 0, width / 2, height, b2, b1, X_AXIS); + // Frente + 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) { + // Gradiente de arriba a abajo + 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) { + // Gradiente de izquierda a derecha + 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/dist/assets/examples/es/07_Color/06_Radial_Gradient.js b/dist/assets/examples/es/07_Color/06_Radial_Gradient.js new file mode 100644 index 0000000000..e100618494 --- /dev/null +++ b/dist/assets/examples/es/07_Color/06_Radial_Gradient.js @@ -0,0 +1,33 @@ +/* + * @name Gradiente radial + * @description Dibuja una serie de círculos concéntros para crear un gradiente + * de un color a otro. + */ +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/dist/assets/examples/es/07_Color/07_Lerp_Color.js b/dist/assets/examples/es/07_Color/07_Lerp_Color.js new file mode 100644 index 0000000000..69bb8f24ce --- /dev/null +++ b/dist/assets/examples/es/07_Color/07_Lerp_Color.js @@ -0,0 +1,49 @@ +/* + * @name Interpolación de color + * @description Crea figuras aleatorias, + * interpola su color de rojo a azul. + */ +function setup() { + createCanvas(720, 400); + background(255); + noStroke(); +} + +function draw() { + background(255); + from = color(255, 0, 0, 0.2 * 255); + to = color(0, 0, 255, 0.2 * 255); + c1 = lerpColor(from, to, 0.33); + c2 = lerpColor(from, to, 0.66); + for (let i = 0; i < 15; i++) { + fill(from); + quad( + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height) + ); + fill(c1); + quad( + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height) + ); + fill(c2); + quad( + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height) + ); + fill(to); + quad( + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height) + ); + } + frameRate(5); +} diff --git a/dist/assets/examples/es/08_Math/00_incrementdecrement.js b/dist/assets/examples/es/08_Math/00_incrementdecrement.js new file mode 100644 index 0000000000..8456e6486b --- /dev/null +++ b/dist/assets/examples/es/08_Math/00_incrementdecrement.js @@ -0,0 +1,42 @@ +/* + * @name Incremento y decremento + * @description Escribir "a++" es equivalente a"a = a + 1". + * Escribir "a--" es equivalente a "a = a - 1". + */ +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/dist/assets/examples/es/08_Math/01_operatorprecedence.js b/dist/assets/examples/es/08_Math/01_operatorprecedence.js new file mode 100644 index 0000000000..c2d92dac05 --- /dev/null +++ b/dist/assets/examples/es/08_Math/01_operatorprecedence.js @@ -0,0 +1,54 @@ +/* + * @name Precedencia de operadores + * @description Si no defines explicitamente el orden en que una + * expresión es evaluada, son evaluadas basándose en la precedencia de operador. + * Por ejemplo, en la instrucción "4+2*8", el 2 será + * primero multiplicado por 8 y luego el resultado será sumado a 4. + * Esto ocurre porque el "*" tiene una precedencia más alta que el "+". Para evitar + * ambigüedad al leer el programa, se recomienda escribir esta instrucción + * como "4+(2*8)". El orden de evaluación puede ser controlado por + * la ubicación de paréntesis en el código. Una tabla de precedencia + * de operadores sigue a continuación. + */ +// La precedencia más alta está al principio de esta lista y +// la más baja al final. +// Multiplicativo: * / % +// Aditivo: + - +// Relacional: < > <= >= +// Igualdad: == != +// AND lógico: && +// OR lógico: || +// Asignación: = += -= *= /= %= +function setup() { + createCanvas(710, 400); + background(51); + noFill(); + stroke(51); + + stroke(204); + for (let i = 0; i < width - 20; i += 4) { + // El 30 es sumado a 70 y luego se evalúa + // si esto es mayor al valor actual de "i" + // Por claridad, escribe "if (i > (30 + 70)) {" + if (i > 30 + 70) { + line(i, 0, i, 50); + } + } + + stroke(255); + // El 2 es multiplicado por 8 y el resultado es sumado a el 4 + // Por claridad, escribe "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) { + // Las instrucciones relacionales son evaluadas + // primero, y luego las declaraciones lógicas AND y + // finalmente el OR lógico. Por claridad, escribe: + // "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/dist/assets/examples/es/08_Math/02_distance1d.js b/dist/assets/examples/es/08_Math/02_distance1d.js new file mode 100644 index 0000000000..70e494b6c1 --- /dev/null +++ b/dist/assets/examples/es/08_Math/02_distance1d.js @@ -0,0 +1,65 @@ +/* + * @name Distancia 1D + * @description Mueve el ratón hacia la izquierda y derecha para controlar + * la velocidad y la dirección de las figuras moviéndose. + */ +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/dist/assets/examples/es/08_Math/03_distance2d.js b/dist/assets/examples/es/08_Math/03_distance2d.js new file mode 100644 index 0000000000..90268132a4 --- /dev/null +++ b/dist/assets/examples/es/08_Math/03_distance2d.js @@ -0,0 +1,24 @@ +/* + * @name Distancia 2D + * @description Mueve el ratón a lo largo de la imagen para oscurecer + * y revelar la matriz. Mide la distancia desde el ratón hasta cada cuadrado y define su tamaño proporcionalmente. + */ +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/dist/assets/examples/es/08_Math/04_sine.js b/dist/assets/examples/es/08_Math/04_sine.js new file mode 100644 index 0000000000..4749a1be59 --- /dev/null +++ b/dist/assets/examples/es/08_Math/04_sine.js @@ -0,0 +1,27 @@ +/* + * @name Seno + * @description Escala suavemente el tamaño con la función seno sin(). + */ +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/dist/assets/examples/es/08_Math/05_sincosine.js b/dist/assets/examples/es/08_Math/05_sincosine.js new file mode 100644 index 0000000000..c903521c5d --- /dev/null +++ b/dist/assets/examples/es/08_Math/05_sincosine.js @@ -0,0 +1,43 @@ +/* + * @name Seno y coseno + * @description Movimiento lineal con las funciones sin() y cos(). + * Números entre 0 y PI*2 + * son usados como argumento para estas funciones, que retornan números -1 y 1. + * Estos valores son luego escalados para producir movimientos de mayor magnitud. + */ +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/dist/assets/examples/es/08_Math/06_sinewave.js b/dist/assets/examples/es/08_Math/06_sinewave.js new file mode 100644 index 0000000000..072e2b5c70 --- /dev/null +++ b/dist/assets/examples/es/08_Math/06_sinewave.js @@ -0,0 +1,48 @@ +/* + * @name Onda sinusoidal + * @description Dibuja una onda sinusoidal simple. + * Original por Daniel Shiffman. + */ + +let xspacing = 16; // Distancia entre posiciones horizontales +let w; // Ancho de la onda entera +let theta = 0.0; // Ángulo inicial en 0 +let amplitude = 75.0; // Altura de la onda +let period = 500.0; // Cantidad de pixeles antes de que la onda se repita +let dx; // Valor de incremento en eje x +let yvalues; // Uso de un arreglo para guardar los valores de altura de la onda + +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() { + // Incrementar theta (prueba valores distintos de + // 'velocidad angular' aquí + theta += 0.02; + + // Por cada valor de x, calcula un valor de y con la función sin() + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = sin(x) * amplitude; + x += dx; + } +} + +function renderWave() { + noStroke(); + fill(255); + // Una manera simple de dibujar la onda con una elipse en cada punto + for (let x = 0; x < yvalues.length; x++) { + ellipse(x * xspacing, height / 2 + yvalues[x], 16, 16); + } +} diff --git a/dist/assets/examples/es/08_Math/07_additivewave.js b/dist/assets/examples/es/08_Math/07_additivewave.js new file mode 100644 index 0000000000..884ba5eec6 --- /dev/null +++ b/dist/assets/examples/es/08_Math/07_additivewave.js @@ -0,0 +1,70 @@ +/* + * @name Onda aditiva + * @description Crea una onda más compleja sumando otras dos ondas. + * Original por Daniel Shiffman + */ +let xspacing = 8; // Distancia entre cada posición en eje x +let w; // Ancho de la onda +let maxwaves = 4; // número total de ondas a sumarse + +let theta = 0.0; +let amplitude = new Array(maxwaves); // Altura de la onda +// Valor para incrementar x, a ser calculado como +// una función de periodo y espaciado en x +let dx = new Array(maxwaves); +// Uso de un arreglo para almacenar los valores de altura +// de la onda (no es del todo necesario) +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); // Número de pixeles antes que la onda se repita + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new Array(floor(w / xspacing)); +} + +function draw() { + background(0); + calcWave(); + renderWave(); +} + +function calcWave() { + // Incrementar theta (pruebas otros valores + // de 'velocidad angular' aquí + theta += 0.02; + + // Hacer cero todos los valores de altura + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // Valores acumulados de altura de onda + for (let j = 0; j < maxwaves; j++) { + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + // Cada otra onda es coseno en vez de seno + if (j % 2 == 0) yvalues[i] += sin(x) * amplitude[j]; + else yvalues[i] += cos(x) * amplitude[j]; + x += dx[j]; + } + } +} + +function renderWave() { + // Una manera simple de dibujar la onda, con una elipse en cada punto + 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/dist/assets/examples/es/08_Math/08_polartocartesian.js b/dist/assets/examples/es/08_Math/08_polartocartesian.js new file mode 100644 index 0000000000..f9c7bd8d1d --- /dev/null +++ b/dist/assets/examples/es/08_Math/08_polartocartesian.js @@ -0,0 +1,44 @@ +/* + * @name Polar a cartesiano + * @description Convierte una coordenada polar (r,theta) + * a cartesiana (x,y): x = r*cos(theta), y = r*sin(theta) + * Original por Daniel Shiffman. + */ +let r; + +// Ángulo, velocidad angular, aceleración angular +let theta; +let theta_vel; +let theta_acc; + +function setup() { + createCanvas(710, 400); + + // Inicializar todos los valores + r = height * 0.45; + theta = 0; + theta_vel = 0; + theta_acc = 0.0001; +} + +function draw() { + background(0); + + // Traslada el punto de origen al centro del lienzo + translate(width / 2, height / 2); + + // Convierte de polar a cartesiano + let x = r * cos(theta); + let y = r * sin(theta); + + // Dibuja la elipse en la coordenada cartesiana + ellipseMode(CENTER); + noStroke(); + fill(200); + ellipse(x, y, 32, 32); + + // Applica aceleración y velocidad al ángulo + // (r permance estático en este ejemplo) + theta_vel += theta_acc; + theta += theta_vel; +} diff --git a/dist/assets/examples/es/08_Math/09_arctangent.js b/dist/assets/examples/es/08_Math/09_arctangent.js new file mode 100644 index 0000000000..7c695d57c7 --- /dev/null +++ b/dist/assets/examples/es/08_Math/09_arctangent.js @@ -0,0 +1,45 @@ +/* + * @name Arcotangente + * @description Mueve el ratón para cambiar la dirección de los ojos.
La función atan2() calcula el ángulo entre cada ojo y el cursor. + */ +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(); + }; +} diff --git a/dist/assets/examples/es/08_Math/10_Interpolate.js b/dist/assets/examples/es/08_Math/10_Interpolate.js new file mode 100644 index 0000000000..58505b4a24 --- /dev/null +++ b/dist/assets/examples/es/08_Math/10_Interpolate.js @@ -0,0 +1,34 @@ +/* + * @name Interpolación Lineal + * @frame 720, 400 + * @description Mueve el ratón a través de la pantalla y el símbolo le seguirá. + * Entre cada fotograma de la animación, la elipse se mueve parte + * de la distancia (0,05) desde su posición actual hacia el cursor + * usando la función lerp(). + * Esto es equivalente al uso de Easing en la sección Input, sólo que con lerp() en su lugar... + */ + +let x = 0; +let y = 0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(51); + + // lerp() calcula un número entre dos números en un incremento específico. + // El parámetro amt (amount) es la cantidad a interpolar entre los dos valores + // donde 0,0 es igual al primer punto, 0,1 está muy cerca del primer punto, 0,5 + // está a mitad de camino, etc. + + // Aquí estamos moviendo el 5% del camino hacia la ubicación del ratón en cada fotograma + x = lerp(x, mouseX, 0.05); + y = lerp(y, mouseY, 0.05); + + fill(255); + stroke(255); + ellipse(x, y, 66, 66); +} diff --git a/dist/assets/examples/es/08_Math/11_doubleRandom.js b/dist/assets/examples/es/08_Math/11_doubleRandom.js new file mode 100644 index 0000000000..323b84fc1e --- /dev/null +++ b/dist/assets/examples/es/08_Math/11_doubleRandom.js @@ -0,0 +1,24 @@ +/* + * @name Doble aleatorio + * @frame 720,400 (optional) + * @description Usando dos llamadas a la función random() y a la función point() + * crea una línea diente de sierra irregular. + * Original por Ira Greenberg. + */ +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/dist/assets/examples/es/08_Math/12_random.js b/dist/assets/examples/es/08_Math/12_random.js new file mode 100644 index 0000000000..cf79183556 --- /dev/null +++ b/dist/assets/examples/es/08_Math/12_random.js @@ -0,0 +1,19 @@ +/* + * @name Aleatorio + * @description Los números aleatorios son la base de esta imagen. + * Cada vez que el programa es ejecutado, el resultado es distinto. + */ +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/dist/assets/examples/es/08_Math/13_noise1D.js b/dist/assets/examples/es/08_Math/13_noise1D.js new file mode 100644 index 0000000000..ad16c996f5 --- /dev/null +++ b/dist/assets/examples/es/08_Math/13_noise1D.js @@ -0,0 +1,31 @@ +/* + * @name Ruido 1D + * @description Uso de ruido Perlin 1D para asignar ubicación. + */ +let xoff = 0.0; +let xincrement = 0.01; + +function setup() { + createCanvas(710, 400); + background(0); + noStroke(); +} + +function draw() { + // Crear un fondo traslúcido + fill(0, 10); + rect(0, 0, width, height); + + //let n = random(0,width); // Prueba esta línea en vez del ruido (noise) + + // Obtener un valor de ruido basado en xoff y escalarlo + // según el ancho de la ventana + let n = noise(xoff) * width; + + // Incrementar xoff en cada ciclo + xoff += xincrement; + + // Dibujar la elipse en la coordenada producida por el ruido Perlin + fill(200); + ellipse(n, height / 2, 64, 64); +} diff --git a/dist/assets/examples/es/08_Math/14_noisewave.js b/dist/assets/examples/es/08_Math/14_noisewave.js new file mode 100644 index 0000000000..ac8cfeed84 --- /dev/null +++ b/dist/assets/examples/es/08_Math/14_noisewave.js @@ -0,0 +1,42 @@ +/* + * @name Onda de ruido + * @description Uso de ruido Perlin para generar un patrón tipo onda. + * Original por Daniel Shiffman. + */ +let yoff = 0.0; // Segunda dimensión del ruido Perlin + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(51); + + fill(255); + // Dibujaremos un polígono a partir de los puntos de la onda + beginShape(); + + let xoff = 0; // Opción #1: ruido 2D + // let xoff = yoff; // Opción #2: ruido 1D + + // Iterar sobre los pixeles horizontales + for (let x = 0; x <= width; x += 10) { + // Calcular un valor de y según el ruido, escalar según + + // Opción #1: ruido 2D + let y = map(noise(xoff, yoff), 0, 1, 200, 300); + + // Opción #2: ruido 1D + // let y = map(noise(xoff), 0, 1, 200,300); + + // Definir el vértice + vertex(x, y); + // Incrementar la dimensión x para el ruido + xoff += 0.05; + } + // Incrementar la dimensión y para el ruido + yoff += 0.01; + vertex(width, height); + vertex(0, height); + endShape(CLOSE); +} diff --git a/dist/assets/examples/es/08_Math/15_Noise2D.js b/dist/assets/examples/es/08_Math/15_Noise2D.js new file mode 100644 index 0000000000..9640287af8 --- /dev/null +++ b/dist/assets/examples/es/08_Math/15_Noise2D.js @@ -0,0 +1,42 @@ +/* + * @name Ruido 2D + * @frame 710,400 (optional) + * @description Crear un ruido 2D con parámetros diferentes. + * + */ + +let noiseVal; +let noiseScale = 0.02; + +function setup() { + createCanvas(640, 360); +} + +function draw() { + background(0); + // Dibujar la mitad izquierda de la imagen + for (let y = 0; y < height - 30; y++) { + for (let x = 0; x < width / 2; x++) { + // noiceDetail (detalle del ruido) del número de octavas y valor de caída de los píxeles + noiseDetail(2, 0.2); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // Dibujar la mitad derecha de la imagen + for (let y = 0; y < height - 30; y++) { + for (let x = width / 2; x < width; x++) { + // noiceDetail (detalle del ruido) del número de octavas y valor de caída de los píxeles + noiseDetail(5, 0.5); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + //Mostrar los detalles de las dos particiones + textSize(18); + fill(255, 255, 255); + text('Noice2D with 2 octaves and 0.2 falloff', 10, 350); + text('Noice2D with 1 octaves and 0.7 falloff', 330, 350); +} diff --git a/dist/assets/examples/es/08_Math/16_Noise3D.js b/dist/assets/examples/es/08_Math/16_Noise3D.js new file mode 100644 index 0000000000..9153f0b794 --- /dev/null +++ b/dist/assets/examples/es/08_Math/16_Noise3D.js @@ -0,0 +1,47 @@ +/* + * @name Ruido 3D + * @frame 710,400 (optional) + * @description Uso de ruido 3D para crear una simple textura animada. + */ +let noiseVal; +//Incrementar x en 0,01 +let x_increment = 0.01; +//Incrementar z en 0.02 cada ciclo de draw() +let z_increment = 0.02; + +//Valores de desviación +let z_off, y_off, x_off; + +function setup() { + //Crear el Lienzo + createCanvas(640, 360); + //Definir la velocidad de cuadro + frameRate(20); + //Valor inicial de z_off + z_off = 0; +} + +function draw() { + x_off = 0; + y_off = 0; + //Hacer que el fondo sea negro + background(0); + //Ajustar el detalle del ruido + noiseDetail(8, 0.65); + + //Para cada x,y calcular el valor del ruido + for (let y = 0; y < height; y++) { + x_off += x_increment; + y_off = 0; + + for (let x = 0; x < width; x++) { + //Calcular y dibujar cada píxel + 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/dist/assets/examples/es/08_Math/17_Randomchords.js b/dist/assets/examples/es/08_Math/17_Randomchords.js new file mode 100644 index 0000000000..600d27afb5 --- /dev/null +++ b/dist/assets/examples/es/08_Math/17_Randomchords.js @@ -0,0 +1,34 @@ +/* + * @name Cuerdas Aleatorias + * @description Acumula cuerdas al azar de un círculo. Cada cuerda es translúcida, + * de modo que se acumulan para dar la ilusión de una esfera sombreada. + * Contribución de Aatish Bhatia, inspirado en Anders Hoff + */ +function setup() { + createCanvas(400, 400); + background(255, 255, 255); + + // trazo translúcido usando el valor alfa + stroke(0, 0, 0, 15); +} + +function draw() { + // trazar dos cuerdas al azar en cada cuadro + randomChord(); + randomChord(); +} + +function randomChord() { + // encontrar un punto aleatorio en un círculo + let angle1 = random(0, 2 * PI); + let xpos1 = 200 + 200 * cos(angle1); + let ypos1 = 200 + 200 * sin(angle1); + + // encontrar otro punto aleatorio en el círculo + let angle2 = random(0, 2 * PI); + let xpos2 = 200 + 200 * cos(angle2); + let ypos2 = 200 + 200 * sin(angle2); + + // trazar una línea entre ellos + line(xpos1, ypos1, xpos2, ypos2); +} diff --git a/dist/assets/examples/es/08_Math/18_Map.js b/dist/assets/examples/es/08_Math/18_Map.js new file mode 100644 index 0000000000..1d293e8a20 --- /dev/null +++ b/dist/assets/examples/es/08_Math/18_Map.js @@ -0,0 +1,22 @@ +/* + * @name Mapear + * @description Utiliza la función map() para tomar cualquier número y escalarlo a un + * nuevo número que sea más útil para el proyecto en el que estés trabajando. + * Por ejemplo, usa los números de la posición del ratón para controlar el tamaño o el color de una figura. + * En este ejemplo, la coordenada x del ratón (números entre 0 y 360) se escalan a nuevos números + * para definir el color y el tamaño de un círculo. + */ +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(0); + // Escala el valor de mouseX de 0 a 720 a un rango entre 0 y 175 + let c = map(mouseX, 0, width, 0, 175); + // Escala el valor de mouseX de 0 a 720 a un rango entre 40 y 300 + let d = map(mouseX, 0, width, 40, 300); + fill(255, c, 0); + ellipse(width/2, height/2, d, d); +} diff --git a/dist/assets/examples/es/08_Math/19_parametricEquation.js b/dist/assets/examples/es/08_Math/19_parametricEquation.js new file mode 100644 index 0000000000..6470ef5ed1 --- /dev/null +++ b/dist/assets/examples/es/08_Math/19_parametricEquation.js @@ -0,0 +1,45 @@ +/* + * @name Ecuaciones Paramétricas + * @description Una ecuación paramétrica es una en la cual las coordenadas x e y + * están escritas en términos de otra variable. + * Esto se llama un parámetro y se suele dar en la letra t o θ. + * La inspiración se tomó del canal de YouTube de Alexander Miller. + */ + +function setup(){ + createCanvas(720,400); +} + +// el parámetro del que dependen x e y +// se suele designar con la letra t o el símbolo de theta +let t = 0; +function draw(){ + background('#fff'); + translate(width/2,height/2); + stroke('#0f0f0f'); + strokeWeight(1.5); + //bucle para añadir 100 líneas + 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; +} +// función para cambiar la coordenada inicial x de la línea +function x1(t){ + return sin(t/10)*125+sin(t/20)*125+sin(t/30)*125; +} + +// función para cambiar la coordenada y inicial de la línea +function y1(t){ + return cos(t/10)*125+cos(t/20)*125+cos(t/30)*125; +} + +// función para cambiar la coordenada x final de la línea +function x2(t){ + return sin(t/15)*125+sin(t/25)*125+sin(t/35)*125; +} + +// función para cambiar la coordenada final de la línea +function y2(t){ + return cos(t/15)*125+cos(t/25)*125+cos(t/35)*125; +} diff --git a/dist/assets/examples/es/08_Math/20_Graphing2DEquations.js b/dist/assets/examples/es/08_Math/20_Graphing2DEquations.js new file mode 100644 index 0000000000..450f33c8ce --- /dev/null +++ b/dist/assets/examples/es/08_Math/20_Graphing2DEquations.js @@ -0,0 +1,52 @@ +/** + * @name Graphing 2D Equations + * @frame 710, 400 + * @description Graphics the following equation: sin(n*cos(r) + 5*theta) where n is a function of horizontal mouse location. Original by Daniel Shiffman + */ +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/dist/assets/examples/es/08_Math/21_parametricEquation.js b/dist/assets/examples/es/08_Math/21_parametricEquation.js new file mode 100644 index 0000000000..83c1a3c336 --- /dev/null +++ b/dist/assets/examples/es/08_Math/21_parametricEquation.js @@ -0,0 +1,44 @@ +/* + * @name Parametric Equations + * @description 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. + */ + +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/dist/assets/examples/es/09_Simulate/00_Forces.js b/dist/assets/examples/es/09_Simulate/00_Forces.js new file mode 100644 index 0000000000..480688a7af --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/00_Forces.js @@ -0,0 +1,140 @@ +/* + * @name Fuerzas + * @description Demostración de múltiples fuerzas actuando en cuerpos + * (natureofcode.com) + */ +// Demonstración de múltiples fuerzas acutando en +// cuerpos (con clase Mover) +// cuerpos sujetos continuamente a gravedad +// cuerpos sujetos a resistencia de fluidos cuando están en el "agua" + +// Cinco cuerpos en movimiento +let movers = []; + +// Líquido +let liquid; + +function setup() { + createCanvas(640, 360); + reset(); + // Crear objeto líquido + liquid = new Liquid(0, height / 2, width, height / 2, 0.1); +} + +function draw() { + background(127); + + // Dibujar el agua + liquid.display(); + + for (let i = 0; i < movers.length; i++) { + + // ¿Está el objeto Mover dentro del objeto líquido? + if (liquid.contains(movers[i])) { + // Calcular fuerza de arrastre + let dragForce = liquid.calculateDrag(movers[i]); + // Aplicar fuerza de arrastre a Mover + movers[i].applyForce(dragForce); + } + + // Aquí se escala la gravedad según la masa + let gravity = createVector(0, 0.1*movers[i].mass); + // Aplicar gravedad + movers[i].applyForce(gravity); + + // Refrescar y mostrar + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } + +} + + +function mousePressed() { + reset(); +} + +// Reiniciar todos los objetos Mover aleatoriamente +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; +}; + +// ¿Está el objeto Mover dentro del objeto líquido? +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; +}; + +// Calcular fuerza de arrastre +Liquid.prototype.calculateDrag = function(m) { + // Magnitud es coeficiente * velocidad al cuadrado + let speed = m.velocity.mag(); + let dragMagnitude = this.c * speed * speed; + + // Dirección es el inverso de la velocidad + let dragForce = m.velocity.copy(); + dragForce.mult(-1); + + // Escalar según magnitud + // 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); +} + +// Segunda ley de Newton: F = M * A +// ó A = F / M +Mover.prototype.applyForce = function(force) { + let f = p5.Vector.div(force,this.mass); + this.acceleration.add(f); +}; + +Mover.prototype.update = function() { + // La velocidad es cambiada según la aceleración + this.velocity.add(this.acceleration); + // La posición es cambiada según la velocidad + this.position.add(this.velocity); + // Borrar aceleración en cada cuadro + 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); +}; + +// Rebotar contra la parte inferior de la ventana +Mover.prototype.checkEdges = function() { + if (this.position.y > (height - this.mass * 8)) { + // Un poco de amortiguamiento al rebotar contra el fondo + this.velocity.y *= -0.9; + this.position.y = (height - this.mass * 8); + } +}; diff --git a/dist/assets/examples/es/09_Simulate/01_ParticleSystem.js b/dist/assets/examples/es/09_Simulate/01_ParticleSystem.js new file mode 100644 index 0000000000..dc994bf66f --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/01_ParticleSystem.js @@ -0,0 +1,73 @@ +/* + * @name Sistema de partículas + * @description Este es un sistema básico de partículas + * (natureofcode.com) + */ +let system; + +function setup() { + createCanvas(720, 400); + system = new ParticleSystem(createVector(width / 2, 50)); +} + +function draw() { + background(51); + system.addParticle(); + system.run(); +} + +// Una clase simple de partícula (Particle) +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(); +}; + +// Método para refrescar posición +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// Método para mostrar en lienzo +Particle.prototype.display = function() { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// ¿La partícula todavía es útil? +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() { + 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/dist/assets/examples/es/09_Simulate/02_Flocking.js b/dist/assets/examples/es/09_Simulate/02_Flocking.js new file mode 100644 index 0000000000..0c2e5a4518 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/02_Flocking.js @@ -0,0 +1,229 @@ +/* + * @name Flocking + * @description Demostración del comportamiento "Flocking" de Craig Reynolds. + *Ver: http://www.red3d.com/cwr/ + * Reglas: cohesión, separación, alineamiento + * (de natureofcode.com). + * Arrastra el mouse para añadir boids al sistema. + */ + + +let flock; + +let text; + +function setup() { + createCanvas(640, 360); + createP("Drag the mouse to generate new boids."); + + flock = new Flock(); + // Añade un conjunto inicial de boids al sistema + for (let i = 0; i < 100; i++) { + let b = new Boid(width / 2,height / 2); + flock.addBoid(b); + } +} + +function draw() { + background(51); + flock.run(); +} + +// Añade un nuevo boid al sistema +function mouseDragged() { + flock.addBoid(new Boid(mouseX, mouseY)); +} + +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Objeto Flock +// Hace pocas cosas, simplemente administra el arreglo de todos los boids + +function Flock() { + // Un arreglo para todos los boids + this.boids = []; // Inicializar el arreglo +} + +Flock.prototype.run = function() { + for (let i = 0; i < this.boids.length; i++) { + this.boids[i].run(this.boids); // Pasar la lista entera de boids a cada boid de forma individual + } +} + +Flock.prototype.addBoid = function(b) { + this.boids.push(b); +} + +// The Nature of Code +// Daniel Shiffman +// http://natureofcode.com + +// Clase Boid +// Métodos para Separación, Cohesión, alineamiento + +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; // Velocidad máxima + this.maxforce = 0.05; // Fuerza de viraje máxima +} + +Boid.prototype.run = function(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); +} + +Boid.prototype.applyForce = function(force) { + // Posibilidad de agregar masa aquí si queremos A = F / M + this.acceleration.add(force); +} + +// Acumular una nueva aceleración cada vez basado en tres reglas +Boid.prototype.flock = function(boids) { + let sep = this.separate(boids); // Separación + let ali = this.align(boids); // Alineamiento + let coh = this.cohesion(boids); // Cohesión + // Dar un peso arbitrario a cada fuerza + sep.mult(1.5); + ali.mult(1.0); + coh.mult(1.0); + // Suma los vectores de fuerza a la aceleración + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); +} + +// Método para actualizar ubicación +Boid.prototype.update = function() { + // Refrescar velocidad + this.velocity.add(this.acceleration); + // Limitar velocidad + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // Resetear acceleración a 0 en cada ciclo + this.acceleration.mult(0); +} + +// Un método que calcula y aplica una fuerza de viraje hacia una posición objetivo +// VIRAJE = DESEADO - VELOCIDAD +Boid.prototype.seek = function(target) { + let desired = p5.Vector.sub(target, this.position); // Un vector apuntando desde la ubicación hacia el objetivo + // Normalizar deseado y escalar según velocidad máxima + desired.normalize(); + desired.mult(this.maxspeed); + // Viraje = Deseado - Velocidad + let steer = p5.Vector.sub(desired, this.velocity); + steer.limit(this.maxforce); // Limita al máximo de fuerza de viraje + return steer; +} + +Boid.prototype.render = function() { + // Dibuja un triángulo rotado en la dirección de la velocidad + 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, salir por un borde y aparecer por el contrario +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; +} + +// Separación +// Método que revisa los boids cercanos y vira para alejarse de ellos +Boid.prototype.separate = function(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // Por cada boid en el sistema, revisa si está muy cerca + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + // Si la distancia es mayor a 0 y menor que una cantidad arbitraria (0 cuando eres tú mismo) + if ((d > 0) && (d < desiredseparation)) { + // Calcular el vector apuntando a alejarse del vecino + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // Peso por distancia + steer.add(diff); + count++; // Mantener registro de cantidad + } + } + // Promedio -- divide por la cantidad + if (count > 0) { + steer.div(count); + } + + // Mientras el vector sea mayor a 0 + if (steer.mag() > 0) { + // Implementa Reynolds: Viraje = Deseado - Velocidad + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; +} + +// Alineamiento +// Para cada boid cercano en el sistema, calcula la velocidad promedio +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); + } +} + +// Cohesión +// Para la ubicación promedio (centro) de todos los boids cercanos, calcula el vector de viraje hacia esa ubicación. +Boid.prototype.cohesion = function(boids) { + let neighbordist = 50; + let sum = createVector(0, 0); // Empieza con un vector vacío para acumular todas las posiciones + 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); // Añada posición + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // Vira hacia la posición + } else { + return createVector(0, 0); + } +} diff --git a/dist/assets/examples/es/09_Simulate/03_WolframCA.js b/dist/assets/examples/es/09_Simulate/03_WolframCA.js new file mode 100644 index 0000000000..8c5f41ed70 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/03_WolframCA.js @@ -0,0 +1,72 @@ +/* + * @name Wolfram CA + * @description Demostración simple de un autómata celular Wolfram unidimensional + * (natureofcode.com) + */ + +let w = 10; +// Arreglo de 1s y 0s +let cells; + + // Arbitrariamente inicializar con solo la célula del medio teniendo un estado de "1" +let generation = 0; + +// Arreglo para almacenar el conjunto de reglas, por ejemplo {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(); + } +} + +// El proceso de crear una nueva generación +function generate() { + //Primero crear un arreglo vacío para los nuevos valores + let nextgen = Array(cells.length); + // Por cada lugar, determinar el nuevo estado según el examen del estado actual y de los estados vecinos + // Ignorar bordes que solo tienen un vecino + for (let i = 1; i < cells.length-1; i++) { + let left = cells[i-1]; // Estado del vecino izquierdo + let me = cells[i]; // Estado actual + let right = cells[i+1]; // Estado del vecino derecho + nextgen[i] = rules(left, me, right); // Calcular el estado siguiente generación basado en el conjunto de reglas + } + // La generación actual es la nueva generación + cells = nextgen; + generation++; +} + + +// Implementar las reglas Wolfram +// Puede ser mejorado y más conciso, pero aquí podemos revisar explicitamente lo que está pasando en cada caso +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/dist/assets/examples/es/09_Simulate/04_GameOfLife.js b/dist/assets/examples/es/09_Simulate/04_GameOfLife.js new file mode 100644 index 0000000000..eb1602008b --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/04_GameOfLife.js @@ -0,0 +1,93 @@ +/* + * @name Juego de la vida + * @description Una implementación básica del "Juego de la vida" de John Conway + * (natureofcode.com) + */ + +let w; +let columns; +let rows; +let board; +let next; + +function setup() { + createCanvas(720, 400); + w = 20; + // Calcular columnas y filas + columns = floor(width / w); + rows = floor(height / w); + // Forma extraña de hacer un arreglo 2D en JS + board = new Array(columns); + for (let i = 0; i < columns; i++) { + board[i] = new Array(rows); + } + // Usar múltiples arreglos 2D e intercambiarlos + 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); + } + } + +} + +// Resetear tablero cuando el ratón es presionado +function mousePressed() { + init(); +} + +// Llenar tablero aleatoriamente +function init() { + for (let i = 0; i < columns; i++) { + for (let j = 0; j < rows; j++) { + // Llenar bordes con 0s + if (i == 0 || j == 0 || i == columns-1 || j == rows-1) board[i][j] = 0; + // Llenar el resto aleatoriamente + else board[i][j] = floor(random(2)); + next[i][j] = 0; + } + } +} + +// El proceso de crear una nueva generación +function generate() { + + // Recorrer cada lugar de nuestro arreglo 2D y revisar lugares vecinos + for (let x = 1; x < columns - 1; x++) { + for (let y = 1; y < rows - 1; y++) { + // Sumar todos los estados en la grilla 3x3 vecina + let neighbors = 0; + for (let i = -1; i <= 1; i++) { + for (let j = -1; j <= 1; j++) { + neighbors += board[x+i][y+j]; + } + } + + // Un pequeño truco para restar el estado actual de la célula ya que + // lo sumamos en el bucle anterior + neighbors -= board[x][y]; + // Reglas de vida + if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0; // Soledad + else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0; // Sobrepoblación + else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1; // Reproducción + else next[x][y] = board[x][y]; // Stasis + } + } + + // Intercambiar! + let temp = board; + board = next; + next = temp; +} diff --git a/dist/assets/examples/es/09_Simulate/05_MultipleParticleSystems.js b/dist/assets/examples/es/09_Simulate/05_MultipleParticleSystems.js new file mode 100644 index 0000000000..3b46f544de --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/05_MultipleParticleSystems.js @@ -0,0 +1,136 @@ +/* + * @name Múltiples sistemas de partículas + * @description Hacer click con el ratón para generar una ráfaga de partículas en la posición del ratón.
Cada ráfaga es una instancia de un sistema de partículas con objetos Particle y CrazyParticle (una subclase de Particle).
Notar el uso de Herencia y Polimorfismo.
+ * Original por Daniel Shiffman. + */ +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); +} + +// Una clase simple de Particle +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(); +}; + +// Método para actualizar posición +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// Método para mostrar en pantalla +Particle.prototype.display = function () { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// ¿Sigue siendo útil la partícula? +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 () { + // Añadir o una Particle o una CrazyParticle al sistema + 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); + } + } +}; + +// Una subclase de Particle +function CrazyParticle(origin) { + // Llamar al constructor padre, asegurándose (usando Función#llamada) + // que "this" está configurado correctamente durante la llamada + Particle.call(this, origin); + + // Inicializar nustras propiedades añadidas + this.theta = 0.0; +}; + +// Crear un objeto Crazy.prototype que hereda de Particle.prototype. +// Nota: un error común aquí es usar "new Particle()" para crear el +// Crazy.prototype. Es incorrecto por muchas razones, +// como que no tenemos qué darle a Particle para el argumento de "origin" +// El lugar correcto para llamar a Particle es arriba, donde lo llamamos desde Crazy. +CrazyParticle.prototype = Object.create(Particle.prototype); // Ver nota abajo + +// 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); + // Incrementar rotación basado en la velocidad horizontal + this.theta += (this.velocity.x * this.velocity.mag()) / 10.0; +} + +// Este método display() anula el método display() de la clase padre +CrazyParticle.prototype.display=function() { + // Render de la elipse como una partícula regular + Particle.prototype.display.call(this); + // Añadir línea giratoria + push(); + translate(this.position.x, this.position.y); + rotate(this.theta); + stroke(255, this.lifespan); + line(0, 0, 25, 0); + pop(); +} diff --git a/dist/assets/examples/es/09_Simulate/06_Spirograph.js b/dist/assets/examples/es/09_Simulate/06_Spirograph.js new file mode 100644 index 0000000000..a13780f4ac --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/06_Spirograph.js @@ -0,0 +1,73 @@ + +/* + * @name Espirógrafo + * @description Este bosquejo usa transformaciones siples para crear un + * efecto tipo espirógrafo con partículas entrelazadas(llamadas sinusoides). + * Presiona la barra espaciadora para alternar entre dibujar y mostrar la geometría subyacente.
+ * Ejemplo creado por R. Luke DuBois.
+ * http://en.wikipedia.org/wiki/Spirograph + */ +let NUMSINES = 20; // cuántas partículas podemos hacer al mismo tiempo? +let sines = new Array(NUMSINES); // un arreglo para almacenar todos los ángulos actuales +let rad; // un valor de radio inicial para la sinusoide central +let i; // una variable contador + +// juega con estos valores para entender lo que está pasando: +let fund = 0.005; // la velocidad de la sinusoide central +let ratio = 1; // ¿cuál es el multiplicador de velocidad por cada sinusoide adicional? +let alpha = 50; // cuán opaco es el sistema de trazado + +let trace = false; // ¿estamos trazando? + +function setup() { + createCanvas(710, 400); + + rad = height / 4; // calcular radio del círculo central + background(204); // limpiar la pantalla + + for (let i = 0; i < sines.length; i++) { + sines[i] = PI; // inicializar cada uno en dirección norte + } +} + +function draw() { + if (!trace) { + background(204); // limpiar pantalla si es necesario + stroke(0, 255); // lápiz negro + noFill(); // sin relleno + } + + // ACCION PRINCIPAL + push(); // empezar una matriz de transformación + translate(width / 2, height / 2); // mover al centro de la pantalla + + for (let i = 0; i < sines.length; i++) { + let erad = 0; // radio del "punto" pequeño dentro del círculo... este es el "lápiz" para trazar + // configuración de trazado + if (trace) { + stroke(0, 0, 255 * (float(i) / sines.length), alpha); // azul + fill(0, 0, 255, alpha / 2); // también azul + erad = 5.0 * (1.0 - float(i) / sines.length); // ancho del lápiz dependerá de la sinusoide + } + let radius = rad / (i + 1); // radio del círculo + rotate(sines[i]); // rotar círculo + if (!trace) ellipse(0, 0, radius * 2, radius * 2); // si estamos simulando, dibujar la sinusoide + push(); // subir un nivel + translate(0, radius); // moverse al borde de la sinusoide + if (!trace) ellipse(0, 0, 5, 5); // dibujar un círculo pequeño + if (trace) ellipse(0, 0, erad, erad); // dibujar con erad si estamos trazando + pop(); // bajar un nivel + translate(0, radius); // moverse a la posición de la siguiente sinusoide + sines[i] = (sines[i] + (fund + (fund * i * ratio))) % TWO_PI; // actualizar ángulo basado en la fundamental + } + + pop(); // bajar a la transformación final + +} + +function keyReleased() { + if (key==' ') { + trace = !trace; + background(255); + } +} diff --git a/dist/assets/examples/es/09_Simulate/07_LSystems.js b/dist/assets/examples/es/09_Simulate/07_LSystems.js new file mode 100644 index 0000000000..dfcfc40d79 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/07_LSystems.js @@ -0,0 +1,106 @@ +/* + * @name Sístemas-L + * @description Este bosquejo crea un dibujo automatizado basado en un sistema Lindenmayer + * o sistema-L. Los sistemas-L son utilizados a menudo en gráfica procedural para hacer + * patrones naturales, geométricos o de tipo fractal.
+ * Ejemplo creado por R. Luke DuBois.
+ * https://en.wikipedia.org/wiki/L-system + */ +// SECCIÓN TORTUGA: +let x, y; // la posición actual de la tortuga +let currentangle = 0; // hacia dónde apunta la tortuga +let step = 20; // cuánto se mueve la tortuga en cada 'F' +let angle = 90; // cuánto gira la tortuga con un '-' or '+' + +// SECCIÓN LINDENMAYER (SISTEMAS-L) +let thestring = 'A'; // "axioma" o inicio de la cadena +let numloops = 5; // cuántas iteraciones a pre-computar +let therules = []; // arreglo para las reglas +therules[0] = ['A', '-BF+AFA+FB-']; // primera regla +therules[1] = ['B', '+AF-BFB-FA+']; // segunda regla + +let whereinstring = 0; // dónde estamos en el sistema-L + +function setup() { + createCanvas(710, 400); + background(255); + stroke(0, 0, 0, 255); + + // inicializar la posición x e y en la esquina inferior izquierda + x = 0; + y = height - 1; + + // CALCULAR EL SISTEMA-L + for (let i = 0; i < numloops; i++) { + thestring = lindenmayer(thestring); + } +} + +function draw() { + + // dibujar el caracter actual en la pantalla + drawIt(thestring[whereinstring]); + + // incrementar el punto de donde leemos la cadena. + // si sobrepasamos el final, volver al inicio. + whereinstring++; + if (whereinstring > thestring.length - 1) whereinstring = 0; + +} + +// interpretar un sistema-L +function lindenmayer(s) { + let outputstring = ''; // inicializar una cadena de salida en blanco + + // iterar a lo largo de las 'reglas' buscando coincidencias de símbolo: + for (let i = 0; i < s.length; i++) { + let ismatch = 0; // por defecto, sin coincidencia + for (let j = 0; j < therules.length; j++) { + if (s[i] == therules[j][0]) { + outputstring += therules[j][1]; //escribir substitución + ismatch = 1; //si tenemos una coincidencia, no copiemos el símbolo + break; // salir de este bucle for() + } + } + // si nada coincide, simplemente copia el símbolo. + if (ismatch == 0) outputstring += s[i]; + } + + return outputstring; // enviar la cadena modificada +} + +// esta es una función que dibuja los comandos de la tortuga +function drawIt(k) { + + if (k=='F') { // dibujar hacia adelante + // de polar a cartesiano basado en paso y ángulo actual: + let x1 = x + step * cos(radians(currentangle)); + let y1 = y + step * sin(radians(currentangle)); + line(x, y, x1, y1); // conectar el anterior y el nuevo + + // actualizar la posición de la tortuga: + x = x1; + y = y1; + } else if (k == '+') { + currentangle += angle; // doblar hacia la izquierda + } else if (k == '-') { + currentangle -= angle; // doblar hacia la derecha + } + + // valores aleatorios de color: + let r = random(128, 255); + let g = random(0, 192); + let b = random(0, 50); + let a = random(50, 100); + + // escoger una distribución gaussiana (D&D) para el radio: + let radius = 0; + radius += random(0, 15); + radius += random(0, 15); + radius += random(0, 15); + radius = radius / 3; + + // dibujar: + fill(r, g, b, a); + ellipse(x, y, radius, radius); +} diff --git a/dist/assets/examples/es/09_Simulate/08_Spring.js b/dist/assets/examples/es/09_Simulate/08_Spring.js new file mode 100644 index 0000000000..887c1849bd --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/08_Spring.js @@ -0,0 +1,92 @@ +/* + * @name Resorte + * @frame 710, 400 + * @description Haz click, arrastra y suelta la barra horizontal para inicializar el resorte. + */ +// Constantes de dibujo de resorte para la barra superior +let springHeight = 32, + left, + right, + maxHeight = 200, + minHeight = 100, + over = false, + move = false; + +// Constantes de simulación de resorte +let M = 0.8, // Masa + K = 0.2, // Constante de resorte + D = 0.92, // Amortiguamiento + R = 150; // Posición de reposo + +// variables de simulación de resorte +let ps = R, // Posición + vs = 0.0, // Velocidad + as = 0, // Aceleración + f = 0; // Fuerza + +function setup() { + createCanvas(710, 400); + rectMode(CORNERS); + noStroke(); + left = width / 2 - 100; + right = width / 2 + 100; +} + +function draw() { + background(102); + updateSpring(); + drawSpring(); +} + +function drawSpring() { + // Dibujar la base + fill(0.2); + let baseWidth = 0.5 * ps + -8; + rect(width/2 - baseWidth, ps + springHeight, width/2 + baseWidth, height); + + // Definir color y dibujar barra superior + if (over || move) { + fill(255); + } else { + fill(204); + } + + rect(left, ps, right, ps + springHeight); +} + +function updateSpring() { + // Actualizar posición del resorte + if ( !move ) { + f = -K * ( ps - R ); // f=-ky + as = f / M; // Definir la aceleración, f=ma == a=f/m + vs = D * (vs + as); // Definir la velocidad + ps = ps + vs; // Actualizar posición + } + + if (abs(vs) < 0.1) { + vs = 0.0; + } + + // Comprobar si el ratón está sobre la barra superior + if (mouseX > left && mouseX < right && mouseY > ps && mouseY < ps + springHeight) { + over = true; + } else { + over = false; + } + + // Definir y limitar la posición de la barra superior + if (move) { + ps = mouseY - springHeight / 2; + ps = constrain(ps, minHeight, maxHeight); + } +} + +function mousePressed() { + if (over) { + move = true; + } +} + +function mouseReleased() { + move = false; +} diff --git a/dist/assets/examples/es/09_Simulate/09_Springs.js b/dist/assets/examples/es/09_Simulate/09_Springs.js new file mode 100644 index 0000000000..3e4d422831 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/09_Springs.js @@ -0,0 +1,147 @@ +/* + * @name Resortes + * @frame 710,400 + * @description Mueve el ratón sobre uno de los círculos y haz clic para reposicionarlo. + * Cuando sueltes el ratón, se volverá a colocar en su posición. + * Cada círculo tiene un comportamiento ligeramente diferente. + * (puerto de https://processing.org/examples/springs.html) + */ +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; + } +}; diff --git a/dist/assets/examples/es/09_Simulate/10_SoftBody.js b/dist/assets/examples/es/09_Simulate/10_SoftBody.js new file mode 100644 index 0000000000..a6a34f9d14 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/10_SoftBody.js @@ -0,0 +1,110 @@ +/* + * @name Cuerpo blando + * @description Ejemplo original por Ira Greenberg. + *

Simulación de dinámica de cuerpo blando usando curveVertex() y curveTightness(). + */ +// Punto central +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; + +// nodos esquina +let nodes = 5; + +// Arreglos vacíos +let nodeStartX = []; +let nodeStartY = []; +let nodeX = []; +let nodeY = []; +let angle = []; +let frequency = []; + +// Dinámica de cuerpo blando +let organicConstant = 1.0; + +function setup() { + createCanvas(710, 400); + + // centrar la figura en la ventana + centerX = width / 2; + centerY = height / 2; + + //inicializar arreglos a 0 + for (let i=0; i.length dentro un bucle for + // pero lo guardamos acá porque en caso contrario, estaríamos recalculando el largo en cada iteración del bucle for + let len = this.particles.length; + + // iterar sobre todas las partículas y hacerlas correr con el método run() + for (let i = len - 1; i >= 0; i--) { + let particle = this.particles[i]; + particle.run(); + + // si la partícula está muerta, la removemos. + // los arreglos en javascript no poseen una función "remover", pero "splice" funciona. + // le damos como parámetro un lugar dónde empezar, y luego especificamos cuántas casillas desde aquí son removidas. + if (particle.isDead()) { + this.particles.splice(i, 1); + } + } +} + +/** + * Método para añadir un vector fuerza a todas las partículas actualmente en el sistema + * @param dir un p5.Vector que describe la dirección de la fuerza. + */ +ParticleSystem.prototype.applyForce = function(dir) { + let len = this.particles.length; + for(let i = 0; i < len; ++i){ + this.particles[i].applyForce(dir); + } +} + +/** + * Agrega una nueva partícula en el origen del sistema y con la textura definida originalmente. + */ +ParticleSystem.prototype.addParticle = function() { + this.particles.push(new Particle(this.origin, this.img)); +} + +//========= PARTÍCULA =========== +/** + * Una clase simple de Particle, hace render de la partícula como una imagen + */ +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_; +} + +/** + * Actualiza y muestra simultáneamente una partícula + */ +Particle.prototype.run = function() { + this.update(); + this.render(); +} + +/** + * Una función para mostrar en pantalla una partícula + */ +Particle.prototype.render = function() { + imageMode(CENTER); + tint(255, this.lifespan); + image(this.texture, this.loc.x, this.loc.y); +} + +/** + * Un método para aplicar un vector fuerza a una partícula. + */ +Particle.prototype.applyForce = function(f) { + this.acc.add(f); +} + +/** + * Este método revisa si la partícula ha llegado al fin de su vida, + * si lo ha hecho, devuelve true, en otro caso devuelve false. + */ +Particle.prototype.isDead = function () { + if (this.lifespan <= 0.0) { + return true; + } else { + return false; + } +} + +/** + * Este método actualiza la posición de la partícula. + */ +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/dist/assets/examples/es/09_Simulate/12_BrownianMotion.js b/dist/assets/examples/es/09_Simulate/12_BrownianMotion.js new file mode 100644 index 0000000000..0db56957c8 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/12_BrownianMotion.js @@ -0,0 +1,46 @@ +/* + * @name Movimiento browniano + * @description Grabar movimiento aleatorio como una líena continua. + * Puerto de un ejemplo original para Processing. + */ + +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); + + // Mover todos los elementos un lugar a la izquierda + for ( let i = 1; i < num; i++ ) { + ax[i - 1] = ax[i]; + ay[i - 1] = ay[i]; + } + + // Poner un nuevo valor al final del arreglo + ax[num - 1] += random(-range, range); + ay[num - 1] += random(-range, range); + + // Limitar la posición de todos los puntos a estar dentro de la pantalla + ax[num - 1] = constrain(ax[num - 1], 0, width); + ay[num - 1] = constrain(ay[num - 1], 0, height); + + // Dibujar una línea conectando los puntos + 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]); + } +} diff --git a/dist/assets/examples/es/09_Simulate/13_Chain.js b/dist/assets/examples/es/09_Simulate/13_Chain.js new file mode 100644 index 0000000000..5431f7e3fe --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/13_Chain.js @@ -0,0 +1,55 @@ +/* + * @name Cadena + * @description Una masa está unida a la posición del ratón y la otra está unida a la posición de la otra masa. La gravedad en el ambiente tira de ambas hacia abajo. + * Puerto de un ejemplo original para Processing. + */ +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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/es/09_Simulate/14_SnowflakeParticleSystem.js b/dist/assets/examples/es/09_Simulate/14_SnowflakeParticleSystem.js new file mode 100644 index 0000000000..b8c1c7f9e5 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/14_SnowflakeParticleSystem.js @@ -0,0 +1,63 @@ +/* + * @name Copos de Nieve + * @description Sistema de partículas que simula el movimiento de copos de nieve cayendo. + * Utiliza un arreglo de objetos para almacenar las particulas de copos de nieve. + * Contribución de Aatish Bhatia. + */ + +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/dist/assets/examples/es/09_Simulate/15_penrose_tiles.js b/dist/assets/examples/es/09_Simulate/15_penrose_tiles.js new file mode 100644 index 0000000000..7bd12af7ae --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/15_penrose_tiles.js @@ -0,0 +1,123 @@ +/* + * @name Baldosas de Penrose + * @frame 710,400 + * @description Este es un puerto de David Blitz del ejemplo "Baldosa de Penrose" de processing.org/examples + */ + +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 < this.steps; ++i) { + let step = this.production.charAt(i); + + //'W', 'X', 'Y', 'Z' symbols don't actually correspond to a turtle action + if( step == 'F') { + stroke(255, 60); + for(let j=0; j < this.repeats; j++) { + line(0, 0, 0, -this.drawLength); + noFill(); + translate(0, -this.drawLength); + } + this.repeats = 1; + } + else if (step == '+') { + rotate(this.theta); + } + else if (step == '-') { + rotate(-this.theta); + } + else if (step == '[') { + push(); + } + else if (step == ']') { + pop(); + } + } +} diff --git a/dist/assets/examples/es/09_Simulate/16_Recursive_Tree.js b/dist/assets/examples/es/09_Simulate/16_Recursive_Tree.js new file mode 100644 index 0000000000..dbdf584a9f --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/16_Recursive_Tree.js @@ -0,0 +1,55 @@ +/* + * @name Árbol Recursivo + * @description Representa una estructura simple en forma de árbol a través de la recursión. + * El ángulo de ramificación se calcula en función de la posición horizontal del ratón. + * Mueve el ratón hacia la izquierda y la derecha para cambiar el ángulo. + * Basado en el Ejemplo de Árbol Recursivo de Daniel Shiffman para Processing. + */ +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/dist/assets/examples/es/09_Simulate/17_Mandelbrot.js b/dist/assets/examples/es/09_Simulate/17_Mandelbrot.js new file mode 100644 index 0000000000..39582e83f1 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/17_Mandelbrot.js @@ -0,0 +1,86 @@ +/* + * @name El Conjunto de Mandelbrot + * @description Renderización simple del conjunto de Mandelbrot. + * Basado en el trabajo para Processing de Daniel Shiffman Ejemplo de Mandelbrot. + */ + +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/dist/assets/examples/es/09_Simulate/18_Koch.js b/dist/assets/examples/es/09_Simulate/18_Koch.js new file mode 100644 index 0000000000..f09f5d4a8a --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/18_Koch.js @@ -0,0 +1,141 @@ +/* + * @name Curva Koch + * @description Renderización de un fractal simple: el copo de nieve de Koch. Cada nivel recursivo se dibuja en secuencia. + * Por Daniel Shiffman. + */ + +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/dist/assets/examples/es/09_Simulate/19_Bubblesort.js b/dist/assets/examples/es/09_Simulate/19_Bubblesort.js new file mode 100644 index 0000000000..188b065864 --- /dev/null +++ b/dist/assets/examples/es/09_Simulate/19_Bubblesort.js @@ -0,0 +1,67 @@ +/* + * @name Ordenamiento de Burbuja + * @description Ordena las barras distribuidas aleatoriamente + * según su altura en orden ascendente mientras simula todo el + * proceso de clasificación. + * Se usaron referencias del 'Coding Challenge' de 'The Coding Train'. + */ + +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= 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); + +// +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 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(paraticles) { + 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
+ * 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
+ */ + +// 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)); +} \ No newline at end of file diff --git a/dist/assets/examples/es/10_Interaction/10_Tickle.js b/dist/assets/examples/es/10_Interaction/10_Tickle.js new file mode 100644 index 0000000000..f7b58375da --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/10_Tickle.js @@ -0,0 +1,48 @@ +/* + * @name Cosquillas + * @description La palabra "tickle" se mueve cuando el cursor está sobre ella. + * A veces, puede ser incluso arrastrada fuera de la pantalla. + */ +let message = 'tickle', + font, + bounds, // almacena la posición, ancho y alto de la caja contenedora del texto + fontsize = 60, + x, + y; // coordenadas x e y del texto + +function preload() { + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // definir la fuente del texto + textFont(font); + textSize(fontsize); + + // obtener ancho y alto del texto para centrarlo inicialmente + bounds = font.textBounds(message, 0, 0, fontsize); + x = width / 2 - bounds.w / 2; + y = height / 2 - bounds.h / 2; +} + +function draw() { + background(204, 120); + + // escribir el texto con negro y obtener su caja contenedora + fill(0); + text(message, x, y); + bounds = font.textBounds(message, x, y, fontsize); + + // revisar si el ratón está dentro de la caja contenedora y moverse si es así + 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/dist/assets/examples/es/10_Interaction/11_WeightLine.js b/dist/assets/examples/es/10_Interaction/11_WeightLine.js new file mode 100644 index 0000000000..a455dcb781 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/11_WeightLine.js @@ -0,0 +1,55 @@ +/* + * @name Weight Line + * @frame 710,400 + * @description contributed by + Prof WM Harris, using the random function with events to color/weight a line
+ How to use the random function with events to color/ weight a line + dependent on mouse location, left mouse button clicks, character key types, and + random key releases.
+ Functions are created for both the canvas set up as well as the creation of + the line. Depending on the action taken by the user the line can + vary in width and color. Left mouse button clicks result in a color + change to blue, while the typing of any character key will change + the color to turquoise, each resulting in a variable stroke weight; + the width of the former will be between 0 – 1 while the width of + the latter will be 0 – 5. The release of any key will result in a + random hue, saturation, and brightness change to the line. + */ + + +function setup() { + createCanvas(400, 400); + background("beige"); + colorMode(HSB); + } + + function draw() { + //Line from prev pt to current pt + //of mouse position + line(mouseX, mouseY, pmouseX, pmouseY); + } + + //listen when we click the mouse + function mouseClicked() { + //weights 0 to 1 + stroke("slateBlue"); + strokeWeight(random()); + + //what if want weights 0 to .4? + //strokeWeight( random(.4) ); + } + + //listen when we release *any* key + function keyReleased() { + //color hue values between 20 and 145 + //saturation 0 to 100 + //brightness 80 to 100 + stroke(random(20, 145), random(100), random(80, 100)); + } + + //listen for only character keys + function keyTyped() { + //weights 0 to 5 + stroke("turquoise"); + strokeWeight(random(5)); + } \ No newline at end of file diff --git a/dist/assets/examples/es/10_Interaction/20_Follow1.js b/dist/assets/examples/es/10_Interaction/20_Follow1.js new file mode 100644 index 0000000000..e4197e4674 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/20_Follow1.js @@ -0,0 +1,37 @@ +/* + * @name Seguir 1 + * @frame 710,400 + * @description Un segmento de línea es empujado y tirado por el cursor. + * Basado en código de Keith Peters. + */ +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/dist/assets/examples/es/10_Interaction/21_Follow2.js b/dist/assets/examples/es/10_Interaction/21_Follow2.js new file mode 100644 index 0000000000..b68d484d3c --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/21_Follow2.js @@ -0,0 +1,39 @@ +/* + * @name Seguir 2 + * @frame 710,400 + * @description Un brazo de dos segmentos sigue la posición del cursor. El ángulo relativo + * entre los segmentos es calculado con la función atan2() y la posición es + * calculada con sin() y cos(). Basado en código de Keith Peters. + */ +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/dist/assets/examples/es/10_Interaction/22_Follow3.js b/dist/assets/examples/es/10_Interaction/22_Follow3.js new file mode 100644 index 0000000000..0c58475589 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/22_Follow3.js @@ -0,0 +1,47 @@ +/* + * @name Seguir 3 + * @frame 710,400 + * @description Una línea segmentada sigue al ratón. El ángulo relativo de + * cada segmento al siguiente es calculado con la función atan2() y la posición + * del siguiente es calculado con sin() y cos(). Basado en código de Keith Peters. + */ +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/dist/assets/examples/es/10_Interaction/23_snake.js b/dist/assets/examples/es/10_Interaction/23_snake.js new file mode 100644 index 0000000000..66d5f5d256 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/23_snake.js @@ -0,0 +1,176 @@ +/* + * @name Juego de Serpiente + * @description El famoso juego de Serpiente! Después de hacer click en run/ejecutar, haz click en cualquier parte + * dentro del área negra, y controla la serpiente usando i,j,k,l. No dejes que + * la serpiente choque contra sí misma o la pared.
+ * Ejemplo creado por Prashant Gupta + */ + +// La serpiente se divide en pequeños segmentos, los que son dibujados y editados en cada ejecución de draw() +let numeroSegmentos = 10; +let direccion = 'derecha'; + +const xInicio = 0; //coordenada x de partida de la serpiente +const yInicio = 250; //coordenada y de partida de la serpiente +const diferencia = 10; + +let xCuerpo = []; +let yCuerpo = []; + +let xFruta = 0; +let yFruta = 0; +let elementoPuntaje; + +function setup() { + elementoPuntaje = createDiv('Puntaje = 0'); + elementoPuntaje.position(20, 20); + elementoPuntaje.id = 'puntaje'; + elementoPuntaje.style('color', 'white'); + + createCanvas(500, 500); + frameRate(15); + stroke(255); + strokeWeight(10); + actualizarCoordenadasFruta(); + + for (let i = 0; i < numeroSegmentos; i++) { + xCuerpo.push(xInicio + i * diferencia); + yCuerpo.push(yInicio); + } +} + +function draw() { + background(0); + for (let i = 0; i < numeroSegmentos - 1; i++) { + line(xCuerpo[i], yCuerpo[i], xCuerpo[i + 1], yCuerpo[i + 1]); + } + actualizarCoordenadasSerpiente(); + comprobarEstadoJuego(); + comprobarFruta(); +} + +/* + Los segmentos son actualizados en la dirección de la serpiente. + Todos los segmentos entre 0 y n-1 son copiados al rango 1 hasta n, por ejemplo, el segmento 0 recibe el valor del segmento 1, el segmento 1 recibe el +vallor del segmento 2, y así, esto resulta en el movimiento de la serpiente. + + El último segmento es añadido según la dirección de movimiento de la serpiente, + si está yendo hacia izquierda o derecha, la coordenada x del último segmento + es igual a sumar un valor predefinido como 'diferencia' al valor del penúltimo + segmento. Y si está yendo hacia arriba o abajo, la coordenada y es afectada. + } + +*/ +function actualizarCoordenadasSerpiente() { + for (let i = 0; i < numeroSegmentos - 1; i++) { + xCuerpo[i] = xCuerpo[i + 1]; + yCuerpo[i] = yCuerpo[i + 1]; + } + switch (direccion) { + case 'derecha': + xCuerpo[numeroSegmentos - 1] = xCuerpo[numeroSegmentos - 2] + diferencia; + yCuerpo[numeroSegmentos - 1] = yCuerpo[numeroSegmentos - 2]; + break; + case 'arriba': + xCuerpo[numeroSegmentos - 1] = xCuerpo[numeroSegmentos - 2]; + yCuerpo[numeroSegmentos - 1] = yCuerpo[numeroSegmentos - 2] - diferencia; + break; + case 'izquierda': + xCuerpo[numeroSegmentos - 1] = xCuerpo[numeroSegmentos - 2] - diferencia; + yCuerpo[numeroSegmentos - 1] = yCuerpo[numeroSegmentos - 2]; + break; + case 'abajo': + xCuerpo[numeroSegmentos - 1] = xCuerpo[numeroSegmentos - 2]; + yCuerpo[numeroSegmentos - 1] = yCuerpo[numeroSegmentos - 2] + diferencia; + break; + } +} + +/* + Siempre reviso la posición de la cabeza de la serpiente + xCuerpo[xCuerpo.length - 1] e yCuerpo[yCuerpo.length - 1] para revisar si toca + los bordes del juego o si la serpiente se estrelló contra sí misma. +*/ +function comprobarEstadoJuego() { + if ( + xCuerpo[xCuerpo.length - 1] > width || + xCuerpo[xCuerpo.length - 1] < 0 || + yCuerpo[yCuerpo.length - 1] > height || + yCuerpo[yCuerpo.length - 1] < 0 || + detectarColision() + ) { + noLoop(); + const puntajeValor = parseInt(elementoPuntaje.html().substring(8)); + elementoPuntaje.html('Juego finalizado! Tu puntaje fue: ' + puntajeValor); + } +} + +/* + Si la serpiente se estrella contra sí misma, esto significa que la coordenada + (x,y) tiene que ser igual a la de un segmento propio. +*/ +function detectarColision() { + const cabezaSerpienteX = xCuerpo[xCuerpo.length - 1]; + const cabezaSerpienteY = yCuerpo[yCuerpo.length - 1]; + for (let i = 0; i < xCuerpo.length - 1; i++) { + if (xCuerpo[i] === cabezaSerpienteX && yCuerpo[i] === cabezaSerpienteY) { + return true; + } + } +} + +/* + Cada vez que la serpiente consume una fruta, incremento el número de segmentos, + y simplemente inserto este segmento de cola nuevamente al principio del arreglo + (básicamente añado el último segmento a la cola, con lo que la alargo). +*/ +function comprobarFruta() { + point(xFruta, yFruta); + if ( + xCuerpo[xCuerpo.length - 1] === xFruta && + yCuerpo[yCuerpo.length - 1] === yFruta + ) { + const prevScore = parseInt(elementoPuntaje.html().substring(8)); + elementoPuntaje.html('Score = ' + (prevScore + 1)); + xCuerpo.unshift(xCuerpo[0]); + yCuerpo.unshift(yCuerpo[0]); + numeroSegmentos++; + actualizarCoordenadasFruta(); + } +} + +function actualizarCoordenadasFruta() { + /* + Hice matemática compleja porque quería que el punto estuviera + entre 100 y width-100, y que fuera aproximado al número divisible + por 10 más cercano, ya que muevo la serpiente en múltiplos de 10. + */ + + xFruta = floor(random(10, (width - 100) / 10)) * 10; + yFruta = floor(random(10, (height - 100) / 10)) * 10; +} + +function keyPressed() { + switch (keyCode) { + case 74: + if (direccion !== 'derecha') { + direccion = 'izquierda'; + } + break; + case 76: + if (direccion !== 'izquierda') { + direccion = 'derecha'; + } + break; + case 73: + if (direccion !== 'abajo') { + direccion = 'arriba'; + } + break; + case 75: + if (direccion !== 'arriba') { + direccion = 'abajo'; + } + break; + } +} diff --git a/dist/assets/examples/es/10_Interaction/24_Wavemaker.js b/dist/assets/examples/es/10_Interaction/24_Wavemaker.js new file mode 100644 index 0000000000..bee0fde1ae --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/24_Wavemaker.js @@ -0,0 +1,37 @@ +/* + * @name Wavemaker + * @description Este ejemplo ilustra cómo las olas (como las del mar) emergen + * a partir de partículas oscilando en su lugar. Mueve el ratón para dirigir la ola. + * Contribución por Aatish Bhatia, inspirada en Orbiters por Dave Whyte. + */ + +let t = 0; // variable de tiempo + +function setup() { + createCanvas(600, 600); + noStroke(); + fill(40, 200, 40); +} + +function draw() { + background(10, 10); // fondo translúcido (crea estelas) + + // grilla de elipses + for (let x = 0; x <= width; x = x + 30) { + for (let y = 0; y <= height; y = y + 30) { + // punto de partida de cada círculo depende de posición del ratón + const anguloX = map(mouseX, 0, width, -4 * PI, 4 * PI, true); + const anguloY = map(mouseY, 0, height, -4 * PI, 4 * PI, true); + // y también varía según la posición de la partícula + const angulo = anguloX * (x / width) + anguloY * (y / height); + + // cada partícula se mueve en forma circular + const myX = x + 20 * cos(2 * PI * t + angulo); + const myY = y + 20 * sin(2 * PI * t + angulo); + + ellipse(myX, myY, 10); // dibujar partícula + } + } + + t = t + 0.01; // actualizar tiempo +} diff --git a/dist/assets/examples/es/10_Interaction/25_reach1.js b/dist/assets/examples/es/10_Interaction/25_reach1.js new file mode 100644 index 0000000000..01475decdc --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/25_reach1.js @@ -0,0 +1,57 @@ +/* + * @name Alcanzar 1 + * @frame 710,400 + * @description El brazo sigue la posición del ratón mediante el cálculo de los + * ángulos con atan2(). Basado en código de Keith Peters. + */ +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/dist/assets/examples/es/10_Interaction/26_reach2.js b/dist/assets/examples/es/10_Interaction/26_reach2.js new file mode 100644 index 0000000000..c701af1bb8 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/26_reach2.js @@ -0,0 +1,65 @@ +/* + * @name Alcanzar 2 + * @frame 710,400 + * @description El brazo sigue la posición del ratón mediante el cálculo de los + * ángulos con atan2(). Basado en código de Keith Peters. + */ +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; // Definir base del eje x + y[x.length - 1] = height; // Definir base del eje y +} + +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/dist/assets/examples/es/10_Interaction/27_reach3.js b/dist/assets/examples/es/10_Interaction/27_reach3.js new file mode 100644 index 0000000000..c7f033cc41 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/27_reach3.js @@ -0,0 +1,81 @@ +/* + * @name Alcanzar 3 + * @frame 710,400 + * @description El brazo sigue la posición de la pelota mediante el cálculo de los + * ángulos con atan2(). Basado en código de Keith Peters. + */ +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; // Definir base del eje x + y[x.length - 1] = height; // Definir base del eje y +} + +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/dist/assets/examples/es/10_Interaction/28_ArduinoSensor.js b/dist/assets/examples/es/10_Interaction/28_ArduinoSensor.js new file mode 100644 index 0000000000..55e5b0c7b0 --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/28_ArduinoSensor.js @@ -0,0 +1,36 @@ +/* + * @name Datos de un sensor Arduino vía WebJack + * @description WebJack es una forma de leer datos de un Arduino (y otras fuentes) + * usando audio... básicamente convierte tu Arduino en un modem de audio. + * + * https://github.com/publiclab/webjack + * + * Importante: Las bibliotecas WebJack y p5-webjack deben ser agregadas a tu index.html de la siguiente manera: + *
<script src="https://webjack.io/dist/webjack.js"></script>
+ *
<script src="https://jywarren.github.io/p5-webjack/lib.js"></script>
+ * + * Ejemplo práctico: https://editor.p5js.org/jywarren/sketches/rkztwSt8M + * + * Audio de prueba https://www.youtube.com/watch?v=GtJW1Dlt3cg + * Carga este lienzo en un Arduino: + * https://create.arduino.cc/editor/jywarren/023158d8-be51-4c78-99ff-36c63126b554/preview + * Arduino emitirá el audio desde el pin 3 + tierra. Usa el micrófono o un cable de audio. + */ + +function setup() { + createCanvas(400, 400); + noStroke(); + fill('#ff00aa22'); + receiveSensorData(handleData); +} + +function handleData(data) { + + console.log(data); // emitir los valores a registrar + // data[0] es el primer valor, data[1] el segundo, etc. + + // Dibuja! Navega http://p5js.org/reference/ + background('#ddd'); + ellipse(100, 200, data[0]+10, data[0]+10); + +} diff --git a/dist/assets/examples/es/10_Interaction/29_kaleidoscope.js b/dist/assets/examples/es/10_Interaction/29_kaleidoscope.js new file mode 100644 index 0000000000..ff372e7aea --- /dev/null +++ b/dist/assets/examples/es/10_Interaction/29_kaleidoscope.js @@ -0,0 +1,73 @@ +/* + * @name Caleidoscopio + * @description Un caleidoscopio es un instrumento óptico con dos o más superficies reflectantes inclinadas entre sí en ángulo. Este ejemplo intenta replicar el comportamiento de un caleidoscopio. Establezca el número de reflexiones en la variable de simetría y comience a dibujar en la pantalla. Ajuste el tamaño del pincel con la ayuda del control deslizante. La pantalla clara como dice borra la pantalla. El botón Guardar descargará un archivo .jpg del arte que ha creado. + */ +// Simetría correspondiente al número de reflejos. +// Cambia el valor para obtener un número diferente de reflexiones +let symmetry = 6; + +let angle = 360 / symmetry; +let saveButton, clearButton, mouseButton, keyboardButton; +let slider; + +function setup() { + createCanvas(710, 710); + angleMode(DEGREES); + background(127); + + // Creando el botón para guardar para el archivo + saveButton = createButton('save'); + saveButton.mousePressed(saveFile); + + // Creando el botón para borrar la pantalla + clearButton = createButton('clear'); + clearButton.mousePressed(clearScreen); + + // Creando el botón para la pantalla completa + fullscreenButton = createButton('Full Screen'); + fullscreenButton.mousePressed(screenFull); + + // Configurando el deslizador para el grosor del pincel + brushSizeSlider = createButton('Brush Size Slider'); + sizeSlider = createSlider(1, 32, 4, 0.1); +} + +// Función para guardar el archivo +function saveFile() { + save('design.jpg'); +} + +// Función para limpiar la pantalla +function clearScreen() { + background(127); +} + +// Función para pantalla completa +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/dist/assets/examples/es/11_Objects/01_Objects.js b/dist/assets/examples/es/11_Objects/01_Objects.js new file mode 100644 index 0000000000..56812fc6b1 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/01_Objects.js @@ -0,0 +1,39 @@ +/* + * @name Objetos + * @description Crea una clase Jitter, instancia un objeto, + * y lo mueve en la pantalla. Adaptado del libro "Getting Started with + * Processing" por Casey Reas y Ben Fry. + */ + +let bug; // declarar objeto + +function setup() { + createCanvas(710, 400); + // crear objeto + bug = new Jitter(); +} + +function draw() { + background(50, 89, 100); + bug.move(); + bug.display(); +} + +// clase Jitter +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/dist/assets/examples/es/11_Objects/02_Multiple_Objects.js b/dist/assets/examples/es/11_Objects/02_Multiple_Objects.js new file mode 100644 index 0000000000..1f1f042973 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/02_Multiple_Objects.js @@ -0,0 +1,44 @@ +/* + * @name Múltiples objetos + * @description Crea una clase Jitter, instancia múltiples objetos, y los mueve en la pantalla. + */ + +function setup() { + createCanvas(710, 400); + // crear objetos + 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(); +} + +// clase Jitter +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/dist/assets/examples/es/11_Objects/03_Objects_Array.js b/dist/assets/examples/es/11_Objects/03_Objects_Array.js new file mode 100644 index 0000000000..4a8ec9d6a6 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/03_Objects_Array.js @@ -0,0 +1,41 @@ +/* + * @name Arreglo de objetos + * @description Crea una clase Jitter, instancia múltiples objetos, y los mueve en la pantalla. + */ + +let bugs = []; //arreglo de objetos Jitter + +function setup() { + createCanvas(710, 400); + // Crear objetos + 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(); + } +} + +// clase Jitter +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/dist/assets/examples/es/11_Objects/03_Objects_Optional_Arguments.js b/dist/assets/examples/es/11_Objects/03_Objects_Optional_Arguments.js new file mode 100644 index 0000000000..a25a0842b2 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/03_Objects_Optional_Arguments.js @@ -0,0 +1,65 @@ +/* + * @name Objetos 2 + * @description Puerto de un ejemplo por hbarragan. Mueve el cursor sobre la + * imagen para cambiar la velocidad y las posiciones de la geometría. La clase MRect + * define un grupo de líneas. + */ + +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; // ancho de una barra + this.xpos = ixp; // posición x del rectángulo + this.h = ih; // altura del rectángulo + this.ypos = iyp; // posición y del rectángulo + this.d = id; // distancia de una barra + this.t = it; // número de barras + } + + 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/dist/assets/examples/es/11_Objects/04_Inheritance.js b/dist/assets/examples/es/11_Objects/04_Inheritance.js new file mode 100644 index 0000000000..b1a0af4203 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/04_Inheritance.js @@ -0,0 +1,70 @@ +/* @name Herencia + * @description Una clase puede ser definida usando otra clase como base. + * En la terminología de la programación orientada a objetos, una clase + * puede heredar campos y métodos de otra. Un objeto que hereda + * de otro se llama subclase, y el objeto del que hereda se + * llama superclase. Una subclase extiende la superclase. + */ +let spots, arm; + +function setup() { + createCanvas(640, 360); + arm = new SpinArm(width/2, height/2, 0.01); + spots = new SpinSpots(width/2, height/2, -0.02, 90.0); +} + +function draw() { + background(204); + arm.update(); + arm.display(); + spots.update(); + spots.display(); +} + +class Spin { + constructor(x, y, s) { + this.x = x; + this.y = y; + this.speed = s; + this.angle = 0.0; + } + + update() { + this.angle += this.speed; + } +} + +class SpinArm extends Spin { + constructor(x, y, s) { + super(x, y, s) + } + + display() { + strokeWeight(1); + stroke(0); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + line(0, 0, 165, 0); + pop(); + } +} + +class SpinSpots extends Spin { + constructor(x, y, s, d) { + super(x, y, s) + this.dim = d; + } + + display() { + noStroke(); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + ellipse(-this.dim/2, 0, this.dim, this.dim); + ellipse(this.dim/2, 0, this.dim, this.dim); + pop(); + } +} \ No newline at end of file diff --git a/dist/assets/examples/es/11_Objects/05_Composite_Objects.js b/dist/assets/examples/es/11_Objects/05_Composite_Objects.js new file mode 100644 index 0000000000..dc794fb519 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/05_Composite_Objects.js @@ -0,0 +1,99 @@ +/* @name Objetos Compuestos + * @description Un objeto puede incluir varios otros objetos. + * La creación de tales objetos compuestos es una buena manera de usar los principios + * de modularidad y construir niveles más altos de abstracción dentro de un programa. + */ +let er1, er2; + +function setup() { + createCanvas(640, 360); + er1 = new EggRing(width*0.45, height*0.5, 0.1, 120); + er2 = new EggRing(width*0.65, height*0.8, 0.05, 180); +} + +function draw() { + background(0); + er1.transmit(); + er2.transmit(); +} + +class Egg { + constructor(xpos, ypos, t, s) { + this.x = xpos; + this.y = ypos; + this.tilt = t; + this.scalar = s / 100.0; + this.angle = 0.0; + } + + wobble() { + this.tilt = cos(this.angle) / 8; + this.angle += 0.1; + } + + display() { + noStroke(); + fill(255); + push(); + translate(this.x, this.y); + rotate(this.tilt); + scale(this.scalar); + beginShape(); + vertex(0, -100); + bezierVertex(25, -100, 40, -65, 40, -40); + bezierVertex(40, -15, 25, 0, 0, 0); + bezierVertex(-25, 0, -40, -15, -40, -40); + bezierVertex(-40, -65, -25, -100, 0, -100); + endShape(); + pop(); + } +} + +class Ring { + start(xpos, ypos) { + this.x = xpos; + this.y = ypos; + this.on = true; + this.diameter = 1; + } + + grow() { + if (this.on == true) { + this.diameter += 0.5; + if (this.diameter > width*2) { + this.diameter = 0.0; + } + } + } + + display() { + if (this.on == true) { + noFill(); + strokeWeight(4); + stroke(155, 153); + ellipse(this.x, this.y, this.diameter, this.diameter); + } + } +} + +class EggRing { + constructor(x, y, t, sp) { + this.x = x; + this.y = y; + this.t = t; + this.sp = sp; + this.circle = new Ring(); + this.ovoid = new Egg(this.x, this.y, this.t, this.sp); + this.circle.start(this.x, this.y - this.sp/2); + } + + transmit() { + this.ovoid.wobble(); + this.ovoid.display(); + this.circle.grow(); + this.circle.display(); + if (this.circle.on == false) { + this.circle.on = true; + } + } +} diff --git a/dist/assets/examples/es/11_Objects/06_Car_Instances.js b/dist/assets/examples/es/11_Objects/06_Car_Instances.js new file mode 100644 index 0000000000..1966f9c8e3 --- /dev/null +++ b/dist/assets/examples/es/11_Objects/06_Car_Instances.js @@ -0,0 +1,82 @@ +/* + * @name Car Instances + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create three instances of Car Class and +invoke class methods.
+ A function is created for the canvas setup, and +3 car instances are initialized with different colors and canvas +positions. The speed of each car is set by passing value to the +instance’s start method. A second function calls class methods to +display and move the cars. +*/ +class Car { + /* Constructor expects parameters for + fill color, x and y coordinates that + will be used to initialize class properties. + */ + constructor(cColor, x, y) { + this.color = cColor; + this.doors = 4; + this.isConvertible = false; + this.x = x; + this.y = y; + this.speed = 0; + } + + start(speed) { // method expects parameter! + this.speed = speed; + } + + display() { // method! + fill(this.color); + rect(this.x, this.y, 20, 10); + } + + move() { // method! + this.x += this.speed; + // Wrap x around boundaries + if (this.x < -20) { + this.x = width; + } else if (this.x > width) { + this.x = -20; + } + } +} //end class Car + +let rav4; +let charger; +let nova; + +function setup() { + createCanvas(200, 400); + /* Construct the 3 Cars */ + //constructor expects cColor, x, y + rav4 = new Car("silver", 100, 300); + charger = new Car("gold", 0, 200); + nova = new Car("blue", 200, 100); + nova.doors = 2; //update nova's doors property + + console.log("rav4", rav4); + console.log("charger", charger); + console.log("nova", nova); + + //call start methods of Car instances + //the start method expects a number for speed + rav4.start(2.3); + charger.start(-4); + nova.start(random(-1, 1)); +} + +function draw() { + background("beige"); + + //display and move all 3 Cars + rav4.display(); + charger.display(); + nova.display(); + + rav4.move(); + charger.move(); + nova.move(); +} diff --git a/dist/assets/examples/es/12_Lights/02_Directional.js b/dist/assets/examples/es/12_Lights/02_Directional.js new file mode 100644 index 0000000000..228a87f06d --- /dev/null +++ b/dist/assets/examples/es/12_Lights/02_Directional.js @@ -0,0 +1,27 @@ +/* + * @name Direccional + * @frame 710,400 + * @description Mueve el ratón para cambiar la dirección de la luz. + * La luz direccional proviene de una dirección y es de mayor intensidad cuando incide sobre + * una superficie perpendicularmente y más suave sobre un ángulo menor. Después de incidir sobre la + * superficie, una luz direccional se dispersa en todas direcciones. + */ +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/dist/assets/examples/es/12_Lights/05_Mixture.js b/dist/assets/examples/es/12_Lights/05_Mixture.js new file mode 100644 index 0000000000..4f6c794f2a --- /dev/null +++ b/dist/assets/examples/es/12_Lights/05_Mixture.js @@ -0,0 +1,44 @@ +/* + * @name Mezcla + * @frame 710,400 (optional) + * @description Muestra una caja con tres tipos diferentes de luces. + */ +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/dist/assets/examples/es/13_Motion/01_non_orthogonal_reflection.js b/dist/assets/examples/es/13_Motion/01_non_orthogonal_reflection.js new file mode 100644 index 0000000000..453bd272f1 --- /dev/null +++ b/dist/assets/examples/es/13_Motion/01_non_orthogonal_reflection.js @@ -0,0 +1,110 @@ +/* + * @name Reflejo no ortogonal + * @frame 710,400 (optional) + * @description Este es un puerto de David Blitz del ejemplo "Reflection 1" en processing.org/examples + */ + +//Posición del lado izquierdo del suelo +let base1; + +//Posición del lado derecho del suelo +let base2; +//La longitud del suelo +//let baseLength; + +// Variables relacionadas con el movimiento de la bola +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(); + + //Empezar la elipse en el centro de la parte superior de la pantalla + position = createVector(width / 2, 0); + + //Calcular la velocidad aleatoria inicial + velocity = p5.Vector.random2D(); + velocity.mult(speed); +} + +function draw() { + //dibujar el fondo + fill(0, 12); + noStroke(); + rect(0, 0, width, height); + + //dibujar la base + fill(200); + quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height); + + //calcular la normal a la base superior + let baseDelta = p5.Vector.sub(base2, base1); + baseDelta.normalize(); + let normal = createVector(-baseDelta.y, baseDelta.x); + let intercept = p5.Vector.dot(base1, normal); + + //dibujar elipse + noStroke(); + fill(255); + ellipse(position.x, position.y, r * 2, r * 2); + + //mover elipse + position.add(velocity); + + //vector de incidencia normalizado + incidence = p5.Vector.mult(velocity, -1); + incidence.normalize(); + + // detectar y gestionar la colisión con la base + if (p5.Vector.dot(normal, position) > intercept) { + //calcular el producto escalar del vector incidente y la parte superior de la base + let dot = incidence.dot(normal); + + //calcular el vector del reflejo + //asignar el vector de reflejo al vector de dirección + velocity.set( + 2 * normal.x * dot - incidence.x, + 2 * normal.y * dot - incidence.y, + 0 + ); + velocity.mult(speed); + + // dibujar la base superior normal en el punto de colisión + stroke(255, 128, 0); + line( + position.x, + position.y, + position.x - normal.x * 100, + position.y - normal.y * 100 + ); + } + //} + + // detectar la colisión límite + // derecha + if (position.x > width - r) { + position.x = width - r; + velocity.x *= -1; + } + // izquierda + if (position.x < r) { + position.x = r; + velocity.x *= -1; + } + // arriba + if (position.y < r) { + position.y = r; + velocity.y *= -1; + + //aleatorizar la parte superior de la base + base1.y = random(height - 100, height); + base2.y = random(height - 100, height); + } +} diff --git a/dist/assets/examples/es/13_Motion/02_Linear_Motion.js b/dist/assets/examples/es/13_Motion/02_Linear_Motion.js new file mode 100644 index 0000000000..8ba05fdc00 --- /dev/null +++ b/dist/assets/examples/es/13_Motion/02_Linear_Motion.js @@ -0,0 +1,24 @@ +/* + * @name Lineal + * @frame 720,400 + * @description Cambiar una variable para crear una línea en movimiento. + * Cuando la línea se mueve fuera del borde de la ventana, + * la variable se pone a 0, lo que coloca la línea de nuevo en la parte inferior de la pantalla. + */ + +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/dist/assets/examples/es/13_Motion/03_Bounce.js b/dist/assets/examples/es/13_Motion/03_Bounce.js new file mode 100644 index 0000000000..363084c6ad --- /dev/null +++ b/dist/assets/examples/es/13_Motion/03_Bounce.js @@ -0,0 +1,44 @@ +/* + * @name Rebote + * @frame 720,400 + * @description Cuando la forma golpea el borde de la ventana, invierte su dirección. + */ + +let rad = 60; // El ancho de la forma +let xpos, ypos; // Posición inicial de la forma + +let xspeed = 2.8; // La velocidad de la forma +let yspeed = 2.2; // La velocidad de la forma + +let xdirection = 1; // Izquierda o derecha +let ydirection = 1; // De arriba a abajo + +function setup() { + createCanvas(720, 400); + noStroke(); + frameRate(30); + ellipseMode(RADIUS); + // Establecer la posición de partida de la forma + xpos = width / 2; + ypos = height / 2; +} + +function draw() { + background(102); + + // Actualizar la posición de la forma + xpos = xpos + xspeed * xdirection; + ypos = ypos + yspeed * ydirection; + + // Prueba para ver si la forma excede los límites de la pantalla + // Si lo hace, invierta su dirección multiplicando por -1 + if (xpos > width - rad || xpos < rad) { + xdirection *= -1; + } + if (ypos > height - rad || ypos < rad) { + ydirection *= -1; + } + + // Dibuja la forma + ellipse(xpos, ypos, rad, rad); +} diff --git a/dist/assets/examples/es/13_Motion/04_Bouncy_Bubbles.js b/dist/assets/examples/es/13_Motion/04_Bouncy_Bubbles.js new file mode 100644 index 0000000000..febbe5ace3 --- /dev/null +++ b/dist/assets/examples/es/13_Motion/04_Bouncy_Bubbles.js @@ -0,0 +1,95 @@ +/* + * @name Burbujas Saltarinas + * @frame 720,400 + * @description basado en el código de Keith Peters. Colisión de múltiples objetos... + */ + +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/dist/assets/examples/es/13_Motion/05_Morph.js b/dist/assets/examples/es/13_Motion/05_Morph.js new file mode 100644 index 0000000000..8830647539 --- /dev/null +++ b/dist/assets/examples/es/13_Motion/05_Morph.js @@ -0,0 +1,93 @@ +/* + * @name Transformar + * @frame 720,400 + * @description Cambiar una forma por otra interpolando vértices de uno a otro. + */ + +// Dos ArrayList para almacenar los vértices de dos geometrías +// Este ejemplo asume que cada forma tendrá el mismo número de vértices +// es decir, el tamaño de cada ArrayList será el mismo +let circle = []; +let square = []; + +// Un ArrayList para un tercer conjunto de vértices, los que dibujaremos +// en la ventana +let morph = []; + +// Esta variable booleana controlará si estamos transformando en un círculo o un cuadrado +let state = false; + +function setup() { + createCanvas(720, 400); + + // Crear un círculo usando vectores que apunten desde el centro + for (let angle = 0; angle < 360; angle += 9) { + // Ten en cuenta que no estamos empezando desde 0 para que coincida con + // la trayectoria de un círculo. + let v = p5.Vector.fromAngle(radians(angle - 135)); + v.mult(100); + circle.push(v); + // Llenemos el ArrayList de transformación con PVectores en blanco mientras estamos en ello. + morph.push(createVector()); + } + + // Un cuadrado es un montón de vértices a lo largo de líneas rectas + // La parte superior del cuadrado + for (let x = -50; x < 50; x += 10) { + square.push(createVector(x, -50)); + } + // Lado derecho + for (let y = -50; y < 50; y += 10) { + square.push(createVector(50, y)); + } + // Parte inferior + for (let x = 50; x > -50; x -= 10) { + square.push(createVector(x, 50)); + } + // Lado izquierdo + for (let y = 50; y > -50; y -= 10) { + square.push(createVector(-50, y)); + } +} + +function draw() { + background(51); + + // Guardaremos la distancia de los vértices de su objetivo + let totalDistance = 0; + + // Mira cada vértice + for (let i = 0; i < circle.length; i++) { + let v1; + // ¿Estamos yendo hacia el círculo o hacia el cuadrado? + if (state) { + v1 = circle[i]; + } else { + v1 = square[i]; + } + // Consigue el vértice que dibujaremos + let v2 = morph[i]; + // Transiciona hacia el objetivo... + v2.lerp(v1, 0.1); + // Comprueba lo lejos que estamos del objetivo + totalDistance += p5.Vector.dist(v1, v2); + } + + // Si todos los vértices están cerca, cambia de forma + if (totalDistance < 0.1) { + state = !state; + } + + // Dibuja relativo al centro + translate(width / 2, height / 2); + strokeWeight(4); + // Dibuja un polígono compuesto de todos los vértices + beginShape(); + noFill(); + stroke(255); + + morph.forEach(v => { + vertex(v.x, v.y); + }); + endShape(CLOSE); +} diff --git a/dist/assets/examples/es/13_Motion/06_Moving_On_Curves.js b/dist/assets/examples/es/13_Motion/06_Moving_On_Curves.js new file mode 100644 index 0000000000..67e9fff123 --- /dev/null +++ b/dist/assets/examples/es/13_Motion/06_Moving_On_Curves.js @@ -0,0 +1,47 @@ +/* + * @name Moviéndose por Curvas + * @frame 720,400 + * @description En este ejemplo, los círculos se mueven a lo largo de la curva y = x^4. + * Haz clic con el ratón para que se mueva a una nueva posición. + */ + +let beginX = 20.0; // Coordenada X inicial +let beginY = 10.0; // Coordenada Y inicial +let endX = 570.0; // Coordenada X final +let endY = 320.0; // Coordenada Y final +let distX; // Distancia a moverse en el eje X +let distY; // Distancia a moverse en el eje Y +let exponent = 4; // Determina la curva +let x = 0.0; // Coordenada X actual +let y = 0.0; // Coordenada Y actual +let step = 0.01; // Tamaño de cada paso a lo largo del camino +let pct = 0.0; // Porcentaje viajado (0.0 a 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/dist/assets/examples/es/13_Motion/07_Circle_Collision.js b/dist/assets/examples/es/13_Motion/07_Circle_Collision.js new file mode 100644 index 0000000000..876bc23d6e --- /dev/null +++ b/dist/assets/examples/es/13_Motion/07_Circle_Collision.js @@ -0,0 +1,145 @@ +/* + * @name Circle Collision + * @frame 710,400 (optional) + * @description This is a port of the "Circle Collision" example from processing.org/examples
This example uses vectors for better visualization of physical Quantity + */ +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]); + } +} diff --git a/dist/assets/examples/es/13_Motion/08_Moving_On_Curves.js b/dist/assets/examples/es/13_Motion/08_Moving_On_Curves.js new file mode 100644 index 0000000000..4c347c7e00 --- /dev/null +++ b/dist/assets/examples/es/13_Motion/08_Moving_On_Curves.js @@ -0,0 +1,47 @@ +/* + * @name Moving On Curves + * @frame 720,400 + * @description In this example, the circles moves along the curve y = x^4. + * Click the mouse to have it move to a new position. + */ + +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/dist/assets/examples/es/15_Instance_Mode/01_Instantiating.js b/dist/assets/examples/es/15_Instance_Mode/01_Instantiating.js new file mode 100644 index 0000000000..6d0b837984 --- /dev/null +++ b/dist/assets/examples/es/15_Instance_Mode/01_Instantiating.js @@ -0,0 +1,35 @@ +/* + * @name Instaciación + * @description Crear una instancia de p5, que mantiene todas las variables + * fuera del scope global de tu página. + */ +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); + +// Compara con el "modo global" +// 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/dist/assets/examples/es/15_Instance_Mode/02_Instance_Container.js b/dist/assets/examples/es/15_Instance_Mode/02_Instance_Container.js new file mode 100644 index 0000000000..e30f50fab1 --- /dev/null +++ b/dist/assets/examples/es/15_Instance_Mode/02_Instance_Container.js @@ -0,0 +1,92 @@ +/* + * @norender + * @name Contenedor de instancia + * @description Opcionalmente, puedes especificar un contenedor por defecto para el lienzo + * y otros elementos que anexes con un segundo argumento. Puedes darle la ID + * de un elemento en tu código html, o incluso un nodo html. + * + * Aquí hay tres opciones diferentes Para seleccionar un elemento contenedor de DOM. + * Todos los elementos DOM (lienzos, botones, divisiones, etc) creados por p5 + * serán adjuntados al elemento DOM especificado como el segundo argumento de la llamada a la función p5(). + */ + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/assets/examples/es/16_Dom/03_Input_Button.js b/dist/assets/examples/es/16_Dom/03_Input_Button.js new file mode 100644 index 0000000000..28751d883e --- /dev/null +++ b/dist/assets/examples/es/16_Dom/03_Input_Button.js @@ -0,0 +1,38 @@ +/* + * @name Entrada y botón + * @description Ingresa texto y haz click en el botón para ver cómo afecta al lienzo + */ +let input, button, greeting; + +function setup() { + // crear un lienzo + createCanvas(710, 400); + + input = createInput(); + input.position(20, 65); + + button = createButton('submit'); + button.position(150, 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/dist/assets/examples/es/16_Dom/04_Slider.js b/dist/assets/examples/es/16_Dom/04_Slider.js new file mode 100644 index 0000000000..041fedfb73 --- /dev/null +++ b/dist/assets/examples/es/16_Dom/04_Slider.js @@ -0,0 +1,30 @@ +/* + * @name Barra deslizante + * @description Mueve las barras deslizantes para controlar los valores de color RGB del fondo. + */ +let rSlider, gSlider, bSlider; + +function setup() { + // crear lienzo + createCanvas(710, 400); + textSize(15); + noStroke(); + + // crear barras deslizantes + 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', 165, 35); + text('green', 165, 65); + text('blue', 165, 95); +} diff --git a/dist/assets/examples/es/16_Dom/07_Modify_DOM.js b/dist/assets/examples/es/16_Dom/07_Modify_DOM.js new file mode 100644 index 0000000000..f4728582a9 --- /dev/null +++ b/dist/assets/examples/es/16_Dom/07_Modify_DOM.js @@ -0,0 +1,51 @@ +/* + * @name Modificar el DOM + * @frame 710,300 + * @description Crea elementos DOM y modifica sus propiedades cada vez que draw() es llamado + */ +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() { + // Este párrafo es creado aparte del bloque principal de código. + // Es para diferenciar entre la creación de un elemento y su selección. + // Los elementos seleccionados no necesitan ser creados por p5js, pueden ser HTML plano. + createP( + 'I learn in this Letter, that Don Peter of Arragon, ' + + ' comes this night to Messina' + ).addClass('text').hide(); + + // Esta línea toma el párrafo recién creado, pero podría también + // tomar otros elementos de la clase 'text' en la página HTML. + 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/dist/assets/examples/es/16_Dom/08_Video.js b/dist/assets/examples/es/16_Dom/08_Video.js new file mode 100644 index 0000000000..155de71b40 --- /dev/null +++ b/dist/assets/examples/es/16_Dom/08_Video.js @@ -0,0 +1,28 @@ +/* + * @name Video + * @frame 710,250 + * @description Carga un video con múltiples formatos y alterna entre reproducir y pausar al presionar un botón. + */ +let playing = false; +let fingers; +let button; + +function setup() { + noCanvas(); + // especificar múltiples formatos para distintos navegadores + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + button = createButton('play'); + button.mousePressed(toggleVid); // adjuntar un listener al botón +} + +// reproduce o pausa el video dependiendo de su estado actual +function toggleVid() { + if (playing) { + fingers.pause(); + button.html('play'); + } else { + fingers.loop(); + button.html('pause'); + } + playing = !playing; +} diff --git a/dist/assets/examples/es/16_Dom/09_Video_Canvas.js b/dist/assets/examples/es/16_Dom/09_Video_Canvas.js new file mode 100644 index 0000000000..684d8dfcd6 --- /dev/null +++ b/dist/assets/examples/es/16_Dom/09_Video_Canvas.js @@ -0,0 +1,26 @@ +/* + * @name Lienzo y video + * @description Cargar un video en múltiples formatos y dibújalo en el lienzo. + * Para correr este ejemplo localmente, necesitarás correr un + * servidor local. + */ +let fingers; + +function setup() { + createCanvas(710, 400); + // especificar múltiples formatos para diferentes navegadores + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + fingers.hide(); // por defecto el video aparece en un elemento dom separado. + // escóndelo y dibújalo en el lienzo en vez de eso. +} + +function draw() { + background(150); + image(fingers, 10, 10); // dibuja el cuadro del video en el lienzo. + filter(GRAY); + image(fingers, 150, 150); // dibuja una segunda copia en el lienzo. +} + +function mousePressed() { + fingers.loop(); // configurar el video para empezar a reproducirse en bucle +} diff --git a/dist/assets/examples/es/16_Dom/10_Video_Pixels.js b/dist/assets/examples/es/16_Dom/10_Video_Pixels.js new file mode 100644 index 0000000000..f722ee9ef4 --- /dev/null +++ b/dist/assets/examples/es/16_Dom/10_Video_Pixels.js @@ -0,0 +1,32 @@ +/* + * @name Pixeles de video + * @frame 320,240 + * @description Cargar un video, manipula sus pixeles y dibújalo en el lienzo. + * Para correr este ejemplo localmente, necesitarás correr un + * servidor local. + */ +let fingers; + +function setup() { + createCanvas(320, 240); + // especifica múltples formatos para distintos navegadores + 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/dist/assets/examples/es/16_Dom/11_Capture.js b/dist/assets/examples/es/16_Dom/11_Capture.js new file mode 100644 index 0000000000..1ce429c057 --- /dev/null +++ b/dist/assets/examples/es/16_Dom/11_Capture.js @@ -0,0 +1,24 @@ +/* + * @name Captura de video + * @frame 710,240 + * @description Captura video desde la webcam, muéstralo + * en el lienzo con un filtro de inversión. Fíjate que por defecto la + * captura también aparece. Puedes esconderla + * si quitas el comentario a la línea de código capture.hide(). + * Para correr este ejemplo localmente, necesitarás correr un + * servidor local. + */ +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/dist/assets/examples/es/16_Dom/12_Drop.js b/dist/assets/examples/es/16_Dom/12_Drop.js new file mode 100644 index 0000000000..ac8c66455b --- /dev/null +++ b/dist/assets/examples/es/16_Dom/12_Drop.js @@ -0,0 +1,33 @@ +/* + * @name Arrojar + * @description Toma un archivo de imagen y arrójalo sobre el lienzo para mostrarlo. + */ + +function setup() { + // crear el lienzo + const c = createCanvas(710, 400); + background(100); + // añadir un evento para cuando un archivo sea arrojado al lienzo + 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) { + // si es un archivo de imagen + if (file.type === 'image') { + // crear un elemento de imagen DOM, pero sin mostrarlo + const img = createImg(file.data).hide(); + // dibujar la imagen en el lienzo + image(img, 0, 0, width, height); + } else { + println('Not an image file!'); + } +} diff --git a/dist/assets/examples/es/16_Dom/13_DOM_Form_Elements.js b/dist/assets/examples/es/16_Dom/13_DOM_Form_Elements.js new file mode 100644 index 0000000000..d83dfdc13e --- /dev/null +++ b/dist/assets/examples/es/16_Dom/13_DOM_Form_Elements.js @@ -0,0 +1,152 @@ +/* + * @name DOM Form Elements + * @frame 600,400 + * @description contributed by + Prof WM Harris, How to use p5 DOM form elements to create a slider, +button, checkbox, radio group, select menu, and entry field.
+Functions are created that include: the canvas +setup, checkbox creation with text, text box with text that projects +typed text onto canvas, slider with button, three selections which +project a rectangle in different areas on the canvas depending on +selection, and a drop down menu with font change. +*/ + +/* global variables */ +//p5 DOM form elements +let slider1; +let button1; +let checkbox1; +let radio1; +let select1; +let entry1; + +function setup() { + createCanvas(200, 200); + background("beige"); + + checkbox1 = createCheckbox("Check me"); + + createP(); //spacer with

tag + + createSpan("What's your name? "); //label for entry1 + // createInput([value], [type]) + // type: "text" (default), "number", + // "date", "password", "email", etc. + entry1 = createInput(); + //If text in the entry field changes, call + //the entryCallback function. + entry1.changed(entryCallback); + + createP(); //spacer with

tag + + //createSlider(min, max, [value], [step]) + slider1 = createSlider(10, 200); + + button1 = createButton("Press me"); //, "pressed"); + //Assign callback fcn for button1 + //when user clicks mouse on it + button1.mouseClicked(button1Clicked); + + createP(); //spacer with

tag + + radio1 = createRadio(); + + //.option([value], [contentLabel]) + //If 1 param, it's both content AND + //value. Values treated as strings. + radio1.option(1, "cranberries"); + radio1.option(2, "almonds"); + radio1.option(3, "gouda"); + + radio1.value("1"); //set init value + + createP(); //spacer with

tag + + select1 = createSelect(); + //.option([contentValue],[value]) + //If 1 param, it's both content AND + //value. Values treated as strings. + select1.option("Sans-serif"); + select1.option("Serif"); + select1.option("Fantasy"); + //If changed, call select1Changed + select1.changed(select1Changed); +} + +function draw() { + //get value from slider 1 + let gray = slider1.value(); + fill(gray); + + //If mouse in corner, turn on checkbox1 + if ((mouseX < width / 3) && + (mouseY < height / 3)) { + checkbox1.checked(true); + } + //Is checkbox1 checked? Say so. + if (checkbox1.checked()) { + text("CHECKED", 20, 40); + } + + switch (radio1.value()) { + //radio value is always a string + case "1": + rect(0, 0, width, 50); + break; + case "2": + rect(0, 70, width, 50); + break; + case "3": + rect(0, 140, width, 50); + break; + } +} + +//callback fcn for button1 +function button1Clicked() { + //reset slider value to 200 + slider1.value(200); +} + + +//callback fcn for select1 +function select1Changed() { + switch (select1.value()) { + case "Sans-serif": + textFont("sans-serif"); + break; + case "Serif": + textFont("serif"); + break; + case "Fantasy": + textFont("fantasy"); + break; + } +} + +//callback function for entry1 +function entryCallback() { + for (let i = 0; i < 25; i++) { + text(entry1.value(), random(width), + random(height)); + } + +} + +function mouseClicked() { + console.log("button1?", button1.value()); + console.log("checkbox1?", checkbox1.value()); + //Update .value of either? No visible change + //to a button or checkbox + checkbox1.value("Check again"); + button1.value("clicked?"); +} + +function keyTyped() { + switch (key) { + case "r": + //move slider1 value to 100 + slider1.value(100); + break; + } +} diff --git a/dist/assets/examples/es/17_Drawing/00_Continuous_Lines.js b/dist/assets/examples/es/17_Drawing/00_Continuous_Lines.js new file mode 100644 index 0000000000..f0a598656f --- /dev/null +++ b/dist/assets/examples/es/17_Drawing/00_Continuous_Lines.js @@ -0,0 +1,15 @@ +/* + * @name Líneas continuas + * @description Haga clic y arrastre el mouse para dibujar una línea. + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + stroke(255); + if (mouseIsPressed === true) { + line(mouseX, mouseY, pmouseX, pmouseY); + } +} diff --git a/dist/assets/examples/es/17_Drawing/01_Pattern.js b/dist/assets/examples/es/17_Drawing/01_Pattern.js new file mode 100644 index 0000000000..5f3401737d --- /dev/null +++ b/dist/assets/examples/es/17_Drawing/01_Pattern.js @@ -0,0 +1,26 @@ +/* + * @name Patrones + * @description Mueva el cursor sobre la imagen para dibujar con una herramienta + * de software que responda a la velocidad del mouse. + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + // Llame al método variableEllipse () y envíele los parámetros + // para la posición actual del mouse y la posición anterior del mouse + variableEllipse(mouseX, mouseY, pmouseX, pmouseY); +} + +// El método simple variableEllipse () fue creado específicamente +// para este programa. Calcula la velocidad del mouse +// y dibuja una pequeña elipse si el mouse se mueve lentamente +// y dibuja una elipse grande si el mouse se mueve rápidamente + +function variableEllipse(x, y, px, py) { + let speed = abs(x - px) + abs(y - py); + stroke(speed); + ellipse(x, y, speed, speed); +} diff --git a/dist/assets/examples/es/17_Drawing/02_Pulses.js b/dist/assets/examples/es/17_Drawing/02_Pulses.js new file mode 100644 index 0000000000..b808a4ece0 --- /dev/null +++ b/dist/assets/examples/es/17_Drawing/02_Pulses.js @@ -0,0 +1,31 @@ +/* + * @name Pulsos + * @description Los instrumentos de dibujo de software pueden seguir un ritmo o + * cumplir las reglas independientemente de los gestos dibujados. Esta es una + * forma de dibujo colaborativo en el que el dibujante controla algunos aspectos + * de la imagen y el software controla a los demás. + */ +let angle = 0; + +function setup() { + createCanvas(710, 400); + background(102); + noStroke(); + fill(0, 102); +} + +function draw() { + // Dibujar solo cuando se presiona el mouse + 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/dist/assets/examples/es/18_Transform/00_Translate.js b/dist/assets/examples/es/18_Transform/00_Translate.js new file mode 100644 index 0000000000..015400b453 --- /dev/null +++ b/dist/assets/examples/es/18_Transform/00_Translate.js @@ -0,0 +1,40 @@ +/* + * @name Translate + * @description La función translate() (del inglés trasladar) permite que + * los objetos sean movidos a cualquier ubicación dentro de la + * ventana. El primer parámetro define la cantidad en el eje x + * y el segundo paráemtro en el eye y. Este ejemplo muestra cómo las + * transformadas se acumulan. + */ + +let x = 0; +let y = 0; +let dim = 80.0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(102); + // Animar al incrementar nuestor valor x + x = x + 0.8; + // Si la figura se sale del lienzo, reinicia la posición + if (x > width + dim) { + x = -dim; + } + + // Aunque nuestro comando rect() dibuja la figura con su centro + // en el origen, translate() lo mueve a una nueva posición x,y + translate(x, height / 2 - dim / 2); + fill(255); + rect(-dim / 2, -dim / 2, dim, dim); + + // Las transformaciones se acumulan. Observa cómo este rect se mueve + // al doble de velocidad que el otro, a pesar de que tiene el mismo + // parámetro para el valor de x. + translate(x, dim); + fill(0); + rect(-dim / 2, -dim / 2, dim, dim); +} diff --git a/dist/assets/examples/es/18_Transform/01_Scale.js b/dist/assets/examples/es/18_Transform/01_Scale.js new file mode 100644 index 0000000000..65863eb539 --- /dev/null +++ b/dist/assets/examples/es/18_Transform/01_Scale.js @@ -0,0 +1,47 @@ +/* + * @name Escalar + * @description Los parámetros de la función scale() (del inglés escalar) + * son valores especificados como porcentajes decimales. Por ejemplo, + * ejecutar scale(2.0) aumentará la dimensión de la digura en un + * 200 por ciento. Los objetos siempre se escalan desde el origen. + * Este ejemplo muestra cómo las transformaciones se acumulan y + * también cómo scale() y translate() interactúan dependiendo de su + * orden. + */ + +let a = 0.0; +let s = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + // Dibuja todos los rectángulos desde su centro, en vez de + // la esquina superior izquierda, que es la forma por defecto. + rectMode(CENTER); +} + +function draw() { + background(102); + + // Lentamente aumenta 'a' y luego anima 's' con un movimiento + // cíclico suave mediante el cálculo de coseno de 'a' + a = a + 0.04; + s = cos(a) * 2; + + // Traslada nuestro rectángulo desde el origen hacia el centro + // del lienzo, luego escálalo con 's' + translate(width / 2, height / 2); + scale(s); + fill(51); + rect(0, 0, 50, 50); + + // Traslación y escalamiento son acumulativos, por lo que esta + // esta traslación mueve el segundo rectángulo más a la derecha del + // primero y el escalamiento es doblado. Observa que el coseno + // está haciendo que 's' sea tanto positivo como negativo, + // por lo que oscila entre izquierda y derecha. + translate(75, 0); + fill(255); + scale(s); + rect(0, 0, 50, 50); +} diff --git a/dist/assets/examples/es/18_Transform/02_Rotate.js b/dist/assets/examples/es/18_Transform/02_Rotate.js new file mode 100644 index 0000000000..dd73728a23 --- /dev/null +++ b/dist/assets/examples/es/18_Transform/02_Rotate.js @@ -0,0 +1,48 @@ +/* + * @name Rotate + * @description Rotar un cuadrado en torno al eje Z + Si prefieres usar grados (0-360) para medir los ángulos, puede usas el + * método radians() para convertir tus valores a radianes + * For example: scale(radians(90)) is identical to the statement + * scale(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. + * Para obtener los resultados que esperas, usa ángulos de la función + * rotate() (del inglés rotar) con valores entre 0 y PI*2 (TWO_PI que + * es aproximadamente 6.28) + * + * + * + */ + +let angulo = 0.0; +let jitter = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + fill(255); + // Dibuja el rectánglo desde el centro y también hará que + //la rotación sea en torno al centro + rectMode(CENTER); +} + +function draw() { + background(51); + + // Durante los segundos pares (0, 2, 4, 6...), añade jitter a + // la rotación + if (second() % 2 === 0) { + jitter = random(-0.1, 0.1); + } + //increase the angle value using the most recent jitter value + angulo = angulo + jitter; + // Usa coseno para obtener un movimiento suave a favor y en contra + // de las manecillas del reloj cuando no esté haciendo jittering + let c = cos(angulo); + // Mueve la figura al centro del lienzo + translate(width / 2, height / 2); + // Aplica la rotación final + rotate(c); + rect(0, 0, 180, 180); +} diff --git a/dist/assets/examples/es/18_Transform/03_Arm.js b/dist/assets/examples/es/18_Transform/03_Arm.js new file mode 100644 index 0000000000..524cffb67e --- /dev/null +++ b/dist/assets/examples/es/18_Transform/03_Arm.js @@ -0,0 +1,48 @@ +/* + * @name Brazo + * @description Este ejemplo usa matrices de transformación para crear + * un brazo. El ángulo de cada segmento es controlado con la posición + * de mouseX y mouseY. Las transformaciones aplicadas al primer segmento + * son aplicadas al segundo segmento porque están dentro del mismo grupo + * de matrices push() y pop() + */ + +let x, y; +let angulo1 = 0.0; +let angulo2 = 0.0; +let largoSegmento = 100; + +function setup() { + createCanvas(720, 400); + strokeWeight(30); + + // Trazo blanco semi-transparente + stroke(255, 160); + + // Posición del "hombro" del brazo en el centro del lienzo + x = width * 0.5; + y = height * 0.5; +} + +function draw() { + background(0); + + //Modifica el ángulo de los segmentos según la posición del ratón + angulo1 = (mouseX / float(width) - 0.5) * -TWO_PI; + angulo2 = (mouseY / float(height) - 0.5) * PI; + + // Usa push y pop para "contener" las transformaciones. Nota que + // aunque dibujamos los segmentos usando una función de fabricación propia, + // las transformaciones igualmente se acumulan. + push(); + segmento(x, y, angulo1); + segmento(largoSegmento, 0, angulo2); + pop(); +} + +// una función de fabricación propia para dibujar segmentos +function segmento(x, y, a) { + translate(x, y); + rotate(a); + line(0, 0, largoSegmento, 0); +} diff --git a/dist/assets/examples/es/19_Typography/00_Letters.js b/dist/assets/examples/es/19_Typography/00_Letters.js new file mode 100644 index 0000000000..44d4f2a7ee --- /dev/null +++ b/dist/assets/examples/es/19_Typography/00_Letters.js @@ -0,0 +1,64 @@ +/* + * @name Letters + * @description 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. + */ +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 (y = 0; y < height - gap; y += gap) { + for (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/dist/assets/examples/es/19_Typography/01_Words.js b/dist/assets/examples/es/19_Typography/01_Words.js new file mode 100644 index 0000000000..d76271f2b8 --- /dev/null +++ b/dist/assets/examples/es/19_Typography/01_Words.js @@ -0,0 +1,59 @@ +/* + * @name Words + * @description 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(). + */ +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/dist/assets/examples/es/19_Typography/02_Text_Rotation.js b/dist/assets/examples/es/19_Typography/02_Text_Rotation.js new file mode 100644 index 0000000000..fdfd7d31a5 --- /dev/null +++ b/dist/assets/examples/es/19_Typography/02_Text_Rotation.js @@ -0,0 +1,62 @@ +/* + * @name Text Rotation + * @description Draws letters to the screen and rotates them at different angles. + * (ported from https://processing.org/examples/textrotation.html) + */ + +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); +} diff --git a/dist/assets/examples/es/20_3D/00_geometries.js b/dist/assets/examples/es/20_3D/00_geometries.js new file mode 100644 index 0000000000..c417a19da6 --- /dev/null +++ b/dist/assets/examples/es/20_3D/00_geometries.js @@ -0,0 +1,54 @@ +/* + * @name Geometrías + * @description Existen seis figuras 3D primitivas en p5 en este momento. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + translate(-250 * 2.5, 0, 0); + normalMaterial(); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + plane(80); + pop(); + translate(250, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(80, 80, 80); + pop(); + translate(250, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cylinder(80, 80); + pop(); + translate(250, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cone(80, 80); + pop(); + translate(250, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + torus(80, 20); + pop(); + translate(250, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + sphere(80); + pop(); +} diff --git a/dist/assets/examples/es/20_3D/01_sine_cosine_in_3D.js b/dist/assets/examples/es/20_3D/01_sine_cosine_in_3D.js new file mode 100644 index 0000000000..07def6643d --- /dev/null +++ b/dist/assets/examples/es/20_3D/01_sine_cosine_in_3D.js @@ -0,0 +1,28 @@ +/* + * @name Seno Coseno en 3D + * @description Seno, coseno, "push" y "pop" pueden ser utilizados también en 3D. + */ +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/dist/assets/examples/es/20_3D/02_multiple_lights.js b/dist/assets/examples/es/20_3D/02_multiple_lights.js new file mode 100644 index 0000000000..21abbdc73c --- /dev/null +++ b/dist/assets/examples/es/20_3D/02_multiple_lights.js @@ -0,0 +1,30 @@ +/* + * @name Múltiples luces + * @description Se pueden usar todos los tipos de luces usados en un mismo bosquejo. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + ambientLight(50); + directionalLight(255, 0, 0, 0.25, 0.25, 0); + 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, 64); +} diff --git a/dist/assets/examples/es/20_3D/03_materials.js b/dist/assets/examples/es/20_3D/03_materials.js new file mode 100644 index 0000000000..fdec1e6057 --- /dev/null +++ b/dist/assets/examples/es/20_3D/03_materials.js @@ -0,0 +1,65 @@ +/* + * @name Materiales + * @description Existen cinco tipos de materiales soportados. + * Reaccionan de distintas formas a la luz. + * Mueve tu ratón para cambiar la posición de la luz. + */ +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/dist/assets/examples/es/20_3D/04_textures.js b/dist/assets/examples/es/20_3D/04_textures.js new file mode 100644 index 0000000000..3b89088a22 --- /dev/null +++ b/dist/assets/examples/es/20_3D/04_textures.js @@ -0,0 +1,40 @@ +/* + * @name Texturas + * @description Tanto imágenes como videos pueden ser usados como texturas. + */ +// fuente del video: 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); + //pasar una imagen como textura + 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/dist/assets/examples/es/20_3D/05_ray_casting.js b/dist/assets/examples/es/20_3D/05_ray_casting.js new file mode 100644 index 0000000000..98906dcb28 --- /dev/null +++ b/dist/assets/examples/es/20_3D/05_ray_casting.js @@ -0,0 +1,100 @@ +/* + * @name Ray Casting + * @description Original example by Jonathan Watson. + *

Detecting the position of the mouse in 3D space with ray casting. + */ +const objects = []; +let eyeZ; + +function setup() { + createCanvas(710, 400, WEBGL); + + eyeZ = height / 2 / tan((30 * PI) / 180); // 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); + } +} diff --git a/dist/assets/examples/es/20_3D/07_orbit_control.js b/dist/assets/examples/es/20_3D/07_orbit_control.js new file mode 100644 index 0000000000..fea8ffecde --- /dev/null +++ b/dist/assets/examples/es/20_3D/07_orbit_control.js @@ -0,0 +1,36 @@ +/* + * @name Control de órbita + * @description El control de órbita te permite arrastrar y mover alrededor del mundo. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + let radius = width * 1.5; + + //arrastra para mover el mundo. + orbitControl(); + + normalMaterial(); + translate(0, 0, -600); + 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/dist/assets/examples/es/20_3D/08_basic_shader.js b/dist/assets/examples/es/20_3D/08_basic_shader.js new file mode 100644 index 0000000000..32610c79e4 --- /dev/null +++ b/dist/assets/examples/es/20_3D/08_basic_shader.js @@ -0,0 +1,27 @@ +/* + * @name Basic Shader + * @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 + */ + +// 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); +} diff --git a/dist/assets/examples/es/20_3D/09_shader_as_a_texture.js b/dist/assets/examples/es/20_3D/09_shader_as_a_texture.js new file mode 100644 index 0000000000..7bffbab11b --- /dev/null +++ b/dist/assets/examples/es/20_3D/09_shader_as_a_texture.js @@ -0,0 +1,68 @@ +/* + * @name Shader as a Texture + * @description Shaders can be applied to 2D/3D shapes as textures. + *
To learn more about using shaders in p5.js: p5.js Shaders + */ + + // 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); + } diff --git a/dist/assets/examples/es/20_3D/10_passing_shader_uniforms.js b/dist/assets/examples/es/20_3D/10_passing_shader_uniforms.js new file mode 100644 index 0000000000..3d6dc2ec1b --- /dev/null +++ b/dist/assets/examples/es/20_3D/10_passing_shader_uniforms.js @@ -0,0 +1,33 @@ +/* + * @name Passing Shader Uniforms + * @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 + */ + + // 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(); + } + + function draw() { + // shader() sets the active shader with our shader + shader(theShader); + + // lets send the resolution, mouse, and time to our shader + // before sending mouse + time we modify the data so it's more easily usable by the shader + theShader.setUniform('resolution', [width, height]); + 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); + } diff --git a/dist/assets/examples/es/20_3D/11_shader_using_webcam.js b/dist/assets/examples/es/20_3D/11_shader_using_webcam.js new file mode 100644 index 0000000000..a3ed382cff --- /dev/null +++ b/dist/assets/examples/es/20_3D/11_shader_using_webcam.js @@ -0,0 +1,37 @@ +/* + * @name Shader Using Webcam + * @description The webcam can be passed to shaders as a texture. + *
To learn more about using shaders in p5.js: p5.js Shaders + */ + + // 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); + } diff --git a/dist/assets/examples/es/21_Input/00_Clock.js b/dist/assets/examples/es/21_Input/00_Clock.js new file mode 100644 index 0000000000..5603db0f3e --- /dev/null +++ b/dist/assets/examples/es/21_Input/00_Clock.js @@ -0,0 +1,62 @@ +/* + * @name Clock + * @description 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. + */ +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/dist/assets/examples/es/21_Input/01_Constrain.js b/dist/assets/examples/es/21_Input/01_Constrain.js new file mode 100644 index 0000000000..36a08abd31 --- /dev/null +++ b/dist/assets/examples/es/21_Input/01_Constrain.js @@ -0,0 +1,36 @@ +/* + * @name Constrain + * @description Move the mouse across the screen to move + * the circle. The program constrains the circle to its box. + */ +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/dist/assets/examples/es/21_Input/02_Easing.js b/dist/assets/examples/es/21_Input/02_Easing.js new file mode 100644 index 0000000000..6fe01dc1b0 --- /dev/null +++ b/dist/assets/examples/es/21_Input/02_Easing.js @@ -0,0 +1,30 @@ +/* + * @name Easing + * @description 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. + */ +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/dist/assets/examples/es/21_Input/03_Keyboard.js b/dist/assets/examples/es/21_Input/03_Keyboard.js new file mode 100644 index 0000000000..c7b50f99a3 --- /dev/null +++ b/dist/assets/examples/es/21_Input/03_Keyboard.js @@ -0,0 +1,38 @@ +/* + * @name Keyboard + * @description 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. + */ +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/dist/assets/examples/es/21_Input/04_Mouse1D.js b/dist/assets/examples/es/21_Input/04_Mouse1D.js new file mode 100644 index 0000000000..eb613fbab9 --- /dev/null +++ b/dist/assets/examples/es/21_Input/04_Mouse1D.js @@ -0,0 +1,24 @@ +/* + * @name Mouse 1D + * @description 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. + */ +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/dist/assets/examples/es/21_Input/05_Mouse2D.js b/dist/assets/examples/es/21_Input/05_Mouse2D.js new file mode 100644 index 0000000000..efc623adae --- /dev/null +++ b/dist/assets/examples/es/21_Input/05_Mouse2D.js @@ -0,0 +1,20 @@ +/* + * @name Mouse 2D + * @description Moving the mouse changes the position and + * size of each box. + */ +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/dist/assets/examples/es/21_Input/06_MouseIsPressed.js b/dist/assets/examples/es/21_Input/06_MouseIsPressed.js new file mode 100644 index 0000000000..27279e99b0 --- /dev/null +++ b/dist/assets/examples/es/21_Input/06_MouseIsPressed.js @@ -0,0 +1,20 @@ +/* + * @name Mouse Press + * @description Move the mouse to position the shape. + * Press the mouse button to invert the color. + */ +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/dist/assets/examples/es/21_Input/07_Mouse_Functions.js b/dist/assets/examples/es/21_Input/07_Mouse_Functions.js new file mode 100644 index 0000000000..ad1acdc7b2 --- /dev/null +++ b/dist/assets/examples/es/21_Input/07_Mouse_Functions.js @@ -0,0 +1,66 @@ +/* + * @name Mouse Functions + * @description Click on the box and drag it across the screen. + */ +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/dist/assets/examples/es/21_Input/08_Mouse_Signals.js b/dist/assets/examples/es/21_Input/08_Mouse_Signals.js new file mode 100644 index 0000000000..8847fe8f1c --- /dev/null +++ b/dist/assets/examples/es/21_Input/08_Mouse_Signals.js @@ -0,0 +1,52 @@ +/* + * @name Mouse Signals + * @description 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". + */ +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/dist/assets/examples/es/21_Input/09_Storing_Input.js b/dist/assets/examples/es/21_Input/09_Storing_Input.js new file mode 100644 index 0000000000..563ff80759 --- /dev/null +++ b/dist/assets/examples/es/21_Input/09_Storing_Input.js @@ -0,0 +1,38 @@ +/* + * @name Storing Input + * @description 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. + */ +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/dist/assets/examples/es/21_Input/10_Rollover.js b/dist/assets/examples/es/21_Input/10_Rollover.js new file mode 100644 index 0000000000..09ebd6648c --- /dev/null +++ b/dist/assets/examples/es/21_Input/10_Rollover.js @@ -0,0 +1,79 @@ +/* + * @name Rollover + * @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 + */ +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; + } +} \ No newline at end of file diff --git a/dist/assets/examples/es/21_Input/11_Storing_Input.js b/dist/assets/examples/es/21_Input/11_Storing_Input.js new file mode 100644 index 0000000000..563ff80759 --- /dev/null +++ b/dist/assets/examples/es/21_Input/11_Storing_Input.js @@ -0,0 +1,38 @@ +/* + * @name Storing Input + * @description 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. + */ +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/dist/assets/examples/es/22_Advanced_Data/00_Load_Saved_JSON.js b/dist/assets/examples/es/22_Advanced_Data/00_Load_Saved_JSON.js new file mode 100644 index 0000000000..7d3e8f4b66 --- /dev/null +++ b/dist/assets/examples/es/22_Advanced_Data/00_Load_Saved_JSON.js @@ -0,0 +1,104 @@ +/* + * @name Load Saved JSON + * @description Create a Bubble class, instantiate multiple bubbles using data from + * a JSON file, and display results on the screen. + * Because the 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. + */ + +// 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); +} diff --git a/dist/assets/examples/es/22_Advanced_Data/01_Load_Saved_Table.js b/dist/assets/examples/es/22_Advanced_Data/01_Load_Saved_Table.js new file mode 100644 index 0000000000..8536abcccc --- /dev/null +++ b/dist/assets/examples/es/22_Advanced_Data/01_Load_Saved_Table.js @@ -0,0 +1,110 @@ +/* + * @name Load Saved Table + * @description Create a Bubble class, instantiate multiple bubbles using data from + * a csv file, and display results on the screen. + * Because the web browsers differ in where they save files, we do not make use of + * + * Based on Daniel Shiffman's LoadSaveTable Example for Processing. + */ + +// 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); +} diff --git a/dist/assets/examples/es/33_Sound/00_Load_and_Play_Sound.js b/dist/assets/examples/es/33_Sound/00_Load_and_Play_Sound.js new file mode 100644 index 0000000000..5497898f68 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/00_Load_and_Play_Sound.js @@ -0,0 +1,25 @@ +/* + * @name Cargar y reproducir sonido + * @description Carga de sonido durante preload(). Reproducir un sonido cuando se hace click en el lienzo. + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +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() retorna una variable booleana + song.stop(); + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/es/33_Sound/01_Preload_Sound.js b/dist/assets/examples/es/33_Sound/01_Preload_Sound.js new file mode 100644 index 0000000000..22b5ed0f1d --- /dev/null +++ b/dist/assets/examples/es/33_Sound/01_Preload_Sound.js @@ -0,0 +1,34 @@ +/* + * @name Precargar archivo de sonido + * @description Llamar a loadSound() durante preload() para asegurar que el + * sonido esté completamente cargado antes de llamar a setup(). Es mejor siempre + * llamar a loadSound() dentro de preload(), si no podría pasar que los sonidos no estén cargados + * al momento de querer reproducirlos en tu bosquejo. + * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ + +let song; + +function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + song.loop(); // la canción está lista para ser reproducida durante setup() porque fue cargada durante preload() + background(0, 255, 0); +} + +function mousePressed() { + if (song.isPlaying()) { + // .isPlaying() retorna una variable booleana + song.pause(); // .play() continuará la reproducción desde la posición definida por .pause() + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/es/33_Sound/02_soundFormats.js b/dist/assets/examples/es/33_Sound/02_soundFormats.js new file mode 100644 index 0000000000..d3e7c53224 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/02_soundFormats.js @@ -0,0 +1,53 @@ +/** + * @name Formatos de sonido + * @description

Técnicamente, por problemas de patente, no existe un único + * formato de sonido que sea soportado por todos los navegadores web. Mientras que el + * mp3 es soportado a lo largo de las + * últimas versiones de los más populares navegadores en OS X y Windows, por ejemplo, + * puede no estar disponible en algunos sistemas operativos o navegadmores menos comunes.

+ * + *

Para asegurarse de tener total compatibilidad, puedes incluir el mismo archivo de sonido + * en múltiples formatos, por ejemplo 'sound.mp3' y 'sound.ogg'. (Ogg es una + * alternativa al mp3 de código abierto.) Puedes convertir archivos de audio + * en formatos amigables con la web de forma gratuita en media.io

. + * + *

El método soundFormats() le dice a loadSound() cuáles formatos + * hemos incluido en nuestro bosquejo. Entonces, loadSound() + * tratará de cargar el primer formato que sea soportado por + * el navegador web del cliente.

+ * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ + +let song; + +function preload() { + // hemos incluido un archivo .ogg y otro .mp3 + soundFormats('ogg', 'mp3'); + + // si mp3 no es soportado por este navegador, + // loadSound() cargará el archivo ogg + // que hemos incluido con nuestro bosquejo + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + + // canción cargada durante preload(), lista para ser reproducida durante setup() + song.play(); + background(0, 255, 0); +} + +function mousePressed() { + if (song.isPlaying()) { + // .isPlaying() retorna una variable booleana + song.pause(); + background(255, 0, 0); + } else { + song.play(); // la reproducción continuará desde el instante en que fue pausado. + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/es/33_Sound/03_Play_Mode.js b/dist/assets/examples/es/33_Sound/03_Play_Mode.js new file mode 100644 index 0000000000..478ee963a7 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/03_Play_Mode.js @@ -0,0 +1,42 @@ +/* + * @name Modo de reproducción + * @description + *

En el modo 'sustain', el sonido se superpone consigo mismo. + * En el modo 'restart', parará y comenzará de nuevo + * Haz click para reproducir un archivo de audio. + * Gatilla muchos sonidos al mismo tiempo. Presiona cualquier tecla para cambiar el modo de reproducción.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +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/dist/assets/examples/es/33_Sound/04_Pan_SoundFile.js b/dist/assets/examples/es/33_Sound/04_Pan_SoundFile.js new file mode 100644 index 0000000000..2b5f659a62 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/04_Pan_SoundFile.js @@ -0,0 +1,33 @@ +/* + * @name Paneo + * @description

Haz click para reproducir el sonido. + * La pelota sigue la posición del ratón y se correlaciona con el paneo del sonido.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +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() { + // mapear la posición x de la pelota a un ángulo de paneo + // entre -1.0 (izquierda) y 1.0 (derecha) + let panning = map(ball.x, 0, width, -1.0, 1.0); + soundFile.pan(panning); + soundFile.play(); +} diff --git a/dist/assets/examples/es/33_Sound/05_Sound_Effect.js b/dist/assets/examples/es/33_Sound/05_Sound_Effect.js new file mode 100644 index 0000000000..dc50db7bbc --- /dev/null +++ b/dist/assets/examples/es/33_Sound/05_Sound_Effect.js @@ -0,0 +1,70 @@ +/* + * @name Efecto de sonido + * @description

Reproduce un efecto de sonido cuando el ratón hace click dentro del círculo.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +// Adaptado de "Learning Processing" de Daniel Shiffman +// http://www.learningprocessing.com +// Sample de timbre por Corsica_S via freesound.org, +// Creative Commons BY 3.0 + +// una clase para describir un "timbre" (realmente un botón) +class Doorbell { + constructor(x_, y_, r_) { + // posición y tamaño + this.x = x_; + this.y = y_; + this.r = r_; + } + + // ¿hay un punto dentro del timbre?(usado para "rollover" del ratón) + contains(mx, my) { + return dist(mx, my, this.x, this.y) < this.r; + } + + // muestra el timbre (colores arbitrarios, podría ser mejorado) + 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); + } +} + +// Un objeto archivo de sonido +let dingdong; + +// un objeto timbre (doorbell), que gatillará el sonido +let doorbell; + +function setup() { + createCanvas(200, 200); + + // cargar el archivo de sonido + // hemos incluido versiones MP3 y OGG. + soundFormats('mp3', 'ogg'); + dingdong = loadSound('assets/doorbell.mp3'); + + // crear un nuevo timbre + doorbell = new Doorbell(width / 2, height / 2, 32); +} + +function draw() { + background(255); + // muestra el timbre + doorbell.display(mouseX, mouseY); +} + +function mousePressed() { + // si el usuario hace click en el timbre, reproduce el sonido + if (doorbell.contains(mouseX, mouseY)) { + dingdong.play(); + } +} diff --git a/dist/assets/examples/es/33_Sound/06_Manipulate_Sound.js b/dist/assets/examples/es/33_Sound/06_Manipulate_Sound.js new file mode 100644 index 0000000000..b38c9dcb34 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/06_Manipulate_Sound.js @@ -0,0 +1,50 @@ +/* + * @name Tasa de reproducción + * @description

Cargar un archivo de sonido y mapear su tasa de reproducción a la posición y del ratón + * y el volumen a la posición x, mouseY y mouseX respectivamente. + * La tasa de reproducción es la velocidad con que + * el contexto web de audio procesa la información del archivo de sonido. + * Tasas más bajas no solo prolongan la duración del sonido, sino que también + * disminuyen la altura (pitch) porque la reproducción es realizada a menor frecuencia.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +// un objeto de archivo de sonido +let song; + +function preload() { + // cargar un archivo de sonido + song = loadSound('assets/Damscray_DancingTiger.mp3'); +} + +function setup() { + createCanvas(710, 400); + + // repite el sonido en bucle por siempre + // (bueno, al menos hasta que se llame a stop()) + song.loop(); +} + +function draw() { + background(200); + + // definir el volumen a un rango entre 0 y 1.0 + let volume = map(mouseX, 0, width, 0, 1); + volume = constrain(volume, 0, 1); + song.amp(volume); + + // define la tasa a un rango entre 0.1 y 4 + // cambiar la tasa altera la altura del sonido (pitch) + let speed = map(mouseY, 0.1, height, 0, 2); + speed = constrain(speed, 0.01, 4); + song.rate(speed); + + // dibuja algunas círculos para mostrar lo que está pasando + stroke(0); + fill(51, 100); + ellipse(mouseX, 100, 48, 48); + stroke(0); + fill(51, 100); + ellipse(100, mouseY, 48, 48); +} diff --git a/dist/assets/examples/es/33_Sound/07_Amplitude_Analysis.js b/dist/assets/examples/es/33_Sound/07_Amplitude_Analysis.js new file mode 100644 index 0000000000..6d15329043 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/07_Amplitude_Analysis.js @@ -0,0 +1,50 @@ +/** + * @name Midiendo la amplitud + * @description

Analiza la amplitud del sonido con + * p5.Amplitude.

+ * + *

La amplitud es la magnitud de la vibración. El sonido es vibración, + * así que la amplitiud se relaciona fuertemente al volumen (loudness).

+ * + *

El métodogetLevel() toma un arreglo de valores de amplitud + * almacenados en un pequeño periodo de tiempo(1024 samples). + * Retorna el Root Mean Square (RMS) de estos valores.

+ * + *

Los valores originales de amplitud para audio digital están entre -1.0 y 1.0. + * No obstante, el valor RMS siempre será positivo, porque está elevado al cuadrado. + * Además, en vez de usar lecturas de amplitud instantáneas que son sampleadas a una tasa de + * 44,100 veces por segundo, RMS es un promedio en el tiempo (1024 samples, en este caso), + * lo que representa de mejor manera cómo nosotros escuchamos la amplitud. + *

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +let song, analyzer; + +function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + song.loop(); + + // crea un nuevo analizador de amplitud + analyzer = new p5.Amplitude(); + + // Conecta la entrada al analizador de amplitud + analyzer.setInput(song); +} + +function draw() { + background(255); + + // Obtén la amplitud RMS (root mean square) + let rms = analyzer.getLevel(); + fill(127); + stroke(0); + + // Dibuja una elipse con su tamaño proporcional al volumen + ellipse(width / 2, height / 2, 10 + rms * 200, 10 + rms * 200); +} diff --git a/dist/assets/examples/es/33_Sound/08_Noise_Envelope.js b/dist/assets/examples/es/33_Sound/08_Noise_Envelope.js new file mode 100644 index 0000000000..4b62c70987 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/08_Noise_Envelope.js @@ -0,0 +1,52 @@ +/** + * @name Tambor con envolvente y ruido + * @description

El ruido blanco es una señal de audio aleatoria con igual energía + * en cada parte del espectro de frecuencia

+ * + *

Una envolvente es una serie de fundidos, definidos como pares de tiempo/valor.

+ * + *

En este ejemplo, el objeto p5.Env + * será usado para "tocar" el objeto p5.Noise como un tambor, por medio de controlar su amplitud de salida. + * Un objeto p5.Amplitude nos dará el nivel de todo el sonido en el bosquejo, y + * usaremos este valor para dibujar un rectángulo verde que muestra la envolvente en acción

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * y un archivo de audio. + */ +let noise, env, analyzer; + +function setup() { + createCanvas(710, 200); + noise = new p5.Noise(); // otros tipos incluyen ruido café (brown) y rosado (pink) + noise.start(); + + // multiplica el volumen del ruido por 0 + // (¡mantenlo callado hasta que estemos listos para hacer ruido!) + noise.amp(0); + + env = new p5.Env(); + // define el tiempo de ataque, el tiempo de decaimiento, la razón de "sustain" y el tiempo de "release" + env.setADSR(0.001, 0.1, 0.2, 0.1); + // configurar el nivel de ataque y de "release" + env.setRange(1, 0); + + // El objeto p5.Amplitude() analizará todo el sonido en el bosquejo + // a menos que el métodosetInput() sea usado para especificar la señal de entrada + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // obtener lectura de volumen del analizador p5.Amplitude + let level = analyzer.getLevel(); + + // usar el nivel para dibujar un rectángulo verde + 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/dist/assets/examples/es/33_Sound/09_Note_Envelope.js b/dist/assets/examples/es/33_Sound/09_Note_Envelope.js new file mode 100644 index 0000000000..cade65804d --- /dev/null +++ b/dist/assets/examples/es/33_Sound/09_Note_Envelope.js @@ -0,0 +1,61 @@ +/** + * @name Envolvente de nota + * @description

Una envolvente es una serie de fundidos, definidos como + * pares tiempo/valor. En este ejemplo, la envolvente + * será usada para "tocar" una nota al controlar la + * amplitud de salida de un oscilador.

+ * El objeto p5.Oscillator() envía su señal de salida a través de + * un nodo de ganancia (GainNode) de tipo Web Audio interno (p5.Oscillator.output). + * Por defecto, ese nodo tiene un valor constante de 0.5. + * Puede ser redefinido con el método osc.amp(). O, como en este ejemplo, con una + * envolvente que toma control de ese nodo, subiendo y bajando + * la amplitud como una perilla de volumen.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * y un archivo de audio. + */ +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(); + + // instanciar la envolvente + envelope = new p5.Env(); + + // definir el tiempo de ataque, de decaimiento, la razón de "sustain" y el tiempo de "release" + envelope.setADSR(0.001, 0.5, 0.1, 0.5); + + // definir el nivel de ataque y de "release" + 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; + } + + // graficar el análisis de frecuencia de FFT.analyze() en el lienzo + 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/dist/assets/examples/es/33_Sound/10_Oscillator_Waveform.js b/dist/assets/examples/es/33_Sound/10_Oscillator_Waveform.js new file mode 100644 index 0000000000..a1d1e3d999 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/10_Oscillator_Waveform.js @@ -0,0 +1,41 @@ +/* + * @name Frecuencia de oscilador + * @description

Controla un oscilador y observa la forma de onda usando FFT. + * La posición horizontal del ratón (mouseX) es mapeada a la frecuencia, y la vertical (mouseY) a la amplitud.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * y un archivo de audio. + */ +let osc, fft; + +function setup() { + createCanvas(720, 256); + + osc = new p5.TriOsc(); // definir frecuencia y tipo + osc.amp(0.5); + + fft = new p5.FFT(); + osc.start(); +} + +function draw() { + background(255); + + let waveform = fft.waveform(); // analiza la forma de onda + 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(); + + // cambia la frecuencia del oscilador según mouseX + let freq = map(mouseX, 0, width, 40, 880); + osc.freq(freq); + + // cambia la amplitud del oscilador según mouseY + let amp = map(mouseY, 0, height, 1, 0.01); + osc.amp(amp); +} diff --git a/dist/assets/examples/es/33_Sound/11_Live_Input.js b/dist/assets/examples/es/33_Sound/11_Live_Input.js new file mode 100644 index 0000000000..75e30ff273 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/11_Live_Input.js @@ -0,0 +1,36 @@ +/** + * @name Entrada de micrófono + * @description

Obtén una entrada de audio desde el micrófono de tu computador. + * Haz ruido para hacer que la elipse flote.

+ *

Nota: p5.AudioIn contiene su propio objeto p5.Amplitude, + * así que puedes llamar a getLevel() en p5.AudioIn() sin + * crear un objeto p5.Amplitude().

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +let mic; + +function setup() { + createCanvas(710, 200); + + // crea una entrada de audio + mic = new p5.AudioIn(); + + // inicia la entrada de audio + // por defecto, no la conecta (.connect()) a los parlantes del computador. + mic.start(); +} + +function draw() { + background(200); + + // obtén el volumen general (entre 0.0 y 1.0) + let vol = mic.getLevel(); + fill(127); + stroke(0); + + // dibuja una elipse con altura según el volumen + let h = map(vol, 0, 1, height, 0); + ellipse(width / 2, h - 25, 50, 50); +} diff --git a/dist/assets/examples/es/33_Sound/12_FFT_Spectrum.js b/dist/assets/examples/es/33_Sound/12_FFT_Spectrum.js new file mode 100644 index 0000000000..7b7379cbfe --- /dev/null +++ b/dist/assets/examples/es/33_Sound/12_FFT_Spectrum.js @@ -0,0 +1,30 @@ +/** + * @name Espectro de frecuencia + * @description

Visualia el espectro de frecuencia de la entrada de audio en vivo.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +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/dist/assets/examples/es/33_Sound/13_Mic_Threshold.js b/dist/assets/examples/es/33_Sound/13_Mic_Threshold.js new file mode 100644 index 0000000000..f3283cfac2 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/13_Mic_Threshold.js @@ -0,0 +1,49 @@ +/** + * @name Umbral de micrófono + * @description

Gatilla un evento (dibujar un rectángulo) cuando el volumen de la entrada + * de audio sobrepasa un umbral.

+ *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +// Adaptado de "Learning Processing" por Daniel Shiffman +// learningprocessing.com +let input; +let analyzer; + +function setup() { + createCanvas(710, 200); + background(255); + + // crea una entrada de audio + input = new p5.AudioIn(); + + input.start(); +} + +function draw() { + // obtén el volumen general (entre 0.0 y 1.0) + let volume = input.getLevel(); + + // si volume > 0.1, se dibuja un rectángulo en una posición aleatoria. + // a mayor volumen, más grande el rectángulo. + let threshold = 0.1; + if (volume > threshold) { + stroke(0); + fill(0, 100); + rect(random(40, width), random(height), volume * 50, volume * 50); + } + + // grafica el volumen potencial general, con una línea en el umbral + let y = map(volume, 0, 1, height, 0); + let ythreshold = map(threshold, 0, 1, height, 0); + + noStroke(); + fill(175); + rect(0, 0, 20, height); + // luego dibuja un rectángulo en el gráfico, con su tamaño acorde al volumen + fill(0); + rect(0, y, 20, y); + stroke(0); + line(0, ythreshold, 19, ythreshold); +} diff --git a/dist/assets/examples/es/33_Sound/14_Filter_LowPass.js b/dist/assets/examples/es/33_Sound/14_Filter_LowPass.js new file mode 100644 index 0000000000..1017aa3f0d --- /dev/null +++ b/dist/assets/examples/es/33_Sound/14_Filter_LowPass.js @@ -0,0 +1,62 @@ +/** + * @name Filtro pasabajos + * @description Aplica un filtro pasabajos (p5.LowPass) a un archivo de audio (p5.SoundFile). + * Visualiza el sonido con FFT. + * Mapea la posición horizontal del ratón (mouseX) a la frecuencia de corte del filtro + * y la vertical (mouseY) a la razón resonancia/ancho de un filtro pasabanda. + * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +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); + + // reproduce el archivo de sonido en bucle + soundFile.loop(); + + filter = new p5.LowPass(); + + // desconecta el archivo de audio de la salida maestra. + // luego, conéctalo al filtro, para que solo escuchemos el sonido filtrado + soundFile.disconnect(); + soundFile.connect(filter); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // Mapea la posición horizontal del ratón (mouseX) a la frecuencia de corte desde + // la frecuencia más grave (10Hz) a la más aguda (22050Hz) que los humanos escuchan + filterFreq = map(mouseX, 0, width, 10, 22050); + + // Mapea la posición vertical del ratón (mouseY) a la resonancia (aumento de volumen) en la frecuencia de corte + filterRes = map(mouseY, 0, height, 15, 5); + + // define los parámetros del filtro + filter.set(filterFreq, filterRes); + + // dibuja cada lugar en el análisis de espectro FFT donde + // x = frecuencia más grave (10Hz) a la más aguda (22050Hz), + // h = energía (amplitud / volumen) en esa frecuencia + 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/dist/assets/examples/es/33_Sound/15_Filter_BandPass.js b/dist/assets/examples/es/33_Sound/15_Filter_BandPass.js new file mode 100644 index 0000000000..59223b268a --- /dev/null +++ b/dist/assets/examples/es/33_Sound/15_Filter_BandPass.js @@ -0,0 +1,51 @@ +/** + * @name Filtro pasabanda + * @description Aplica un filtro pasabanda (p5.BandPass) a ruido blanco. + * Visualiza el sonido con FFT. + * Mapea la posición horizontal del ratón (mouseX) a la frecuencia de pasabanda + * y la vertical (mouseY) a la razón resonancia/ancho del filtro pasabanda + * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +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(); // desconecta el archivo de sonido de la salida maestra + filter.process(noise); // y conéctalo al filtro para solo escuchar el sonido filtrado por el filtro pasabanda + noise.start(); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // mapea la posición horizontal del ratón (mouseX) a una frecuencia de pasabanda dentro del rango del espectro FFT: 10Hz - 22050Hz + filterFreq = map(mouseX, 0, width, 10, 22050); + // mapea la posición vertical del ratón (mouseY) a la razón resonancia/ancho + filterWidth = map(mouseY, 0, height, 0, 90); + // definir los parámetros del filtor + filter.set(filterFreq, filterWidth); + + // Dibuja cada valor en el análisis de espectro FFT donde + // x = frecuencia más grave (10Hz) a más aguda (22050Hz), + // h = energía / amplitud en esa frecuencia + 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/dist/assets/examples/es/33_Sound/16_Delay.js b/dist/assets/examples/es/33_Sound/16_Delay.js new file mode 100644 index 0000000000..d374129f33 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/16_Delay.js @@ -0,0 +1,56 @@ +/** + * @name Delay + * @description + * Haz click para escuchar cómo el objeto (p5.Delay) procesa un archivo de audio. + * La posición horizontal del ratón (mouseX) controla la frecuencia de filtrado del objeto p5.Delay. + * La posición vertical del ratón (mouseY) controla tanto el tiempo de retraso como la resonancia del objeto p5.Delay. + * Visualiza el volumen resultante del sonido con un objeto Amplitude. + * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ + +let soundFile, analyzer, delay; + +function preload() { + soundFormats('ogg', 'mp3'); + soundFile = loadSound('assets/beatbox.mp3'); +} + +function setup() { + createCanvas(710, 400); + + soundFile.disconnect(); // para que solo escuchemos el delay + + delay = new p5.Delay(); + delay.process(soundFile, 0.12, 0.7, 2300); + delay.setType('pingPong'); // un tipo de efecto stereo + + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // obtener una lectura de volumen del analizador p5.Amplitude + let level = analyzer.getLevel(); + + // usar el nivel para dibujar un rectángulo verde + 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/dist/assets/examples/es/33_Sound/17_Reverb.js b/dist/assets/examples/es/33_Sound/17_Reverb.js new file mode 100644 index 0000000000..ee829fbfef --- /dev/null +++ b/dist/assets/examples/es/33_Sound/17_Reverb.js @@ -0,0 +1,37 @@ +/** + * @name Reverb + * @description El reverb le da profundidad y sensación de espacio a un sonido. Aquí, + * estamos procesando ruido con reverb. + * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ + +let sound, reverb; + +function preload() { + soundFormats('mp3', 'ogg'); + soundFile = loadSound('assets/Damscray_DancingTiger'); + + // desconectar la conexión por defecto + // para solor escuchar el sonido a través de reverb.process() + soundFile.disconnect(); +} + +function setup() { + createCanvas(720, 100); + background(0); + + reverb = new p5.Reverb(); + + // conectar el archivo de audio al reverb, con un + // tiempo de reverb de 6 segundos, y una tasa de decaimiento de 0.2% + reverb.process(soundFile, 6, 0.2); + + reverb.amp(4); // ¡súbele el volumen! +} + +function mousePressed() { + soundFile.play(); +} diff --git a/dist/assets/examples/es/33_Sound/18_Convolution_Reverb.js b/dist/assets/examples/es/33_Sound/18_Convolution_Reverb.js new file mode 100644 index 0000000000..c1960577a3 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/18_Convolution_Reverb.js @@ -0,0 +1,86 @@ +/** + * @name Reverb de convolución + * @description

El objeto p5.Convolver puede recrear el sonido de un espacio + * real usando convolución. La convolución toma una respuesta al impulso, + * (el sonido de un espacio reverberando), y usa eso para recrear el sonido en ese espacio + *

Haz click para reproducir el sonido convolucionado + * Cada vez que haces click, el sonido es convolucionado con + * una respuesta al impulso diferente. Para escuchar la respuesta al impulso, presiona cualquier tecla.

+ * + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + * Estos samples de convolución son Creative Commons BY + * + * recordinghopkins

+ */ +let sound, env, cVerb, fft; +let currentIR = 0; +let rawImpulse; + +function preload() { + // hemos incluido versiones MP3 y OGG de todos los impulsos y sonidos + soundFormats('ogg', 'mp3'); + + // crear un objeto p5.Convolver + cVerb = createConvolver('assets/bx-spring'); + + // añadir respuestas al impulso al arreglo cVerb.impulses, además del ya agregado bx-spring + cVerb.addImpulse('assets/small-plate'); + cVerb.addImpulse('assets/drum'); + cVerb.addImpulse('assets/beatbox'); + cVerb.addImpulse('assets/concrete-tunnel'); + + // cargar un sonido que será procesado por el objeto p5.ConvultionReverb + sound = loadSound('assets/Damscray_DancingTiger'); +} + +function setup() { + createCanvas(710, 400); + rawImpulse = loadSound('assets/' + cVerb.impulses[currentIR].name); + + // desconectar de la salida maestra + sound.disconnect(); + // y procesarlo con cVerb + // para que solo escuchemos el reverb + cVerb.process(sound); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + fill(0, 255, 40); + + let spectrum = fft.analyze(); + + // dibuja cada valor en el arreglo de espectro de frecuencia como un rectángulo + 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() { + // recorre el arreglo cVerb.impulses + currentIR++; + if (currentIR >= cVerb.impulses.length) { + currentIR = 0; + } + cVerb.toggleImpulse(currentIR); + + // reproduce el sonido a través del impulso + sound.play(); + + // muestra en pantalla el nombre de la respuesta al impulso actual (el nombre del archivo) + println('Convolution Impulse Response: ' + cVerb.impulses[currentIR].name); + + rawImpulse.setPath('assets/' + cVerb.impulses[currentIR].name); +} + +// reproduce el impulso (sin convolución) +function keyPressed() { + rawImpulse.play(); +} diff --git a/dist/assets/examples/es/33_Sound/19_Record_Save.js b/dist/assets/examples/es/33_Sound/19_Record_Save.js new file mode 100644 index 0000000000..41e8577c0f --- /dev/null +++ b/dist/assets/examples/es/33_Sound/19_Record_Save.js @@ -0,0 +1,58 @@ +/** + * @name Graba y almacena audio + * @description Graba un sonido, reprodúcelo y almacénalo como + * un archivo .wav file en el computador cliente. + * Necesitamos tres objetos: un p5.AudioIn (micrófono / fuente de sonido), + * p5.SoundRecorder (graba el sonido), y un + * p5.SoundFile (reproduce / almacena). + *

Para correr localmente este ejemplo, necesitarás la + * biblioteca p5.sound + * un archivo de audio y correr un servidor local. + */ +let mic, recorder, soundFile; + +let state = 0; // presionar el ratón cambiará el estado de grabar, a parar y a reproducir + +function setup() { + createCanvas(400, 400); + background(200); + fill(0); + text('Enable mic and click the mouse to begin recording', 20, 20); + + // crear una entrada de audio + mic = new p5.AudioIn(); + + // los usuarios deben manualmente permitir en su navegador que el micrófono funcione para que la grabación funcione de manera correcta + mic.start(); + + // crear un nuevo grabador de sonido + recorder = new p5.SoundRecorder(); + + // conectar el micrófono al grabador + recorder.setInput(mic); + + // crear un archivo de audio vacío que será usado para la reproducción de la grabación + soundFile = new p5.SoundFile(); +} + +function mousePressed() { + // usar el booleano '.enabled' (permitido) para asegurarse que el micrófono haya sido habilitado por el usuario (si no grabaríamos silencio) + if (state === 0 && mic.enabled) { + // indicar al grabador que grabe en el objeto p5.SoundFile, que usaremos para la reproducción + recorder.record(soundFile); + + background(255, 0, 0); + text('Recording now! Click to stop.', 20, 20); + state++; + } else if (state === 1) { + recorder.stop(); // parar el grabador, y enviar el resultado al archivo de audio soundFile + + background(0, 255, 0); + text('Recording stopped. Click to play & save', 20, 20); + state++; + } else if (state === 2) { + soundFile.play(); // reproduce el sonido + saveSound(soundFile, 'mySound.wav'); // almacena el archivo + state++; + } +} diff --git a/dist/assets/examples/es/33_Sound/21_FreqModulation.js b/dist/assets/examples/es/33_Sound/21_FreqModulation.js new file mode 100644 index 0000000000..ff8a0554d3 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/21_FreqModulation.js @@ -0,0 +1,147 @@ +/** + * @name Modulación en frecuencia + * @description

La modulación en frecuencia (FM) es una poderosa forma de síntesis. + * En su forma más simple , la FM involucra dos osciladores, referidos + * como la portadora y la modulante. Mientras la onda modulante oscila + * entre algún valor mínimo y maximo de amplitud, el valor momentáneo + * es sumado a ("modula") la frecuencia de la portadora.

+ *

La portadora es típicamente definida para oscilar a una frecuencia audible + * que percibimos como una altura — en este caso, es un oscilador sinusoidal a 220 Hz, + * equivalenta a una nota "A3". La portadora es conectada a la salida maestra por defecto + * (este es el caso para todos los objetos p5.Oscillator).

+ *

Nosotros desconectaremos la modulante de la salida maestra, + * y la conectaremos a la frecuencia de la portadora: + * carrier.freq(modulator). Esto suma la amplitud de salida de la moduante + * a la frecuencia de la portadora.

+ *

+ * La profundida de modulación describe cúanto será modulada la frecuencia de la portadora. + * Está basada en la amplitud de la modulante. + * La modulante produce un torrente continuo de valores de amplitud que sumaremos + * a la frecuencia de la portadora. Una amplitud nula (0) significa silencio, así que la modulación no tendría efecto. + * Una amplitud de 1.0 escala el rango de los valores de salida + * entre +1.0 y -1.0. Este es el rango estándar de sonido que es enviado a tus parlantes, + * pero en FM estamos enviando la salida de la modulante a la frecuencia de la portadora, + * donde casi no notaríamosla modulación +1Hz / -1Hz. + * Es por eso que típicamente aumentamos la amplitud (profundidad) de la modulante a números a muchos más altos + * que los que enviaríamos a nuestros parlantes.

+ *

La frecuencia de modulación es la velocidad de la modulación. Cuando la frecuencia de modulación es menor a + * 20Hz, dejamos de escuchar su frecuencia como una altura, y empezamos a escucharla como un ritmo pulsante. + * Por ejemplo, prueba 7.5Hz a una profundidad de 20 para imitar el efecto "vibrato" de un vocalista de ópera. + * El térmio par esto es un oscilador de baja frecuencia (LFO, Low Frequency Oscillator). Las modulantes configuradas a frecuencias más altas + * pueden también producir efectos interesantes, especialmente cuando la frecuencia tiene una relación harmónica + * con la señal portadora. Por ejemplo, escucha lo que sucede cuando la frecuencia modulante es + * la mitad o el doble de la portadora. Esto es la base de la síntesis FM, desarrollada por John Chowning + * en los años 1960s, lo que revolucionó la síntesis en los años 1980s y es a menudo utilizada para sintesizar sonidos de instrumentos metálicos de viento y campanas. + * + *

En este ejemplo,

+ * - la posición horizontal del ratón (mouseX) controla la profundidad de la modulación (la amplituda de la modulante) entre -150 y 150. + * Cuando la amplitud de la modulante es anulada (0) en la mitad del lienzo, date cuenta cómo la modulación + * no tiene efecto. A mayor (aplicando valor absoluto) el número, mayor el efecto. + * Si la forma de onda de la modulante es simétrica como una onda cuadrada [], sinusoidal ~ + * o triangular /\, la amplitud negativa será la misma que la amplitud positiva. + * Pero en este ejemplo, la modulante es una onda diente de sierra asimétrica, con una forma así /. + * Cuando la multiplicamos por un número negativo, se invierte así \. + * Para observar mejor la diferencia, baja la frecuencia. + *

+ *

- La posición vertical del ratón (mouseY) controla la frecuencia de la modulante entre 0 y 112 Hz. + * Prueba comparando frecuencias de modulación bajo el rango audible (que empieza en torno a los 20 Hz), + * y sobre él, especialmente en relación armónica a la frecuencia de la portadora (que es de 220hz, así que + * prueba con la mitad, 1/3, 1/4 etc...). + * + *

Necesitarás incluir la + * biblioteca p5.sound + * para que este ejemplo funcione en tu proyecto propio.

+ */ + +let carrier; // este es el oscilador que escucharemos, la portadora +let modulator; // este oscilador modulará la frecuencia de la portadora + +let analyzer; // lo usaremos para visualizar la forma de onda + +// la frecuencia de la portadora antes de ser modulada +let carrierBaseFreq = 220; + +// rangos mínimo y máximo para la modulante +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); // definir la amplitud + carrier.freq(carrierBaseFreq); // definir la frecuencia + carrier.start(); // empezar a oscilar + + // prueba a cambiar el tipo a 'square', 'sine' or 'triangle' + modulator = new p5.Oscillator('sawtooth'); + modulator.start(); + + // suma la salida de la modulante para modular la frecuencia de la portadora + modulator.disconnect(); + carrier.freq(modulator); + + // crea una FFT para analizar el audio + analyzer = new p5.FFT(); + + // prende o apaga la portadora según si el ratón está sobre el botón de inicio o lo presiona + toggleAudio(cnv); +} + +function draw() { + background(30); + + // mapea la posición vertical del ratón (mouseY) a la frecuencia modulante entre las frecuencias mínima y máxima + let modFreq = map(mouseY, height, 0, modMinFreq, modMaxFreq); + modulator.freq(modFreq); + + // cambia la amplitud de la modulante + // la amplitud negativa pone en reversa la forma de onda diente de sierra, suena percusiva + // + let modDepth = map(mouseX, 0, width, modMinDepth, modMaxDepth); + modulator.amp(modDepth); + + // analiza la forma de onda + waveform = analyzer.waveform(); + + // dibuja la forma de onda + 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); + // añade una nota sobre lo que está pasando + text('Frecuencia modulante: ' + modFreq.toFixed(3) + ' Hz', 20, 20); + text( + 'Amplitud modulante (profundidad de modulación): ' + modDepth.toFixed(3), + 20, + 40 + ); + text( + 'Frecuencia portadora (antes de la modulación): ' + carrierBaseFreq + ' Hz', + width / 2, + 20 + ); +} + +// función de ayuda para prender y apagar el sonido +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); + }); +} diff --git a/dist/assets/examples/es/33_Sound/22_AmplitudeModulation.js b/dist/assets/examples/es/33_Sound/22_AmplitudeModulation.js new file mode 100644 index 0000000000..18065a4d07 --- /dev/null +++ b/dist/assets/examples/es/33_Sound/22_AmplitudeModulation.js @@ -0,0 +1,95 @@ +/** + * @name Modulación en amplitud + * @description

La modulación en amplitud involucra dos osciladores, referidos como + * la portadora (carrier) y la modulante, donde la modulante controla la amplitud de la portadora.

+ * + *

La portadora es típicamente definida a una frecuencia audible (por ejemplo, 440 Hz) + * y conectada a la salida maestra por defecto. La amplitud de la portadora (carrier.amp) es anulada (0) + * porque así la modulante tiene total control sobre su amplitud.

+ * + *

La modulante es desconectada de la salida maestra. En vez de eso, es conectada + * a la amplitud de la portadora, así: carrier.amp(modulator).

+ * + *

En este ejemplo:

+ *

- la posición horizontal del ratón (mouseX) contrla la amplitud de la modulante + * entre 0 y 1. Cuando la amplitud modulante es hecha 0, la + * modulación en amplitud no hace efecto.

+ * + *

- La posición vertical del ratón (mouseY) controla la frecuencia de la modulante entre 0 y 20 Hz. + * Este rango es más grave que las frecuencias que los humanos pueden escuchar, y percibimos la + * modulación como un ritmo. Este rango simula un efecto conocido como tremolo. + * La modulación en anillo (ring modulation) es un tipo de modulación en amplitud donde la + * señal portadora original no está presente, y a menudo involucra modulación a una mayor + * frecuencia.

+ * + *

Necesitarás incluir la + * biblioteca p5.sound + * para que este ejemplo funcione en tu proyecto propio.

+ */ + +let carrier; // este es el oscilador que escucharemos +let modulator; // este oscilador modulará la amplitud de la portadora +let fft; // visualizaremos la forma de onda + +function setup() { + createCanvas(800, 400); + noFill(); + background(30); // alpha + + carrier = new p5.Oscillator(); // se conecta la salida a la salida maestra por defecto + carrier.freq(340); + carrier.amp(0); + // la amplitud de la portadora es 0 por defecto, dándole así a a la modulante control total + + carrier.start(); + + modulator = new p5.Oscillator('triangle'); + modulator.disconnect(); // desconecta la moduladora de la salida maestra + modulator.freq(5); + modulator.amp(1); + modulator.start(); + + // modula la ampltiud de la portadora con la modulante + // opcionalmente, podemos escalar la señal + carrier.amp(modulator.scale(-1, 1, 1, -1)); + + // crea una FFT para analizar el audio + fft = new p5.FFT(); +} + +function draw() { + background(30, 30, 30, 100); // alpha + + // mapea la posición vertical del ratón (mouseY) a la frecuencia de la modulante entre 0 y 20 Hz + let modFreq = map(mouseY, 0, height, 20, 0); + modulator.freq(modFreq); + + let modAmp = map(mouseX, 0, width, 0, 1); + modulator.amp(modAmp, 0.01); // tiempo de transición de 0.1 para mayor suavidad + + // analiza la forma de onda + waveform = fft.waveform(); + + // dibuja la forma de onda + 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); +} diff --git a/dist/assets/examples/es/35_Mobile/00_Acceleration_Ball_Bounce.js b/dist/assets/examples/es/35_Mobile/00_Acceleration_Ball_Bounce.js new file mode 100644 index 0000000000..50d34cc00b --- /dev/null +++ b/dist/assets/examples/es/35_Mobile/00_Acceleration_Ball_Bounce.js @@ -0,0 +1,58 @@ +/* + * @name Pelota rebote aceleración + * @description Mueve una elipse basado en los valores de aceleración en x y en y (accelerationX, accelerationY) y rebota cuando toca el borde del lienzo. + */ + +// variables de posición +let x = 0; +let y = 0; + +// velocidad +let vx = 0; +let vy = 0; + +// aceleración +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; + + // rebotar cuando tocar el borde del lienzo + 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/dist/assets/examples/es/35_Mobile/01_Simple_Draw.js b/dist/assets/examples/es/35_Mobile/01_Simple_Draw.js new file mode 100644 index 0000000000..5fbfc95364 --- /dev/null +++ b/dist/assets/examples/es/35_Mobile/01_Simple_Draw.js @@ -0,0 +1,15 @@ +/* + * @name Dibujo simple + * @description Toca para dibujar en la pantalla usando los valores de posición x e y de toque actual y anterior (mouseX, mouseY, pmouseX, pmouseY). + */ + +function setup() { + createCanvas(displayWidth, displayHeight); + strokeWeight(10); + stroke(0); +} + +function touchMoved() { + line(mouseX, mouseY, pmouseX, pmouseY); + return false; +} diff --git a/dist/assets/examples/es/35_Mobile/02_Acceleration_Color.js b/dist/assets/examples/es/35_Mobile/02_Acceleration_Color.js new file mode 100644 index 0000000000..35f9498c6b --- /dev/null +++ b/dist/assets/examples/es/35_Mobile/02_Acceleration_Color.js @@ -0,0 +1,24 @@ +/* + * @name Aceleración y color + * @description Usar la función deviceMoved() para detectar la rotación del dispositivo. Los valores RGB del fondo son mapeados a los valores de aceleración en los ejes x, y,z (accelerationX, accelerationY,accelerationZ). + */ + +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/dist/assets/examples/es/35_Mobile/03_Shake_Ball_Bounce.js b/dist/assets/examples/es/35_Mobile/03_Shake_Ball_Bounce.js new file mode 100644 index 0000000000..9e49ffe0b7 --- /dev/null +++ b/dist/assets/examples/es/35_Mobile/03_Shake_Ball_Bounce.js @@ -0,0 +1,114 @@ +/* + * @name Pelota rebote agitar + * @description Crea una clase Ball, instancia múltiples objetos, múevelos alrededor de la pantalla, que reboten cuando toquen el borde del lienzo. + * Detectar el evento agitar basado en el cambio total de aceleración en los ejes x e y (accelerationX, accelerationY) y aumenta o disminuye su velocidad basado en la detección. + */ + +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() { + // Calcular cambio total de aceleración en x e y, (accelerationX, accelerationY) + accChangeX = abs(accelerationX - pAccelerationX); + accChangeY = abs(accelerationY - pAccelerationY); + accChangeT = accChangeX + accChangeY; + // Si hay agitamiento + if (accChangeT >= threshold) { + for (let i = 0; i < balls.length; i++) { + balls[i].shake(); + balls[i].turn(); + } + } + // Si no hay + else { + for (let i = 0; i < balls.length; i++) { + balls[i].stopShake(); + balls[i].turn(); + balls[i].move(); + } + } +} + +// clase Ball +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; + } + + // Rebota cuando toca el borde del lienzo + 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; + } + } + + // Cambia la velocidad en x e y (xspeed, yspeed) según + // el cambio en el valor de la aceleración en x, accelerationX + shake() { + this.xspeed += random(5, accChangeX / 3); + this.yspeed += random(5, accChangeX / 3); + } + + // Desacelera gradualmente + 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/dist/assets/examples/es/35_Mobile/04_Tilted_3D_Box.js b/dist/assets/examples/es/35_Mobile/04_Tilted_3D_Box.js new file mode 100644 index 0000000000..3abf35da45 --- /dev/null +++ b/dist/assets/examples/es/35_Mobile/04_Tilted_3D_Box.js @@ -0,0 +1,15 @@ +/* + * @name Caja 3D + * @description Usar dispositivo móvil para inclinar una caja + */ +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/dist/assets/examples/es/90_Hello_P5/01_shapes.js b/dist/assets/examples/es/90_Hello_P5/01_shapes.js new file mode 100644 index 0000000000..35fc294b57 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/01_shapes.js @@ -0,0 +1,28 @@ +/* + * @name Figuras simples + * @description Este ejemplo incluye una elipse, un rectángulo, un triángulo y una flor. + */ +function setup() { + // crear el lienzo + createCanvas(720, 400); + background(200); + + // Definir colores + fill(204, 101, 192, 127); + stroke(127, 63, 120); + + // Un rectángulo + rect(40, 120, 120, 40); + // Una elipse + ellipse(240, 240, 80, 80); + // Un triángulo + triangle(300, 100, 320, 100, 310, 80); + + // Un diseño de una flor simple + translate(580, 200); + noStroke(); + for (let i = 0; i < 10; i ++) { + ellipse(0, 30, 20, 80); + rotate(PI/5); + } +} diff --git a/dist/assets/examples/es/90_Hello_P5/02_interactivity.js b/dist/assets/examples/es/90_Hello_P5/02_interactivity.js new file mode 100644 index 0000000000..24bdb12b30 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/02_interactivity.js @@ -0,0 +1,37 @@ +/* + * @name Interactividad 1 + * @frame 720,425 + * @description El círculo cambia de color cuando ahces click en él. + */ + +// variables para los valores de rojo, verde y azul (r, g, b) +let r, g, b; + +function setup() { + createCanvas(720, 400); + // colores aleatorios + r = random(255); + g = random(255); + b = random(255); +} + +function draw() { + background(127); + // dibujar el círculo + strokeWeight(2); + stroke(r, g, b); + fill(r, g, b, 127); + ellipse(360, 200, 200, 200); +} + +// cuando el usuario hace click +function mousePressed() { + // revisar si el ratón está dentro del círculo + let d = dist(mouseX, mouseY, 360, 200); + if (d < 100) { + // escoger nuevos colores aleatorios + r = random(255); + g = random(255); + b = random(255); + } +} diff --git a/dist/assets/examples/es/90_Hello_P5/03_interactivity.js b/dist/assets/examples/es/90_Hello_P5/03_interactivity.js new file mode 100644 index 0000000000..4fa554c275 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/03_interactivity.js @@ -0,0 +1,26 @@ +/* + * @name Interactividad 2 + * @frame 720,425 + * @description El círculo cambia de color cuando mueves la barra deslizante. + */ + +// Una barra deslizante de rango HTML +let slider; + +function setup() { + createCanvas(720, 400); + // Tinte, saturación, brillo + colorMode(HSB, 255); + // La barra deslizante tiene un valor entre 0 y 255 con un valor inicial de 127 + slider = createSlider(0, 255, 127); +} + +function draw() { + background(127); + strokeWeight(2); + + // Definir el tinte según la barra deslizante + stroke(slider.value(), 255, 255); + fill(slider.value(), 255, 255, 127); + ellipse(360, 200, 200, 200); +} diff --git a/dist/assets/examples/es/90_Hello_P5/04_animate.js b/dist/assets/examples/es/90_Hello_P5/04_animate.js new file mode 100644 index 0000000000..32d81aa18e --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/04_animate.js @@ -0,0 +1,32 @@ +/* + * @name Animación + * @description El círculo se mueve + */ +// posición del círculo +let x, y; + +function setup() { + createCanvas(720, 400); + // empieza en el centro + x = width / 2; + y = height; +} + +function draw() { + background(200); + + // dibujar el círculo + stroke(50); + fill(100); + ellipse(x, y, 24, 24); + + // moverse aleatoriamente en el eje x + x = x + random(-1, 1); + // mover hacia arriba a velocidad constante + y = y - 1; + + // reset al fondo + if (y < 0) { + y = height; + } +} diff --git a/dist/assets/examples/es/90_Hello_P5/04_flocking.js b/dist/assets/examples/es/90_Hello_P5/04_flocking.js new file mode 100644 index 0000000000..15198abaf5 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/04_flocking.js @@ -0,0 +1,184 @@ +/* + * @name Flocking + * @description Demostración del comportamiento "Flocking" según Craig Reynolds.
+ * (Reglas: cohesión, separación, alineamiento.)
+ * Extraído de natureofcode.com. + */ +let boids = []; + +function setup() { + createCanvas(720, 400); + + // Agregar un conjunto inicial de boids al sistema + for (let i = 0; i < 100; i++) { + boids[i] = new Boid(random(width), random(height)); + } +} + +function draw() { + background(51); + // Ejecutar todos los boids + for (let i = 0; i < boids.length; i++) { + boids[i].run(boids); + } +} + +// clase Boid +// Métodos para separación, cohesión y alineamiento +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; // velocidad máxima + this.maxforce = 0.05; // fuerza máxima de viraje + } + + run(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); + } + + // las fuerzas son añadidas a la aceleración + applyForce(force) { + this.acceleration.add(force); + } + + // acumulamos una nueva aceleración cada vez que el tiempo pasa, basado en tres reglas + flock(boids) { + let sep = this.separate(boids); // separación + let ali = this.align(boids); // alineamiento + let coh = this.cohesion(boids); // cohesión + // darle un peso arbitrario a las fuerzas + sep.mult(2.5); + ali.mult(1.0); + coh.mult(1.0); + // añade los vectores de fuerza a la aceleración + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); + } + + // método para actualizar ubicación + update() { + // actualizar velocidad + this.velocity.add(this.acceleration); + // limitar velocidad + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // resetear aceleración a 0 en cada ciclo + this.acceleration.mult(0); + } + + // un método que aplica y calcula una fuera de viraje a un objetivo + // viraje = deseado - velocidad + seek(target) { + let desired = p5.Vector.sub(target, this.position); // un vector apuntanto desde la ubicación y hacia el objetivo + // normalizar deseado y escalar a velocidad máxima + desired.normalize(); + desired.mult(this.maxspeed); + // viraje = deseado menos velocidad + let steer = p5.Vector.sub(desired, this.velocity); + steer.limit(this.maxforce); // limitar a la fuerza máxima de viraje + return steer; + } + + // dibujar el boid como un círculo + render() { + fill(127, 127); + stroke(200); + ellipse(this.position.x, this.position.y, 16, 16); + } + + // wraparound, si se llega a un borde, aparecer por el borde opuesto + 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; + } + + // separación + // método que revisa si hay boids cercanos y vira para alejarse de ellos + separate(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // por cada boid en el sistema, revisar si está muy cerca + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + // si la distancia es mayor a 0 y menor que un tamaño arbitrario (0 cuando es sí mismo) + if ((d > 0) && (d < desiredseparation)) { + // calcular vector apuntando para alejarse del vecino + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // peso según distancia + steer.add(diff); + count++; // contar cuántos + } + } + // promedio -- dividir por la cantidad + if (count > 0) { + steer.div(count); + } + + // mientas el vector sea mayor que 0 + if (steer.mag() > 0) { + // implementar Reynolds: viraje = deseado - velocidad + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; + } + + // alineamiento + // por cada boid cercano en el sistema, calcular la velocidad promedio + 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); + } + } + + // cohesión + // Para la ubicación promedio (centro) de todos los boids vecinos, calcular el vector de viraje hacia esa ubicación + cohesion(boids) { + let neighbordist = 50; + let sum = createVector(0, 0); // empezar con un vector vacío para acumular todas las ubicaciones + 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); // Agregar ubicación + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // Virar hacia la ubicación + } else { + return createVector(0, 0); + } + } +} diff --git a/dist/assets/examples/es/90_Hello_P5/05_weather.js b/dist/assets/examples/es/90_Hello_P5/05_weather.js new file mode 100644 index 0000000000..0745826388 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/05_weather.js @@ -0,0 +1,72 @@ +/* + * @name Clima + * @frame 720,280 + * @description Este ejemplo usa datos de clima en formato JSON desde www.metaweather.com. +*/ + +// un vector de dirección de viento +let wind; +// posición del círculo +let position; + +function setup() { + createCanvas(720, 200); + // pedir datos a metaweather.com + let url = 'https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/2459115/'; + loadJSON(url, gotWeather); + // el círculo empieza en el centro + position = createVector(width/2, height/2); + // el viento empieza en (0, 0) + wind = createVector(); +} + +function draw() { + background(200); + + // esta sección dibuja una flecha apuntando en la dirección del viento + push(); + translate(32, height - 32); + // rotar según el ángulo del viento + 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(); + + // mover en la dirección del viento + 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] + // obtener el ángulo (convertir a radianes) + let angle = radians(Number(weather_today.wind_direction)); + // obtener la velocidad del viento + let windmag = Number(weather_today.wind_speed); + + // mostrar como elementos HTML + let temperatureDiv = createDiv(floor(weather_today.the_temp) + '°C'); + let windDiv = createDiv("WIND " + windmag + " MPH"); + + // hacer un vector + wind = p5.Vector.fromAngle(angle); +} diff --git a/dist/assets/examples/es/90_Hello_P5/06_drawing.js b/dist/assets/examples/es/90_Hello_P5/06_drawing.js new file mode 100644 index 0000000000..e5a7521a39 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/06_drawing.js @@ -0,0 +1,133 @@ +/* +* @name Dibujar +* @description Programa de pintura generativa. +*/ + +// todos los caminos +let paths = []; +// si estamos pintando o no +let painting = false; +// cuánto tiempo pasa antes de hacer el siguiente círculo +let next = 0; +// dónde estamos ahora y donde estuvimos antes +let current; +let previous; + +function setup() { + createCanvas(720, 400); + current = createVector(0,0); + previous = createVector(0,0); +}; + +function draw() { + background(200); + + // si es tiempo de hacer un nuevo punto + if (millis() > next && painting) { + + // obtener posición del ratón + current.x = mouseX; + current.y = mouseY; + + // la fuerza de la nueva partícula depende del movimiento del ratón + let force = p5.Vector.sub(current, previous); + force.mult(0.05); + + // añadir nueva partícula + paths[paths.length - 1].add(current, force); + + // programar el siguiente círculo + next = millis() + random(100); + + // Guardar las posiciones del ratón + previous.x = current.x; + previous.y = current.y; + } + + // dibujar todos los caminos + for( let i = 0; i < paths.length; i++) { + paths[i].update(); + paths[i].display(); + } +} + +// empezar +function mousePressed() { + next = 0; + painting = true; + previous.x = mouseX; + previous.y = mouseY; + paths.push(new Path()); +} + +// parar +function mouseReleased() { + painting = false; +} + +// un camino Path es una lista de partículas +class Path { + constructor() { + this.particles = []; + this.hue = random(100); + } + + add(position, force) { + // agregar una nueva partícula con una posición, fuerza y tinte + this.particles.push(new Particle(position, force, this.hue)); + } + + // mostrar camino + update() { + for (let i = 0; i < this.particles.length; i++) { + this.particles[i].update(); + } + } + + // mostrar camino + display() { + + // iterar sobre el camino de atrás hacia adelante + for (let i = this.particles.length - 1; i >= 0; i--) { + // si debemos removerlo + if (this.particles[i].lifespan <= 0) { + this.particles.splice(i, 1); + // si no, mostrarlo en pantalla + } else { + this.particles[i].display(this.particles[i+1]); + } + } + } +} + +// partículas en el camino +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() { + // muévela + this.position.add(this.velocity); + // disminuye su velocidad + this.velocity.mult(this.drag); + // hazla más transparente + this.lifespan--; + } + + // dibujar una partícula y conectarla con una línea + // dibuja una línea a otra + display(other) { + stroke(0, this.lifespan); + fill(0, this.lifespan/2); + ellipse(this.position.x,this.position.y, 8, 8); + // si necesitamos dibujar otra línea + if (other) { + line(this.position.x, this.position.y, other.position.x, other.position.y); + } + } +} + diff --git a/dist/assets/examples/es/90_Hello_P5/07_song.js b/dist/assets/examples/es/90_Hello_P5/07_song.js new file mode 100644 index 0000000000..f0fe774272 --- /dev/null +++ b/dist/assets/examples/es/90_Hello_P5/07_song.js @@ -0,0 +1,120 @@ +/* + * @name Canción + * @frame 720, 430 + * @description Toca una canción. + * Necesitarás incluir la + * biblioteca p5.sound + * a este ejemplo para que corra en tu máquina. +*/ + +// las notas midi de una escala +let notes = [ 60, 62, 64, 65, 67, 69, 71]; + +// para tocar la canción de forma automática +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("Haz click para tocar las notas") + div.id("instructions"); + let button = createButton("toca la canción automáticamente."); + button.parent("instructions"); + // gatillar la reproducción automática + button.mousePressed(function() { + if (!autoplay) { + index = 0; + autoplay = true; + } + }); + + // un oscilador de onda triangular + osc = new p5.TriOsc(); + // empezar en silencio + osc.start(); + osc.amp(0); +} + +// una función para tocar una nota +function playNote(note, duration) { + osc.freq(midiToFreq(note)); + // aparición gradual + osc.fade(0.5,0.2); + + // si definimos una duración, apagar gradualmente + if (duration) { + setTimeout(function() { + osc.fade(0,0.2); + }, duration-50); + } +} + +function draw() { + + // Si estamos tocando automáticamente y es tiempo de tocar la siguiente nota + if (autoplay && millis() > trigger){ + playNote(notes[song[index].note], song[index].duration); + trigger = millis() + song[index].duration; + // ir a la siguiente nota + index ++; + // cuando llegamos al final, dejar de tocar en automático + } else if (index >= song.length) { + autoplay = false; + } + + + // dibujar un teclado + + // el ancho de cada tecla + let w = width / notes.length; + for (let i = 0; i < notes.length; i++) { + let x = i * w; + // si el ratón está sobre la tecla + if (mouseX > x && mouseX < x + w && mouseY < height) { + // si estamos haciendo click + if (mouseIsPressed) { + fill(100,255,200); + // o solamente estamos sobre ella + } else { + fill(127); + } + } else { + fill(200); + } + + // si estamos tocando la canción, resaltemos + if (autoplay && i === song[index-1].note) { + fill(100,255,200); + } + + // dibujar la tecla + rect(x, 0, w-1, height-1); + } + +} + +// cuando hacemos click +function mousePressed(event) { + if(event.button == 0 && event.clientX < width && event.clientY < height) { + // mapear el ratón al índice de la tecla + let key = floor(map(mouseX, 0, width, 0, notes.length)); + playNote(notes[key]); + } +} + +// Disminuye gradualmente cuando soltamos el botón del ratón +function mouseReleased() { + osc.fade(0,0.5); +} diff --git a/dist/assets/examples/example.html b/dist/assets/examples/example.html new file mode 100644 index 0000000000..e093b6ba56 --- /dev/null +++ b/dist/assets/examples/example.html @@ -0,0 +1,19 @@ + + + + + + + + +
+ + + diff --git a/dist/assets/examples/hi/00_Structure/00_Coordinates.js b/dist/assets/examples/hi/00_Structure/00_Coordinates.js new file mode 100644 index 0000000000..fe8eb5b4a8 --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/00_Coordinates.js @@ -0,0 +1,39 @@ +/* + * @name निर्देशांक + * @description स्क्रीन पर खींची गई सभी आकृतियों में एक स्थिति होती है जो है + * एक समन्वय के रूप में निर्दिष्ट। सभी निर्देशांकों को से दूरी के रूप में मापा जाता है + * पिक्सेल की इकाइयों में उत्पत्ति। मूल [0, 0] में निर्देशांक है + * खिड़की के ऊपरी बाएँ और निचले दाएँ में निर्देशांक [चौड़ाई -1, + * ऊंचाई -1]। + */ +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/dist/assets/examples/hi/00_Structure/01_Width_and_Height.js b/dist/assets/examples/hi/00_Structure/01_Width_and_Height.js new file mode 100644 index 0000000000..550c70eb9c --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/01_Width_and_Height.js @@ -0,0 +1,20 @@ +/* + * @name चौड़ाई और ऊंचाई + * @description 'चौड़ाई' और 'ऊंचाई' चर में शामिल हैं + * createCanvas () में परिभाषित डिस्प्ले विंडो की चौड़ाई और ऊंचाई + * समारोह। + */ +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/dist/assets/examples/hi/00_Structure/02_Setup_and_Draw.js b/dist/assets/examples/hi/00_Structure/02_Setup_and_Draw.js new file mode 100644 index 0000000000..5838e8aab9 --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/02_Setup_and_Draw.js @@ -0,0 +1,27 @@ +/* + * @name सेटअप और ड्रा + * @description ड्रा () फ़ंक्शन के अंदर का कोड ऊपर से लगातार चलता है + * कार्यक्रम बंद होने तक नीचे तक। + */ +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/dist/assets/examples/hi/00_Structure/03_No_Loop.js b/dist/assets/examples/hi/00_Structure/03_No_Loop.js new file mode 100644 index 0000000000..dd7f0f0dd6 --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/03_No_Loop.js @@ -0,0 +1,30 @@ +/* + * @name और ड्रा + * @description ड्रा () फ़ंक्शन + * योजना बनने तक तक। + */ +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/dist/assets/examples/hi/00_Structure/04_Loop.js b/dist/assets/examples/hi/00_Structure/04_Loop.js new file mode 100644 index 0000000000..5edeb7c0bb --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/04_Loop.js @@ -0,0 +1,26 @@ +/* + * @name लूप + * @description ड्रा () फ़ंक्शन के अंदर का कोड ऊपर से लगातार चलता है + * कार्यक्रम बंद होने तक नीचे तक। + */ +let y = 100; + +// 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); +} +// 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/dist/assets/examples/hi/00_Structure/05_Redraw.js b/dist/assets/examples/hi/00_Structure/05_Redraw.js new file mode 100644 index 0000000000..5ed2d392e6 --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/05_Redraw.js @@ -0,0 +1,33 @@ +/* + * @name रेड्रा + * @description रेड्रा () फ़ंक्शन ड्रा () को एक बार निष्पादित करता है। इस उदाहरण में, + * ड्रा () को हर बार माउस क्लिक करने पर एक बार निष्पादित किया जाता है। + */ + +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/dist/assets/examples/hi/00_Structure/06_Functions.js b/dist/assets/examples/hi/00_Structure/06_Functions.js new file mode 100644 index 0000000000..60f420429f --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/06_Functions.js @@ -0,0 +1,28 @@ +/* + *@name कार्य + *@description DrawTarget () फ़ंक्शन कई अलग-अलग आकर्षित करना आसान बनाता है + *लक्ष्य। DrawTarget () के लिए प्रत्येक कॉल की स्थिति, आकार और संख्या निर्दिष्ट करता है + * प्रत्येक लक्ष्य के लिए बजता है। + */ + +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/dist/assets/examples/hi/00_Structure/07_Recursion.js b/dist/assets/examples/hi/00_Structure/07_Recursion.js new file mode 100644 index 0000000000..cc8ec10c88 --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/07_Recursion.js @@ -0,0 +1,27 @@ +/* + *@name रिकर्सन + *@description रिकर्सन का एक प्रदर्शन, जिसका अर्थ है कि फ़ंक्शन स्वयं को कॉल करते हैं। + * ध्यान दें कि कैसे drawCircle () फ़ंक्शन अपने ब्लॉक के अंत में खुद को कॉल करता है। + * यह तब तक करना जारी रखता है जब तक कि चर "स्तर" 1 के बराबर न हो जाए। + */ + +function setup() { + createCanvas(720, 560); + noStroke(); + noLoop(); +} + +function draw() { + drawCircle(width / 2, 280, 6); +} + +function drawCircle(x, radius, level) { + const tt = (126 * level) / 4.0; + fill(tt); + ellipse(x, height / 2, radius * 2, radius * 2); + if (level > 1) { + level = level - 1; + drawCircle(x - radius / 2, radius / 2, level); + drawCircle(x + radius / 2, radius / 2, level); + } +} diff --git a/dist/assets/examples/hi/00_Structure/08_Create_Graphics.js b/dist/assets/examples/hi/00_Structure/08_Create_Graphics.js new file mode 100644 index 0000000000..883b19db79 --- /dev/null +++ b/dist/assets/examples/hi/00_Structure/08_Create_Graphics.js @@ -0,0 +1,29 @@ +/* + * @name ग्राफिक्स बनाएं + * @description एक नया p5.Renderer ऑब्जेक्ट बनाता और लौटाता है। इस का उपयोग करें + * वर्ग यदि आपको ऑफ-स्क्रीन ग्राफिक्स बफर में आकर्षित करने की आवश्यकता है। दो पैरामीटर + * पिक्सल में चौड़ाई और ऊंचाई को परिभाषित करें। + */ + +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/dist/assets/examples/hi/01_Form/00_Points_and_Lines.js b/dist/assets/examples/hi/01_Form/00_Points_and_Lines.js new file mode 100644 index 0000000000..c68ade9622 --- /dev/null +++ b/dist/assets/examples/hi/01_Form/00_Points_and_Lines.js @@ -0,0 +1,36 @@ +/* + * @name अंक और रेखाएं + * @description पॉइंट्स और लाइन्स का इस्तेमाल बेसिक ज्योमेट्री ड्रा करने के लिए किया जा सकता है। + * फॉर्म को स्केल करने के लिए वेरिएबल 'd' का मान बदलें। चार + * चर 'डी' के मान के आधार पर स्थिति निर्धारित करते हैं। + */ +function setup() { + let d = 70; + let p1 = d; + let p2 = p1 + d; + let p3 = p2 + d; + let p4 = p3 + d; + + // स्क्रीन को 720 पिक्सल चौड़ा और 400 पिक्सल ऊंचा सेट करता है + createCanvas(720, 400); + background(0); + noSmooth(); + + translate(140, 0); + + // ग्रे बॉक्स बनाएं + stroke(153); + line(p3, p3, p2, p3); + line(p2, p3, p2, p2); + line(p2, p2, p3, p2); + line(p3, p2, p3, p3); + + // सफेद बिंदु बनाएं + stroke(255); + point(p1, p1); + point(p1, p3); + point(p2, p4); + point(p3, p1); + point(p4, p2); + point(p4, p4); +} diff --git a/dist/assets/examples/hi/01_Form/01_Shape_Primitives.js b/dist/assets/examples/hi/01_Form/01_Shape_Primitives.js new file mode 100644 index 0000000000..b70f7e404c --- /dev/null +++ b/dist/assets/examples/hi/01_Form/01_Shape_Primitives.js @@ -0,0 +1,31 @@ +/* + * @name शेप प्रिमिटिव्स + * @description मूल आकार के आदिम कार्य triangle() हैं, + * rect(), quad(), ellipse(), और arc()। वर्ग रेक्ट के साथ बने होते हैं () + * और ellipse() से बनाए जाते हैं। इन कार्यों में से प्रत्येक की आवश्यकता है + * आकार की स्थिति और आकार निर्धारित करने के लिए कई पैरामीटर। + */ +function setup() { + // स्क्रीन को 720 पिक्सल चौड़ा और 400 पिक्सल ऊंचा सेट करता है + 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/dist/assets/examples/hi/01_Form/02_Pie_Chart.js b/dist/assets/examples/hi/01_Form/02_Pie_Chart.js new file mode 100644 index 0000000000..1240e9dda2 --- /dev/null +++ b/dist/assets/examples/hi/01_Form/02_Pie_Chart.js @@ -0,0 +1,34 @@ +/* + * @name पाई चार्ट + * @description डेटा से पाई चार्ट बनाने के लिए arc() फ़ंक्शन का उपयोग करता है + * एक सरणी में संग्रहीत। + */ +let angles = [30, 10, 45, 35, 60, 38, 75, 67]; + +function setup() { + createCanvas(720, 400); + noStroke(); + noLoop(); // एक बार दौड़ें और रुकें +} + +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/dist/assets/examples/hi/01_Form/03_Regular_Polygon.js b/dist/assets/examples/hi/01_Form/03_Regular_Polygon.js new file mode 100644 index 0000000000..7409757cf7 --- /dev/null +++ b/dist/assets/examples/hi/01_Form/03_Regular_Polygon.js @@ -0,0 +1,43 @@ +/* + * @name नियमित बहुभुज + * @description आपका पसंदीदा क्या है? पेंटागन? षट्भुज? हेप्टागन? नहीं न? + *आइकोसैगन के बारे में क्या? इस उदाहरण के लिए बनाया गया polygon() फ़ंक्शन है + * किसी भी नियमित बहुभुज को खींचने में सक्षम। अलग-अलग नंबरों को रखने का प्रयास करें Try + * polygon() फ़ंक्शन कॉल के भीतर draw() का पता लगाने के लिए। + */ +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/dist/assets/examples/hi/01_Form/04_Star.js b/dist/assets/examples/hi/01_Form/04_Star.js new file mode 100644 index 0000000000..c07641104b --- /dev/null +++ b/dist/assets/examples/hi/01_Form/04_Star.js @@ -0,0 +1,46 @@ +/* + * @name स्टार + * @description इस उदाहरण के लिए बनाया गया star() फ़ंक्शन सक्षम है + * विभिन्न रूपों की एक विस्तृत श्रृंखला को चित्रित करना। अलग-अलग नंबर रखने की कोशिश करें + * star() फ़ंक्शन कॉल में draw() का पता लगाने के लिए +*/ +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/dist/assets/examples/hi/01_Form/05_Triangle_Strip.js b/dist/assets/examples/hi/01_Form/05_Triangle_Strip.js new file mode 100644 index 0000000000..dc9c9009bc --- /dev/null +++ b/dist/assets/examples/hi/01_Form/05_Triangle_Strip.js @@ -0,0 +1,38 @@ +/* + *@name त्रिभुज पट्टी + * @description उदाहरण इरा ग्रीनबर्ग द्वारा। का उपयोग करके एक बंद रिंग उत्पन्न करें + * vertex() फ़ंक्शन और beginShape (TRIANGLE_STRIP) मोड। बाहरी त्रिज्या + * और इनसाइडरेडियस वेरिएबल्स क्रमशः रिंग की त्रिज्या को नियंत्रित करते हैं। + */ +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/dist/assets/examples/hi/01_Form/06_Bezier.js b/dist/assets/examples/hi/01_Form/06_Bezier.js new file mode 100644 index 0000000000..864c4c0021 --- /dev/null +++ b/dist/assets/examples/hi/01_Form/06_Bezier.js @@ -0,0 +1,28 @@ +/* + * @name बेज़ियर + * @description bezier() फ़ंक्शन के लिए पहले दो पैरामीटर निर्दिष्ट करते हैं + * वक्र में पहला बिंदु और अंतिम दो पैरामीटर अंतिम बिंदु निर्दिष्ट करते हैं। + * मध्य पैरामीटर नियंत्रण बिंदु निर्धारित करते हैं जो आकार को परिभाषित करते हैं + * वक्र। + */ +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/dist/assets/examples/hi/01_Form/07_3D_Primitives.js b/dist/assets/examples/hi/01_Form/07_3D_Primitives.js new file mode 100644 index 0000000000..d1d7735646 --- /dev/null +++ b/dist/assets/examples/hi/01_Form/07_3D_Primitives.js @@ -0,0 +1,30 @@ +/* + * @name ३डी प्रिमिटिव्स + * @frame 720,400 (वैकल्पिक) + * @description गणितीय रूप से 3D ऑब्जेक्ट को सिंथेटिक स्पेस में रखना। + * box() और sphere() फ़ंक्शन उनके निर्दिष्ट करने के लिए कम से कम एक पैरामीटर लेते हैं + * आकार। इन आकृतियों को translate() फ़ंक्शन का उपयोग करके स्थित किया जाता है। + */ +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/dist/assets/examples/hi/02_Data/00_Variables.js b/dist/assets/examples/hi/02_Data/00_Variables.js new file mode 100644 index 0000000000..97d0dd49a5 --- /dev/null +++ b/dist/assets/examples/hi/02_Data/00_Variables.js @@ -0,0 +1,37 @@ +/* + * @name चर + * @description वेरिएबल्स का उपयोग वैल्यू स्टोर करने के लिए किया जाता है। इस उदाहरण में, बदलें + * रचना को प्रभावित करने के लिए चर के मान। + */ +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/dist/assets/examples/hi/02_Data/01_True_and_False.js b/dist/assets/examples/hi/02_Data/01_True_and_False.js new file mode 100644 index 0000000000..380d2f53e2 --- /dev/null +++ b/dist/assets/examples/hi/02_Data/01_True_and_False.js @@ -0,0 +1,31 @@ +/* + * @name सही और गलत + * @description एक बूलियन वैरिएबल के केवल दो संभावित मान हैं: सही या गलत। + * प्रवाह को निर्धारित करने के लिए नियंत्रण कथनों के साथ बूलियन का उपयोग करना आम है + * एक कार्यक्रम का। इस उदाहरण में, जब बूलियन मान "बी" सत्य है, लंबवत + * रेखाएँ खींची जाती हैं और जब बूलियन मान "बी" गलत होता है, क्षैतिज + *रेखाएँ खींची जाती हैं। + */ +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) { + // ऊर्ध्वाधर रेखा + line(i, d, i, height - d); + } + + if (b === false) { + // क्षैतिज रेखा + line(middle, i - middle + d, width - d, i - middle + d); + } + } +} diff --git a/dist/assets/examples/hi/02_Data/03_Variable_Scope.js b/dist/assets/examples/hi/02_Data/03_Variable_Scope.js new file mode 100644 index 0000000000..c365807ae2 --- /dev/null +++ b/dist/assets/examples/hi/02_Data/03_Variable_Scope.js @@ -0,0 +1,48 @@ +/* + * @name परिवर्तनीय दायरा + * @description वेरिएबल्स का एक ग्लोबल या फंक्शन "स्कोप" होता है। उदाहरण के लिए, + * या तो setup() या draw() फ़ंक्शन के भीतर घोषित चर हो सकते हैं + * केवल इन कार्यों में उपयोग किया जाता है। वैश्विक चर, बाहर घोषित चर + * setup() और draw(), कार्यक्रम के भीतर कहीं भी इस्तेमाल किया जा सकता है। यदि एक समारोह + * वैरिएबल को ग्लोबल वैरिएबल के समान नाम से घोषित किया जाता है, प्रोग्राम + * वर्तमान के भीतर अपनी गणना करने के लिए फ़ंक्शन चर का उपयोग करेगा + * गुंजाइश। + */ +let a = 80; // एक वैश्विक चर "ए" बनाएं + +function setup() { + createCanvas(720, 400); + background(0); + stroke(255); + noLoop(); +} + +function draw() { + // वैश्विक चर "ए" का उपयोग करके एक रेखा खींचें + line(a, 0, a, height); + + // लूप के लिए स्थानीय चर a का उपयोग करें + for (let a = 120; a < 200; a += 3) { + line(a, 0, a, height); + } + + // कस्टम फ़ंक्शन को कॉल करें drawAnotherLine () + drawAnotherLine(); + + // कस्टम फ़ंक्शन पर कॉल करें drawYetAnotherLine () + drawYetAnotherLine(); +} + +function drawAnotherLine() { + // इस फ़ंक्शन के लिए एक नया चर "ए" स्थानीय बनाएं + let a = 320; + // स्थानीय चर "ए" का उपयोग करके एक रेखा खींचें + line(a, 0, a, height); +} + +function drawYetAnotherLine() { + // क्योंकि कोई नया स्थानीय चर "ए" सेट नहीं है, + // यह रेखा मूल वैश्विक का उपयोग करके खींची गई है + // चर "ए" जो मान 20 पर सेट है। + line(a + 3, 0, a + 3, height); +} diff --git a/dist/assets/examples/hi/02_Data/04_Numbers.js b/dist/assets/examples/hi/02_Data/04_Numbers.js new file mode 100644 index 0000000000..1d91c2c94a --- /dev/null +++ b/dist/assets/examples/hi/02_Data/04_Numbers.js @@ -0,0 +1,31 @@ +/* + * @name नंबर + * @frame 720,400 + * @description नंबर को दशमलव के साथ या बिना लिखा जा सकता है। पूर्णांक + * (आमतौर पर एक इंट कहा जाता है) एक दशमलव बिंदु के बिना एक संख्या है। एक फ्लोट + * एक फ़्लोटिंग-पॉइंट नंबर है, जिसका अर्थ है कि यह एक संख्या है जिसमें दशमलव है + * जगह। + */ +let a = 0; // एक वैश्विक चर "ए" प्रकार की संख्या बनाएं +let b = 0; // संख्या प्रकार का एक वैश्विक चर "बी" बनाएं + +function setup() { + createCanvas(720, 400); + stroke(255); +} + +function draw() { + background(0); + + a = a + 1; // एक पूर्णांक के साथ वृद्धि करें + b = b + 0.2; // वृद्धि बी एक फ्लोट के साथ + 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/dist/assets/examples/hi/03_Arrays/00_Array.js b/dist/assets/examples/hi/03_Arrays/00_Array.js new file mode 100644 index 0000000000..31de72acce --- /dev/null +++ b/dist/assets/examples/hi/03_Arrays/00_Array.js @@ -0,0 +1,44 @@ +/* + * @name ऐरे + * @description एक सरणी डेटा की एक सूची है। एक सरणी में डेटा का प्रत्येक टुकड़ा + * को एक सूचकांक संख्या द्वारा पहचाना जाता है जो इसकी स्थिति का प्रतिनिधित्व करता है + * सरणी। Arrays शून्य आधारित हैं, जिसका अर्थ है कि पहला + * सरणी में तत्व [0] है, दूसरा तत्व [1] है, और इसी तरह। + * इस उदाहरण में, "coswave" नामक एक सरणी बनाई गई है और + * कोसाइन मूल्यों से भरा हुआ। यह डेटा तीन प्रदर्शित होता है + * स्क्रीन पर अलग तरीके। + */ +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/dist/assets/examples/hi/03_Arrays/01_Array_2d.js b/dist/assets/examples/hi/03_Arrays/01_Array_2d.js new file mode 100644 index 0000000000..eb166bc468 --- /dev/null +++ b/dist/assets/examples/hi/03_Arrays/01_Array_2d.js @@ -0,0 +1,38 @@ +/* + * @name ऐरे 2D + * @description द्वि-आयामी (2D) बनाने के लिए सिंटैक्स प्रदर्शित करता है + * सरणी। 2D सरणी में मानों को दो अनुक्रमणिका मानों के माध्यम से एक्सेस किया जाता है। + * 2D सरणियाँ छवियों को संग्रहीत करने के लिए उपयोगी हैं। इस उदाहरण में, प्रत्येक बिंदु + * छवि के केंद्र से इसकी दूरी के संबंध में रंगीन है। + */ +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); + // यह एम्बेडेड लूप के आधार पर सरणियों में मूल्यों पर छोड़ देता है + // स्पेसर चर, इसलिए सरणी में अधिक मान हैं + // यहाँ से खींचे गए हैं। स्पेसर वैरिएबल का मान बदलें of + // बिंदुओं के घनत्व को बदलने के लिए + 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/dist/assets/examples/hi/03_Arrays/02_Array_Objects.js b/dist/assets/examples/hi/03_Arrays/02_Array_Objects.js new file mode 100644 index 0000000000..fda498ef6d --- /dev/null +++ b/dist/assets/examples/hi/03_Arrays/02_Array_Objects.js @@ -0,0 +1,71 @@ +/* + * @name ऐरे ऑब्जेक्ट्स + * @description कस्टम ऑब्जेक्ट्स की एक सरणी बनाने के लिए सिंटैक्स प्रदर्शित करता है। + */ + +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; + } + + // चर को अद्यतन करने के लिए कस्टम विधि + 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; + } + } + + // वस्तु को खींचने के लिए कस्टम विधि + 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/dist/assets/examples/hi/04_Control/00_Iteration.js b/dist/assets/examples/hi/04_Control/00_Iteration.js new file mode 100644 index 0000000000..4902a49afc --- /dev/null +++ b/dist/assets/examples/hi/04_Control/00_Iteration.js @@ -0,0 +1,41 @@ +/* + * @name पुनरावृत्ति + * @description पुनरावृत्ति रूपों के निर्माण के लिए "के लिए" संरचना के साथ पुनरावृत्ति। + */ +let y; +let num = 14; + +function setup() { + createCanvas(720, 360); + background(102); + noStroke(); + + // सफेद सलाखों को ड्रा करें + fill(255); + y = 60; + for (let i = 0; i < num / 3; i++) { + rect(50, y, 475, 10); + y += 20; + } + + // ग्रे बार + 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; + } + + // पतली रेखाएं + y = 45; + fill(0); + for (let i = 0; i < num - 1; i++) { + rect(120, y, 40, 1); + y += 20; + } +} diff --git a/dist/assets/examples/hi/04_Control/01_Embedded_Iteration.js b/dist/assets/examples/hi/04_Control/01_Embedded_Iteration.js new file mode 100644 index 0000000000..15183ca09d --- /dev/null +++ b/dist/assets/examples/hi/04_Control/01_Embedded_Iteration.js @@ -0,0 +1,21 @@ +/* +* @name एंबेडेड इटरेशन +* @description "के लिए" संरचनाओं को एम्बेड करना दो आयामों में पुनरावृत्ति की अनुमति देता है। +*/ +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/dist/assets/examples/hi/04_Control/02_Conditionals_1.js b/dist/assets/examples/hi/04_Control/02_Conditionals_1.js new file mode 100644 index 0000000000..f4f2ba09af --- /dev/null +++ b/dist/assets/examples/hi/04_Control/02_Conditionals_1.js @@ -0,0 +1,26 @@ +/* + * @name सशर्त 1 + * @description शर्तें सवालों की तरह हैं। + * वे एक कार्यक्रम को एक कार्रवाई करने का निर्णय लेने की अनुमति देते हैं यदि + * किसी प्रश्न का उत्तर सत्य है या कोई अन्य क्रिया करना + * यदि प्रश्न का उत्तर गलत है। + * एक कार्यक्रम के भीतर पूछे जाने वाले प्रश्न हमेशा तार्किक होते हैं + * या संबंधपरक बयान। उदाहरण के लिए, यदि चर 'i' is + * शून्य के बराबर फिर एक रेखा खींचे। + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 10; i < width; i += 10) { + // यदि 'i' को 20 से विभाजित किया जाता है और कोई शेष नहीं है तो पहली पंक्ति बनाएं + // अन्यथा दूसरी पंक्ति बनाएं + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + } else { + stroke(153); + line(i, 20, i, 180); + } + } +} diff --git a/dist/assets/examples/hi/04_Control/03_Conditionals_2.js b/dist/assets/examples/hi/04_Control/03_Conditionals_2.js new file mode 100644 index 0000000000..2e8f855364 --- /dev/null +++ b/dist/assets/examples/hi/04_Control/03_Conditionals_2.js @@ -0,0 +1,28 @@ +/* + * @name सशर्त 2 + * @description हम पिछले से सशर्त की भाषा का विस्तार करते हैं + * उदाहरण "और" कीवर्ड जोड़कर। यह सशर्त अनुमति देता है + * दो या दो से अधिक क्रमिक प्रश्न पूछने के लिए, प्रत्येक एक अलग के साथ + * क्रिया। + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 2; i < width - 2; i += 4) { + // यदि 'i' को 20 से विभाजित किया जाता है और कोई शेषफल नहीं है + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + // यदि 'i' को 10 से विभाजित किया जाता है और कोई शेषफल नहीं है + } else if (i % 10 === 0) { + stroke(153); + line(i, 20, i, 180); + // यदि उपरोक्त दो शर्तों में से कोई भी पूरा नहीं हुआ है + // फिर इस लाइन को ड्रा करें + } else { + stroke(102); + line(i, height / 2, i, height - 20); + } + } +} diff --git a/dist/assets/examples/hi/04_Control/04_Logical_Operators.js b/dist/assets/examples/hi/04_Control/04_Logical_Operators.js new file mode 100644 index 0000000000..804c7fdcb8 --- /dev/null +++ b/dist/assets/examples/hi/04_Control/04_Logical_Operators.js @@ -0,0 +1,42 @@ +/* + * @name लॉजिकल ऑपरेटर्स + * @description AND (&&) और OR (||) के लिए तार्किक ऑपरेटरों का उपयोग किया जाता है + * सरल संबंधपरक कथनों को अधिक जटिल अभिव्यक्तियों में संयोजित करें। + * NOT (!) ऑपरेटर का उपयोग बूलियन स्टेटमेंट को नकारने के लिए किया जाता है। + */ +let test = false; + +function setup() { + createCanvas(720, 360); + background(126); + + for (let i = 5; i <= height; i += 5) { + // तार्किक और + stroke(0); + if (i > 35 && i < 100) { + line(width / 4, i, width / 2, i); + test = false; + } + + // तार्किक OR + stroke(76); + if (i <= 35 || i >= 100) { + line(width / 2, i, width, i); + test = true; + } + + // परीक्षण करें कि क्या बूलियन मान "सत्य" है + // अभिव्यक्ति "अगर (परीक्षण)" "अगर (परीक्षण == सत्य)" के बराबर है + if (test) { + stroke(0); + point(width / 3, i); + } + + // परीक्षण करें कि क्या बूलियन मान "गलत" है + // अभिव्यक्ति "if(!test)" बराबर है "if(test == false)" + if (!test) { + stroke(255); + point(width / 4, i); + } + } +} diff --git a/dist/assets/examples/hi/05_Image/00_Load_and_Display_Image.js b/dist/assets/examples/hi/05_Image/00_Load_and_Display_Image.js new file mode 100644 index 0000000000..e11491f400 --- /dev/null +++ b/dist/assets/examples/hi/05_Image/00_Load_and_Display_Image.js @@ -0,0 +1,21 @@ +/* + * @name लोड और डिस्प्ले इमेज + * @description छवियों को लोड किया जा सकता है और स्क्रीन पर प्रदर्शित किया जा सकता है + * वास्तविक आकार या कोई अन्य आकार। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको एक की आवश्यकता होगी + * छवि फ़ाइल, और चल रही + * स्थानीय सर्वर.

+ */ +let img; // वैरिएबल 'img' घोषित करें। + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // छवि लोड करें +} + +function draw() { + // छवि को उसके वास्तविक आकार में बिंदु (0,0) पर प्रदर्शित करता है + image(img, 0, 0); + // आधे आकार में छवि को बिंदु (0, ऊंचाई / 2) पर प्रदर्शित करता है + image(img, 0, height / 2, img.width / 2, img.height / 2); +} diff --git a/dist/assets/examples/hi/05_Image/01_Background_Image.js b/dist/assets/examples/hi/05_Image/01_Background_Image.js new file mode 100644 index 0000000000..58b70942a2 --- /dev/null +++ b/dist/assets/examples/hi/05_Image/01_Background_Image.js @@ -0,0 +1,31 @@ +/* + * @name पृष्ठभूमि छवि + * @description यह उदाहरण लोड करने का सबसे तेज़ तरीका प्रस्तुत करता है a + * पृष्ठभूमि छवि। एक छवि को पृष्ठभूमि के रूप में लोड करने के लिए, + * यह कार्यक्रम के समान चौड़ाई और ऊंचाई का होना चाहिए। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको एक की आवश्यकता होगी + * छवि फ़ाइल, और चल रही + * स्थानीय सर्वर.

+ */ +let bg; +let y = 0; + +function setup() { + // पृष्ठभूमि की छवि मापदंडों के समान आकार की होनी चाहिए + // createCanvas () विधि में। इस कार्यक्रम में, का आकार + // इमेज 720x400 पिक्सल है। + 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/dist/assets/examples/hi/05_Image/02_Transparency.js b/dist/assets/examples/hi/05_Image/02_Transparency.js new file mode 100644 index 0000000000..a2befe2d72 --- /dev/null +++ b/dist/assets/examples/hi/05_Image/02_Transparency.js @@ -0,0 +1,25 @@ +/* + * @name पारदर्शिता + * @description चित्र पर पॉइंटर को बाएँ और दाएँ घुमाएँ ताकि वह बदल जाए + * पद। यह प्रोग्राम एक छवि को दूसरे के ऊपर संशोधित करके ओवरले करता है + * tint() फ़ंक्शन के साथ छवि का अल्फा मान। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको एक की आवश्यकता होगी + * छवि फ़ाइल, और चल रही + * स्थानीय सर्वर.

+ */ +let img; +let offset = 0; +let easing = 0.05; + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // प्रोग्राम में एक छवि लोड करें +} + +function draw() { + image(img, 0, 0); // पूर्ण अस्पष्टता पर प्रदर्शित करें + let dx = mouseX - img.width / 2 - offset; + offset += dx * easing; + tint(255, 127); // आधी अस्पष्टता पर प्रदर्शित करें + image(img, offset, 0); +} diff --git a/dist/assets/examples/hi/05_Image/03_Alpha_Mask.js b/dist/assets/examples/hi/05_Image/03_Alpha_Mask.js new file mode 100644 index 0000000000..a15cf7e9a8 --- /dev/null +++ b/dist/assets/examples/hi/05_Image/03_Alpha_Mask.js @@ -0,0 +1,28 @@ +/* + * @name अल्फा मास्क + * @description में पारदर्शिता निर्दिष्ट करने के लिए एक छवि के लिए "मास्क" लोड करता है + * छवि के विभिन्न भाग। दो छवियों को एक साथ मिश्रित कर रहे हैं + * mask() p5.Image की विधि। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको दो की आवश्यकता होगी + * छवि फ़ाइलें, और चल रहे + * स्थानीय सर्वर.

+ */ +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/dist/assets/examples/hi/05_Image/04_Create_Image.js b/dist/assets/examples/hi/05_Image/04_Create_Image.js new file mode 100644 index 0000000000..f9a7e8afd5 --- /dev/null +++ b/dist/assets/examples/hi/05_Image/04_Create_Image.js @@ -0,0 +1,25 @@ +/* + * @name इमेज बनाएं + * @description createImage() फ़ंक्शन पिक्सेल का एक ताज़ा बफर प्रदान करता है + * सोचना। यह उदाहरण एक छवि ढाल बनाता है। + */ +let img; // वैरिएबल '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/dist/assets/examples/hi/05_Image/05_Pointillism.js b/dist/assets/examples/hi/05_Image/05_Pointillism.js new file mode 100644 index 0000000000..0ba91bad34 --- /dev/null +++ b/dist/assets/examples/hi/05_Image/05_Pointillism.js @@ -0,0 +1,34 @@ +/* + * @name पॉइंटिलिज्म + * @description डैन शिफमैन द्वारा। माउस क्षैतिज स्थान का आकार नियंत्रित करता है + * डॉट्स। रंग के अनुसार दीर्घवृत्त का उपयोग करके एक साधारण पॉइंटिलिस्ट प्रभाव बनाता है + * एक छवि में पिक्सेल के लिए। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको एक की आवश्यकता होगी + * छवि फ़ाइल, और चल रही + * स्थानीय सर्वर.

+ */ +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/dist/assets/examples/hi/07_Color/00_Hue.js b/dist/assets/examples/hi/07_Color/00_Hue.js new file mode 100644 index 0000000000..773f2a48b6 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/00_Hue.js @@ -0,0 +1,25 @@ +/* + * @name ह्यू + * @description Hue वह रंग है जो a . से परावर्तित या प्रसारित होता है + * वस्तु और आमतौर पर रंग के नाम के रूप में जाना जाता है (लाल, नीला, + * पीला, आदि।) रंग बदलने के लिए कर्सर को प्रत्येक बार पर लंबवत ले जाएं। + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, height, height, height); + noStroke(); + background(0); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(mouseY, height, height); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/hi/07_Color/01_Saturation.js b/dist/assets/examples/hi/07_Color/01_Saturation.js new file mode 100644 index 0000000000..7894327066 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/01_Saturation.js @@ -0,0 +1,25 @@ +/* + * @name संतृप्ति + * @description संतृप्ति रंग की ताकत या शुद्धता है और + * रंग के अनुपात में ग्रे की मात्रा का प्रतिनिधित्व करता है। एक "संतृप्त" + * रंग शुद्ध होता है और "असंतृप्त" रंग में ग्रे का एक बड़ा प्रतिशत होता है। + * इसकी संतृप्ति को बदलने के लिए कर्सर को प्रत्येक पट्टी पर लंबवत ले जाएँ। + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, width, height, 100); + noStroke(); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(barX, mouseY, 66); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/hi/07_Color/02_Brightness.js b/dist/assets/examples/hi/07_Color/02_Brightness.js new file mode 100644 index 0000000000..de0e03ace6 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/02_Brightness.js @@ -0,0 +1,46 @@ +/* + * @name चमक + * @description डैन शिफमैन द्वारा। यह प्रोग्राम एक हिस्से की चमक को समायोजित करता है + * माउस से प्रत्येक पिक्सेल की दूरी की गणना करके छवि का। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको आवश्यकता होगी + * कम से कम एक छवि फ़ाइल और चल रहे स्थानीय सर्वर।

+ */ +let img; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 200); + pixelDensity(1); + img.loadPixels(); + loadPixels(); +} + +function draw() { + 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]; + // Calculate an amount to change brightness based on proximity to the mouse + let maxdist = 50; + let d = dist(x, y, mouseX, mouseY); + let adjustbrightness = (255 * (maxdist - d)) / maxdist; + r += adjustbrightness; + // Constrain RGB to make sure they are within 0-255 color range + r = constrain(r, 0, 255); + // Make a new color and set pixel in the window + //color c = color(r, g, b); + let pixloc = (y * width + x) * 4; + pixels[pixloc] = r; + pixels[pixloc + 1] = r; + pixels[pixloc + 2] = r; + pixels[pixloc + 3] = 255; + } + } + updatePixels(); +} diff --git a/dist/assets/examples/hi/07_Color/03_Color_Variables.js b/dist/assets/examples/hi/07_Color/03_Color_Variables.js new file mode 100644 index 0000000000..2a58ef7125 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/03_Color_Variables.js @@ -0,0 +1,39 @@ +/* + * @name रंग चर + * @description (अलबर्स को श्रद्धांजलि।) यह उदाहरण रंगों के लिए चर बनाता है + * जिसे कार्यक्रम में एक संख्या के बजाय एक नाम से संदर्भित किया जा सकता है। + */ +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); + + // ये बयान ऊपर दिए गए बयानों के बराबर हैं। + // प्रोग्रामर अपने पसंदीदा प्रारूप का उपयोग कर सकते हैं। + // अंदर जाने दें = रंग ('# CC6600'); + // चलो मध्य = रंग ('# CC9900'); + // बाहर जाने दें = रंग ('#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/dist/assets/examples/hi/07_Color/04_Relativity.js b/dist/assets/examples/hi/07_Color/04_Relativity.js new file mode 100644 index 0000000000..fb654bd192 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/04_Relativity.js @@ -0,0 +1,34 @@ +/* + * @name सापेक्षता + * @description प्रत्येक रंग अन्य रंगों के संबंध में माना जाता है। चोटी + * और नीचे की सलाखों में प्रत्येक में समान घटक रंग होते हैं, लेकिन एक अलग + * डिस्प्ले ऑर्डर के कारण अलग-अलग रंग अलग-अलग दिखाई देते हैं। + */ +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(); // केवल एक बार ड्रा करें +} + +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/dist/assets/examples/hi/07_Color/05_Linear_Gradient.js b/dist/assets/examples/hi/07_Color/05_Linear_Gradient.js new file mode 100644 index 0000000000..16fc43adcc --- /dev/null +++ b/dist/assets/examples/hi/07_Color/05_Linear_Gradient.js @@ -0,0 +1,52 @@ +/* + * @name रैखिक ढाल + * @description lerpColor () फ़ंक्शन के बीच इंटरपोल करने के लिए उपयोगी है + * दो रंग। + */ +// स्थिरांक +const Y_AXIS = 1; +const X_AXIS = 2; +let b1, b2, c1, c2; + +function setup() { + createCanvas(710, 400); + + // रंगों को परिभाषित करें + b1 = color(255); + b2 = color(0); + c1 = color(204, 102, 0); + c2 = color(0, 102, 153); + + noLoop(); +} + +function draw() { + // पृष्ठभूमि + setGradient(0, 0, width / 2, height, b1, b2, X_AXIS); + setGradient(width / 2, 0, width / 2, height, b2, b1, X_AXIS); + // अग्रभूमि + 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) { + // ऊपर से नीचे की ओर ढाल + 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) { + // बाएं से दाएं ढाल + 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/dist/assets/examples/hi/07_Color/06_Radial_Gradient.js b/dist/assets/examples/hi/07_Color/06_Radial_Gradient.js new file mode 100644 index 0000000000..a4bb1da4b6 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/06_Radial_Gradient.js @@ -0,0 +1,33 @@ +/* + * @name रेडियल ग्रेडिएंट + * @description एक ढाल बनाने के लिए संकेंद्रित वृत्तों की एक श्रृंखला बनाता है + * एक रंग से दूसरे रंग में। + */ +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/dist/assets/examples/hi/07_Color/07_Lerp_Color.js b/dist/assets/examples/hi/07_Color/07_Lerp_Color.js new file mode 100644 index 0000000000..51338784c4 --- /dev/null +++ b/dist/assets/examples/hi/07_Color/07_Lerp_Color.js @@ -0,0 +1,49 @@ +/* + * @name Lerp Color + * @description लूप यादृच्छिक आकार, + * लाल से नीले रंग में लाल रंग का रंग। + */ +function setup() { + createCanvas(720, 400); + background(255); + noStroke(); +} + +function draw() { + background(255); + from = color(255, 0, 0, 0.2 * 255); + to = color(0, 0, 255, 0.2 * 255); + c1 = lerpColor(from, to, 0.33); + c2 = lerpColor(from, to, 0.66); + for (let i = 0; i < 15; i++) { + fill(from); + quad( + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height) + ); + fill(c1); + quad( + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height) + ); + fill(c2); + quad( + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height) + ); + fill(to); + quad( + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height) + ); + } + frameRate(5); +} diff --git a/dist/assets/examples/hi/08_Math/00_incrementdecrement.js b/dist/assets/examples/hi/08_Math/00_incrementdecrement.js new file mode 100644 index 0000000000..bb34253b2f --- /dev/null +++ b/dist/assets/examples/hi/08_Math/00_incrementdecrement.js @@ -0,0 +1,42 @@ +/* + * @name वेतन वृद्धि + * @description "a++" लिखना "a = a + 1" के बराबर है। + * "ए--" लिखना "ए = ए -1" के बराबर है। + */ +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/dist/assets/examples/hi/08_Math/01_operatorprecedence.js b/dist/assets/examples/hi/08_Math/01_operatorprecedence.js new file mode 100644 index 0000000000..3fd05af720 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/01_operatorprecedence.js @@ -0,0 +1,54 @@ +/* + * @name ऑपरेटर वरीयता + * @description यदि आप स्पष्ट रूप से उस क्रम का उल्लेख नहीं करते हैं जिसमें a + * अभिव्यक्ति का मूल्यांकन किया जाता है, उनका मूल्यांकन ऑपरेटर के आधार पर किया जाता है + * वरीयता। उदाहरण के लिए, "4+2*8" कथन में, 2 होगा + * पहले 8 से गुणा करें और फिर परिणाम 4 में जोड़ दिया जाएगा। + * ऐसा इसलिए है क्योंकि "*" की "+" की तुलना में अधिक प्राथमिकता है। कन्नी काटना + * कार्यक्रम को पढ़ने में अस्पष्टता, यह अनुशंसा की जाती है कि कथन है + * को "4+(2*8)" लिखा जाता है। मूल्यांकन के क्रम को नियंत्रित किया जा सकता है + * कोड में कोष्ठक लगाने के माध्यम से। ऑपरेटर की एक तालिका + * वरीयता नीचे दी गई है। + */ +// सर्वोच्च प्राथमिकता सूची में सबसे ऊपर है और +// सबसे नीचे सबसे नीचे है। +// गुणक: * /% +// योजक: + - +// संबंधपरक: <> <= >= +// समानता: ==!= +// तार्किक और: && +// तार्किक या: || +// असाइनमेंट: = += -= *= /= %= +function setup() { + createCanvas(710, 400); + background(51); + noFill(); + stroke(51); + + stroke(204); + for (let i = 0; i < width - 20; i += 4) { + // 30 को 70 में जोड़ा जाता है और फिर मूल्यांकन किया जाता है + // यदि यह "i" के वर्तमान मान से अधिक है + // स्पष्टता के लिए, "if (i> (30 + 70)) {" के रूप में लिखें + if (i > 30 + 70) { + line(i, 0, i, 50); + } + } + + stroke(255); + // 2 को 8 से गुणा किया जाता है और परिणाम 4 . में जोड़ा जाता है + // स्पष्टता के लिए, "रेक्ट (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) { + // संबंधपरक बयानों का मूल्यांकन किया जाता है + // पहले, और फिर तार्किक और कथन और + // अंत में तार्किक OR. स्पष्टता के लिए, इस प्रकार लिखें: + // "अगर (((i> 20) && (i <50)) || ((i> 100) && (i <चौड़ाई-20))) {" + if ((i > 20 && i < 50) || (i > 100 && i < width - 20)) { + line(i, 151, i, height - 1); + } + } +} diff --git a/dist/assets/examples/hi/08_Math/02_distance1d.js b/dist/assets/examples/hi/08_Math/02_distance1d.js new file mode 100644 index 0000000000..29d8ff66c6 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/02_distance1d.js @@ -0,0 +1,65 @@ +/* + * @name दूरी 1डी + * @description नियंत्रित करने के लिए माउस को बाएँ और दाएँ घुमाएँ + * चलती आकृतियों की गति और दिशा। + */ +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/dist/assets/examples/hi/08_Math/03_distance2d.js b/dist/assets/examples/hi/08_Math/03_distance2d.js new file mode 100644 index 0000000000..8d7c79aa76 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/03_distance2d.js @@ -0,0 +1,25 @@ +/* + * @name दूरी 2डी + * @description छवि पर माउस को अस्पष्ट करने के लिए ले जाएं + * और मैट्रिक्स प्रकट करें। माउस से दूरी मापता है + * प्रत्येक सर्कल के लिए और आनुपातिक रूप से आकार निर्धारित करता है। + */ +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/dist/assets/examples/hi/08_Math/04_sine.js b/dist/assets/examples/hi/08_Math/04_sine.js new file mode 100644 index 0000000000..f9ba5e1b2a --- /dev/null +++ b/dist/assets/examples/hi/08_Math/04_sine.js @@ -0,0 +1,27 @@ + /* + *@name साइन + * @description sin() फ़ंक्शन के साथ आसानी से स्केलिंग आकार। + */ +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/dist/assets/examples/hi/08_Math/05_sincosine.js b/dist/assets/examples/hi/08_Math/05_sincosine.js new file mode 100644 index 0000000000..91062f6520 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/05_sincosine.js @@ -0,0 +1,43 @@ +/* + * @name साइन कोसाइन + * @description लीनियर मूवमेंट विथ sin() और cos()। + * 0 और PI*2 के बीच की संख्या (TWO_PI जिसका कोण लगभग 6.28 है) + * इन कार्यों में डाल दिया जाता है और -1 और 1 के बीच की संख्या वापस कर दी जाती है। + * इन मूल्यों को तब बड़े आंदोलनों का उत्पादन करने के लिए बढ़ाया जाता है। + */ +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/dist/assets/examples/hi/08_Math/06_sinewave.js b/dist/assets/examples/hi/08_Math/06_sinewave.js new file mode 100644 index 0000000000..0ec43a3c7e --- /dev/null +++ b/dist/assets/examples/hi/08_Math/06_sinewave.js @@ -0,0 +1,48 @@ +/* + * @name साइन वेव + * @description एक साधारण साइन वेव रेंडर करें। + * डैनियल शिफमैन द्वारा मूल। + */ + +let xspacing = 16; // प्रत्येक क्षैतिज स्थान के बीच की दूरी +let w; // पूरी लहर की चौड़ाई +let theta = 0.0; // 0 . पर कोण प्रारंभ करें +let amplitude = 75.0; // लहर की ऊंचाई +let period = 500.0; // वेव रिपीट होने से पहले कितने पिक्सेल होते हैं +let dx; // एक्स बढ़ाने के लिए मूल्य +let yvalues; // तरंग के लिए ऊंचाई मानों को संग्रहीत करने के लिए एक सरणी का उपयोग करना + +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() { + // वृद्धि थीटा (के लिए विभिन्न मूल्यों का प्रयास करें values + // 'कोणीय वेग' यहाँ) + theta += 0.02; + + // प्रत्येक x मान के लिए, साइन फ़ंक्शन के साथ y मान की गणना करें + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = sin(x) * amplitude; + x += dx; + } +} + +function renderWave() { + noStroke(); + fill(255); + // प्रत्येक स्थान पर एक अंडाकार के साथ लहर खींचने का एक आसान तरीका simple + for (let x = 0; x < yvalues.length; x++) { + ellipse(x * xspacing, height / 2 + yvalues[x], 16, 16); + } +} diff --git a/dist/assets/examples/hi/08_Math/07_additivewave.js b/dist/assets/examples/hi/08_Math/07_additivewave.js new file mode 100644 index 0000000000..9ca17de600 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/07_additivewave.js @@ -0,0 +1,70 @@ +/* + * @name Additive Wave + * @description दो तरंगों को एक साथ जोड़कर अधिक जटिल तरंग बनाएं। + * डैनियल शिफमैन द्वारा मूल + */ +let xspacing = 8; // प्रत्येक क्षैतिज स्थान के बीच की दूरी +let w; // पूरी लहर की चौड़ाई +let maxwaves = 4; // कुल # तरंगों को एक साथ जोड़ने के लिए + +let theta = 0.0; +let amplitude = new Array(maxwaves); // लहर की ऊंचाई +// एक्स बढ़ाने के लिए मूल्य, गणना की जानी है +// अवधि और xspacing के एक समारोह के रूप में +let dx = new Array(maxwaves); +// ऊंचाई मूल्यों को संग्रहीत करने के लिए एक सरणी का उपयोग करना +// लहर के लिए (पूरी तरह से आवश्यक नहीं) +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); // तरंग दोहराने से पहले पिक्सेल की संख्या before + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new Array(floor(w / xspacing)); +} + +function draw() { + background(0); + calcWave(); + renderWave(); +} + +function calcWave() { + // वृद्धि थीटा (विभिन्न मूल्यों का प्रयास करें + // यहां 'कोणीय वेग' के लिए + theta += 0.02; + + // सभी ऊंचाई मानों को शून्य पर सेट करें + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // तरंग ऊंचाई मान संचित करें + for (let j = 0; j < maxwaves; j++) { + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + // हर दूसरी लहर साइन के बजाय कोसाइन है + if (j % 2 == 0) yvalues[i] += sin(x) * amplitude[j]; + else yvalues[i] += cos(x) * amplitude[j]; + x += dx[j]; + } + } +} + +function renderWave() { + // प्रत्येक स्थान पर एक अंडाकार के साथ लहर खींचने का एक आसान तरीका simple + 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/dist/assets/examples/hi/08_Math/08_polartocartesian.js b/dist/assets/examples/hi/08_Math/08_polartocartesian.js new file mode 100644 index 0000000000..0939f7e3c6 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/08_polartocartesian.js @@ -0,0 +1,44 @@ +/* + * @name PolarToCartesian + * @description एक ध्रुवीय निर्देशांक परिवर्तित करें (r, थीटा) + * कार्तीय (x, y) के लिए: x = rcos (थीटा) y = rsin (थीटा) + * डैनियल शिफमैन द्वारा मूल। + */ +let r; + +// कोण और कोणीय वेग, त्वरण +let theta; +let theta_vel; +let theta_acc; + +function setup() { + createCanvas(710, 400); + + // सभी मूल्यों को प्रारंभ करें + r = height * 0.45; + theta = 0; + theta_vel = 0; + theta_acc = 0.0001; +} + +function draw() { + background(0); + + // मूल बिंदु को स्क्रीन के केंद्र में अनुवाद करें + translate(width / 2, height / 2); + + // ध्रुवीय को कार्टेशियन में बदलें + let x = r * cos(theta); + let y = r * sin(theta); + + // कार्तीय निर्देशांक पर दीर्घवृत्त ड्रा करें + ellipseMode(CENTER); + noStroke(); + fill(200); + ellipse(x, y, 32, 32); + + // कोण पर त्वरण और वेग लागू करें + // (r इस उदाहरण में स्थिर रहता है) + theta_vel += theta_acc; + theta += theta_vel; +} diff --git a/dist/assets/examples/hi/08_Math/09_arctangent.js b/dist/assets/examples/hi/08_Math/09_arctangent.js new file mode 100644 index 0000000000..4d352779e7 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/09_arctangent.js @@ -0,0 +1,45 @@ +/* + * @name आर्कटिक + * @description आंखों की दिशा बदलने के लिए माउस ले जाएं।
atan2() फ़ंक्शन प्रत्येक आंख से कर्सर तक के कोण की गणना करता है। + */ +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(); + }; +} diff --git a/dist/assets/examples/hi/08_Math/10_Interpolate.js b/dist/assets/examples/hi/08_Math/10_Interpolate.js new file mode 100644 index 0000000000..a52d1c30a3 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/10_Interpolate.js @@ -0,0 +1,34 @@ +/* + * @name रैखिक इंटरपोलेशन + * @frame 720, 400 + * @description माउस को स्क्रीन पर ले जाएँ और सिंबल उसके पीछे आ जाएगा। + * एनीमेशन के प्रत्येक फ्रेम को खींचने के बीच, दीर्घवृत्त भाग जाता है + * दूरी (0.05) की वर्तमान स्थिति से कर्सर की ओर का उपयोग कर + * lerp () फ़ंक्शन। + * यह केवल lerp() के साथ इनपुट के तहत ईजिंग जैसा ही है .. + */ + +let x = 0; +let y = 0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(51); + + // lerp () एक विशिष्ट वेतन वृद्धि पर दो संख्याओं के बीच की संख्या की गणना करता है। + // एएमटी पैरामीटर दो मानों के बीच प्रक्षेपित करने की राशि है + // जहां 0.0 पहले बिंदु के बराबर है, 0.1 पहले बिंदु के बहुत करीब है, 0.5 + // बीच में आधा रास्ता है, आदि। + + // यहां हम प्रत्येक फ्रेम में 5% रास्ते को माउस स्थान पर ले जा रहे हैं + x = lerp(x, mouseX, 0.05); + y = lerp(y, mouseY, 0.05); + + fill(255); + stroke(255); + ellipse(x, y, 66, 66); +} diff --git a/dist/assets/examples/hi/08_Math/11_doubleRandom.js b/dist/assets/examples/hi/08_Math/11_doubleRandom.js new file mode 100644 index 0000000000..e14d61e213 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/11_doubleRandom.js @@ -0,0 +1,24 @@ +/* + * @name डबल रैंडम + * @frame 720,400 (वैकल्पिक) + * @description दो random() कॉल और point() का उपयोग करना + * अनियमित चूरा रेखा बनाने का कार्य। + * मूल ईरा ग्रीनबर्ग द्वारा। + */ +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/dist/assets/examples/hi/08_Math/12_random.js b/dist/assets/examples/hi/08_Math/12_random.js new file mode 100644 index 0000000000..20262af6f4 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/12_random.js @@ -0,0 +1,19 @@ +/* + * @name रैंडम + * @description रैंडम नंबर इस इमेज का आधार बनाते हैं। + * हर बार प्रोग्राम लोड होने पर परिणाम अलग होता है। + */ +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/dist/assets/examples/hi/08_Math/13_noise1D.js b/dist/assets/examples/hi/08_Math/13_noise1D.js new file mode 100644 index 0000000000..6e42276175 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/13_noise1D.js @@ -0,0 +1,31 @@ +/* + * @name Noise1D + * @description स्थान निर्दिष्ट करने के लिए 1D Perlin Noise का उपयोग करना। + */ +let xoff = 0.0; +let xincrement = 0.01; + +function setup() { + createCanvas(710, 400); + background(0); + noStroke(); +} + +function draw() { + // एक अल्फा ब्लेंडेड बैकग्राउंड बनाएं + fill(0, 10); + rect(0, 0, width, height); + + // चलो n = यादृच्छिक (0, चौड़ाई); // शोर के बजाय इस लाइन को आजमाएं + + // xoff और स्केल के आधार पर शोर मान प्राप्त करें + // यह खिड़की की चौड़ाई के अनुसार है + let n = noise(xoff) * width; + + // प्रत्येक चक्र के साथ, वृद्धि xoff + xoff += xincrement; + + // पर्लिन शोर द्वारा उत्पन्न मूल्य पर दीर्घवृत्त को ड्रा करें + fill(200); + ellipse(n, height / 2, 64, 64); +} diff --git a/dist/assets/examples/hi/08_Math/14_noisewave.js b/dist/assets/examples/hi/08_Math/14_noisewave.js new file mode 100644 index 0000000000..24402452a1 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/14_noisewave.js @@ -0,0 +1,42 @@ +/* + * @name शोर लहर + * @description तरंग जैसा पैटर्न उत्पन्न करने के लिए पर्लिन शोर का उपयोग करना। + * डैनियल शिफमैन द्वारा मूल। + */ +let yoff = 0.0; // पर्लिन शोर का दूसरा आयाम + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(51); + + fill(255); + // हम तरंग बिंदुओं से एक बहुभुज बनाने जा रहे हैं + beginShape(); + + let xoff = 0; // विकल्प # 1: 2D शोर + // चलो xoff = yoff; // विकल्प # 2: 1D शोर + + // क्षैतिज पिक्सेल पर पुनरावृति + for (let x = 0; x <= width; x += 10) { + // शोर के अनुसार y मान की गणना करें, मानचित्र करें + + // विकल्प # 1: 2D शोर + let y = map(noise(xoff, yoff), 0, 1, 200, 300); + + // विकल्प # 2: 1D शोर + // चलो y = नक्शा (शोर (xoff), 0, 1, 200,300); + + // शीर्ष सेट करें + vertex(x, y); + // शोर के लिए वृद्धि x आयाम + xoff += 0.05; + } + // शोर के लिए वृद्धि y आयाम + yoff += 0.01; + vertex(width, height); + vertex(0, height); + endShape(CLOSE); +} diff --git a/dist/assets/examples/hi/08_Math/15_Noise2D.js b/dist/assets/examples/hi/08_Math/15_Noise2D.js new file mode 100644 index 0000000000..0c9dcf85ba --- /dev/null +++ b/dist/assets/examples/hi/08_Math/15_Noise2D.js @@ -0,0 +1,41 @@ +/* + * @name Noise2D + * @frame 710,400 (वैकल्पिक) + * @description विभिन्न मापदंडों के साथ एक 2D शोर बनाएँ। + * + */ +let noiseVal; +let noiseScale = 0.02; + +function setup() { + createCanvas(640, 360); +} + +function draw() { + background(0); + // छवि का बायां आधा भाग बनाएं + for (let y = 0; y < height - 30; y++) { + for (let x = 0; x < width / 2; x++) { + // पिक्सल ऑक्टेव काउंट और फॉलऑफ वैल्यू का noiceDetail + noiseDetail(2, 0.2); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // छवि का दाहिना आधा भाग बनाएं + for (let y = 0; y < height - 30; y++) { + for (let x = width / 2; x < width; x++) { + // पिक्सल ऑक्टेव काउंट और फॉलऑफ वैल्यू का noiceDetail + noiseDetail(5, 0.5); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // दो विभाजनों का विवरण दिखाएं + textSize(18); + fill(255, 255, 255); + text('Noice2D with 2 octaves and 0.2 falloff', 10, 350); + text('Noice2D with 1 octaves and 0.7 falloff', 330, 350); +} diff --git a/dist/assets/examples/hi/08_Math/16_Noise3D.js b/dist/assets/examples/hi/08_Math/16_Noise3D.js new file mode 100644 index 0000000000..beeb77b3f4 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/16_Noise3D.js @@ -0,0 +1,48 @@ +/* + * @name Noise3D + * @frame 710,400 (वैकल्पिक) + * @description सरल एनिमेटेड बनावट बनाने के लिए 3D शोर का उपयोग करना। + */ + +let noiseVal; +// वृद्धि x 0.01 +let x_increment = 0.01; +// प्रत्येक draw() चक्र में ०.०२ से z बढ़ाएँ +let z_increment = 0.02; + +// ऑफसेट मान +let z_off, y_off, x_off; + +function setup() { + // कैनवास बनाएं + createCanvas(640, 360); + // फ्रेम दर को परिभाषित करें + frameRate(20); + // z_off का प्रारंभिक मान + z_off = 0; +} + +function draw() { + x_off = 0; + y_off = 0; + // बैकग्राउंड को काला करें + background(0); + // नोटिस विवरण समायोजित करें + noiseDetail(8, 0.65); + + // प्रत्येक x, y के लिए नोइस मान की गणना करें + for (let y = 0; y < height; y++) { + x_off += x_increment; + y_off = 0; + + for (let x = 0; x < width; x++) { + // प्रत्येक पिक्सेल की गणना और ड्रा करें + 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/dist/assets/examples/hi/08_Math/17_Randomchords.js b/dist/assets/examples/hi/08_Math/17_Randomchords.js new file mode 100644 index 0000000000..b3bc8184de --- /dev/null +++ b/dist/assets/examples/hi/08_Math/17_Randomchords.js @@ -0,0 +1,35 @@ +/* + * @name रैंडम कॉर्ड्स + * @description एक वृत्त की यादृच्छिक जीवाओं को संचित करता है। पारभासी में प्रत्येक राग + * इसलिए वे एक छायांकित गोले का भ्रम देने के लिए जमा होते हैं। + * आतिश भाटिया द्वारा योगदान, एंडर्स हॉफ से प्रेरित + */ + +function setup() { + createCanvas(400, 400); + background(255, 255, 255); + + // अल्फा मान का उपयोग करके पारभासी स्ट्रोक + stroke(0, 0, 0, 15); +} + +function draw() { + // प्रत्येक फ्रेम में दो यादृच्छिक तार बनाएं + randomChord(); + randomChord(); +} + +function randomChord() { + // एक सर्कल पर एक यादृच्छिक बिंदु खोजें + let angle1 = random(0, 2 * PI); + let xpos1 = 200 + 200 * cos(angle1); + let ypos1 = 200 + 200 * sin(angle1); + + // सर्कल पर एक और यादृच्छिक बिंदु खोजें + let angle2 = random(0, 2 * PI); + let xpos2 = 200 + 200 * cos(angle2); + let ypos2 = 200 + 200 * sin(angle2); + + // उनके बीच एक रेखा खींचें + line(xpos1, ypos1, xpos2, ypos2); +} diff --git a/dist/assets/examples/hi/08_Math/18_Map.js b/dist/assets/examples/hi/08_Math/18_Map.js new file mode 100644 index 0000000000..c032d2ced6 --- /dev/null +++ b/dist/assets/examples/hi/08_Math/18_Map.js @@ -0,0 +1,22 @@ +/* + * @name नक्शा + * @description किसी भी संख्या को लेने के लिए map() फ़ंक्शन का उपयोग करें और इसे स्केल करें a + * नया नंबर जो उस प्रोजेक्ट के लिए अधिक उपयोगी है जिस पर आप काम कर रहे हैं। + * उदाहरण के लिए, किसी आकृति के आकार या रंग को नियंत्रित करने के लिए माउस की स्थिति से संख्याओं का उपयोग करें। + * इस उदाहरण में, माउस के x-निर्देशांक (0 और 360 के बीच की संख्या) को नए नंबरों तक बढ़ाया जाता है + * एक सर्कल के रंग और आकार को परिभाषित करने के लिए। + */ +function setup() { + createCanvas(640, 400); + noStroke(); +} + +function draw() { + background(0); + // माउसएक्स मान को 0 से 640 तक 0 और 175 . के बीच की सीमा तक स्केल करें + let c = map(mouseX, 0, width, 0, 175); + // माउसएक्स मान को 0 से 640 तक 40 और 300 के बीच की सीमा तक स्केल करें + let d = map(mouseX, 0, width, 40, 300); + fill(255, c, 0); + ellipse(width/2, height/2, d, d); +} diff --git a/dist/assets/examples/hi/08_Math/19_parametricEquation.js b/dist/assets/examples/hi/08_Math/19_parametricEquation.js new file mode 100644 index 0000000000..c4459068ef --- /dev/null +++ b/dist/assets/examples/hi/08_Math/19_parametricEquation.js @@ -0,0 +1,44 @@ +/* + * @name पैरामीट्रिक समीकरण + * @description एक पैरामीट्रिक समीकरण है जहाँ x और y + * निर्देशांक दोनों एक दूसरे अक्षर के रूप में लिखे गए हैं। यह है + * एक पैरामीटर कहा जाता है और आमतौर पर अक्षर t या में दिया जाता है। + * इसकी प्रेरणा एलेक्जेंडर मिलर के यूट्यूब चैनल से ली गई है। + */ + +function setup(){ + createCanvas(720,400); +} + +// वह पैरामीटर जिस पर x और y निर्भर करते हैं, आमतौर पर या तो t या थीटा के प्रतीक के रूप में लिया जाता है +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; +} +// लाइन के प्रारंभिक x समन्वय को बदलने के लिए कार्य +function x1(t){ + return sin(t/10)*125+sin(t/20)*125+sin(t/30)*125; +} + +// लाइन के प्रारंभिक y समन्वय को बदलने के लिए कार्य change +function y1(t){ + return cos(t/10)*125+cos(t/20)*125+cos(t/30)*125; +} + +// लाइन के अंतिम x समन्वय को बदलने के लिए कार्य +function x2(t){ + return sin(t/15)*125+sin(t/25)*125+sin(t/35)*125; +} + +// लाइन के अंतिम y समन्वय को बदलने के लिए कार्य +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/dist/assets/examples/hi/09_Simulate/00_Forces.js b/dist/assets/examples/hi/09_Simulate/00_Forces.js new file mode 100644 index 0000000000..60d9de27a4 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/00_Forces.js @@ -0,0 +1,148 @@ +/* + * @name बल + * @description निकायों पर अभिनय करने वाले कई बल का प्रदर्शन + * (natureofcode.com) + */ +// कई बल अभिनय का प्रदर्शन +// निकायों (प्रस्तावक वर्ग) +// शरीर लगातार गुरुत्वाकर्षण का अनुभव करते हैं +// जब "पानी" में निकायों को द्रव प्रतिरोध का अनुभव होता है + +// पांच गतिमान पिंड +let movers = []; + +// तरल +let liquid; + +function setup() { + createCanvas(640, 360); + reset(); + // तरल वस्तु बनाएं + liquid = new Liquid(0, height / 2, width, height / 2, 0.1); +} + +function draw() { + background(127); + + // पानी खींचो + liquid.display(); + + for (let i = 0; i < movers.length; i++) { + + // क्या प्रस्तावक तरल में है? + if (liquid.contains(movers[i])) { + // ड्रैग फोर्स की गणना करें + let dragForce = liquid.calculateDrag(movers[i]); + // मूवर पर ड्रैग फोर्स लागू करें + movers[i].applyForce(dragForce); + } + + // यहाँ द्रव्यमान द्वारा गुरुत्वाकर्षण को बढ़ाया जाता है! + let gravity = createVector(0, 0.1 * movers[i].mass); + // गुरुत्वाकर्षण लागू करें + movers[i].applyForce(gravity); + + // अद्यतन और प्रदर्शित करें + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } + +} + + +function mousePressed() { + reset(); +} + +// सभी मूवर ऑब्जेक्ट को बेतरतीब ढंग से पुनरारंभ करें +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; +}; + +// तरल में प्रस्तावक है? +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; +}; + +// ड्रैग फोर्स की गणना करें +Liquid.prototype.calculateDrag = function(m) { + // परिमाण गुणांक है * गति चुकता + let speed = m.velocity.mag(); + let dragMagnitude = this.c * speed * speed; + + // दिशा वेग के विपरीत है + let dragForce = m.velocity.copy(); + dragForce.mult(-1); + + // परिमाण के अनुसार पैमाना + // ड्रैगफोर्स.सेटमैग (ड्रैगमैग्निट्यूड); + 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); +} + +// न्यूटन का दूसरा नियम: F = M * A +// या ए = एफ / एम +Mover.prototype.applyForce = function(force) { + let f = p5.Vector.div(force, this.mass); + this.acceleration.add(f); +}; + +Mover.prototype.update = function() { + // त्वरण के अनुसार वेग बदलता है + this.velocity.add(this.acceleration); + // स्थिति वेग से बदलती है + this.position.add(this.velocity); + // हमें प्रत्येक फ्रेम में त्वरण को साफ करना चाहिए + 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); +}; + +// विंडो के नीचे से बाउंस करें +Mover.prototype.checkEdges = function() { + if (this.position.y > (height - this.mass * 8)) { + // नीचे से टकराते समय थोड़ा भीगना + this.velocity.y *= -0.9; + this.position.y = (height - this.mass * 8); + } +}; + + + + + + + + diff --git a/dist/assets/examples/hi/09_Simulate/01_ParticleSystem.js b/dist/assets/examples/hi/09_Simulate/01_ParticleSystem.js new file mode 100644 index 0000000000..c271b73916 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/01_ParticleSystem.js @@ -0,0 +1,69 @@ +/* + * @name कण प्रणाली + * @description यह एक मूल कण प्रणाली है + * (natureofcode.com) + */ +let system; + +function setup() { + createCanvas(720, 400); + system = new ParticleSystem(createVector(width / 2, 50)); +} + +function draw() { + background(51); + system.addParticle(); + system.run(); +} + +// एक साधारण कण वर्ग +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(); +}; + +// स्थिति को अद्यतन करने की विधि +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// प्रदर्शित करने की विधि +Particle.prototype.display = function() { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// क्या कण अभी भी उपयोगी है? +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/dist/assets/examples/hi/09_Simulate/02_Flocking.js b/dist/assets/examples/hi/09_Simulate/02_Flocking.js new file mode 100644 index 0000000000..c40524fca7 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/02_Flocking.js @@ -0,0 +1,229 @@ +/* + * @name झुंड + * @description क्रेग रेनॉल्ड्स के "झुंड" व्यवहार का प्रदर्शन। + * देखें: http://www.red3d.com/cwr/ + * नियम: सामंजस्य, पृथक्करण, संरेखण + * (natureofcode.com से)। + * सिस्टम में बोड्स जोड़ने के लिए माउस को ड्रैग करें। + */ + + +let flock; + +function setup() { + createCanvas(640, 360); + createP("Drag the mouse to generate new boids."); + + flock = new Flock(); + // सिस्टम में बोलियों का एक प्रारंभिक सेट जोड़ें + for (let i = 0; i < 100; i++) { + let b = new Boid(width / 2,height / 2); + flock.addBoid(b); + } +} + +function draw() { + background(51); + flock.run(); +} + +// सिस्टम में एक नया बोड जोड़ें +function mouseDragged() { + flock.addBoid(new Boid(mouseX, mouseY)); +} + +// कोड की प्रकृति +// डैनियल शिफमैन +// http://natureofcode.com + +// झुंड वस्तु +// बहुत कम करता है, बस सभी बोलियों की सरणी का प्रबंधन करता है + +function Flock() { + // सभी बोलियों के लिए एक सरणी + this.boids = []; // सरणी को इनिशियलाइज़ करें +} + +Flock.prototype.run = function() { + for (let i = 0; i < this.boids.length; i++) { + this.boids[i].run(this.boids); // प्रत्येक बोली को व्यक्तिगत रूप से बोलियों की पूरी सूची पास करना + } +} + +Flock.prototype.addBoid = function(b) { + this.boids.push(b); +} + +// कोड की प्रकृति +// डैनियल शिफमैन +// http://natureofcode.com + +// बोएड क्लास +// पृथक्करण, सामंजस्य, संरेखण के तरीके जोड़े गए + +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; // अधिकतम गति + this.maxforce = 0.05; // अधिकतम स्टीयरिंग बल +} + +Boid.prototype.run = function(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); +} + +Boid.prototype.applyForce = function(force) { + // यदि हम A = F / M . चाहते हैं तो हम यहाँ द्रव्यमान जोड़ सकते हैं + this.acceleration.add(force); +} + +// हम हर बार तीन नियमों के आधार पर एक नया त्वरण जमा करते हैं +Boid.prototype.flock = function(boids) { + let sep = this.separate(boids); // पृथक्करण + let ali = this.align(boids); // संरेखण + let coh = this.cohesion(boids); // सामंजस्य + // मनमाने ढंग से इन ताकतों को तौलें + sep.mult(1.5); + ali.mult(1.0); + coh.mult(1.0); + // बल वैक्टर को त्वरण में जोड़ें + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); +} + +// स्थान अपडेट करने की विधि +Boid.prototype.update = function() { + // वेग अपडेट करें + this.velocity.add(this.acceleration); + // सीमा गति + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // त्वरण को प्रत्येक चक्र में 0 पर रीसेट करें + this.acceleration.mult(0); +} + +// एक विधि जो एक लक्ष्य की ओर एक स्टीयरिंग बल की गणना और लागू करती है +// स्टीयर = वांछित माइनस वेलोसिटी +Boid.prototype.seek = function(target) { + let desired = p5.Vector.sub(target,this.position); // स्थान से लक्ष्य की ओर इशारा करते हुए एक वेक्टर + // वांछित और स्केल को अधिकतम गति के लिए सामान्यीकृत करें + desired.normalize(); + desired.mult(this.maxspeed); + // संचालन = वांछित शून्य वेग + let steer = p5.Vector.sub(desired,this.velocity); + steer.limit(this.maxforce); // अधिकतम स्टीयरिंग बल तक सीमित करें + return steer; +} + +Boid.prototype.render = function() { + // वेग की दिशा में घुमाया गया एक त्रिभुज बनाएं + 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(); +} + +// चारों ओर लपेट दो +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; +} + +// पृथक्करण +// विधि आस-पास के boids के लिए जाँच करता है और दूर चला जाता है +Boid.prototype.separate = function(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // सिस्टम में प्रत्येक बोड के लिए, जांचें कि क्या यह बहुत करीब है + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position,boids[i].position); + // यदि दूरी 0 से अधिक है और मनमानी राशि से कम है (0 जब आप स्वयं हों) + if ((d > 0) && (d < desiredseparation)) { + // पड़ोसी से दूर की ओर इशारा करते हुए वेक्टर की गणना करें + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // दूरी से वजन + steer.add(diff); + count++; // कितने का ट्रैक रखें + } + } + // औसत -- कितने से विभाजित करें + if (count > 0) { + steer.div(count); + } + + // जब तक वेक्टर 0 . से बड़ा है + if (steer.mag() > 0) { + // रेनॉल्ड्स को लागू करें: संचालन = वांछित - वेग + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; +} + +// संरेखण +// सिस्टम में प्रत्येक पास के बोड के लिए, औसत वेग की गणना करें +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); + } +} + +// सामंजस्य +// आस-पास के सभी बोड्स के औसत स्थान (अर्थात केंद्र) के लिए, उस स्थान की ओर स्टीयरिंग वेक्टर की गणना करें +Boid.prototype.cohesion = 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].position); // स्थान जोड़ना + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // स्थान की ओर बढ़ें + } else { + return createVector(0, 0); + } +} + + diff --git a/dist/assets/examples/hi/09_Simulate/03_WolframCA.js b/dist/assets/examples/hi/09_Simulate/03_WolframCA.js new file mode 100644 index 0000000000..fd36eb4880 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/03_WolframCA.js @@ -0,0 +1,73 @@ +/* + * @name वोल्फ्राम सीए + * @description वुल्फराम 1-आयामी सेलुलर ऑटोमेटा का सरल प्रदर्शन + * (natureofcode.com) + */ + +let w = 10; +// 0s और 1s की एक सरणी +let cells; + +// हम मनमाने ढंग से "1" की स्थिति वाले केवल मध्य सेल से शुरू करते हैं +let generation = 0; + +// नियम सेट को स्टोर करने के लिए एक सरणी, उदाहरण के लिए {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(); + } +} + +// नई पीढ़ी बनाने की प्रक्रिया +function generate() { + // पहले हम नए मूल्यों के लिए एक खाली सरणी बनाते हैं + let nextgen = Array(cells.length); + // प्रत्येक स्थान के लिए, वर्तमान स्थिति और पड़ोसी राज्यों की जांच करके नए राज्य का निर्धारण करें + // किनारों को अनदेखा करें जिनमें केवल एक पड़ोसी हो + for (let i = 1; i < cells.length-1; i++) { + let left = cells[i-1]; // वाम पड़ोसी राज्य + let me = cells[i]; // वर्तमान स्थिति + let right = cells[i+1]; // सही पड़ोसी राज्य + nextgen[i] = rules(left, me, right); // नियमों के आधार पर अगली पीढ़ी की स्थिति की गणना करें + } + // वर्तमान पीढ़ी नई पीढ़ी है + cells = nextgen; + generation++; +} + + +// वोल्फ्राम नियमों को लागू करना +// सुधार किया जा सकता है और अधिक संक्षिप्त बनाया जा सकता है, लेकिन यहां हम स्पष्ट रूप से देख सकते हैं कि प्रत्येक मामले के लिए क्या चल रहा है +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/dist/assets/examples/hi/09_Simulate/04_GameOfLife.js b/dist/assets/examples/hi/09_Simulate/04_GameOfLife.js new file mode 100644 index 0000000000..6da1a7670d --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/04_GameOfLife.js @@ -0,0 +1,93 @@ + /* + * @name Game of Life + * @description जॉन कॉनवे के गेम ऑफ लाइफ सीए का एक बुनियादी कार्यान्वयन + * (natureofcode.com) + */ +let w; +let columns; +let rows; +let board; +let next; + +function setup() { + createCanvas(720, 400); + w = 20; + // कॉलम और पंक्तियों की गणना करें + columns = floor(width / w); + rows = floor(height / w); + // 2D सरणी बनाने का निराला तरीका JS है + board = new Array(columns); + for (let i = 0; i < columns; i++) { + board[i] = new Array(rows); + } + // कई 2D सरणियों का उपयोग करने जा रहे हैं और उन्हें स्वैप करें + 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); + } + } + +} + +// माउस दबाए जाने पर बोर्ड को रीसेट करें +function mousePressed() { + init(); +} + +// बेतरतीब ढंग से बोर्ड भरें +function init() { + for (let i = 0; i < columns; i++) { + for (let j = 0; j < rows; j++) { + // किनारों को 0s . के साथ पंक्तिबद्ध करना + if (i == 0 || j == 0 || i == columns-1 || j == rows-1) board[i][j] = 0; + // बाकी को बेतरतीब ढंग से भरना + else board[i][j] = floor(random(2)); + next[i][j] = 0; + } + } +} + +// नई पीढ़ी बनाने की प्रक्रिया +function generate() { + +// हमारे 2D सरणी में प्रत्येक स्थान के माध्यम से लूप करें और स्पॉट पड़ोसियों की जाँच करें + for (let x = 1; x < columns - 1; x++) { + for (let y = 1; y < rows - 1; y++) { + // सभी राज्यों को 3x3 आसपास के ग्रिड में जोड़ें + let neighbors = 0; + for (let i = -1; i <= 1; i++) { + for (let j = -1; j <= 1; j++) { + neighbors += board[x+i][y+j]; + } + } + + // वर्तमान सेल की स्थिति को घटाने के लिए एक छोटी सी चाल + // हमने इसे उपरोक्त लूप में जोड़ा है + neighbors -= board[x][y]; + // Rules of Life + if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0; // तनहाई + else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0; // अधिक आबादी वाला + else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1; //पुन: उत्पन्न करें + else next[x][y] = board[x][y]; // ठहराव + } + } + + // स्वैप करें! + let temp = board; + board = next; + next = temp; +} + diff --git a/dist/assets/examples/hi/09_Simulate/05_MultipleParticleSystems.js b/dist/assets/examples/hi/09_Simulate/05_MultipleParticleSystems.js new file mode 100644 index 0000000000..04456e7f3e --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/05_MultipleParticleSystems.js @@ -0,0 +1,138 @@ +/* + * @name मल्टीपल पार्टिकल सिस्टम + * @description माउस स्थान पर कणों का एक विस्फोट उत्पन्न करने के लिए माउस पर क्लिक करें।
प्रत्येक फट कण और क्रेज़ीपार्टिकल्स (कण का एक उपवर्ग) के साथ एक कण प्रणाली का एक उदाहरण है।
यहां वंशानुक्रम और बहुरूपता के उपयोग पर ध्यान दें।
+ * डैनियल शिफमैन द्वारा मूल। + */ +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); +} + +// एक साधारण कण वर्ग +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(); +}; + +// स्थिति को अद्यतन करने की विधि +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// प्रदर्शित करने की विधि +Particle.prototype.display = function () { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// क्या कण अभी भी उपयोगी है? +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 () { + // सिस्टम में या तो एक कण या क्रेजीपार्टिकल जोड़ें + 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); + } + } +}; + +// कण का एक उपवर्ग + +function CrazyParticle(origin) { + // सुनिश्चित करें कि पैरेंट कंस्ट्रक्टर को कॉल करें (फ़ंक्शन # कॉल का उपयोग करके) + // कि "यह" कॉल के दौरान सही ढंग से सेट है + Particle.call(this, origin); + + // हमारे जोड़े गए गुणों को प्रारंभ करें + this.theta = 0.0; +}; + +// एक क्रेजी.प्रोटोटाइप ऑब्जेक्ट बनाएं जो पार्टिकल.प्रोटोटाइप से विरासत में मिले। +// नोट: यहां एक सामान्य त्रुटि "नया कण ()" बनाने के लिए उपयोग करना है +// क्रेजी.प्रोटोटाइप। यह कई कारणों से गलत है, कम से कम +// कि हमारे पास "मूल" के लिए कण देने के लिए कुछ भी नहीं है +// बहस। पार्टिकल को कॉल करने का सही स्थान ऊपर है, जहां हम कॉल करते हैं +// यह पागल से। +CrazyParticle.prototype = Object.create(Particle.prototype); // नीचे दिए गए नोट देखें + +// क्रेजीपार्टिकल को संदर्भित करने के लिए "कन्स्ट्रक्टर" संपत्ति सेट करें +CrazyParticle.prototype.constructor = CrazyParticle; + +// ध्यान दें कि हमारे पास यहां रन () विधि नहीं है; यह कण से विरासत में मिला है + +// यह अद्यतन () विधि मूल वर्ग अद्यतन () विधि को ओवरराइड करती है +CrazyParticle.prototype.update=function() { + Particle.prototype.update.call(this); + // क्षैतिज वेग के आधार पर वृद्धि रोटेशन + this.theta += (this.velocity.x * this.velocity.mag()) / 10.0; +} + +// यह डिस्प्ले () मेथड पैरेंट क्लास डिस्प्ले () मेथड को ओवरराइड करता है +CrazyParticle.prototype.display=function() { + // एक नियमित कण की तरह ही दीर्घवृत्त को प्रस्तुत करें + Particle.prototype.display.call(this); + // फिर एक घूर्णन रेखा जोड़ें + push(); + translate(this.position.x, this.position.y); + rotate(this.theta); + stroke(255, this.lifespan); + line(0, 0, 25, 0); + pop(); +} diff --git a/dist/assets/examples/hi/09_Simulate/06_Spirograph.js b/dist/assets/examples/hi/09_Simulate/06_Spirograph.js new file mode 100644 index 0000000000..0401c344d4 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/06_Spirograph.js @@ -0,0 +1,73 @@ + +/* + * @name स्पाइरोग्राफ + * @description यह स्केच a . बनाने के लिए सरल परिवर्तनों का उपयोग करता है + * इंटरलॉकिंग सर्कल (साइन कहा जाता है) के साथ स्पाइरोग्राफ जैसा प्रभाव। + * ट्रेसिंग और अंतर्निहित ज्यामिति दिखाने के बीच स्विच करने के लिए स्पेसबार दबाएं।
+ * उदाहरण R द्वारा बनाया गया है। ल्यूक डुबोइस.
+ * http://en.wikipedia.org/wiki/Spirograph + */ +let NUMSINES = 20; // इनमें से कितनी चीजें हम एक साथ कर सकते हैं? +let sines = new Array(NUMSINES); // सभी मौजूदा कोणों को पकड़ने के लिए एक सरणी +let rad; // केंद्रीय साइन के लिए एक प्रारंभिक त्रिज्या मान +let i; // एक काउंटर चर + +// क्या हो रहा है इसका अंदाजा लगाने के लिए इनके साथ खेलें: +let fund = 0.005; // केंद्रीय साइन की गति +let ratio = 1; // गति के लिए कौन सा गुणक प्रत्येक अतिरिक्त ज्या है? +let alpha = 50; // ट्रेसिंग सिस्टम कितना अपारदर्शी है + +let trace = false; // क्या हम ट्रेस कर रहे हैं? + +function setup() { + createCanvas(710, 400); + + rad = height / 4; // केंद्रीय सर्कल के लिए त्रिज्या की गणना करें + background(204); // स्क्रीन साफ़ करें + + for (let i = 0; i + * उदाहरण R द्वारा बनाया गया है। ल्यूक डुबोइस.
+ * https://en.wikipedia.org/wiki/L-system + */ +// कछुआ सामान: +let x, y; // कछुए की वर्तमान स्थिति +let currentangle = 0; // कछुआ किस ओर इशारा कर रहा है +let step = 20; // प्रत्येक 'एफ' के साथ कछुआ कितना चलता है +let angle = 90; // कछुआ '-' या '+' से कितना मुड़ता है + +// लिंडेनमेयर स्टफ (एल-सिस्टम) +let thestring = 'A'; // "स्वयंसिद्ध" या स्ट्रिंग की शुरुआत +let numloops = 5; // पूर्व-गणना करने के लिए कितने पुनरावृत्तियों +let therules = []; // नियमों के लिए सरणी +therules[0] = ['A', '-BF+AFA+FB-']; // पहला नियम +therules[1] = ['B', '+AF-BFB-FA+']; // दूसरा नियम + +let whereinstring = 0; // एल-सिस्टम में हम कहां हैं? + +function setup() { + createCanvas(710, 400); + background(255); + stroke(0, 0, 0, 255); + + // निचले-बाएँ कोने पर x और y स्थिति शुरू करें + x = 0; + y = height-1; + + // एल-सिस्टम की गणना करें + for (let i = 0; i < numloops; i++) { + thestring = lindenmayer(thestring); + } +} + +function draw() { + + // स्ट्रिंग में वर्तमान वर्ण बनाएं: + drawIt(thestring[whereinstring]); + + // उस बिंदु को बढ़ाएं जहां हम स्ट्रिंग पढ़ रहे हैं। + // अंत में चारों ओर लपेटें। + whereinstring++; + if (whereinstring > thestring.length-1) whereinstring = 0; + +} + +// एल-सिस्टम की व्याख्या करें +function lindenmayer(s) { + let outputstring = ''; // एक खाली आउटपुट स्ट्रिंग शुरू करें + + // प्रतीक मिलान की तलाश में 'थेरुल्स' के माध्यम से पुनरावृति करें: + for (let i = 0; i < s.length; i++) { + let ismatch = 0; // डिफ़ॉल्ट रूप से, कोई मिलान नहीं + for (let j = 0; j < therules.length; j++) { + if (s[i] == therules[j][0]) { + outputstring += therules[j][1]; // प्रतिस्थापन लिखें + ismatch = 1; // हमारे पास एक मैच है, इसलिए प्रतीक पर कॉपी न करें + break; // इसके लिए () लूप से बाहर निकलें + } + } + // अगर कुछ भी मेल नहीं खाता है, तो बस प्रतीक को कॉपी करें। + if (ismatch == 0) outputstring+= s[i]; + } + + return outputstring; // संशोधित स्ट्रिंग भेजें +} + +// यह एक कस्टम फ़ंक्शन है जो टर्टल कमांड खींचता है +function drawIt(k) { + + if (k=='F') { // आगे बढ़ें + // स्टेप और करंट एंगल के आधार पर ध्रुवीय से कार्टेशियन: + let x1 = x + step*cos(radians(currentangle)); + let y1 = y + step*sin(radians(currentangle)); + line(x, y, x1, y1); // पुराने और नए को कनेक्ट करें + + // कछुए की स्थिति को अपडेट करें: + x = x1; + y = y1; + } else if (k == '+') { + currentangle += angle; // बांए मुड़िए + } else if (k == '-') { + currentangle -= angle; // दांए मुड़िए + } + + // मुझे कुछ यादृच्छिक रंग मान दें: + let r = random(128, 255); + let g = random(0, 192); + let b = random(0, 50); + let a = random(50, 100); + + // त्रिज्या के लिए एक गाऊसी (डी एंड डी) वितरण चुनें: + let radius = 0; + radius += random(0, 15); + radius += random(0, 15); + radius += random(0, 15); + radius = radius / 3; + + // सामान ड्रा करें: + fill(r, g, b, a); + ellipse(x, y, radius, radius); +} \ No newline at end of file diff --git a/dist/assets/examples/hi/09_Simulate/08_Spring.js b/dist/assets/examples/hi/09_Simulate/08_Spring.js new file mode 100644 index 0000000000..a88e27454a --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/08_Spring.js @@ -0,0 +1,92 @@ +/* + * @name वसंत + * @frame 710, 400 + * @description वसंत शुरू करने के लिए क्षैतिज पट्टी पर क्लिक करें, खींचें और छोड़ें। + */ +// शीर्ष बार के लिए स्प्रिंग ड्राइंग स्थिरांक +let springHeight = 32, + left, + right, + maxHeight = 200, + minHeight = 100, + over = false, + move = false; + +// स्प्रिंग सिमुलेशन स्थिरांक +let M = 0.8, // द्रव्यमान + K = 0.2, // वसंत निरंतर + D = 0.92, // भिगोना + R = 150; // स्थिति को विश्राम दें + +// स्प्रिंग सिमुलेशन चर +let ps = R, // पद + vs = 0.0, // वेग + as = 0, // त्वरण + f = 0; // बल + +function setup() { + createCanvas(710, 400); + rectMode(CORNERS); + noStroke(); + left = width / 2 - 100; + right = width / 2 + 100; +} + +function draw() { + background(102); + updateSpring(); + drawSpring(); +} + +function drawSpring() { + // ड्रा बेस + fill(0.2); + let baseWidth = 0.5 * ps + -8; + rect(width / 2 - baseWidth, ps + springHeight, width / 2 + baseWidth, height); + + // रंग सेट करें और शीर्ष पट्टी बनाएं + if (over || move) { + fill(255); + } else { + fill(204); + } + + rect(left, ps, right, ps + springHeight); +} + +function updateSpring() { + // वसंत की स्थिति को अपडेट करें + if ( !move ) { + f = -K * ( ps - R ); // f=-ky + as = f / M; // त्वरण सेट करें, f=ma == a=f/m + vs = D * (vs + as); // वेग सेट करें + ps = ps + vs; // अद्यतन स्थिति + } + + if (abs(vs) < 0.1) { + vs = 0.0; + } + + // परीक्षण करें कि क्या माउस शीर्ष बार पर है + if (mouseX > left && mouseX < right && mouseY > ps && mouseY < ps + springHeight) { + over = true; + } else { + over = false; + } + + // शीर्ष बार की स्थिति को सेट और विवश करें + if (move) { + ps = mouseY - springHeight / 2; + ps = constrain(ps, minHeight, maxHeight); + } +} + +function mousePressed() { + if (over) { + move = true; + } +} + +function mouseReleased() { + move = false; +} diff --git a/dist/assets/examples/hi/09_Simulate/09_Springs.js b/dist/assets/examples/hi/09_Simulate/09_Springs.js new file mode 100644 index 0000000000..94bbc8133b --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/09_Springs.js @@ -0,0 +1,147 @@ +/* + * @name स्प्रिंग्स + * @frame 710,400 + * @description माउस को किसी एक सर्कल के ऊपर ले जाएं और फिर से स्थिति में लाने के लिए क्लिक करें। + * जब आप माउस को छोड़ते हैं, तो यह वापस स्थिति में आ जाएगा। + * प्रत्येक मंडली का व्यवहार थोड़ा अलग होता है। + * (https://processing.org/examples/springs.html से पोर्ट किया गया) + */ +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(); + } +} + +// स्प्रिंग क्लास +function Spring (_x, _y, _s, _d, _m, _k_in, _others, _id) { +// स्क्रीन मान + // यह। एक्सपोस = _x; + // this.ypos = _y; + + this.x_pos = _x; + this.y_pos= _y; + + this.size = 20; + this.size = _s; + + this.over = false; + this.move = false; + + // स्प्रिंग सिमुलेशन स्थिरांक + this.mass = _m; // द्रव्यमान + this.k = 0.2; // वसंत निरंतर + this.k = _k_in; + this.damp = _d; // भिगोना + this.rest_posx = _x; // आराम की स्थिति X + this.rest_posy = _y; // आराम की स्थिति Y + + // स्प्रिंग सिमुलेशन चर + // फ्लोट पॉज़ = 20.0; // पद + this.velx = 0.0; // एक्स वेग + this.vely = 0.0; // वाई वेग + this.accel = 0; // त्वरण + this.force = 0; // बल + + 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; // त्वरण सेट करें, f=ma == a=f/m + this.vely = this.damp * (this.vely + this.accel); // वेग सेट करें + this.y_pos = this.y_pos + this.vely; // अद्यतन स्थिति + + + this.force = -this.k * (this.x_pos - this.rest_posx); // f=-ky + this.accel = this.force / this.mass; // त्वरण सेट करें, f=ma == a=f/m + this.velx = this.damp * (this.velx + this.accel); // वेग सेट करें + this.x_pos = this.x_pos + this.velx; // अद्यतन स्थिति + + + if ((this.overEvent() || this.move) && !(this.otherOver()) ) { + this.over = true; + } else { + this.over = false; + } + } + + // यह देखने के लिए परीक्षण करें कि क्या माउस इस वसंत के ऊपर है + 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; + } + } + + // सुनिश्चित करें कि कोई अन्य स्प्रिंग सक्रिय नहीं है + 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; + } +}; \ No newline at end of file diff --git a/dist/assets/examples/hi/09_Simulate/10_SoftBody.js b/dist/assets/examples/hi/09_Simulate/10_SoftBody.js new file mode 100644 index 0000000000..fb69999bdd --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/10_SoftBody.js @@ -0,0 +1,110 @@ +/* + * @name शीतल शरीर + * @description इरा ग्रीनबर्ग द्वारा मूल उदाहरण। + *

कर्ववर्टेक्स () और कर्वटाइटनेस () का उपयोग करके सॉफ्टबॉडी डायनेमिक्स सिमुलेशन। + */ +// केंद्र बिंदु +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; + +// कोने के नोड्स +let nodes = 5; + +// शून्य भरण सरणियाँ +let nodeStartX = []; +let nodeStartY = []; +let nodeX = []; +let nodeY = []; +let angle = []; +let frequency = []; + +// सॉफ्ट-बॉडी डायनामिक्स +let organicConstant = 1.0; + +function setup() { + createCanvas(710, 400); + + // विंडो में केंद्र का आकार + centerX = width / 2; + centerY = height / 2; + + // सरणियों को 0 . पर इनिशियलाइज़ करें + for (let i = 0; i < nodes; i++){ + nodeStartX[i] = 0; + nodeStartY[i] = 0; + nodeY[i] = 0; + nodeY[i] = 0; + angle[i] = 0; + } + + // कोने के नोड्स के लिए आवृत्तियों को प्रारंभ करें + for (let i = 0; i < nodes; i++){ + frequency[i] = random(5, 12); + } + + noStroke(); + frameRate(30); +} + +function draw() { + // फीका पृष्ठभूमि + fill(0, 100); + rect(0, 0, width, height); + drawShape(); + moveShape(); +} + +function drawShape() { + // नोड के शुरुआती स्थानों की गणना करें + 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; + } + + // बहुभुज बनाएं + 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() { + // केंद्र बिंदु ले जाएँ + deltaX = mouseX - centerX; + deltaY = mouseY - centerY; + + // स्प्रिंग इफेक्ट बनाएं + deltaX *= springing; + deltaY *= springing; + accelX += deltaX; + accelY += deltaY; + + // शिकारी के केंद्र को स्थानांतरित करें + centerX += accelX; + centerY += accelY; + + // स्प्रिंगिंग को धीमा करें + accelX *= damping; + accelY *= damping; + + // वक्र की जकड़न बदलें + organicConstant = 1 - ((abs(accelX) + abs(accelY)) * 0.1); + + // नोड्स ले जाएँ + 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]; + } +} diff --git a/dist/assets/examples/hi/09_Simulate/11_SmokeParticleSystem.js b/dist/assets/examples/hi/09_Simulate/11_SmokeParticleSystem.js new file mode 100644 index 0000000000..259275ac0b --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/11_SmokeParticleSystem.js @@ -0,0 +1,178 @@ +/* + * @name स्मोकपार्टिकल्स + * @description डैन शिफमैन के स्मोकपार्टिकल सिस्टम उदाहरण का एक पोर्ट मूल रूप से वर्णन करें + * प्रसंस्करण के लिए। धुएँ के रंग के कण बनाता है :p + */ + +// कण के लिए बनावट +let particle_texture = null; + +// हमारे कण प्रणाली को धारण करने वाला चर +let ps = null; + +function preload() { + particle_texture = loadImage("assets/particle_texture.png"); +} + +function setup() { + + // कैनवास का आकार निर्धारित करें + createCanvas(640, 360); + + // हमारे कण प्रणाली को इनिशियलाइज़ करें + 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(); + } + + // वायु शक्ति का प्रतिनिधित्व करने वाला एक तीर खींचें + drawVector(wind, createVector(width / 2, 50, 0), 500); +} + +/** + * यह फ़ंक्शन हमारी "हवा" की दिशा को दर्शाने वाला एक तीर खींचता है। + */ +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(); +} +//========= कण प्रणाली ========== + +/** + * एक बुनियादी कण प्रणाली वर्ग + * @param num कणों की संख्या + * @param v कण प्रणाली की उत्पत्ति + * @param img_ सिस्टम में प्रत्येक कण के लिए एक बनावट + * @constructor + */ +let ParticleSystem = function(num, v, img_) { + + this.particles = []; + this.origin = v.copy(); // यदि हम गलती से मूल को गलती से बदल देते हैं, तो हम वेक्टर मान की प्रतिलिपि बनाना सुनिश्चित करते हैं + this.img = img_ + for(let i = 0; i < num; ++i){ + this.particles.push(new Particle(this.origin, this.img)); + } +}; + +/** + * यह फ़ंक्शन पूरे कण प्रणाली को चलाता है। + */ +ParticleSystem.prototype.run = function() { + + // उस सरणी की कैश लंबाई जिसे हम एक चर में लूप करने जा रहे हैं + // आप समय-समय पर लूप के लिए .length देख सकते हैं लेकिन + // हम इसे यहां कैश करते हैं क्योंकि अन्यथा लूप के प्रत्येक पुनरावृत्ति के लिए लंबाई की फिर से गणना की जाती है + let len = this.particles.length; + + // लूप के माध्यम से और कणों को चलाएं + for (let i = len - 1; i >= 0; i--) { + let particle = this.particles[i]; + particle.run(); + + // यदि कण मर चुका है, तो हम इसे हटा देते हैं। + // जावास्क्रिप्ट सरणियों में "निकालें" फ़ंक्शन नहीं है, लेकिन "स्प्लिस" भी काम करता है। + // हम इसे शुरू करने के लिए एक सूचकांक खिलाते हैं, फिर उस बिंदु से कितनी संख्या को निकालना है। + if (particle.isDead()) { + this.particles.splice(i, 1); + } + } +} + +/** + * सिस्टम में वर्तमान में मौजूद सभी कणों में एक बल वेक्टर जोड़ने की विधि + * @param dir a p5.बल की दिशा का वर्णन करने वाला सदिश। + */ +ParticleSystem.prototype.applyForce = function(dir) { + let len = this.particles.length; + for(let i = 0; i < len; ++i){ + this.particles[i].applyForce(dir); + } +} + +/** + * सिस्टम के मूल में और साथ में सिस्टम में एक नया कण जोड़ता है + * मूल रूप से सेट बनावट। + */ +ParticleSystem.prototype.addParticle = function() { + this.particles.push(new Particle(this.origin, this.img)); +} + +//========= कण ========== +/** + * एक साधारण कण वर्ग, कण को एक छवि के रूप में प्रस्तुत करता है + */ +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_; +} + +// साथ ही एक कण को अपडेट और प्रदर्शित करें। +Particle.prototype.run = function() { + this.update(); + this.render(); +} + +/** + * एक कण प्रदर्शित करने के लिए एक समारोह + */ +Particle.prototype.render = function() { + imageMode(CENTER); + tint(255, this.lifespan); + image(this.texture, this.loc.x, this.loc.y); +} + +/** + * किसी कण पर बल सदिश लगाने की एक विधि। + */ +Particle.prototype.applyForce = function(f) { + this.acc.add(f); +} + +/** + * यह विधि यह देखने के लिए जाँच करती है कि क्या कण अपने जीवन काल के अंत तक पहुँच गया है, + * यदि यह है, तो सत्य लौटाएँ, अन्यथा असत्य लौटाएँ। + */ +Particle.prototype.isDead = function () { + if (this.lifespan <= 0.0) { + return true; + } else { + return false; + } +} + +/** + * यह विधि कण की स्थिति को अद्यतन करती है। + */ +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/dist/assets/examples/hi/09_Simulate/12_BrownianMotion.js b/dist/assets/examples/hi/09_Simulate/12_BrownianMotion.js new file mode 100644 index 0000000000..307b816bf5 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/12_BrownianMotion.js @@ -0,0 +1,45 @@ +/* + * @name ब्राउनियन मोशन + * @description एक सतत लाइन के रूप में यादृच्छिक गति को रिकॉर्ड करना। + * प्रसंस्करण उदाहरण पृष्ठ से मूल उदाहरण का पोर्ट। + */ +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); + + // सभी तत्वों को 1 स्थान पर बाईं ओर शिफ्ट करें + for ( let i = 1; i < num; i++ ) { + ax[i - 1] = ax[i]; + ay[i - 1] = ay[i]; + } + + // सरणी के अंत में एक नया मान डालें + ax[num - 1] += random(-range, range); + ay[num - 1] += random(-range, range); + + // स्क्रीन पर सभी बिंदुओं को रोकें + ax[num - 1] = constrain(ax[num - 1], 0, width); + ay[num - 1] = constrain(ay[num - 1], 0, height); + + // बिंदुओं को जोड़ने वाली एक रेखा खींचें + 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/dist/assets/examples/hi/09_Simulate/13_Chain.js b/dist/assets/examples/hi/09_Simulate/13_Chain.js new file mode 100644 index 0000000000..63cfc80984 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/13_Chain.js @@ -0,0 +1,55 @@ +/* + * @name चैन + * @description एक द्रव्यमान माउस की स्थिति से जुड़ा होता है और दूसरा दूसरे द्रव्यमान की स्थिति से जुड़ा होता है। वातावरण में गुरुत्वाकर्षण दोनों को नीचे खींचता है। + * प्रसंस्करण उदाहरण पृष्ठ से पोर्ट किया गया। + */ +let s1, s2; +let gravity = 9.0; +let mass = 2.0; + +function setup() { + createCanvas(720, 400); + fill(255, 126); + // इनपुट: x, y, द्रव्यमान, गुरुत्वाकर्षण + 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; // x- और y-निर्देशांक + this.y = ypos; + this.vx = 0; // x- और y-अक्ष वेग + 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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/hi/09_Simulate/14_SnowflakeParticleSystem.js b/dist/assets/examples/hi/09_Simulate/14_SnowflakeParticleSystem.js new file mode 100644 index 0000000000..192a7b72b0 --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/14_SnowflakeParticleSystem.js @@ -0,0 +1,63 @@ +/* + * @name स्नोफ्लेक्स + * @description पार्टिकल सिस्टम बर्फ के टुकड़े गिरने की गति का अनुकरण करता है। + * स्नोफ्लेक कणों को धारण करने के लिए वस्तुओं की एक सरणी का उपयोग करता है। + * आतिश भाटिया द्वारा योगदान दिया गया। + */ + +let snowflakes = []; // स्नोफ्लेक वस्तुओं को रखने के लिए सरणी + +function setup() { + createCanvas(400, 600); + fill(240); + noStroke(); +} + +function draw() { + background('brown'); + let t = frameCount / 60; // समय सुधारें + + // प्रत्येक फ्रेम में यादृच्छिक संख्या में स्नोफ्लेक्स बनाएं + for (let i = 0; i < random(5); i++) { + snowflakes.push(new snowflake()); // स्नोफ्लेक ऑब्जेक्ट संलग्न करें + } + + // लूप के लिए स्नोफ्लेक्स के माध्यम से लूप के लिए लूप + for (let flake of snowflakes) { + flake.update(t); // स्नोफ्लेक स्थिति अपडेट करें + flake.display(); // स्नोफ्लेक ड्रा करें + } +} + +// स्नोफ्लेक क्लास +function snowflake() { + // निर्देशांक आरंभ करें + this.posX = 0; + this.posY = random(-50, 0); + this.initialangle = random(0, 2 * PI); + this.size = random(2, 5); + + // स्नोफ्लेक सर्पिल की त्रिज्या + // चुना गया ताकि बर्फ के टुकड़े समान रूप से क्षेत्र में फैले हों + this.radius = sqrt(random(pow(width / 2, 2))); + + this.update = function(time) { + // x स्थिति एक सर्कल का अनुसरण करती है + let w = 0.6; // कोणीय गति + let angle = w * time + this.initialangle; + this.posX = width / 2 + this.radius * sin(angle); + + // अलग-अलग आकार के बर्फ के टुकड़े थोड़े अलग y गति से गिरते हैं + this.posY += pow(this.size, 0.5); + + // स्क्रीन के पिछले छोर पर बर्फ के टुकड़े को हटा दें + 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/dist/assets/examples/hi/09_Simulate/15_penrose_tiles.js b/dist/assets/examples/hi/09_Simulate/15_penrose_tiles.js new file mode 100644 index 0000000000..b911fea01a --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/15_penrose_tiles.js @@ -0,0 +1,125 @@ +/* + * @name पेनरोज़ टाइलें + * @frame 710,400 + * @description यह प्रोसेसिंग.org/examples से "पेनरोज़ टाइल" उदाहरण के डेविड ब्लिट्ज का एक पोर्ट है + */ + +let ds; + +function setup() { + createCanvas(710, 400); + ds = new PenroseLSystem(); + // कृपया, निम्न पंक्ति के साथ खेलें + ds.simulate(5); +} + +function draw() { + background(0); + ds.render(); +} + +function PenroseLSystem() { + this.steps = 0; + + // ये पेनरोज़ रोम्बस एल-सिस्टम के लिए स्वयंसिद्ध और नियम हैं + // एक संदर्भ अच्छा होगा, लेकिन मुझे एक अच्छा नहीं मिला + 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"; + + // कृपया निम्नलिखित दो पंक्तियों के साथ खेलें + this.startLength = 460.0; + this.theta = TWO_PI / 10.0; // 36 डिग्री, 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; + } + +// उत्पादन स्ट्रिंग का नया पुनरावृत्ति बनाने के लिए प्रतिस्थापन नियम लागू करें +PenroseLSystem.prototype.iterate = function() { + let newProduction = ""; + + for(let i=0; i < this.production.length; ++i) { + let step = this.production.charAt(i); + // यदि वर्तमान वर्ण 'W' है, तो वर्तमान वर्ण को बदलें + // संबंधित नियम के अनुसार + 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 { + // सभी 'एफ' वर्णों को छोड़ दें, अन्य को स्पर्श न करें + // वर्ण (यानी '+', '-', '[', ']' + if (step != 'F') { + newProduction = newProduction + step; + } + } + } + + this.drawLength = this.drawLength * 0.5; + this.generations++; + this.production = newProduction; +} + +// प्रोडक्शन स्ट्रिंग को टर्टल ग्राफिक में बदलें +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रिकर्सिव ट्री उदाहरण पर आधारित। + */ +let theta; + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(0); + frameRate(30); + stroke(255); + // आइए माउस की स्थिति के आधार पर 0 से 90 डिग्री का कोण चुनें + let a = (mouseX / width) * 90; + // इसे रेडियन में बदलें + theta = radians(a); + // स्क्रीन के नीचे से पेड़ शुरू करें + translate(width/2,height); + // 120 पिक्सल की एक लाइन बनाएं + line(0,0,0,-120); + // उस लाइन के अंत में जाएँ + translate(0,-120); + // रिकर्सिव ब्रांचिंग शुरू करें! + branch(120); + +} + +function branch(h) { + // प्रत्येक शाखा पिछले एक के आकार का 2/3 होगा + h *= 0.66; + + // सभी पुनरावर्ती कार्यों में बाहर निकलने की स्थिति होनी चाहिए !!!! + // यहाँ, हमारा है जब शाखा की लंबाई 2 पिक्सेल या उससे कम है + if (h > 2) { + push(); // परिवर्तन की वर्तमान स्थिति को बचाएं (अर्थात अब हम कहां हैं) + rotate(theta); // थीटा द्वारा घुमाएं + line(0, 0, 0, -h); // शाखा ड्रा करें + translate(0, -h); // शाखा के अंत में ले जाएँ + branch(h); // ठीक है, अब दो नई शाखाएँ बनाने के लिए खुद को बुलाएँ !! + pop(); // जब भी हम यहां वापस आते हैं, तो हम पिछली मैट्रिक्स स्थिति को पुनर्स्थापित करने के लिए "पॉप" करते हैं + + // एक ही बात दोहराएं, इस बार केवल "बाईं ओर" शाखा बंद करें! + push(); + rotate(-theta); + line(0, 0, 0, -h); + translate(0, -h); + branch(h); + pop(); + } +} diff --git a/dist/assets/examples/hi/09_Simulate/17_Mandelbrot.js b/dist/assets/examples/hi/09_Simulate/17_Mandelbrot.js new file mode 100644 index 0000000000..b775652b5e --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/17_Mandelbrot.js @@ -0,0 +1,86 @@ +/* + * @name मंडेलब्रॉट सेत + * @description मैंडलब्रॉट सेट का सरल प्रतिपादन। + * प्रोसेसिंग के लिए डेनियल शिफमैन के Mandelbrot उदाहरण पर आधारित। + */ + +function setup() { + createCanvas(710, 400); + pixelDensity(1); + noLoop(); +} + +function draw() { + background(0); + + // जटिल तल पर मूल्यों की एक श्रृंखला स्थापित करें + // एक अलग रेंज हमें फ्रैक्टल पर "ज़ूम" करने की अनुमति देगा + + // यह सब चौड़ाई से शुरू होता है, उच्च या निम्न मानों का प्रयास करें + const w = 4; + const h = (w * height) / width; + + // चौड़ाई और ऊंचाई के नकारात्मक आधे से शुरू करें + const xmin = -w/2; + const ymin = -h/2; + + // सुनिश्चित करें कि हम पिक्सल [] सरणी में लिख सकते हैं। + // केवल एक बार ऐसा करने की आवश्यकता है क्योंकि हम कोई अन्य ड्राइंग नहीं करते हैं। + loadPixels(); + + // जटिल विमान पर प्रत्येक बिंदु के लिए पुनरावृत्तियों की अधिकतम संख्या + const maxiterations = 100; + + // x xmin से xmax तक जाता है + const xmax = xmin + w; + // y ymin से ymax . तक जाता है + const ymax = ymin + h; + + // गणना करें कि हम प्रत्येक पिक्सेल के लिए x, y में वृद्धि करते हैं + const dx = (xmax - xmin) / (width); + const dy = (ymax - ymin) / (height); + + // प्रारंभ करें + let y = ymin; + for (let j = 0; j < height; j++) { + // एक्स शुरू करें + let x = xmin; + for (let i = 0; i < width; i++) { + + // अब हम परीक्षण करते हैं, जैसा कि हम z = z^2 + cm को पुनरावृत्त करते हैं, क्या z अनंत की ओर जाता है? + 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; + // हमारी सीमित दुनिया में अनंत सरल है, आइए इसे 16 . पर विचार करें + if (dist(aa, bb, 0, 0) > 16) { + break; // टूटना + } + n++; + } + + // हम प्रत्येक पिक्सेल को इस आधार पर रंगते हैं कि अनंत तक पहुंचने में कितना समय लगता है + // अगर हम वहां कभी नहीं पहुंचे, तो आइए काले रंग को चुनें + 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 { + // भगवान, अगर हम चाहते तो हम यहाँ फैंसी रंग बना सकते थे + pixels[pix + 0] = bright; + pixels[pix + 1] = bright; + pixels[pix + 2] = bright; + pixels[pix + 3] = 255; + } + x += dx; + } + y += dy; + } + updatePixels(); +} diff --git a/dist/assets/examples/hi/09_Simulate/18_Koch.js b/dist/assets/examples/hi/09_Simulate/18_Koch.js new file mode 100644 index 0000000000..a6dd65a99a --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/18_Koch.js @@ -0,0 +1,140 @@ +/* + * @name कोच कर्व + * @description एक साधारण फ्रैक्टल, कोच स्नोफ्लेक प्रस्तुत करता है। प्रत्येक पुनरावर्ती स्तर क्रम में तैयार किया गया है। + * डैनियल शिफमैन द्वारा + */ +let k; + +function setup() { + createCanvas(710, 400); + frameRate(1); // धीरे-धीरे चेतन करें + k = new KochFractal(); +} + +function draw() { + background(0); + // बर्फ के टुकड़े खींचता है! + k.render(); + // पुनरावृति + k.nextLevel(); + // आइए इसे 5 बार से अधिक न करें। . . + if (k.getCount() > 5) { + k.restart(); + } +} + +// भग्न में एक रेखा खंड का वर्णन करने के लिए एक वर्ग +// कोच एल्गोरिथ्म के अनुसार लाइन के साथ midp5.Vectors की गणना करने के तरीके शामिल हैं + +class KochLine { + constructor(a,b) { + // दो p5.Vectors, + // प्रारंभ "बाएं" p5 है। वेक्टर और + // अंत "सही 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(); + } + + // यह आसान है, रास्ते का सिर्फ 1/3 + kochB() { + let v = p5.Vector.sub(this.end, this.start); + v.div(3); + v.add(this.start); + return v; + } + + // अधिक जटिल, यह पता लगाने के लिए थोड़ा ट्रिगर का उपयोग करना होगा कि यह p5.Vector कहाँ है! + kochC() { + let a = this.start.copy(); // शुरुआत में शुरू करें + let v = p5.Vector.sub(this.end, this.start); + v.div(3); + a.add(v); // बिंदु बी पर ले जाएँ + v.rotate(-PI/3); // 60 डिग्री घुमाएँate + a.add(v); // बिंदु C . पर जाएँ + return a; + } + + // आसान, रास्ते का सिर्फ 2/3 + 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(); + } +} + +// स्नोफ्लेक पैटर्न में लाइन सेगमेंट की सूची को प्रबंधित करने के लिए एक वर्ग + +class KochFractal { + constructor() { + this.start = createVector(0,height-20); // एक p5. शुरुआत के लिए वेक्टर + this.end = createVector(width,height-20); // एक p5। अंत के लिए वेक्टर + this.lines = []; // सभी लाइनों का ट्रैक रखने के लिए एक सरणी + this.count = 0; + this.restart(); + } + + nextLevel() { + // प्रत्येक पंक्ति के लिए जो सरणी सूची में है + // एक नई सरणी सूची में 4 और लाइनें बनाएं + this.lines = this.iterate(this.lines); + this.count++; + } + + restart() { + this.count = 0; // रीसेट गिनती + this.lines = []; // सरणी सूची खाली करें + this.lines.push(new KochLine(this.start,this.end)); // प्रारंभिक पंक्ति जोड़ें (एक छोर p5.Vector से दूसरे तक) + } + + getCount() { + return this.count; + } + + // यह आसान है, बस सभी रेखाएँ खींचें + render() { + for(let i = 0; i < this.lines.length; i++) { + this.lines[i].display(); + } + } + + // यहां जादू पैदा होता है + // चरण 1: एक खाली सरणी सूची बनाएं + // चरण 2: वर्तमान में सरणी सूची में प्रत्येक पंक्ति के लिए + // - कोच एल्गोरिथम के आधार पर 4 लाइन सेगमेंट की गणना करें + // - सभी 4 लाइन सेगमेंट को नई सरणी सूची में जोड़ें + // चरण 3: नई सरणी सूची लौटाएं और यह संरचना के लिए रेखा खंडों की सूची बन जाती है + + // जैसा कि हम इसे बार-बार करते हैं, प्रत्येक पंक्ति 4 पंक्तियों में टूट जाती है, जो 4 पंक्तियों में टूट जाती है, और इसी तरह। . . + iterate(before) { + let now = []; // खाली सूची बनाएं + for(let i = 0; i < this.lines.length; i++) { + let l = this.lines[i]; + // 5 koch p5.Vectors की गणना करें (लाइन ऑब्जेक्ट द्वारा हमारे लिए किया गया) + let a = l.kochA(); + let b = l.kochB(); + let c = l.kochC(); + let d = l.kochD(); + let e = l.kochE(); + // सभी p5.Vectors के बीच लाइन सेगमेंट बनाएं और उन्हें जोड़ें + 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/dist/assets/examples/hi/09_Simulate/19_Bubblesort.js b/dist/assets/examples/hi/09_Simulate/19_Bubblesort.js new file mode 100644 index 0000000000..a3ce18d07a --- /dev/null +++ b/dist/assets/examples/hi/09_Simulate/19_Bubblesort.js @@ -0,0 +1,67 @@ +/* + * @name बबल सॉर्ट + * @description बेतरतीब ढंग से वितरित बार को क्रमबद्ध करता है + *ऊंचाई के अनुसार आरोही क्रम में + * पूरी छँटाई प्रक्रिया का अनुकरण करते हुए। + * द कोडिंग ट्रेन द्वारा कोडिंग चैलेंज से संदर्भ लिया। + */ + +let values = []; +let i = 0; +let j = 0; + +// सेटअप () फ़ंक्शन में बयान +// प्रोग्राम शुरू होने पर एक बार निष्पादित करें +// सरणी सेटअप () फ़ंक्शन में यादृच्छिक मानों से भरी हुई है। +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(); + } + } +} + +// सिम्युलेटसॉर्टिंग () फ़ंक्शन एनिमेट करने में मदद करता है +// पूरे बबल सॉर्ट एल्गोरिथ्म +// मानों का उपयोग करके आयतों को खींचकर +// सरणी में आयत की लंबाई के रूप में। +function simulateSorting(){ + for(let i = 0;i= 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'); +} + +// की दो ईंटें बनाना +// रंग सफेद और काला +let brick1 = new Brick("white",100); +let brick2 = new Brick("black",250); + +// +brick1.setSpeed(); +brick2.setSpeed(); + +function draw () { + background(0); + if(mouseIsPressed){ + background(50); + } + brick1.createBrick(); + brick1.moveBrick(); + if(!mouseIsPressed){ + createBars(); + } + brick2.createBrick(); + brick2.moveBrick(); +} + +// यह फ़ंक्शन काला बनाता है और +// स्क्रीन पर सफेद पट्टियां +function createBars() { + let len = 12; + for(let i = 0;i width) + this.xSpeed*=-1; + if(this.y < 0 || this.y > height) + this.ySpeed*=-1; + this.x+=this.xSpeed; + this.y+=this.ySpeed; + } + +// यह फ़ंक्शन कनेक्शन बनाता है (लाइनें) +// कणों के बीच जो एक निश्चित दूरी से कम दूरी पर हैं + joinParticles(paraticles) { + 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); + } + }); + } +} + +// कई कणों को जोड़ने के लिए एक सरणी +let particles = []; + +function setup() { + createCanvas(720, 400); + for(let i = 0;i= 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/dist/assets/examples/hi/10_Interaction/20_Follow1.js b/dist/assets/examples/hi/10_Interaction/20_Follow1.js new file mode 100644 index 0000000000..3cead9f911 --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/20_Follow1.js @@ -0,0 +1,37 @@ +/* + * @name फॉलो 1 + * @frame 710,400 + * @description एक रेखा खंड को कर्सर द्वारा धकेला और खींचा जाता है। + * कीथ पीटर्स के कोड के आधार पर। + */ +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/dist/assets/examples/hi/10_Interaction/21_Follow2.js b/dist/assets/examples/hi/10_Interaction/21_Follow2.js new file mode 100644 index 0000000000..8d14e12aeb --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/21_Follow2.js @@ -0,0 +1,39 @@ +/* + * @name फॉलो 2 + * @frame 710,400 + * @description दो खंडों वाली भुजा कर्सर की स्थिति का अनुसरण करती है। संबंधी + * खंडों के बीच के कोण की गणना atan2 () और स्थिति के साथ की जाती है + * sin() और cos() के साथ गणना की गई। कीथ पीटर्स के कोड के आधार पर। + */ +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/dist/assets/examples/hi/10_Interaction/22_Follow3.js b/dist/assets/examples/hi/10_Interaction/22_Follow3.js new file mode 100644 index 0000000000..f8f91dc665 --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/22_Follow3.js @@ -0,0 +1,47 @@ +/* + * @name फॉलो 3 + * @frame 710,400 + * @description एक खंडित रेखा माउस का अनुसरण करती है। से आपेक्षिक कोण + * अगले से प्रत्येक खंड की गणना atan2 () और की स्थिति के साथ की जाती है + * अगले की गणना sin() और cos() के साथ की जाती है। कीथ पीटर्स के कोड के आधार पर। + */ +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/dist/assets/examples/hi/10_Interaction/23_snake.js b/dist/assets/examples/hi/10_Interaction/23_snake.js new file mode 100644 index 0000000000..ddaa719564 --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/23_snake.js @@ -0,0 +1,172 @@ +/* + * @name सांप का खेल + * @description प्रसिद्ध सांप का खेल! रन पर क्लिक करने के बाद, कहीं भी क्लिक करें + * काले क्षेत्र के अंदर, और i j k और l का उपयोग करके सांप को नियंत्रित करें। मत जाने दो + *सांप खुद को या दीवार से टकराया!
+ * उदाहरण प्रशांत गुप्ता द्वारा बनाया गया + */ + +// सांप को छोटे-छोटे खंडों में विभाजित किया जाता है, जिन्हें प्रत्येक 'ड्रा' कॉल पर खींचा और संपादित किया जाता है +let numSegments = 10; +let direction = 'right'; + +const xStart = 0; // सांप के लिए x निर्देशांक शुरू करना +const yStart = 250; // सांप के लिए y समन्वय शुरू करना +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(); +} + +/* + साँप की दिशा के आधार पर खंडों को अद्यतन किया जाता है। + 0 से n-1 तक के सभी खंडों को 1 से n तक कॉपी किया जाता है, अर्थात खंड 0 + खंड 1 का मान प्राप्त करता है, खंड 1 को खंड 2 का मान मिलता है, और इसी तरह, + और इसके परिणामस्वरूप सांप की गति होती है। + + सांप जिस दिशा में जा रहा है, उसके आधार पर अंतिम खंड जोड़ा जाता है, + यदि यह बाएँ या दाएँ जा रहा है, तो अंतिम खंड का x निर्देशांक a . से बढ़ जाता है + इसके दूसरे से अंतिम खंड की तुलना में पूर्वनिर्धारित मान 'diff'। और अगर यह ऊपर जा रहा है + या नीचे, खंड का y निर्देशांक प्रभावित होता है। +*/ +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; + } +} + +/* + मैं हमेशा सांप के सिर की स्थिति की जांच करता हूं xCor[xCor.length - 1] और + yCor[yCor.length - 1] यह देखने के लिए कि क्या यह खेल की सीमाओं को छूता है + या अगर सांप खुद को मारता है। +*/ +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); + } +} + +/* + यदि सांप खुद को मारता है, तो इसका मतलब है कि सांप का सिर (x,y) समन्वय करता है + अपने स्वयं के खंड (x, y) निर्देशांक में से एक के समान होना चाहिए। +*/ +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; + } + } +} + +/* + जब भी सांप फल खाता है, मैं खंडों की संख्या बढ़ा देता हूं, + और सरणी की शुरुआत में फिर से पूंछ खंड डालें (मूल रूप से + मैं अंतिम खंड को फिर से पूंछ में जोड़ता हूं, जिससे पूंछ का विस्तार होता है) +*/ +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() { + /* + जटिल गणित तर्क इसलिए है क्योंकि मैं चाहता था कि बिंदु झूठ बोलें + १०० और चौड़ाई १०० के बीच में, और निकटतम तक पूर्णांकित किया जाए + संख्या १० से विभाज्य है, क्योंकि मैं साँप को १० के गुणकों में घुमाता हूँ। + */ + + 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/dist/assets/examples/hi/10_Interaction/24_Wavemaker.js b/dist/assets/examples/hi/10_Interaction/24_Wavemaker.js new file mode 100644 index 0000000000..2e1c847268 --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/24_Wavemaker.js @@ -0,0 +1,37 @@ +/* + * @name वेवमेकर + * @description यह दर्शाता है कि कैसे लहरें (जैसे पानी की लहरें) उभरती हैं + * जगह-जगह दोलन करने वाले कणों से। तरंग को निर्देशित करने के लिए अपने माउस को ले जाएं। + * डेव व्हाईट के Orbiters से प्रेरित आतिश भाटिया द्वारा योगदान दिया गया। + */ + +let t = 0; // समय चर + +function setup() { + createCanvas(600, 600); + noStroke(); + fill(40, 200, 40); +} + +function draw() { + background(10, 10); // पारभासी पृष्ठभूमि (ट्रेल्स बनाता है) + + // दीर्घवृत्त का x और y ग्रिड बनाएं + for (let x = 0; x <= width; x = x + 30) { + for (let y = 0; y <= height; y = y + 30) { + // प्रत्येक सर्कल का प्रारंभिक बिंदु माउस की स्थिति पर निर्भर करता है + const xAngle = map(mouseX, 0, width, -4 * PI, 4 * PI, true); + const yAngle = map(mouseY, 0, height, -4 * PI, 4 * PI, true); + // और कण के स्थान के आधार पर भी बदलता रहता है + const angle = xAngle * (x / width) + yAngle * (y / height); + + // प्रत्येक कण एक वृत्त में चलता है + const myX = x + 20 * cos(2 * PI * t + angle); + const myY = y + 20 * sin(2 * PI * t + angle); + + ellipse(myX, myY, 10); // कण खींचे + } + } + + t = t + 0.01; // समय सुधारें +} diff --git a/dist/assets/examples/hi/10_Interaction/25_reach1.js b/dist/assets/examples/hi/10_Interaction/25_reach1.js new file mode 100644 index 0000000000..6aac76c662 --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/25_reach1.js @@ -0,0 +1,57 @@ +/* + * @name रीच 1 + * @frame 710,400 + * @description हाथ की गणना करके माउस की स्थिति का अनुसरण करता है + * atan2 () के साथ कोण। कीथ पीटर्स के कोड के आधार पर। + */ +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/dist/assets/examples/hi/10_Interaction/26_reach2.js b/dist/assets/examples/hi/10_Interaction/26_reach2.js new file mode 100644 index 0000000000..b821b66c42 --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/26_reach2.js @@ -0,0 +1,65 @@ +/* + * @name रीच 2 + * @frame 710,400 + * @description हाथ की गणना करके माउस की स्थिति का अनुसरण करता है + * atan2 () के साथ कोण। कीथ पीटर्स के कोड के आधार पर। + */ +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; // बेस एक्स-कोऑर्डिनेट सेट करें + y[x.length - 1] = height; // आधार y- निर्देशांक सेट करें +} + +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/dist/assets/examples/hi/10_Interaction/27_reach3.js b/dist/assets/examples/hi/10_Interaction/27_reach3.js new file mode 100644 index 0000000000..d5b58c9b3c --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/27_reach3.js @@ -0,0 +1,81 @@ +/* + * @name पहुंच ३ + * @frame 710,400 + * @description हाथ की गणना करके गेंद की स्थिति का अनुसरण करता है + * atan2 () के साथ कोण। कीथ पीटर्स के कोड के आधार पर। + */ +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; // बेस एक्स-कोऑर्डिनेट सेट करें + y[x.length - 1] = height; // आधार y- निर्देशांक सेट करें +} + +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/dist/assets/examples/hi/10_Interaction/28_ArduinoSensor.js b/dist/assets/examples/hi/10_Interaction/28_ArduinoSensor.js new file mode 100644 index 0000000000..a9f42313ec --- /dev/null +++ b/dist/assets/examples/hi/10_Interaction/28_ArduinoSensor.js @@ -0,0 +1,37 @@ +/* + * @name Arduino सेंसर डेटा WebJack के माध्यम से + * @description WebJack एक Arduino (और अन्य स्रोतों) से डेटा पढ़ने का एक तरीका है + * ऑडियो का उपयोग करना - यह मूल रूप से आपके Arduino को एक ऑडियो मॉडेम में बदल देता है। + * + * https://github.com/publiclab/webjack + * + * नोट: WebJack और p5-webjack लाइब्रेरी को आपके index.html में निम्नानुसार जोड़ा जाना चाहिए: + *
<script src="https://webjack.io/dist/webjack.js"></script>
+ *
<script src="https://jywarren.github.io/p5-webjack/lib.js"></script>
+  *
+  * कार्य उदाहरण: https://editor.p5js.org/jywarren/sketches/rkztwSt8M
+  *
+  * परीक्षण ऑडियो: https://www.youtube.com/watch?v=GtJW1Dlt3cg
+  * इस स्केच को एक Arduino पर लोड करें:
+  * https://create.arduino.cc/editor/jywarren/023158d8-be51-4c78-99ff-36c63126b554/preview
+  * Arduino पिन 3 + ग्राउंड से ऑडियो आउटपुट करेगा। माइक्रोफ़ोन या ऑडियो केबल का उपयोग करें।
+  */
+
+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/dist/assets/examples/hi/10_Interaction/29_kaleidoscope.js b/dist/assets/examples/hi/10_Interaction/29_kaleidoscope.js
new file mode 100644
index 0000000000..700f15c810
--- /dev/null
+++ b/dist/assets/examples/hi/10_Interaction/29_kaleidoscope.js
@@ -0,0 +1,72 @@
+/*
+  * @name बहुरूपदर्शक
+  * @description एक बहुरूपदर्शक एक ऑप्टिकल उपकरण है जिसमें दो या दो से अधिक परावर्तक सतहें एक कोण में एक दूसरे की ओर झुकी होती हैं। यह उदाहरण एक बहुरूपदर्शक के व्यवहार को दोहराने का प्रयास करता है। समरूपता चर पर प्रतिबिंबों की संख्या निर्धारित करें और स्क्रीन पर चित्र बनाना शुरू करें। स्लाइडर की सहायता से ब्रश का आकार समायोजित करें। स्पष्ट स्क्रीन, जैसा कि यह कहती है, स्क्रीन को साफ़ करती है। सेव बटन आपके द्वारा बनाई गई कला की एक .jpg फ़ाइल डाउनलोड करेगा।
+  */
+// प्रतिबिंबों की संख्या के अनुरूप समरूपता। विभिन्न संख्या में परावर्तनों के लिए संख्या बदलें
+let symmetry = 6;   
+
+let angle = 360 / symmetry;
+let saveButton, clearButton, mouseButton, keyboardButton;
+let slider;
+
+function setup() { 
+  createCanvas(710, 710);
+  angleMode(DEGREES);
+  background(127);
+
+  // फाइल के लिए सेव बटन बनाना
+  saveButton = createButton('save');
+  saveButton.mousePressed(saveFile);
+
+  // स्पष्ट स्क्रीन बटन बनाना
+  clearButton = createButton('clear');
+  clearButton.mousePressed(clearScreen);
+
+  // पूर्ण स्क्रीन के लिए बटन बनाना
+  fullscreenButton = createButton('Full Screen');
+  fullscreenButton.mousePressed(screenFull);
+
+  // ब्रश की मोटाई के लिए स्लाइडर सेट करना
+  brushSizeSlider = createButton('Brush Size Slider');
+  sizeSlider = createSlider(1, 32, 4, 0.1);
+}
+
+// फ़ाइल फ़ंक्शन सहेजें
+function saveFile() {
+  save('design.jpg');
+}
+
+// साफ़ स्क्रीन फ़ंक्शन
+function clearScreen() {
+  background(127);
+}
+
+// फुल स्क्रीन फंक्शन
+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/dist/assets/examples/hi/11_Objects/01_Objects.js b/dist/assets/examples/hi/11_Objects/01_Objects.js
new file mode 100644
index 0000000000..bed1f8973e
--- /dev/null
+++ b/dist/assets/examples/hi/11_Objects/01_Objects.js
@@ -0,0 +1,39 @@
+/*
+  * @name वस्तु
+  * @description एक जिटर क्लास बनाएं, किसी ऑब्जेक्ट को इंस्टेंट करें,
+  * और इसे स्क्रीन के चारों ओर ले जाएँ। के साथ आरंभ करने से अनुकूलित
+  * केसी रियास और बेन फ्राई द्वारा प्रसंस्करण।
+  */
+
+let bug; // ऑब्जेक्ट घोषित करें
+
+function setup() {
+  createCanvas(710, 400);
+  // ऑब्जेक्ट बनाएं
+  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/dist/assets/examples/hi/11_Objects/02_Multiple_Objects.js b/dist/assets/examples/hi/11_Objects/02_Multiple_Objects.js
new file mode 100644
index 0000000000..0f2e561ca3
--- /dev/null
+++ b/dist/assets/examples/hi/11_Objects/02_Multiple_Objects.js
@@ -0,0 +1,50 @@
+/*
+  * @name वस्तुओं का नाम दें
+  * @description एक जिटर क्लास बनाएं, कई ऑब्जेक्ट्स को इंस्टेंट करें,
+  * और इसे स्क्रीन के चारों ओर ले जाएँ।
+  */
+
+let bug1; // वस्तुओं की घोषणा करें
+let bug2;
+let bug3;
+let bug4;
+
+function setup() {
+  createCanvas(710, 400);
+  // ऑब्जेक्ट बनाएं
+  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();
+}
+
+// जिटर क्लास
+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/dist/assets/examples/hi/11_Objects/03_Objects_Array.js b/dist/assets/examples/hi/11_Objects/03_Objects_Array.js
new file mode 100644
index 0000000000..92a979d22e
--- /dev/null
+++ b/dist/assets/examples/hi/11_Objects/03_Objects_Array.js
@@ -0,0 +1,42 @@
+/*
+  * @name वस्तुओं की सरणी
+  * @description एक जिटर क्लास बनाएं, वस्तुओं की एक सरणी को इंस्टेंट करें
+  * और उन्हें स्क्रीन के चारों ओर ले जाएँ।
+  */
+
+let bugs = []; // जिटर ऑब्जेक्ट्स की सरणी
+
+function setup() {
+  createCanvas(710, 400);
+  // ऑब्जेक्ट बनाएं
+  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();
+  }
+}
+
+// जिटर क्लास
+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/dist/assets/examples/hi/11_Objects/03_Objects_Optional_Arguments.js b/dist/assets/examples/hi/11_Objects/03_Objects_Optional_Arguments.js
new file mode 100644
index 0000000000..79a2de8448
--- /dev/null
+++ b/dist/assets/examples/hi/11_Objects/03_Objects_Optional_Arguments.js
@@ -0,0 +1,65 @@
+/*
+  * @name वस्तु 2
+  * @description उदाहरण के लिए hbarragan द्वारा पोर्ट किया गया। कर्सर को इसके पार ले जाएँ
+  * छवि ज्यामिति की गति और स्थिति को बदलने के लिए। कक्षा MRect
+  * लाइनों के समूह को परिभाषित करता है।
+  */
+
+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; // सिंगल बार चौड़ाई
+    this.xpos = ixp; // रेक्ट एक्सपोजिशन
+    this.h = ih; // रेक्ट ऊंचाई
+    this.ypos = iyp; // रेक्ट योपोजिशन
+    this.d = id; // सिंगल बार दूरी
+    this.t = it; // बार की संख्या
+  }
+
+  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/dist/assets/examples/hi/11_Objects/04_Inheritance.js b/dist/assets/examples/hi/11_Objects/04_Inheritance.js
new file mode 100644
index 0000000000..9fddbcd0e9
--- /dev/null
+++ b/dist/assets/examples/hi/11_Objects/04_Inheritance.js
@@ -0,0 +1,71 @@
+/*  @name वंशानुक्रम
+  * @description एक वर्ग को दूसरे वर्ग का उपयोग करके परिभाषित किया जा सकता है a
+  * नींव। वस्तु-उन्मुख प्रोग्रामिंग शब्दावली में, एक वर्ग कर सकता है
+  * फ़ील्ड और विधियों को दूसरे से प्राप्त करें। एक वस्तु जो विरासत में मिलती है
+  * दूसरे को उपवर्ग कहा जाता है, और जिस वस्तु से इसे विरासत में मिला है उसे कहा जाता है
+  * एक सुपरक्लास। एक उपवर्ग सुपरक्लास का विस्तार करता है।
+  */
+let spots, arm;
+
+function setup() {
+  createCanvas(640, 360);
+  arm = new SpinArm(width/2, height/2, 0.01);
+  spots = new SpinSpots(width/2, height/2, -0.02, 90.0);
+}
+
+function draw() {
+  background(204);
+  arm.update();
+  arm.display();
+  spots.update();
+  spots.display();
+}
+
+class SpinArm {
+  constructor(x, y, s) {
+    this.x = x;
+    this.y = y;
+    this.speed = s;
+    this.angle = 0.0;
+  }
+
+  update() {
+    this.angle += this.speed;
+  }
+
+  display() {
+    strokeWeight(1);
+    stroke(0);
+    push();
+    translate(this.x, this.y);
+    this.angle += this.speed;
+    rotate(this.angle);
+    line(0, 0, 165, 0);
+    pop();
+  }
+}
+
+class SpinSpots {
+  constructor(x, y, s, d) {
+    this.x = x;
+    this.y = y;
+    this.speed = s;
+    this.dim = d;
+    this.angle = 0.0;
+  }
+
+  update() {
+    this.angle += this.speed;
+  }
+
+  display() {
+    noStroke();
+    push();
+    translate(this.x, this.y);
+    this.angle += this.speed;
+    rotate(this.angle);
+    ellipse(-this.dim/2, 0, this.dim, this.dim);
+    ellipse(this.dim/2, 0, this.dim, this.dim);
+    pop();
+  }
+}
diff --git a/dist/assets/examples/hi/11_Objects/05_Composite_Objects.js b/dist/assets/examples/hi/11_Objects/05_Composite_Objects.js
new file mode 100644
index 0000000000..f13f7df52f
--- /dev/null
+++ b/dist/assets/examples/hi/11_Objects/05_Composite_Objects.js
@@ -0,0 +1,99 @@
+/*  @name समग्र वस्तु
+  * @description एक ऑब्जेक्ट में कई अन्य ऑब्जेक्ट शामिल हो सकते हैं।
+  * इस तरह की मिश्रित वस्तुओं का निर्माण सिद्धांतों का उपयोग करने का एक अच्छा तरीका है
+  * प्रतिरूपकता और एक कार्यक्रम के भीतर अमूर्तता के उच्च स्तर का निर्माण।
+  */
+let er1, er2;
+
+function setup() {
+  createCanvas(640, 360);
+  er1 = new EggRing(width*0.45, height*0.5, 0.1, 120);
+  er2 = new EggRing(width*0.65, height*0.8, 0.05, 180);
+}
+
+function draw() {
+  background(0);
+  er1.transmit();
+  er2.transmit();
+}
+
+class Egg {
+  constructor(xpos, ypos, t, s) {
+    this.x = xpos;
+    this.y = ypos;
+    this.tilt = t;
+    this.scalar = s / 100.0;
+    this.angle = 0.0;
+  }
+
+  wobble() {
+    this.tilt = cos(this.angle) / 8;
+    this.angle += 0.1;
+  }
+
+  display() {
+    noStroke();
+    fill(255);
+    push();
+    translate(this.x, this.y);
+    rotate(this.tilt);
+    scale(this.scalar);
+    beginShape();
+    vertex(0, -100);
+    bezierVertex(25, -100, 40, -65, 40, -40);
+    bezierVertex(40, -15, 25, 0, 0, 0);
+    bezierVertex(-25, 0, -40, -15, -40, -40);
+    bezierVertex(-40, -65, -25, -100, 0, -100);
+    endShape();
+    pop();
+  }
+}
+
+class Ring {
+  start(xpos, ypos) {
+    this.x = xpos;
+    this.y = ypos;
+    this.on = true;
+    this.diameter = 1;
+  }
+
+  grow() {
+    if (this.on == true) {
+      this.diameter += 0.5;
+      if (this.diameter > width*2) {
+        this.diameter = 0.0;
+      }
+    }
+  }
+
+  display() {
+    if (this.on == true) {
+      noFill();
+      strokeWeight(4);
+      stroke(155, 153);
+      ellipse(this.x, this.y, this.diameter, this.diameter);
+    }
+  }
+}
+
+class EggRing {
+  constructor(x, y, t, sp) {
+    this.x = x;
+    this.y = y;
+    this.t = t;
+    this.sp = sp;
+    this.circle = new Ring();
+    this.ovoid = new Egg(this.x, this.y, this.t, this.sp);
+    this.circle.start(this.x, this.y - this.sp/2);
+  }
+
+  transmit() {
+    this.ovoid.wobble();
+    this.ovoid.display();
+    this.circle.grow();
+    this.circle.display();
+    if (circle.on == false) {
+      circle.on = true;
+    }
+  }
+}
diff --git a/dist/assets/examples/hi/12_Lights/02_Directional.js b/dist/assets/examples/hi/12_Lights/02_Directional.js
new file mode 100644
index 0000000000..d3c6242edc
--- /dev/null
+++ b/dist/assets/examples/hi/12_Lights/02_Directional.js
@@ -0,0 +1,27 @@
+/*
+  * @name दिशात्मक
+  * @frame 710,400
+  * @description प्रकाश की दिशा बदलने के लिए माउस ले जाएँ।
+  * दिशात्मक प्रकाश एक दिशा से आता है और हिट करने पर मजबूत होता है
+  * सतह वर्गाकार और कमजोर अगर यह एक कोमल कोण से टकराती है। मारने के बाद
+  * सतह, एक दिशात्मक प्रकाश सभी दिशाओं में बिखरता है।
+  */
+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/dist/assets/examples/hi/12_Lights/05_Mixture.js b/dist/assets/examples/hi/12_Lights/05_Mixture.js
new file mode 100644
index 0000000000..2b99d66f1f
--- /dev/null
+++ b/dist/assets/examples/hi/12_Lights/05_Mixture.js
@@ -0,0 +1,26 @@
+/*
+  * @name मिश्रण
+  * @frame 710,400 (वैकल्पिक)
+  * @description तीन अलग-अलग प्रकार की रोशनी वाला एक बॉक्स प्रदर्शित करें।
+  */
+function setup() {
+  createCanvas(710, 400, WEBGL);
+  noStroke();
+}
+
+function draw() {
+  background(0);
+
+  // दाईं ओर नारंगी बिंदु प्रकाश
+  pointLight(150, 100, 0, 500, 0, 200);
+
+  // बाईं ओर से नीली दिशात्मक रोशनी
+  directionalLight(0, 102, 255, -1, 0, 0);
+
+  // सामने से पीला स्पॉटलाइट
+  pointLight(255, 255, 109, 0, 0, 300);
+
+  rotateY(map(mouseX, 0, width, 0, PI));
+  rotateX(map(mouseY, 0, height, 0, PI));
+  box(200);
+}
diff --git a/dist/assets/examples/hi/13_Motion/01_non_orthogonal_reflection.js b/dist/assets/examples/hi/13_Motion/01_non_orthogonal_reflection.js
new file mode 100644
index 0000000000..ac8f5cfc29
--- /dev/null
+++ b/dist/assets/examples/hi/13_Motion/01_non_orthogonal_reflection.js
@@ -0,0 +1,110 @@
+/*
+  * @name नॉन ऑर्थोगोनल रिफ्लेक्शन
+  * @frame 710,400 (वैकल्पिक)
+  * @description यह प्रोसेसिंग.org/examples से "प्रतिबिंब 1" उदाहरण के डेविड ब्लिट्ज का एक पोर्ट है
+  */
+
+// फर्श के बाएं हाथ की स्थिति
+let base1;
+
+// फर्श के दाहिने हाथ की स्थिति
+let base2;
+// फर्श की लंबाई
+// बेसलेंथ दें;
+
+// चलती गेंद से संबंधित चर
+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();
+
+   // स्क्रीन के मध्य शीर्ष पर अंडाकार प्रारंभ करें
+  position = createVector(width / 2, 0);
+
+  // प्रारंभिक यादृच्छिक वेग की गणना करें
+  velocity = p5.Vector.random2D();
+  velocity.mult(speed);
+}
+
+function draw() {
+  // ड्रा बैकग्राउंड
+  fill(0, 12);
+  noStroke();
+  rect(0, 0, width, height);
+
+  // ड्रा बेस
+  fill(200);
+  quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height);
+
+  // बेस टॉप नॉर्मल की गणना करें
+  let baseDelta = p5.Vector.sub(base2, base1);
+  baseDelta.normalize();
+  let normal = createVector(-baseDelta.y, baseDelta.x);
+  let intercept = p5.Vector.dot(base1, normal);
+
+  // दीर्घवृत्त खींचें
+  noStroke();
+  fill(255);
+  ellipse(position.x, position.y, r * 2, r * 2);
+
+  // दीर्घवृत्त ले जाएँ
+  position.add(velocity);
+
+  // सामान्यीकृत घटना वेक्टर
+  incidence = p5.Vector.mult(velocity, -1);
+  incidence.normalize();
+
+  // बेस के साथ टकराव का पता लगाएं और संभालें
+  if (p5.Vector.dot(normal, position) > intercept) {
+    // घटना वेक्टर और बेस टॉप के डॉट उत्पाद की गणना करें
+    let dot = incidence.dot(normal);
+
+    // प्रतिबिंब वेक्टर की गणना करें
+    // दिशा वेक्टर को प्रतिबिंब वेक्टर असाइन करें
+    velocity.set(
+      2 * normal.x * dot - incidence.x,
+      2 * normal.y * dot - incidence.y,
+      0
+    );
+    velocity.mult(speed);
+
+    // टकराव बिंदु पर आधार शीर्ष सामान्य बनाएं
+    stroke(255, 128, 0);
+    line(
+      position.x,
+      position.y,
+      position.x - normal.x * 100,
+      position.y - normal.y * 100
+    );
+  }
+  //}
+
+  // सीमा टकराव का पता लगाएं
+  // सही
+  if (position.x > width - r) {
+    position.x = width - r;
+    velocity.x *= -1;
+  }
+  // बाएं
+  if (position.x < r) {
+    position.x = r;
+    velocity.x *= -1;
+  }
+  // ऊपर
+  if (position.y < r) {
+    position.y = r;
+    velocity.y *= -1;
+
+    // बेस टॉप को रैंडमाइज करें
+    base1.y = random(height - 100, height);
+    base2.y = random(height - 100, height);
+  }
+}
diff --git a/dist/assets/examples/hi/13_Motion/02_Linear_Motion.js b/dist/assets/examples/hi/13_Motion/02_Linear_Motion.js
new file mode 100644
index 0000000000..bd57d50460
--- /dev/null
+++ b/dist/assets/examples/hi/13_Motion/02_Linear_Motion.js
@@ -0,0 +1,24 @@
+/*
+  * @name रैखिक
+  * @frame 720,400
+  * @description मूविंग लाइन बनाने के लिए वेरिएबल को बदलना।
+  * जब रेखा खिड़की के किनारे से हटती है,
+  * वेरिएबल को 0 पर सेट किया जाता है, जो लाइन को स्क्रीन के निचले हिस्से में वापस रखता है।
+  */
+
+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/dist/assets/examples/hi/13_Motion/03_Bounce.js b/dist/assets/examples/hi/13_Motion/03_Bounce.js
new file mode 100644
index 0000000000..7b7f678f88
--- /dev/null
+++ b/dist/assets/examples/hi/13_Motion/03_Bounce.js
@@ -0,0 +1,44 @@
+/*
+  * @name उछाल
+  * @frame 720,400
+  * @description जब आकृति खिड़की के किनारे से टकराती है, तो वह अपनी दिशा उलट देती है।
+  */
+
+let rad = 60; // आकार की चौड़ाई
+let xpos, ypos; // आकार की प्रारंभिक स्थिति
+
+let xspeed = 2.8; // आकार की गति
+let yspeed = 2.2; // आकार की गति
+
+let xdirection = 1; // बायें या दायें
+let ydirection = 1; // ऊपर से नीचे
+
+function setup() {
+  createCanvas(720, 400);
+  noStroke();
+  frameRate(30);
+  ellipseMode(RADIUS);
+  // आकृति की प्रारंभिक स्थिति निर्धारित करें
+  xpos = width / 2;
+  ypos = height / 2;
+}
+
+function draw() {
+  background(102);
+
+  // आकृति की स्थिति को अपडेट करें
+  xpos = xpos + xspeed * xdirection;
+  ypos = ypos + yspeed * ydirection;
+
+   // यह देखने के लिए परीक्षण करें कि क्या आकार स्क्रीन की सीमाओं से अधिक है
+   // यदि ऐसा होता है, तो -1 . से गुणा करके इसकी दिशा उलट दें
+  if (xpos > width - rad || xpos < rad) {
+    xdirection *= -1;
+  }
+  if (ypos > height - rad || ypos < rad) {
+    ydirection *= -1;
+  }
+
+  // आकृति बनाएं
+  ellipse(xpos, ypos, rad, rad);
+}
diff --git a/dist/assets/examples/hi/13_Motion/04_Bouncy_Bubbles.js b/dist/assets/examples/hi/13_Motion/04_Bouncy_Bubbles.js
new file mode 100644
index 0000000000..6fa76833fc
--- /dev/null
+++ b/dist/assets/examples/hi/13_Motion/04_Bouncy_Bubbles.js
@@ -0,0 +1,95 @@
+/*
+  * @name उछाल वाले बुलबुले
+  * @frame 720,400
+  * @description कीथ पीटर्स के कोड पर आधारित विवरण। एकाधिक-वस्तु टकराव ..
+  */
+
+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++) {
+      // कंसोल.लॉग (अन्य [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;
+       // कंसोल.लॉग (दूरी);
+       // कंसोल.लॉग (मिनडिस्ट);
+      if (distance < minDist) {
+        // कंसोल.लॉग ("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/dist/assets/examples/hi/13_Motion/05_Morph.js b/dist/assets/examples/hi/13_Motion/05_Morph.js
new file mode 100644
index 0000000000..cca26800e3
--- /dev/null
+++ b/dist/assets/examples/hi/13_Motion/05_Morph.js
@@ -0,0 +1,93 @@
+/*
+  * @name मॉर्फ
+  * @frame 720,400
+  * @description शीर्षों को एक से दूसरे में प्रक्षेपित करके एक आकृति को दूसरी आकृति में बदलना।
+  */
+
+// दो ऐरेलिस्ट दो आकृतियों के लिए कोने को स्टोर करने के लिए
+// यह उदाहरण मानता है कि प्रत्येक आकृति में समान होगा
+// कोने की संख्या, यानी प्रत्येक ArrayList का आकार समान होगा
+let circle = [];
+let square = [];
+
+// एक तीसरे सेट के लिए एक ऐरेलिस्ट, जिसे हम चित्रित करेंगे
+// खिड़की में
+let morph = [];
+
+// यह बूलियन चर नियंत्रित करेगा यदि हम किसी वृत्त या वर्ग में रूपांतरित कर रहे हैं
+let state = false;
+
+function setup() {
+  createCanvas(720, 400);
+
+// केंद्र से इंगित करने वाले वैक्टर का उपयोग करके एक सर्कल बनाएं
+  for (let angle = 0; angle < 360; angle += 9) {
+    // ध्यान दें कि मिलान करने के लिए हम 0 से शुरू नहीं कर रहे हैं
+     // एक सर्कल का पथ।
+    let v = p5.Vector.fromAngle(radians(angle - 135));
+    v.mult(100);
+    circle.push(v);
+    // जब हम इस पर होते हैं तो खाली PVectors के साथ morph ArrayList को भरते हैं
+    morph.push(createVector());
+  }
+
+   // एक वर्ग सीधी रेखाओं के साथ कोने का एक गुच्छा है
+   // वर्ग के ऊपर
+  for (let x = -50; x < 50; x += 10) {
+    square.push(createVector(x, -50));
+  }
+  // दाईं ओर
+  for (let y = -50; y < 50; y += 10) {
+    square.push(createVector(50, y));
+  }
+  // तल
+  for (let x = 50; x > -50; x -= 10) {
+    square.push(createVector(x, 50));
+  }
+  // बाईं तरफ
+  for (let y = 50; y > -50; y -= 10) {
+    square.push(createVector(-50, y));
+  }
+}
+
+function draw() {
+  background(51);
+
+  // हम रखेंगे कि उनके लक्ष्य से कोने कितनी दूर हैं
+  let totalDistance = 0;
+
+  // प्रत्येक शीर्ष को देखें
+  for (let i = 0; i < circle.length; i++) {
+    let v1;
+    // क्या हम वृत्त या वर्ग की ओर झुक रहे हैं?
+    if (state) {
+      v1 = circle[i];
+    } else {
+      v1 = square[i];
+    }
+    // वह शीर्ष प्राप्त करें जिसे हम खींचेंगे
+    let v2 = morph[i];
+    // लक्ष्य के लिए Lerp
+    v2.lerp(v1, 0.1);
+    // जांचें कि हम लक्ष्य से कितनी दूर हैं
+    totalDistance += p5.Vector.dist(v1, v2);
+  }
+
+  // यदि सभी कोने करीब हैं, तो आकार बदलें
+  if (totalDistance < 0.1) {
+    state = !state;
+  }
+
+  // केंद्र के सापेक्ष ड्रा करें
+  translate(width / 2, height / 2);
+  strokeWeight(4);
+  // एक बहुभुज बनाएं जो सभी शीर्षों को बनाता है
+  beginShape();
+  noFill();
+  stroke(255);
+
+  morph.forEach(v => {
+    vertex(v.x, v.y);
+  });
+  endShape(CLOSE);
+}
diff --git a/dist/assets/examples/hi/13_Motion/06_Moving_On_Curves.js b/dist/assets/examples/hi/13_Motion/06_Moving_On_Curves.js
new file mode 100644
index 0000000000..8d8c22bfd4
--- /dev/null
+++ b/dist/assets/examples/hi/13_Motion/06_Moving_On_Curves.js
@@ -0,0 +1,47 @@
+/*
+  * @name मूविंग ऑन कर्व्स
+  * @frame 720,400
+  * @description इस उदाहरण में, वृत्त वक्र y = x^4 के अनुदिश चलते हैं।
+  * माउस को नई स्थिति में ले जाने के लिए उस पर क्लिक करें।
+  */
+
+let beginX = 20.0; // वर्तमान x-निर्देशांक
+let beginY = 10.0; // प्रारंभिक y-निर्देशांक
+let endX = 570.0; // वर्तमान x-निर्देशांक
+let endY = 320.0; // अंतिम y-निर्देशांक
+let distX; // एक्स-अक्ष दूरी को स्थानांतरित करने के लिए
+let distY; // वाई-अक्ष दूरी को स्थानांतरित करने के लिए
+let exponent = 4; // वक्र निर्धारित करता है
+let x = 0.0; // वर्तमान x-निर्देशांक
+let y = 0.0; // वर्तमान y-निर्देशांक
+let step = 0.01; // पथ के साथ प्रत्येक चरण का आकार
+let pct = 0.0; // यात्रा का प्रतिशत (0.0 से 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/dist/assets/examples/hi/15_Instance_Mode/01_Instantiating.js b/dist/assets/examples/hi/15_Instance_Mode/01_Instantiating.js
new file mode 100644
index 0000000000..1b779c4742
--- /dev/null
+++ b/dist/assets/examples/hi/15_Instance_Mode/01_Instantiating.js
@@ -0,0 +1,35 @@
+/*
+  * @name इंस्टेंटेशन
+  * @description एक p5 इंस्टेंस बनाएं, जो सभी वेरिएबल को बनाए रखता है
+  * आपके पेज के वैश्विक दायरे से बाहर।
+  */
+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/dist/assets/examples/hi/15_Instance_Mode/02_Instance_Container.js b/dist/assets/examples/hi/15_Instance_Mode/02_Instance_Container.js
new file mode 100644
index 0000000000..a20622ef84
--- /dev/null
+++ b/dist/assets/examples/hi/15_Instance_Mode/02_Instance_Container.js
@@ -0,0 +1,94 @@
+/*
+  * @norender
+  * @name इंस्टेंस कंटेनर
+  * @description वैकल्पिक रूप से, आप कैनवास के लिए एक डिफ़ॉल्ट कंटेनर निर्दिष्ट कर सकते हैं
+  * और किसी अन्य तत्व को दूसरे तर्क के साथ जोड़ने के लिए। आप दे सकते हैं
+  * आपके html में किसी तत्व की आईडी, या स्वयं एक html नोड।
+  *
+  * कंटेनर चुनने के लिए यहां तीन अलग-अलग विकल्प दिए गए हैं
+  * डोम तत्व। p5 द्वारा बनाए गए सभी DOM तत्व (कैनवास, बटन, डिव, आदि)
+  * को दूसरे तर्क के रूप में निर्दिष्ट DOM तत्व से जोड़ा जाएगा
+  * p5 () कॉल।
+  */
+
+
+
+  
+
+
+  
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dist/assets/examples/hi/16_Dom/03_Input_Button.js b/dist/assets/examples/hi/16_Dom/03_Input_Button.js new file mode 100644 index 0000000000..0af112c0f5 --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/03_Input_Button.js @@ -0,0 +1,41 @@ +/* + * @name इनपुट और बटन + * @description आपको शामिल करना होगा + * p5.dom लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए।

+ * इनपुट टेक्स्ट और यह देखने के लिए बटन पर क्लिक करें कि यह कैनवास को प्रभावित करता है। + */ +let input, button, greeting; + +function setup() { + // कैनवास बनाएं + 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/dist/assets/examples/hi/16_Dom/04_Slider.js b/dist/assets/examples/hi/16_Dom/04_Slider.js new file mode 100644 index 0000000000..a952164025 --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/04_Slider.js @@ -0,0 +1,33 @@ +/* + * @name स्लाइडर + * @description आपको शामिल करना होगा + * p5.dom लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए।

+ * पृष्ठभूमि के आर, जी, बी मूल्यों को नियंत्रित करने के लिए स्लाइडर्स को स्थानांतरित करें। + */ +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/dist/assets/examples/hi/16_Dom/07_Modify_DOM.js b/dist/assets/examples/hi/16_Dom/07_Modify_DOM.js new file mode 100644 index 0000000000..8bbc81cabb --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/07_Modify_DOM.js @@ -0,0 +1,56 @@ +/* + * @name डोम को संशोधित करना + * @frame 710,300 + * @description

DOM एलिमेंट बनाएं और हर बार उनके गुणों को संशोधित करें + * draw() कहा जाता है। आपको शामिल करने की आवश्यकता होगी + * p5.dom लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए।

+ */ +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() { + // यह पैराग्राफ कोड के मुख्य ब्लॉक से अलग बनाया गया है। + // यह किसी तत्व के निर्माण को उसके . से अलग करना है + // चयन। चयनित तत्वों को बनाने की आवश्यकता नहीं है + // p5js, वे सिर्फ सादा HTML हो सकते हैं। + createP( + 'I learn in this Letter, that Don Peter of Aragon, ' + + ' comes this night to Messina' + ).addClass('text').hide(); + + // यह लाइन अभी बनाए गए पैराग्राफ को पकड़ लेती है, लेकिन यह but + // HTML में वर्ग 'पाठ' के साथ किसी अन्य तत्व को भी पकड़ें + // पृष्ठ। + 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/dist/assets/examples/hi/16_Dom/08_Video.js b/dist/assets/examples/hi/16_Dom/08_Video.js new file mode 100644 index 0000000000..fb0c95966d --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/08_Video.js @@ -0,0 +1,32 @@ +/* + * @name वीडियो + * @frame 710,250 + * @description

एक वीडियो को कई फ़ॉर्मैट में लोड करें और खेलने के बीच टॉगल करें + * और एक बटन प्रेस के साथ रुक गया। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको कम से कम की आवश्यकता होगी + * एक वीडियो फ़ाइल, और + * p5.dom लाइब्रेरी।

+ */ +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/dist/assets/examples/hi/16_Dom/09_Video_Canvas.js b/dist/assets/examples/hi/16_Dom/09_Video_Canvas.js new file mode 100644 index 0000000000..a6e8a0854d --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/09_Video_Canvas.js @@ -0,0 +1,28 @@ +/* + * @name वीडियो कैनवास + * @description

एक वीडियो को कई फ़ॉर्मैट में लोड करें और उसे कैनवास पर ड्रा करें।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.dom लाइब्रेरी + * कम से कम एक वीडियो फ़ाइल, और एक चालू स्थानीय सर्वर। + */ +let fingers; + +function setup() { + createCanvas(710, 400); + // विभिन्न ब्राउज़रों के लिए कई प्रारूप निर्दिष्ट करें + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + fingers.hide(); // डिफ़ॉल्ट रूप से वीडियो अलग डोम में दिखाई देता है + // तत्व। इसे छुपाएं और इसे कैनवास पर खींचें + // बजाय +} + +function draw() { + background(150); + image(fingers, 10, 10); // वीडियो फ्रेम को कैनवास पर ड्रा करें + filter(GRAY); + image(fingers, 150, 150); // कैनवास पर दूसरी कॉपी बनाएं +} + +function mousePressed() { + fingers.loop(); // वीडियो को लूप में सेट करें और खेलना शुरू करें +} diff --git a/dist/assets/examples/hi/16_Dom/10_Video_Pixels.js b/dist/assets/examples/hi/16_Dom/10_Video_Pixels.js new file mode 100644 index 0000000000..05d323e875 --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/10_Video_Pixels.js @@ -0,0 +1,33 @@ +/* + * @name वीडियो पिक्सल + * @frame 320,240 + * @description

वीडियो लोड करें, उसके पिक्सल में हेरफेर करें और कैनवास पर ड्रा करें। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.dom लाइब्रेरी + * कम से कम एक वीडियो फ़ाइल, और एक चालू स्थानीय सर्वर। + */ +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/dist/assets/examples/hi/16_Dom/11_Capture.js b/dist/assets/examples/hi/16_Dom/11_Capture.js new file mode 100644 index 0000000000..43d1a84590 --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/11_Capture.js @@ -0,0 +1,25 @@ +/* + * @name वीडियो कैप्चर + * @frame 710,240 + * @description

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.dom लाइब्रेरी + * कम से कम एक वीडियो फ़ाइल, और एक चालू स्थानीय सर्वर।

+ * वेबकैम से वीडियो कैप्चर करें और प्रदर्शित करें + * कैनवास पर और साथ ही इनवर्ट फिल्टर के साथ। ध्यान दें कि द्वारा + * डिफॉल्ट कैप्चर फीड भी दिखाई देता है। आप छुपा सकते हैं + * capture.hide() लाइन को अनकम्मेंट करके फीड करें। + */ +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/dist/assets/examples/hi/16_Dom/12_Drop.js b/dist/assets/examples/hi/16_Dom/12_Drop.js new file mode 100644 index 0000000000..b60a3d4fa3 --- /dev/null +++ b/dist/assets/examples/hi/16_Dom/12_Drop.js @@ -0,0 +1,36 @@ +/* + * @name छोड़ देना + * @description आपको शामिल करना होगा + * p5.dom लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए।

+ * एक छवि फ़ाइल को प्रदर्शित करने के लिए उसे कैनवास पर खींचें। + */ + +function setup() { + // कैनवास बनाएं + const c = createCanvas(710, 400); + background(100); + // जब कोई फ़ाइल कैनवास पर गिराई जाती है, तो उसके लिए एक ईवेंट जोड़ें + 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 (file.type === 'image') { + // एक छवि DOM तत्व बनाएं, लेकिन इसे न दिखाएं + const img = createImg(file.data).hide(); + // कैनवास पर चित्र बनाएं + image(img, 0, 0, width, height); + } else { + console.log('Not an image file!'); + } +} diff --git a/dist/assets/examples/hi/17_Drawing/00_Continuous_Lines.js b/dist/assets/examples/hi/17_Drawing/00_Continuous_Lines.js new file mode 100644 index 0000000000..242a7ccf9a --- /dev/null +++ b/dist/assets/examples/hi/17_Drawing/00_Continuous_Lines.js @@ -0,0 +1,15 @@ +/* +* @name सतत रेखा +* @description एक रेखा खींचने के लिए माउस को क्लिक करें और खींचें। +*/ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + stroke(255); + if (mouseIsPressed === true) { + line(mouseX, mouseY, pmouseX, pmouseY); + } +} diff --git a/dist/assets/examples/hi/17_Drawing/01_Pattern.js b/dist/assets/examples/hi/17_Drawing/01_Pattern.js new file mode 100644 index 0000000000..baef5d6f14 --- /dev/null +++ b/dist/assets/examples/hi/17_Drawing/01_Pattern.js @@ -0,0 +1,27 @@ +/* + * @name पैटर्न + * @description सॉफ़्टवेयर टूल से चित्र बनाने के लिए कर्सर को छवि पर ले जाएं + * जो माउस की गति के प्रति प्रतिक्रिया करता है। + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + // variableEllipse() विधि को कॉल करें और इसे भेजें + // वर्तमान माउस स्थिति के लिए पैरामीटर + // और पिछली माउस स्थिति + variableEllipse(mouseX, mouseY, pmouseX, pmouseY); +} + +// सरल विधि variableEllipse() विशेष रूप से बनाई गई थी +// इस कार्यक्रम के लिए। यह माउस की गति की गणना करता है +// और यदि माउस धीरे-धीरे आगे बढ़ रहा है तो एक छोटा दीर्घवृत्त खींचता है +// और यदि माउस तेजी से आगे बढ़ रहा है तो एक बड़ा दीर्घवृत्त खींचता है + +function variableEllipse(x, y, px, py) { + let speed = abs(x - px) + abs(y - py); + stroke(speed); + ellipse(x, y, speed, speed); +} diff --git a/dist/assets/examples/hi/17_Drawing/02_Pulses.js b/dist/assets/examples/hi/17_Drawing/02_Pulses.js new file mode 100644 index 0000000000..6ac965a816 --- /dev/null +++ b/dist/assets/examples/hi/17_Drawing/02_Pulses.js @@ -0,0 +1,31 @@ +/* + * @name दालें + * @description सॉफ्टवेयर ड्राइंग इंस्ट्रूमेंट्स एक लय का अनुसरण कर सकते हैं या इसका पालन कर सकते हैं + * खींचे गए इशारों से स्वतंत्र नियम। यह सहयोगी आरेखण का एक रूप है + * जिसमें ड्राफ्ट्सपर्सन इमेज और सॉफ्टवेयर के कुछ पहलुओं को नियंत्रित करता है + *दूसरों को नियंत्रित करता है। + */ +let angle = 0; + +function setup() { + createCanvas(710, 400); + background(102); + noStroke(); + fill(0, 102); +} + +function draw() { + // तभी ड्रा करें जब माउस दबाया जाए + 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/dist/assets/examples/hi/18_Transform/00_Translate.js b/dist/assets/examples/hi/18_Transform/00_Translate.js new file mode 100644 index 0000000000..4284790624 --- /dev/null +++ b/dist/assets/examples/hi/18_Transform/00_Translate.js @@ -0,0 +1,39 @@ +/* + * @name अनुवाद + * @description translate() फ़ंक्शन वस्तुओं को होने की अनुमति देता है + * खिड़की के भीतर किसी भी स्थान पर ले जाया गया। पहला पैरामीटर + * एक्स-अक्ष ऑफसेट सेट करता है और दूसरा पैरामीटर सेट करता है + * वाई-अक्ष ऑफसेट। यह उदाहरण दिखाता है कि परिवर्तन कैसे जमा होते हैं। + */ +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/dist/assets/examples/hi/18_Transform/01_Scale.js b/dist/assets/examples/hi/18_Transform/01_Scale.js new file mode 100644 index 0000000000..57c1cf140f --- /dev/null +++ b/dist/assets/examples/hi/18_Transform/01_Scale.js @@ -0,0 +1,46 @@ +/* + * @name स्केल + * @description scale() फ़ंक्शन के लिए पैरामीटर मान हैं + * दशमलव प्रतिशत के रूप में निर्दिष्ट। उदाहरण के लिए, विधि + * कॉल स्केल (2.0) आकार के आयाम को बढ़ा देगा + * 200 प्रतिशत। वस्तुएं हमेशा मूल से मापी जाती हैं। यह उदाहरण + * दिखाता है कि परिवर्तन कैसे जमा होते हैं और यह भी कि कैसे पैमाने और अनुवाद and + * उनके आदेश के आधार पर बातचीत करें। + */ + +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/dist/assets/examples/hi/18_Transform/02_Rotate.js b/dist/assets/examples/hi/18_Transform/02_Rotate.js new file mode 100644 index 0000000000..eb91de39aa --- /dev/null +++ b/dist/assets/examples/hi/18_Transform/02_Rotate.js @@ -0,0 +1,43 @@ +/* + * @name घुमाएँ + * @description Z अक्ष के चारों ओर एक वर्ग को घुमाते हुए। + * अपेक्षित परिणाम प्राप्त करने के लिए, रोटेट फंक्शन एंगल भेजें + * पैरामीटर जो 0 और PI*2 के बीच के मान हैं (TWO_PI जो है + * मोटे तौर पर 6.28)। यदि आप कोणों को डिग्री के रूप में सोचना पसंद करते हैं + * (0-360), आप अपने मूल्यों को परिवर्तित करने के लिए radians() विधि का उपयोग कर सकते हैं। + * उदाहरण के लिए: घुमाएं (radians(90)) कथन के समान है + * घुमाएँ (पीआई / 2)। इस उदाहरण में, प्रत्येक सम संख्या वाला दूसरा एक जिटर + * रोटेशन में जोड़ा जाता है। विषम सेकंड के दौरान, घुमाव CW को गति देता है और + * सीसीडब्ल्यू अंतिम जिटर मूल्य द्वारा निर्धारित गति पर। + */ + +let angle = 0.0; +let jitter = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + fill(255); + // केंद्र से आयत बनाएं और यह भी होगा + // उस केंद्र के चारों ओर घुमाएं + rectMode(CENTER); +} + +function draw() { + background(51); + + // सम-संख्या वाले सेकंड (0, 2, 4, 6...) के दौरान घबराना जोड़ें + // रोटेशन + if (second() % 2 === 0) { + jitter = random(-0.1, 0.1); + } + // सबसे हालिया जिटर वैल्यू का उपयोग करके कोण मान बढ़ाएं + angle = angle + jitter; + // घबराहट न होने पर एक सहज CW और CCW गति प्राप्त करने के लिए कोसाइन का उपयोग करें + let c = cos(angle); + // आकार को कैनवास के केंद्र में ले जाएं + translate(width / 2, height / 2); + // अंतिम रोटेशन लागू करें + rotate(c); + rect(0, 0, 180, 180); +} diff --git a/dist/assets/examples/hi/18_Transform/03_Arm.js b/dist/assets/examples/hi/18_Transform/03_Arm.js new file mode 100644 index 0000000000..85278c6dfe --- /dev/null +++ b/dist/assets/examples/hi/18_Transform/03_Arm.js @@ -0,0 +1,49 @@ +/* + * @name आर्म + * @description यह उदाहरण बनाने के लिए ट्रांसफ़ॉर्म मैट्रिसेस का उपयोग करता है + * एक हाथ। प्रत्येक खंड के कोण को द्वारा नियंत्रित किया जाता है + * माउसएक्स और माउसवाई स्थिति। पर लागू किए गए परिवर्तन + * पहला खंड दूसरे खंड पर भी लागू होता है + * क्योंकि वे एक ही push() और . के अंदर हैं + * pop() मैट्रिक्स समूह। + */ + +let x, y; +let angle1 = 0.0; +let angle2 = 0.0; +let segLength = 100; + +function setup() { + createCanvas(720, 400); + strokeWeight(30); + + // अर्ध-पारदर्शी सफेद के साथ स्ट्रोक + stroke(255, 160); + + // हाथ के "कंधे" को कैनवास के केंद्र में रखें + x = width * 0.5; + y = height * 0.5; +} + +function draw() { + background(0); + + // माउस की स्थिति के अनुसार खंडों के कोण को बदलें + angle1 = (mouseX / float(width) - 0.5) * -TWO_PI; + angle2 = (mouseY / float(height) - 0.5) * PI; + + // ट्रांसफ़ॉर्म को "शामिल" करने के लिए पुश और पॉप का उपयोग करें। ध्यान दें कि + // भले ही हम एक कस्टम फ़ंक्शन का उपयोग करके सेगमेंट बनाते हैं, + // परिवर्तन अभी भी जमा होते हैं + push(); + segment(x, y, angle1); + segment(segLength, 0, angle2); + pop(); +} + +// सेगमेंट ड्राइंग के लिए एक कस्टम फ़ंक्शन +function segment(x, y, a) { + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); +} diff --git a/dist/assets/examples/hi/19_Typography/00_Letters.js b/dist/assets/examples/hi/19_Typography/00_Letters.js new file mode 100644 index 0000000000..4438894f30 --- /dev/null +++ b/dist/assets/examples/hi/19_Typography/00_Letters.js @@ -0,0 +1,64 @@ +/* + * @name पत्र + * @description पत्र एक फ़ॉन्ट लोड करके स्क्रीन पर खींचा जा सकता है, सेटिंग + * इसकी विशेषताएँ और फिर अक्षर खींचना। यह उदाहरण for . का उपयोग करता है + * कैनवास को स्वचालित रूप से भरने के लिए लूप और यूनिकोड संदर्भ संख्या + * एक ग्रिड में वर्ण। स्वरों का चयन किया जाता है और एक विशिष्ट भरण रंग दिया जाता है। + */ +let font, + fontsize = 32; + +function preload() { + // सुनिश्चित करें कि .ttf या .otf फ़ॉन्ट संपत्ति निर्देशिका में संग्रहीत है + // सेटअप से पहले लोड किया जाता है setup() और draw() कहा जाता है + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // टेक्स्ट विशेषताओं को सेट करें + textFont(font); + textSize(fontsize); + textAlign(CENTER, CENTER); +} + +function draw() { + background(160); + + // अक्षरों और बाएँ और शीर्ष हाशिये के बीच की खाई को सेट करें + let gap = 52; + let margin = 10; + translate(margin * 4, margin * 4); + + // अपने इच्छित चरित्र पर शुरू करने के लिए काउंटर सेट करें + // इस मामले में 35, जो # प्रतीक . है + let counter = 35; + + // जब तक कैनवास पर जगह है तब तक लूप करें + for (let y = 0; y < height - gap; y += gap) { + for (let x = 0; x < width - gap; x += gap) { + // उनके यूनिकोड नंबर द्वारा अलग-अलग अक्षरों को पुनः प्राप्त करने के लिए काउंटर का उपयोग करें + let letter = char(counter); + + // स्वरों और अन्य वर्णों में अलग-अलग रंग जोड़ें + if ( + letter === 'A' || + letter === 'E' || + letter === 'I' || + letter === 'O' || + letter === 'U' + ) { + fill('#ed225d'); + } else { + fill(255); + } + + // पत्र को स्क्रीन पर ड्रा करें + text(letter, x, y); + + // काउंटर बढ़ाएँ + counter++; + } + } +} diff --git a/dist/assets/examples/hi/19_Typography/01_Words.js b/dist/assets/examples/hi/19_Typography/01_Words.js new file mode 100644 index 0000000000..df116b4f7e --- /dev/null +++ b/dist/assets/examples/hi/19_Typography/01_Words.js @@ -0,0 +1,59 @@ +/* + * @name शब्द + * @description text() फ़ंक्शन का उपयोग स्क्रीन पर शब्द लिखने के लिए किया जाता है। + * शब्दों को textAlign() के साथ बाएं, केंद्र या दाएं संरेखित किया जा सकता है + * फ़ंक्शन, और आकृतियों की तरह, शब्दों को fill() के साथ रंगा जा सकता है। + */ +let font, + fontsize = 40; + +function preload() { + // सुनिश्चित करें कि .ttf या .otf फ़ॉन्ट संपत्ति निर्देशिका में संग्रहीत है + // सेटअप से पहले लोड किया जाता है setup() और draw() कहा जाता है + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // टेक्स्ट विशेषताओं को सेट करें + textFont(font); + textSize(fontsize); + textAlign(CENTER, CENTER); +} + +function draw() { + background(160); + + // टेक्स्ट को दाईं ओर संरेखित करें + // और कैनवास के बाएँ तीसरे भाग में drawWords () चलाएँ + textAlign(RIGHT); + drawWords(width * 0.25); + + // पाठ को केंद्र में संरेखित करें + // और कैनवास के बीच में drawWords() चलाएँ + textAlign(CENTER); + drawWords(width * 0.5); + + // टेक्स्ट को बाईं ओर संरेखित करें + // और कैनवास के दाहिने तीसरे भाग में drawWords () चलाएँ + textAlign(LEFT); + drawWords(width * 0.75); +} + +function drawWords(x) { + // text() फ़ंक्शन को तीन मापदंडों की आवश्यकता होती है: + // आकर्षित करने के लिए पाठ, क्षैतिज स्थिति, + // और ऊर्ध्वाधर स्थिति + 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/dist/assets/examples/hi/20_3D/00_geometries.js b/dist/assets/examples/hi/20_3D/00_geometries.js new file mode 100644 index 0000000000..1bc949fbee --- /dev/null +++ b/dist/assets/examples/hi/20_3D/00_geometries.js @@ -0,0 +1,60 @@ +/* + * @name ज्यामिति + * @description अब p5 में छह 3D प्रिमिटिव हैं। + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + + translate(-240, -100, 0); + normalMaterial(); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + plane(70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(70, 70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cylinder(70, 70); + pop(); + + translate(-240 * 2, 200, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cone(70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + torus(70, 20); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + sphere(70); + pop(); +} diff --git a/dist/assets/examples/hi/20_3D/01_sine_cosine_in_3D.js b/dist/assets/examples/hi/20_3D/01_sine_cosine_in_3D.js new file mode 100644 index 0000000000..963c1f0040 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/01_sine_cosine_in_3D.js @@ -0,0 +1,28 @@ +/* + * @name 3D में साइन कोसाइन + * @description साइन, कोसाइन और पुश/पॉप को 3D में भी लागू किया जा सकता है। + */ +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/dist/assets/examples/hi/20_3D/02_multiple_lights.js b/dist/assets/examples/hi/20_3D/02_multiple_lights.js new file mode 100644 index 0000000000..66bf5d45c5 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/02_multiple_lights.js @@ -0,0 +1,30 @@ +/* + * @name मल्टीपल लाइट्स + * @description एक स्केच में सभी प्रकार की रोशनी का उपयोग किया जा सकता है। + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + ambientLight(50); + directionalLight(255, 0, 0, 0.25, 0.25, 0); + 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, 64); +} diff --git a/dist/assets/examples/hi/20_3D/03_materials.js b/dist/assets/examples/hi/20_3D/03_materials.js new file mode 100644 index 0000000000..662d8d2cf2 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/03_materials.js @@ -0,0 +1,65 @@ +/* + * @name सामग्री + * @description पांच प्रकार की सामग्री समर्थित हैं। + * वे प्रकाश के प्रति अलग तरह से प्रतिक्रिया करते हैं। + * प्रकाश की स्थिति बदलने के लिए अपने माउस को घुमाएँ। + */ +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/dist/assets/examples/hi/20_3D/04_textures.js b/dist/assets/examples/hi/20_3D/04_textures.js new file mode 100644 index 0000000000..ea6d50b791 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/04_textures.js @@ -0,0 +1,40 @@ +/* + * @name बनावट + * @description चित्र और वीडियो बनावट के लिए समर्थित हैं। + */ +// वीडियो स्रोत: 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/dist/assets/examples/hi/20_3D/05_ray_casting.js b/dist/assets/examples/hi/20_3D/05_ray_casting.js new file mode 100644 index 0000000000..1d1e6e5c66 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/05_ray_casting.js @@ -0,0 +1,100 @@ +/* + * @name रे कास्टिंग + * @description जोनाथन वाटसन द्वारा मूल उदाहरण। + *

रे कास्टिंग के साथ 3डी स्पेस में माउस की स्थिति का पता लगाना। + */ +const objects = []; +let eyeZ; + +function setup() { + createCanvas(710, 400, WEBGL); + + eyeZ = height / 2 / tan((30 * PI) / 180); // डिफ़ॉल्ट दूरी कैमरा मूल से दूर है। + + objects.push(new IntersectPlane(1, 0, 0, -100, 0, 0)); // बाईं दीवार + objects.push(new IntersectPlane(1, 0, 0, 100, 0, 0)); // दाहिनी दीवार + objects.push(new IntersectPlane(0, 1, 0, 0, -100, 0)); // नीचे की दीवार + objects.push(new IntersectPlane(0, 1, 0, 0, 100, 0)); // शीर्ष दीवार + objects.push(new IntersectPlane(0, 0, 1, 0, 0, 0)); // पीछे की दीवार + + noStroke(); + ambientMaterial(250); +} + +function draw() { + background(0); + + // रोशनी + pointLight(255, 255, 255, 0, 0, 400); + ambientLight(244, 122, 158); + + // बाईं दीवार + push(); + translate(-100, 0, 200); + rotateY((90 * PI) / 180); + plane(400, 200); + pop(); + + // दाहिनी दीवार + push(); + translate(100, 0, 200); + rotateY((90 * PI) / 180); + plane(400, 200); + pop(); + + // नीचे की दीवार + push(); + translate(0, 100, 200); + rotateX((90 * PI) / 180); + plane(200, 400); + pop(); + + // शीर्ष दीवार + push(); + translate(0, -100, 200); + rotateX((90 * PI) / 180); + plane(200, 400); + pop(); + + plane(200, 200); // पीछे की दीवार + + const x = mouseX - width / 2; + const y = mouseY - height / 2; + + const Q = createVector(0, 0, eyeZ); // किरण पर एक बिंदु और कैमरे की डिफ़ॉल्ट स्थिति। + const v = createVector(x, y, -eyeZ); // किरण की दिशा वेक्टर। + + let intersect; // किरण और समतल के बीच का प्रतिच्छेदन बिंदु। + let closestLambda = eyeZ * 10; // ड्रा दूरी। + + for (let x = 0; x < objects.length; x += 1) { + let object = objects[x]; + let lambda = object.getLambda(Q, v); // लैम्ब्डा का मान जहां किरण वस्तु को काटती है + + if (lambda < closestLambda && lambda > 0) { + // किरण और वस्तु के प्रतिच्छेदन की स्थिति का पता लगाएं। + intersect = p5.Vector.add(Q, p5.Vector.mult(v, lambda)); + closestLambda = lambda; + } + } + + // कर्सर + push(); + translate(intersect); + fill(237, 34, 93); + sphere(10); + pop(); +} + +// एक विमान के लिए कक्षा जो अनंत तक फैली हुई है। +class IntersectPlane { + constructor(n1, n2, n3, p1, p2, p3) { + this.normal = createVector(n1, n2, n3); // विमान का सामान्य वेक्टर + this.point = createVector(p1, p2, p3); // विमान पर एक बिंदु + this.d = this.point.dot(this.normal); + } + + getLambda(Q, v) { + return (-this.d - this.normal.dot(Q)) / this.normal.dot(v); + } +} diff --git a/dist/assets/examples/hi/20_3D/07_orbit_control.js b/dist/assets/examples/hi/20_3D/07_orbit_control.js new file mode 100644 index 0000000000..e68b4b8efe --- /dev/null +++ b/dist/assets/examples/hi/20_3D/07_orbit_control.js @@ -0,0 +1,36 @@ +/* + * @name कक्षा नियंत्रण + * @description कक्षा नियंत्रण आपको दुनिया भर में खींचने और स्थानांतरित करने की अनुमति देता है। + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + let radius = width * 1.5; + + // दुनिया को स्थानांतरित करने के लिए खींचें। + orbitControl(); + + normalMaterial(); + translate(0, 0, -600); + 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/dist/assets/examples/hi/20_3D/08_basic_shader.js b/dist/assets/examples/hi/20_3D/08_basic_shader.js new file mode 100644 index 0000000000..b9dbbb6d6f --- /dev/null +++ b/dist/assets/examples/hi/20_3D/08_basic_shader.js @@ -0,0 +1,27 @@ +/* + * @name बेसिक शेडर + * @description यह एक बुनियादी उदाहरण है जिसमें दिखाया गया है कि p5.js में शेडर्स को कैसे लोड किया जाए। + *
p5.js में शेडर्स का उपयोग करने के बारे में अधिक जानने के लिए: p5.js Shaders + */ + +// यह वेरिएबल हमारे शेडर ऑब्जेक्ट को होल्ड करेगा +let theShader; + +function preload(){ + // शेडर लोड करें + theShader = loadShader('assets/basic.vert', 'assets/basic.frag'); +} + +function setup() { + // शेडर्स को काम करने के लिए WEBGL मोड की आवश्यकता होती है + createCanvas(710, 400, WEBGL); + noStroke(); +} + +function draw() { + // shader() हमारे शेडर के साथ सक्रिय शेडर सेट करता है + shader(theShader); + + // रेक्ट हमें स्क्रीन पर कुछ ज्योमेट्री देता है + rect(0,0,width, height); +} diff --git a/dist/assets/examples/hi/20_3D/09_shader_as_a_texture.js b/dist/assets/examples/hi/20_3D/09_shader_as_a_texture.js new file mode 100644 index 0000000000..0c10b5e341 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/09_shader_as_a_texture.js @@ -0,0 +1,68 @@ +/* + * @name शेडर एक बनावट के रूप में + * @description Shaders को बनावट के रूप में 2D/3D आकृतियों पर लागू किया जा सकता है। + *
p5.js में शेडर्स का उपयोग करने के बारे में अधिक जानने के लिए: p5.js Shaders + */ + + // यह वेरिएबल हमारे शेडर ऑब्जेक्ट को होल्ड करेगा + let theShader; + // यह वेरिएबल हमारी createGraphics लेयर को होल्ड करेगा + let shaderTexture; + + let theta = 0; + + let x; + let y; + let outsideRadius = 200; + let insideRadius = 100; + + function preload(){ + // शेडर लोड करें + theShader = loadShader('assets/texture.vert','assets/texture.frag'); + } + + function setup() { + // शेडर्स को काम करने के लिए WEBGL मोड की आवश्यकता होती है + createCanvas(710, 400, WEBGL); + noStroke(); + + // createGraphics लेयर्स को इनिशियलाइज़ करें + shaderTexture = createGraphics(710, 400, WEBGL); + + // createGraphics लेयर्स स्ट्रोक को बंद करें + shaderTexture.noStroke(); + + x = -50; + y = 0; + } + + function draw() { + + // केवल सक्रिय शेडर को सेट करने के बजाय हम इसे createGraphics लेयर में पास कर रहे हैं + shaderTexture.shader(theShader); + + // यहां हम अपने समान मूल्यों को शेडर में भेजने के लिए setUniform () का उपयोग कर रहे हैं + theShader.setUniform("resolution", [width, height]); + theShader.setUniform("time", millis() / 1000.0); + theShader.setUniform("mouse", [mouseX, map(mouseY, 0, height, height, 0)]); + + // रेंडर करने के लिए shaderTexture लेयर ज्योमेट्री पास करना + shaderTexture.rect(0,0,width,height); + + background(255); + + // शेडर को एक बनावट के रूप में पास करें + 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(); + + // 3D में चिकने किनारों के लिए दीर्घवृत्त के लिए पाँचवाँ पैरामीटर पास करना + ellipse(260,0,200,200,100); + } diff --git a/dist/assets/examples/hi/20_3D/10_passing_shader_uniforms.js b/dist/assets/examples/hi/20_3D/10_passing_shader_uniforms.js new file mode 100644 index 0000000000..24275c1322 --- /dev/null +++ b/dist/assets/examples/hi/20_3D/10_passing_shader_uniforms.js @@ -0,0 +1,33 @@ +/* + * @name पासिंग शेडर यूनिफॉर्म + * @description यूनिफ़ॉर्म वह तरीका है जिससे जानकारी को p5 से शेडर तक पहुँचाया जाता है। + *
p5.js में शेडर्स का उपयोग करने के बारे में अधिक जानने के लिए: p5.js Shaders + */ + + // यह वेरिएबल हमारे शेडर ऑब्जेक्ट को होल्ड करेगा + let theShader; + + function preload(){ + // शेडर लोड करें + theShader = loadShader('assets/uniforms.vert', 'assets/uniforms.frag'); + } + + function setup() { + // शेडर्स को काम करने के लिए WEBGL मोड की आवश्यकता होती है + createCanvas(710, 400, WEBGL); + noStroke(); + } + + function draw() { + // शेडर () हमारे शेडर के साथ सक्रिय शेडर सेट करता है + shader(theShader); + + // हमारे शेडर को रिज़ॉल्यूशन, माउस और समय भेजें + // माउस + समय भेजने से पहले हम डेटा को संशोधित करते हैं ताकि यह शेडर द्वारा अधिक आसानी से उपयोग किया जा सके + theShader.setUniform('resolution', [width, height]); + theShader.setUniform('mouse', map(mouseX, 0, width, 0, 7)); + theShader.setUniform('time', frameCount * 0.01); + + // रेक्ट हमें स्क्रीन पर कुछ ज्योमेट्री देता है + rect(0,0,width, height); + } diff --git a/dist/assets/examples/hi/20_3D/11_shader_using_webcam.js b/dist/assets/examples/hi/20_3D/11_shader_using_webcam.js new file mode 100644 index 0000000000..09de5a744b --- /dev/null +++ b/dist/assets/examples/hi/20_3D/11_shader_using_webcam.js @@ -0,0 +1,37 @@ +/* + * @name Shader वेबकैम का उपयोग कर रहा है + * @description वेबकैम को टेक्सचर के रूप में शेडर्स को पास किया जा सकता है। + *
p5.js में शेडर्स का उपयोग करने के बारे में अधिक जानने के लिए: p5.js Shaders + */ + + // यह वेरिएबल हमारे शेडर ऑब्जेक्ट को होल्ड करेगा + let theShader; + // यह वेरिएबल हमारे वेबकैम वीडियो को होल्ड करेगा + let cam; + + function preload(){ + // शेडर लोड करें + theShader = loadShader('assets/webcam.vert', 'assets/webcam.frag'); + } + + function setup() { + // शेडर्स को काम करने के लिए WEBGL मोड की आवश्यकता होती है + createCanvas(710, 400, WEBGL); + noStroke(); + + cam = createCapture(VIDEO); + cam.size(710, 400); + + cam.hide(); + } + + function draw() { + // shader() हमारे शेडर के साथ सक्रिय शेडर सेट करता है + shader(theShader); + + // एक बनावट के रूप में कैम पास करना + theShader.setUniform('tex0', cam); + + // रेक्ट हमें स्क्रीन पर कुछ ज्योमेट्री देता है + rect(0,0,width,height); + } diff --git a/dist/assets/examples/hi/21_Input/00_Clock.js b/dist/assets/examples/hi/21_Input/00_Clock.js new file mode 100644 index 0000000000..b5bbb269b0 --- /dev/null +++ b/dist/assets/examples/hi/21_Input/00_Clock.js @@ -0,0 +1,62 @@ +/* + * @name घड़ी + * @description वर्तमान समय को second() के साथ पढ़ा जा सकता है, + * minute(), और hour() फ़ंक्शन। इस उदाहरण में, sin() और + * cos () मानों का उपयोग हाथों की स्थिति निर्धारित करने के लिए किया जाता है। + */ +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); + + // घड़ी की पृष्ठभूमि बनाएं + noStroke(); + fill(244, 122, 158); + ellipse(cx, cy, clockDiameter + 25, clockDiameter + 25); + fill(237, 34, 93); + ellipse(cx, cy, clockDiameter, clockDiameter); + + // पाप के sin() और cos() 3 बजे शुरू होते हैं; + // शीर्ष पर प्रारंभ करने के लिए HALF_PI घटाएं + 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; + + // घड़ी की सुई खींचे + 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); + + // मिनट टिक ड्रा करें + 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/dist/assets/examples/hi/21_Input/01_Constrain.js b/dist/assets/examples/hi/21_Input/01_Constrain.js new file mode 100644 index 0000000000..1ce4a66b38 --- /dev/null +++ b/dist/assets/examples/hi/21_Input/01_Constrain.js @@ -0,0 +1,36 @@ +/* + * @name बाधा + * @description माउस को स्क्रीन पर घुमाने के लिए ले जाएँ + * वृत्त। कार्यक्रम सर्कल को उसके बॉक्स में सीमित करता है। + */ +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/dist/assets/examples/hi/21_Input/02_Easing.js b/dist/assets/examples/hi/21_Input/02_Easing.js new file mode 100644 index 0000000000..ca7ced8dd5 --- /dev/null +++ b/dist/assets/examples/hi/21_Input/02_Easing.js @@ -0,0 +1,30 @@ +/* + * @name आसान + * @description माउस को स्क्रीन और सिंबल पर ले जाएं + * का पालन करेंगे। एनीमेशन के प्रत्येक फ्रेम को खींचने के बीच, + * कार्यक्रम की स्थिति के बीच अंतर की गणना करता है + * प्रतीक और कर्सर। यदि दूरी 1 पिक्सेल से बड़ी है, + * प्रतीक अपनी धारा से कुछ दूरी (0.05) को आगे बढ़ाता है + * कर्सर की ओर स्थिति। + */ +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/dist/assets/examples/hi/21_Input/03_Keyboard.js b/dist/assets/examples/hi/21_Input/03_Keyboard.js new file mode 100644 index 0000000000..5309d3e81e --- /dev/null +++ b/dist/assets/examples/hi/21_Input/03_Keyboard.js @@ -0,0 +1,38 @@ +/* + * @name कीबोर्ड + * @description इमेज को फोकस करने के लिए उस पर क्लिक करें और + * समय और स्थान में फ़ॉर्म बनाने के लिए अक्षर कुंजियाँ दबाएँ। + * प्रत्येक कुंजी की एक विशिष्ट पहचान संख्या होती है। ये नंबर + * अंतरिक्ष में आकृतियों की स्थिति के लिए इस्तेमाल किया जा सकता है। + */ +let rectWidth; + +function setup() { + createCanvas(720, 400); + noStroke(); + background(230); + rectWidth = width / 4; +} + +function draw() { + // चाबियों की प्रतीक्षा करते हुए लूपिंग जारी रखने के लिए यहां draw() रखें +} + +function keyPressed() { + let keyIndex = -1; + if (key >= 'a' && key <= 'z') { + keyIndex = key.charCodeAt(0) - 'a'.charCodeAt(0); + } + if (keyIndex === -1) { + // यदि यह एक अक्षर कुंजी नहीं है, तो स्क्रीन को साफ़ करें + background(230); + } else { + // यह एक अक्षर कुंजी है, एक आयत भरें + 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/dist/assets/examples/hi/21_Input/04_Mouse1D.js b/dist/assets/examples/hi/21_Input/04_Mouse1D.js new file mode 100644 index 0000000000..6471fcf6ec --- /dev/null +++ b/dist/assets/examples/hi/21_Input/04_Mouse1D.js @@ -0,0 +1,24 @@ +/* + * @name माउस 1D + * @description माउस को बाएँ और दाएँ ले जाएँ + * संतुलन शिफ्ट करें। "माउसएक्स" चर का उपयोग किया जाता है + * आयतों के आकार और रंग दोनों को नियंत्रित करने के लिए। + */ +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/dist/assets/examples/hi/21_Input/05_Mouse2D.js b/dist/assets/examples/hi/21_Input/05_Mouse2D.js new file mode 100644 index 0000000000..16d0eea4ec --- /dev/null +++ b/dist/assets/examples/hi/21_Input/05_Mouse2D.js @@ -0,0 +1,20 @@ +/* + * @name माउस 2D + * @description माउस को हिलाने से स्थिति बदल जाती है और + * प्रत्येक बॉक्स का आकार। + */ +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/dist/assets/examples/hi/21_Input/06_MouseIsPressed.js b/dist/assets/examples/hi/21_Input/06_MouseIsPressed.js new file mode 100644 index 0000000000..0a780f3f2a --- /dev/null +++ b/dist/assets/examples/hi/21_Input/06_MouseIsPressed.js @@ -0,0 +1,20 @@ +/* + * @name माउस प्रेस + * @description माउस को शेप में लाने के लिए मूव करें। + * रंग बदलने के लिए माउस बटन दबाएं। + */ +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/dist/assets/examples/hi/21_Input/07_Mouse_Functions.js b/dist/assets/examples/hi/21_Input/07_Mouse_Functions.js new file mode 100644 index 0000000000..bb9a876331 --- /dev/null +++ b/dist/assets/examples/hi/21_Input/07_Mouse_Functions.js @@ -0,0 +1,66 @@ +/* + * @name माउस फंक्शन्स + * @description बॉक्स पर क्लिक करें और इसे स्क्रीन पर खींचें। + */ +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); + + // परीक्षण करें कि क्या कर्सर बॉक्स के ऊपर है + 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; + } + + // बॉक्स को ड्रा करें + 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/dist/assets/examples/hi/21_Input/08_Mouse_Signals.js b/dist/assets/examples/hi/21_Input/08_Mouse_Signals.js new file mode 100644 index 0000000000..858640b4ec --- /dev/null +++ b/dist/assets/examples/hi/21_Input/08_Mouse_Signals.js @@ -0,0 +1,52 @@ +/* + * @name माउस सिग्नल + * @description सिग्नल जेनरेट करने के लिए माउस को मूव करें और क्लिक करें। + * शीर्ष पंक्ति "माउसएक्स" से संकेत है, मध्य पंक्ति है + * "माउसवाई" से संकेत, और नीचे की पंक्ति संकेत है + * "mouseIsPressed" से। + */ +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]; + } + // सरणी के अंत में नए मान जोड़ें + 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/dist/assets/examples/hi/21_Input/09_Storing_Input.js b/dist/assets/examples/hi/21_Input/09_Storing_Input.js new file mode 100644 index 0000000000..aca6bafec1 --- /dev/null +++ b/dist/assets/examples/hi/21_Input/09_Storing_Input.js @@ -0,0 +1,38 @@ +/* + * @name भंडारण इनपुट + * @description माउस को स्क्रीन पर ले जाएँ + * मंडलियों की स्थिति बदलें। पदों + * माउस को एक ऐरे में रिकॉर्ड किया जाता है और खेला जाता है + * हर फ्रेम वापस। प्रत्येक फ्रेम के बीच, नवीनतम + * मान प्रत्येक सरणी के अंत में जोड़ा जाता है और + * सबसे पुराना मान हटा दिया गया है। + */ +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); + + // प्रत्येक फ्रेम पर एक अलग प्रविष्टि का उपयोग करके, सरणी के माध्यम से साइकिल चलाएं। + // इस तरह से मोडुलो (%) का उपयोग करना सभी मूल्यों को खत्म करने की तुलना में तेज़ है। + let which = frameCount % num; + mx[which] = mouseX; + my[which] = mouseY; + + for (let i = 0; i < num; i++) { + // कौन सा+1 सबसे छोटा है (सरणी में सबसे पुराना) + let index = (which + 1 + i) % num; + ellipse(mx[index], my[index], i, i); + } +} diff --git a/dist/assets/examples/hi/22_Advanced_Data/00_Load_Saved_JSON.js b/dist/assets/examples/hi/22_Advanced_Data/00_Load_Saved_JSON.js new file mode 100644 index 0000000000..7a260da550 --- /dev/null +++ b/dist/assets/examples/hi/22_Advanced_Data/00_Load_Saved_JSON.js @@ -0,0 +1,104 @@ +/* + * @name लोड सेव किया गया JSON + * @description बबल क्लास बनाएं, डेटा का उपयोग करके कई बबल को इंस्टेंट करें + * एक JSON फ़ाइल, और स्क्रीन पर परिणाम प्रदर्शित करें। + * क्योंकि वेब ब्राउजर फाइलों को सेव करने में भिन्न होते हैं, हम इसका उपयोग नहीं करते हैं + * saveJSON, प्रोसेसिंग उदाहरण के विपरीत।

+ * प्रोसेसिंग के लिए डेनियल शिफमैन के LoadSaveJSON उदाहरण पर आधारित। + */ + +// बबल क्लास +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; + } + + // जांचें कि क्या माउस बुलबुले के ऊपर है + rollover(px, py) { + let d = dist(px, py, this.x, this.y); + this.over = d < this.radius; + } + + // बबल प्रदर्शित करें + 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 = {}; // loadJSON कॉल से परिणाम धारण करने के लिए वैश्विक वस्तु +let bubbles = []; // सभी बबल ऑब्जेक्ट्स को होल्ड करने के लिए ग्लोबल ऐरे + +// "सेटअप" चलाने से पहले किसी भी एसिंक्रोनस डेटा लोडिंग को प्रीलोड में रखें +function preload() { + data = loadJSON('assets/bubbles.json'); +} + +// सहेजे गए बबल डेटा को बबल ऑब्जेक्ट में बदलें +function loadData() { + let bubbleData = data['bubbles']; + for (let i = 0; i < bubbleData.length; i++) { + // प्रत्येक वस्तु को सरणी में प्राप्त करें + let bubble = bubbleData[i]; + // एक स्थिति वस्तु प्राप्त करें + let position = bubble['position']; + // स्थिति से x, y प्राप्त करें + let x = position['x']; + let y = position['y']; + + // व्यास और लेबल प्राप्त करें + let diameter = bubble['diameter']; + let label = bubble['label']; + + // ऑब्जेक्ट को सरणी में रखें + bubbles.push(new Bubble(x, y, diameter, label)); + } +} + +// हर बार माउस क्लिक करने पर एक नया बबल बनाएं। +function mousePressed() { + // बबल में व्यास और लेबल जोड़ें + let diameter = random(40, 80); + let label = 'New Label'; + + // नई JSON बबल ऑब्जेक्ट को सरणी में जोड़ें + bubbles.push(new Bubble(mouseX, mouseY, diameter, label)); + + // यदि बहुत अधिक हैं तो बबल काउंट प्रून करें + if (bubbles.length > 10) { + bubbles.shift(); // सरणी से पहले आइटम को हटा दें + } +} + +function setup() { + createCanvas(640, 360); + loadData(); +} + +function draw() { + background(255); + + // सभी बुलबुले प्रदर्शित करें + for (let i = 0; i < bubbles.length; i++) { + bubbles[i].display(); + bubbles[i].rollover(mouseX, mouseY); + } + + // नीचे की ओर लेबल निर्देश + textAlign(LEFT); + fill(0); + text('Click to add bubbles.', 10, height - 10); +} diff --git a/dist/assets/examples/hi/33_Sound/00_Load_and_Play_Sound.js b/dist/assets/examples/hi/33_Sound/00_Load_and_Play_Sound.js new file mode 100644 index 0000000000..28f63363dc --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/00_Load_and_Play_Sound.js @@ -0,0 +1,25 @@ +/* + * @name लोड और प्ले साउंड + * @description प्रीलोड के दौरान ध्वनि लोड करें ()। कैनवास पर क्लिक करने पर ध्वनि बजाएं। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर। + */ +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 () एक बूलियन लौटाता है + song.stop(); + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/hi/33_Sound/01_Preload_Sound.js b/dist/assets/examples/hi/33_Sound/01_Preload_Sound.js new file mode 100644 index 0000000000..55e1af05c2 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/01_Preload_Sound.js @@ -0,0 +1,34 @@ +/* + * @name प्रीलोड साउंडफाइल + * @description loadsound() के दौरान preload() कॉल करें यह सुनिश्चित करने के लिए कि + * setup() कहे जाने से पहले ध्वनि पूरी तरह से भरी हुई है। यह हमेशा के लिए सबसे अच्छा है + * preload() में loadsound() को कॉल करें, अन्यथा ध्वनियों को लोड करने की आवश्यकता नहीं होगी + * जब तक आप उन्हें अपने स्केच में खेलना चाहें। + * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर। + */ + +let song; + +function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + song.loop(); // गाना सेटअप के दौरान चलने के लिए तैयार है () क्योंकि यह प्रीलोड के दौरान लोड किया गया था + background(0, 255, 0); +} + +function mousePressed() { + if (song.isPlaying()) { + // .isPlaying () एक बूलियन लौटाता है + song.pause(); // .play() .pause() स्थिति से फिर से शुरू होगा + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/hi/33_Sound/02_soundFormats.js b/dist/assets/examples/hi/33_Sound/02_soundFormats.js new file mode 100644 index 0000000000..2af9a6bebe --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/02_soundFormats.js @@ -0,0 +1,54 @@ +/** + * @name ध्वनि प्रारूप + * @description

तकनीकी रूप से, पेटेंट मुद्दों के कारण, कोई एकल नहीं है + * ध्वनि प्रारूप जो सभी वेब ब्राउज़र द्वारा समर्थित है। जबकि + * mp3 समर्थित है पर + * OS X और Windows पर प्रमुख ब्राउज़रों के नवीनतम संस्करण, उदाहरण के लिए, + * यह कुछ कम मुख्यधारा के ऑपरेटिंग सिस्टम पर उपलब्ध नहीं हो सकता है और + * ब्राउज़र।

+ * + *

पूर्ण संगतता सुनिश्चित करने के लिए, आप समान ध्वनि फ़ाइल शामिल कर सकते हैं + * कई स्वरूपों में, उदा। 'sound.mp3' और 'sound.ogg'। (ओग एक है + * एमपी3 का ओपन सोर्स विकल्प।) आप ऑडियो फाइलों को कन्वर्ट कर सकते हैं + * वेब अनुकूल प्रारूपों में media.io

। + * + *

soundformats() विधि लोडसाउंड को बताती है कि कौन से प्रारूप हैं + * हमने अपने स्केच के साथ शामिल किया है। फिर, लोडसाउंड होगा + * द्वारा समर्थित पहले प्रारूप को लोड करने का प्रयास + * क्लाइंट का वेब ब्राउज़र।

+ * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।< /पी> + */ +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/dist/assets/examples/hi/33_Sound/03_Play_Mode.js b/dist/assets/examples/hi/33_Sound/03_Play_Mode.js new file mode 100644 index 0000000000..443b324633 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/03_Play_Mode.js @@ -0,0 +1,42 @@ +/* + * @name प्ले मोड + * @description + *

'सस्टेनेबल' मोड में, ध्वनि अपने आप ओवरलैप हो जाएगी। + * 'पुनरारंभ' मोड में यह रुक जाएगा और फिर से शुरू होगा। + * ध्वनि फ़ाइल चलाने के लिए माउस क्लिक करें। + * एक बार में बहुत सारी आवाज़ें ट्रिगर करें! प्लेमोड बदलने के लिए कोई भी कुंजी दबाएं।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।< /पी> + */ +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/dist/assets/examples/hi/33_Sound/04_Pan_SoundFile.js b/dist/assets/examples/hi/33_Sound/04_Pan_SoundFile.js new file mode 100644 index 0000000000..3751f0fd68 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/04_Pan_SoundFile.js @@ -0,0 +1,34 @@ +/* + * @name पैन साउंड + * @description

ध्वनि चलाने के लिए माउस क्लिक करें। + * गेंद की स्थिति माउस का अनुसरण करती है और ध्वनि की पैनिंग से संबंधित होती है।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।< /पी> + * + */ +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() { + // गेंद के x स्थान को पैनिंग डिग्री पर मैप करें + // -1.0 (बाएं) और 1.0 (दाएं) के बीच + let panning = map(ball.x, 0, width, -1.0, 1.0); + soundFile.pan(panning); + soundFile.play(); +} diff --git a/dist/assets/examples/hi/33_Sound/05_Sound_Effect.js b/dist/assets/examples/hi/33_Sound/05_Sound_Effect.js new file mode 100644 index 0000000000..70d99f136f --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/05_Sound_Effect.js @@ -0,0 +1,69 @@ +/* + * @name ध्वनि प्रभाव + * @description

माउस को सर्कल के अंदर क्लिक करने पर ध्वनि प्रभाव चलाएं।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ +// डैनियल शिफमैन द्वारा लर्निंग प्रोसेसिंग से अनुकूलित from +// http://www.learningprocessing.com +// डोरबेल का नमूना Corsica_S द्वारा freesound.org के माध्यम से, +// क्रिएटिव कॉमन्स BY 3.0 + +// एक "डोरबेल" (वास्तव में एक बटन) का वर्णन करने के लिए एक वर्ग +class Doorbell { + constructor(x_, y_, r_) { + // स्थान और आकार + this.x = x_; + this.y = y_; + this.r = r_; + } + // दरवाजे की घंटी के अंदर एक बिंदु है? (माउस रोलओवर आदि के लिए प्रयुक्त) + contains(mx, my) { + return dist(mx, my, this.x, this.y) < this.r; + } + + // डोरबेल दिखाएं (हार्डकोडेड रंग, बेहतर किया जा सकता है) + 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); + } +} + +// एक ध्वनि फ़ाइल वस्तु +let dingdong; + +// एक डोरबेल ऑब्जेक्ट (जो ध्वनि को ट्रिगर करेगा) +let doorbell; + +function setup() { + createCanvas(200, 200); + + // ध्वनि फ़ाइल लोड करें। + // हमने एक एमपी3 और एक ओजीजी संस्करण दोनों को शामिल किया है। + soundFormats('mp3', 'ogg'); + dingdong = loadSound('assets/doorbell.mp3'); + + // एक नया डोरबेल बनाएं + doorbell = new Doorbell(width / 2, height / 2, 32); +} + +function draw() { + background(255); + // दरवाजे की घंटी दिखाओ + doorbell.display(mouseX, mouseY); +} + +function mousePressed() { + // यदि उपयोगकर्ता दरवाजे की घंटी पर क्लिक करता है, तो ध्वनि बजाएं! + if (doorbell.contains(mouseX, mouseY)) { + dingdong.play(); + } +} diff --git a/dist/assets/examples/hi/33_Sound/06_Manipulate_Sound.js b/dist/assets/examples/hi/33_Sound/06_Manipulate_Sound.js new file mode 100644 index 0000000000..3a6f0e8677 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/06_Manipulate_Sound.js @@ -0,0 +1,49 @@ +/* + * @name प्लेबैक दर + * @description

एक साउंडफाइल लोड करें और इसकी प्लेबैक दर को इस पर मैप करें + * माउसवाई, वॉल्यूम टू माउसएक्स। प्लेबैक दर गति के साथ है + * जो वेब ऑडियो संदर्भ ध्वनि फ़ाइल जानकारी को संसाधित करता है। + * धीमी दरें न केवल ध्वनि की अवधि को बढ़ाती हैं, बल्कि + * पिच को कम करें क्योंकि इसे धीमी आवृत्ति पर वापस खेला जा रहा है।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।< /p> + */ +// एक ध्वनि फ़ाइल वस्तु +let song; + +function preload() { + // एक ध्वनि फ़ाइल लोड करें + song = loadSound('assets/Damscray_DancingTiger.mp3'); +} + +function setup() { + createCanvas(710, 400); + + // ध्वनि को हमेशा के लिए लूप करें + // (ठीक है, कम से कम स्टॉप () कहा जाता है) + song.loop(); +} + +function draw() { + background(200); + + // वॉल्यूम को 0 और 1.0 . के बीच की सीमा पर सेट करें + let volume = map(mouseX, 0, width, 0, 1); + volume = constrain(volume, 0, 1); + song.amp(volume); + + // दर को 0.1 और 4 . के बीच की सीमा पर सेट करें + // दर बदलने से पिच बदल जाती है + let speed = map(mouseY, 0.1, height, 0, 2); + speed = constrain(speed, 0.01, 4); + song.rate(speed); + + // क्या हो रहा है यह दिखाने के लिए कुछ मंडल बनाएं + stroke(0); + fill(51, 100); + ellipse(mouseX, 100, 48, 48); + stroke(0); + fill(51, 100); + ellipse(100, mouseY, 48, 48); +} diff --git a/dist/assets/examples/hi/33_Sound/07_Amplitude_Analysis.js b/dist/assets/examples/hi/33_Sound/07_Amplitude_Analysis.js new file mode 100644 index 0000000000..01dec46bc8 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/07_Amplitude_Analysis.js @@ -0,0 +1,50 @@ +/** + * @name मापने वाला आयाम + * @description

ध्वनि के आयाम का विश्लेषण करें + * p5.आयाम।

+ * + *

आयाम कंपन का परिमाण है। ध्वनि कंपन है, + * इसलिए इसका आयाम आयतन / प्रबलता से निकटता से संबंधित है।

+ * + *

getLevel() विधि एक सरणी लेती है + * एक छोटी अवधि (1024 नमूने) में एकत्र किए गए आयाम मानों का। + * फिर यह इन मानों का रूट मीन स्क्वायर (RMS) लौटाता है।

+ * + *

डिजिटल ऑडियो के लिए मूल आयाम मान -1.0 और 1.0 के बीच हैं। + * लेकिन आरएमएस हमेशा सकारात्मक रहेगा, क्योंकि यह चुकता है। + * और, तात्कालिक आयाम रीडिंग का उपयोग करने के बजाय, जिन्हें एक दर पर नमूना लिया जाता है + * प्रति सेकंड ४४,१०० बार, आरएमएस समय के साथ औसत है (इस मामले में १०२४ नमूने), + * जो बेहतर ढंग से दर्शाता है कि हम आयाम कैसे सुनते हैं। + *

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ +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); +} diff --git a/dist/assets/examples/hi/33_Sound/08_Noise_Envelope.js b/dist/assets/examples/hi/33_Sound/08_Noise_Envelope.js new file mode 100644 index 0000000000..e92d67f842 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/08_Noise_Envelope.js @@ -0,0 +1,54 @@ +/** + * @name शोर ड्रम लिफाफा + * @description

श्वेत शोर समान ऊर्जा वाला एक यादृच्छिक ऑडियो संकेत है + * फ़्रीक्वेंसी स्पेक्ट्रम के हर हिस्से पर

+ * + *

एक लिफाफा फीका पड़ने की एक श्रृंखला है, परिभाषित + * समय / मान जोड़े के रूप में।

+ * + *

इस उदाहरण में, p5.Env + * p5 को "प्ले" करने के लिए इस्तेमाल किया जाएगा। इसके आउटपुट को नियंत्रित करके ड्रम की तरह शोर + * आयाम। A p5. आयाम स्केच में सभी ध्वनि का स्तर प्राप्त करेगा, और + * हम इस मान का उपयोग एक हरे रंग का आयत बनाने के लिए करेंगे जो लिफाफा दिखाता है + * कार्रवाई में।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी और a + * ध्वनि फ़ाइल।

+ */ +let noise, env, analyzer; + +function setup() { + createCanvas(710, 200); + noise = new p5.Noise(); // अन्य प्रकारों में 'भूरा' और 'गुलाबी' शामिल हैं + noise.start(); + + // शोर की मात्रा को 0 . से गुणा करें + // (जब तक हम शोर करने के लिए तैयार न हों तब तक इसे शांत रखें!) + noise.amp(0); + + env = new p5.Env(); + // सेट अटैकटाइम, डिकेटाइम, सस्टेनरैटियो, रिलीजटाइम + env.setADSR(0.001, 0.1, 0.2, 0.1); + // अटैकलेवल सेट करें, रिलीजलेवल + env.setRange(1, 0); + + // p5. आयाम स्केच में सभी ध्वनि का विश्लेषण करेगा + // जब तक कि इनपुट निर्दिष्ट करने के लिए setInput () विधि का उपयोग नहीं किया जाता है। + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // p5 से वॉल्यूम रीडिंग प्राप्त करें। आयाम विश्लेषक + let level = analyzer.getLevel(); + + // हरे रंग की आयत बनाने के लिए स्तर का उपयोग करें + 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/dist/assets/examples/hi/33_Sound/09_Note_Envelope.js b/dist/assets/examples/hi/33_Sound/09_Note_Envelope.js new file mode 100644 index 0000000000..1c2ba4bcf6 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/09_Note_Envelope.js @@ -0,0 +1,61 @@ +/** + * @name नोट लिफाफा + * @description

एक लिफाफा फीका पड़ने की एक श्रृंखला है, परिभाषित + * समय / मूल्य जोड़े के रूप में। इस उदाहरण में, लिफाफा + * आउटपुट को नियंत्रित करके किसी नोट को "प्ले" करने के लिए उपयोग किया जाएगा + * एक थरथरानवाला का आयाम।

+ * p5.Oscillator इसके माध्यम से अपना आउटपुट भेजता है + * एक आंतरिक वेब ऑडियो GainNode (p5.Oscillator.output)। + * डिफ़ॉल्ट रूप से, उस नोड का निरंतर मान 0.5 होता है। यह + * osc.amp() विधि से रीसेट करें। या, इस उदाहरण में, an + * लिफाफा आयाम को मोड़ते हुए उस नोड को नियंत्रित करता है + * वॉल्यूम नॉब की तरह ऊपर और नीचे।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी और a + * ध्वनि फ़ाइल।

+ */ +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(); + + // लिफाफे को तुरंत चालू करें + envelope = new p5.Env(); + + // सेट अटैकटाइम, डिकेटाइम, सस्टेनरैटियो, रिलीजटाइम + envelope.setADSR(0.001, 0.5, 0.1, 0.5); + + // अटैकलेवल सेट करें, रिलीजलेवल + 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; + } + + // प्लॉट FFT.analyze () कैनवास पर आवृत्ति विश्लेषण + 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/dist/assets/examples/hi/33_Sound/10_Oscillator_Waveform.js b/dist/assets/examples/hi/33_Sound/10_Oscillator_Waveform.js new file mode 100644 index 0000000000..6b49a56e49 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/10_Oscillator_Waveform.js @@ -0,0 +1,40 @@ +/* + * @name थरथरानवाला आवृत्ति + * @description

ऑसिलेटर को नियंत्रित करें और FFT का उपयोग करके तरंग देखें। + * माउसएक्स को फ़्रीक्वेंसी से मैप किया जाता है, माउसवाई को एम्पलीट्यूड में मैप किया जाता है।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी और a + * ध्वनि फ़ाइल।

+ */ +let osc, fft; + +function setup() { + createCanvas(720, 256); + + osc = new p5.TriOsc(); // आवृत्ति और प्रकार सेट करें + osc.amp(0.5); + + fft = new p5.FFT(); + osc.start(); +} + +function draw() { + background(255); + + let waveform = fft.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(); + + // माउसएक्स के आधार पर थरथरानवाला आवृत्ति बदलें + 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/dist/assets/examples/hi/33_Sound/11_Live_Input.js b/dist/assets/examples/hi/33_Sound/11_Live_Input.js new file mode 100644 index 0000000000..b8cb836bb8 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/11_Live_Input.js @@ -0,0 +1,36 @@ +/** + * @name Mic Input + * @description

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.

+ */ +let mic; + +function setup() { + createCanvas(710, 200); + + // एक ऑडियो इनपुट बनाएं + mic = new p5.AudioIn(); + + // ऑडियो इनपुट शुरू करें। + // डिफ़ॉल्ट रूप से, यह .connect() (कंप्यूटर स्पीकर के लिए) नहीं करता है + mic.start(); +} + +function draw() { + background(200); + + // कुल मात्रा प्राप्त करें (0 और 1.0 के बीच) + let vol = mic.getLevel(); + fill(127); + stroke(0); + + // आयतन के आधार पर ऊंचाई के साथ एक दीर्घवृत्त बनाएं + let h = map(vol, 0, 1, height, 0); + ellipse(width / 2, h - 25, 50, 50); +} diff --git a/dist/assets/examples/hi/33_Sound/12_FFT_Spectrum.js b/dist/assets/examples/hi/33_Sound/12_FFT_Spectrum.js new file mode 100644 index 0000000000..098e1247c8 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/12_FFT_Spectrum.js @@ -0,0 +1,30 @@ +/** + * @name फ्रीक्वेंसी स्पेक्ट्रम Spec + * @description

लाइव ऑडियो इनपुट के फ़्रीक्वेंसी स्पेक्ट्रम की कल्पना करें।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * और एक चालू स्थानीय सर्वर।

+ */ +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/dist/assets/examples/hi/33_Sound/13_Mic_Threshold.js b/dist/assets/examples/hi/33_Sound/13_Mic_Threshold.js new file mode 100644 index 0000000000..341215ba1b --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/13_Mic_Threshold.js @@ -0,0 +1,49 @@ +/** + * @name माइक थ्रेशोल्ड + * @description

ऑडियो इनपुट होने पर एक ईवेंट ट्रिगर करें (एक आयत बनाएं)) + * वॉल्यूम एक सीमा से अधिक है।

+ *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * और एक चालू स्थानीय सर्वर।

+ */ +// लर्निंग प्रोसेसिंग से अनुकूलित, डैनियल शिफमैन +// Learningprocessing.com +let input; +let analyzer; + +function setup() { + createCanvas(710, 200); + background(255); + + // एक ऑडियो इनपुट बनाएं + input = new p5.AudioIn(); + + input.start(); +} + +function draw() { + // कुल मात्रा प्राप्त करें (0 और 1.0 के बीच) + let volume = input.getLevel(); + + // यदि वॉल्यूम> 0.1, एक यादृच्छिक स्थान पर एक रेक्ट खींचा जाता है। + // वॉल्यूम जितना बड़ा होगा, आयत उतना ही बड़ा होगा। + let threshold = 0.1; + if (volume > threshold) { + stroke(0); + fill(0, 100); + rect(random(40, width), random(height), volume * 50, volume * 50); + } + + // थ्रेशोल्ड पर समग्र संभावित आयतन, w / एक रेखा का ग्राफ़ + let y = map(volume, 0, 1, height, 0); + let ythreshold = map(threshold, 0, 1, height, 0); + + noStroke(); + fill(175); + rect(0, 0, 20, height); + // फिर ग्राफ़ पर एक आयत बनाएं, जिसका आकार आयतन के अनुसार हो + fill(0); + rect(0, y, 20, y); + stroke(0); + line(0, ythreshold, 19, ythreshold); +} diff --git a/dist/assets/examples/hi/33_Sound/14_Filter_LowPass.js b/dist/assets/examples/hi/33_Sound/14_Filter_LowPass.js new file mode 100644 index 0000000000..0480b4b3ea --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/14_Filter_LowPass.js @@ -0,0 +1,62 @@ +/** + * @name फ़िल्टर लोपास + * @description p5.LowPass फ़िल्टर को p5.SoundFile पर लागू करें। + * एफएफटी के साथ ध्वनि की कल्पना करें। + * फ़िल्टर की कटऑफ आवृत्ति के लिए माउसX को मैप करें + * और माउसवाई बैंडपास फिल्टर की प्रतिध्वनि/चौड़ाई के लिएY + * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ +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(); + + // मास्टर आउटपुट से साउंडफाइल को डिस्कनेक्ट करें। + // फिर, इसे फ़िल्टर से कनेक्ट करें, ताकि हम केवल फ़िल्टर की गई ध्वनि सुन सकें + soundFile.disconnect(); + soundFile.connect(filter); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // माउसX को न्यूनतम से कटऑफ आवृत्ति पर मैप करें + // आवृत्ति (10 हर्ट्ज) से उच्चतम (22050 हर्ट्ज) जो मनुष्य सुन सकते हैं + filterFreq = map(mouseX, 0, width, 10, 22050); + + // मानचित्र माउसY कटऑफ आवृत्ति पर प्रतिध्वनि (वॉल्यूम बूस्ट) के लिए + filterRes = map(mouseY, 0, height, 15, 5); + + // set filter parameters + filter.set(filterFreq, filterRes); + + // एफएफटी स्पेक्ट्रम विश्लेषण में हर मूल्य ड्रा करें जहां + // x = निम्नतम (10 हर्ट्ज) से उच्चतम (22050 हर्ट्ज) आवृत्तियों, + // h = उस आवृत्ति पर ऊर्जा (आयाम / आयतन) + 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/dist/assets/examples/hi/33_Sound/15_Filter_BandPass.js b/dist/assets/examples/hi/33_Sound/15_Filter_BandPass.js new file mode 100644 index 0000000000..7285e2d040 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/15_Filter_BandPass.js @@ -0,0 +1,51 @@ +/** + * @name फ़िल्टर बैंडपास + * @description सफेद शोर के लिए p5.BandPass फ़िल्टर लागू करें। + * एफएफटी के साथ ध्वनि की कल्पना करें। + * मैप माउसX को बैंडपास फ़्रीक्वेंसी के लिए + * और माउसवाई बैंडपास फिल्टर की प्रतिध्वनि/चौड़ाई के लिएY + * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ +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(); // मास्टर आउटपुट से साउंडफाइल को डिस्कनेक्ट करें ... + filter.process(noise); // ... और फ़िल्टर से कनेक्ट करें ताकि हम केवल बैंडपास सुन सकें। + noise.start(); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // FFT स्पेक्ट्रम रेंज से एक बैंडपास फ्रीक के लिए माउसX को मैप करें: 10Hz - 22050Hz + filterFreq = map(mouseX, 0, width, 10, 22050); + // मानचित्र माउसY प्रतिध्वनि/चौड़ाई के लिए + filterWidth = map(mouseY, 0, height, 0, 90); + // फ़िल्टर पैरामीटर सेट करें + filter.set(filterFreq, filterWidth); + + // एफएफटी स्पेक्ट्रम विश्लेषण में हर मूल्य ड्रा करें जहां + // x = निम्नतम (10 हर्ट्ज) से उच्चतम (22050 हर्ट्ज) आवृत्तियों, + // एच = उस आवृत्ति पर ऊर्जा / आयाम + 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/dist/assets/examples/hi/33_Sound/16_Delay.js b/dist/assets/examples/hi/33_Sound/16_Delay.js new file mode 100644 index 0000000000..fd24f0cbe4 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/16_Delay.js @@ -0,0 +1,56 @@ +/** + * @name देरी + * @description + * p5 सुनने के लिए माउस क्लिक करें। साउंडफाइल को प्रोसेस करने में देरी करें। + * MouseX p5.Delay फ़िल्टर फ़्रीक्वेंसी को नियंत्रित करता है। + * MouseY p5.Delay Time और Resonance दोनों को नियंत्रित करता है। + * एक आयाम वस्तु के साथ परिणामी ध्वनि की मात्रा की कल्पना करें। + * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ + +let soundFile, analyzer, delay; + +function preload() { + soundFormats('ogg', 'mp3'); + soundFile = loadSound('assets/beatbox.mp3'); +} + +function setup() { + createCanvas(710, 400); + + soundFile.disconnect(); // तो हम केवल देरी सुनेंगे + + delay = new p5.Delay(); + delay.process(soundFile, 0.12, 0.7, 2300); + delay.setType('pingPong'); // एक स्टीरियो प्रभाव + + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // p5 से वॉल्यूम रीडिंग प्राप्त करें। आयाम विश्लेषक + let level = analyzer.getLevel(); + + // हरे रंग की आयत बनाने के लिए स्तर का उपयोग करें + 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/dist/assets/examples/hi/33_Sound/17_Reverb.js b/dist/assets/examples/hi/33_Sound/17_Reverb.js new file mode 100644 index 0000000000..26e7713d4c --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/17_Reverb.js @@ -0,0 +1,36 @@ +/** + * @name रेवरब + * @description Reverb ध्वनि को गहराई और कथित स्थान देता है। यहाँ, + * शोर reverb के साथ संसाधित किया जाता है। + * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ +let sound, reverb; + +function preload() { + soundFormats('mp3', 'ogg'); + soundFile = loadSound('assets/Damscray_DancingTiger'); + + // डिफ़ॉल्ट कनेक्शन को डिस्कनेक्ट करें + // ताकि हम केवल ध्वनि को reverb.process के माध्यम से सुनें + soundFile.disconnect(); +} + +function setup() { + createCanvas(720, 100); + background(0); + + reverb = new p5.Reverb(); + + // सोननेक्ट्स साउंडफाइल a with के साथ रीवरब करने के लिए + // reverb 6 सेकंड का समय, 0.2% की क्षय दर + reverb.process(soundFile, 6, 0.2); + + reverb.amp(4); // और बढ़ाओ! +} + +function mousePressed() { + soundFile.play(); +} diff --git a/dist/assets/examples/hi/33_Sound/18_Convolution_Reverb.js b/dist/assets/examples/hi/33_Sound/18_Convolution_Reverb.js new file mode 100644 index 0000000000..43390c4ac5 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/18_Convolution_Reverb.js @@ -0,0 +1,87 @@ +/** + * @name कनवल्शन रेवरब + * @description

p5.Convolver वास्तविक ध्वनि को फिर से बना सकता है + * कनवल्शन का उपयोग करके रिक्त स्थान। कनवल्शन एक आवेग प्रतिक्रिया लेता है, + * (एक कमरे की आवाज़ गूंजती है), और इसका उपयोग करता है + * उस स्थान की ध्वनि को फिर से बनाएं।

किसी ध्वनि को चलाने के लिए क्लिक करें + * संकल्प। हर बार जब आप क्लिक करते हैं, तो ध्वनि संकुचित हो जाती है + * एक अलग आवेग प्रतिक्रिया। इंपल्स रिस्पांस को ही सुनने के लिए, + * कोई भी कुंजी दबाएं।

+ * + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर। + * ये कनवल्शन नमूने Creative Commons BY . हैं + * + * रिकॉर्डिंगहॉपकिंस

+ */ +let sound, env, cVerb, fft; +let currentIR = 0; +let rawImpulse; + +function preload() { + // हमने सभी आवेगों / ध्वनियों के एमपी 3 और ओजीजी दोनों संस्करणों को शामिल किया है + soundFormats('ogg', 'mp3'); + + // एक p5.Convolver बनाएं + cVerb = createConvolver('assets/bx-spring'); + + // bx-spring के अलावा cVerb.impulses ऐरे में इंपल्स रिस्पॉन्स जोड़ें + cVerb.addImpulse('assets/small-plate'); + cVerb.addImpulse('assets/drum'); + cVerb.addImpulse('assets/beatbox'); + cVerb.addImpulse('assets/concrete-tunnel'); + + // एक ध्वनि लोड करें जिसे p5.ConvultionReverb द्वारा संसाधित किया जाएगा + sound = loadSound('assets/Damscray_DancingTiger'); +} + +function setup() { + createCanvas(710, 400); + rawImpulse = loadSound('assets/' + cVerb.impulses[currentIR].name); + + // मास्टर आउटपुट से डिस्कनेक्ट करें ... + sound.disconnect(); + // ... और cVerb . के साथ प्रक्रिया करें + // ताकि हम केवल reverb सुनें + cVerb.process(sound); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + fill(0, 255, 40); + + 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); + } +} + +function mousePressed() { + // cVerb.impulses की सरणी के माध्यम से चक्र + currentIR++; + if (currentIR >= cVerb.impulses.length) { + currentIR = 0; + } + cVerb.toggleImpulse(currentIR); + + // आवेग के माध्यम से ध्वनि बजाएं + sound.play(); + + // वर्तमान आवेग प्रतिक्रिया नाम प्रदर्शित करें (फ़ाइलपथ) + println('Convolution Impulse Response: ' + cVerb.impulses[currentIR].name); + + rawImpulse.setPath('assets/' + cVerb.impulses[currentIR].name); +} + +// आवेग खेलें (बिना दृढ़ संकल्प के) +function keyPressed() { + rawImpulse.play(); +} diff --git a/dist/assets/examples/hi/33_Sound/19_Record_Save.js b/dist/assets/examples/hi/33_Sound/19_Record_Save.js new file mode 100644 index 0000000000..9cee1ee715 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/19_Record_Save.js @@ -0,0 +1,58 @@ +/** + * @name रिकॉर्ड ऑडियो सहेजें + * @description एक ध्वनि रिकॉर्ड करें, इसे वापस चलाएं और सहेजें + * यह क्लाइंट के कंप्यूटर पर .wav फ़ाइल के रूप में। + * हमें तीन वस्तुओं की आवश्यकता है: एक p5.ऑडियोइन (माइक / ध्वनि स्रोत), + * p5.SoundRecorder (ध्वनि रिकॉर्ड करता है), और a + * p5.SoundFile (प्ले बैक / सेव)। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.sound लाइब्रेरी + * एक ध्वनि फ़ाइल, और एक चल रहा स्थानीय सर्वर।

+ */ +let mic, recorder, soundFile; + +let state = 0; // माउसप्रेस रिकॉर्ड, स्टॉप, प्ले से बढ़ेगा + +function setup() { + createCanvas(400, 400); + background(200); + fill(0); + text('Enable mic and click the mouse to begin recording', 20, 20); + + // में एक ऑडियो बनाएं + mic = new p5.AudioIn(); + + // उपयोगकर्ताओं को ठीक से काम करने के लिए रिकॉर्डिंग के लिए अपने ब्राउज़र माइक्रोफ़ोन को मैन्युअल रूप से सक्षम करना होगा! + mic.start(); + + // एक साउंड रिकॉर्डर बनाएं + recorder = new p5.SoundRecorder(); + + // माइक को रिकॉर्डर से कनेक्ट करें + recorder.setInput(mic); + + // एक खाली ध्वनि फ़ाइल बनाएं जिसका उपयोग हम रिकॉर्डिंग को प्लेबैक करने के लिए करेंगे + soundFile = new p5.SoundFile(); +} + +function mousePressed() { + // यह सुनिश्चित करने के लिए '.सक्षम' बूलियन का उपयोग करें कि उपयोगकर्ता ने माइक को सक्षम किया है (अन्यथा हम मौन रिकॉर्ड करेंगे) + if (state === 0 && mic.enabled) { + // रिकॉर्डर को p5.SoundFile पर रिकॉर्ड करने के लिए कहें, जिसका उपयोग हम प्लेबैक के लिए करेंगे + recorder.record(soundFile); + + background(255, 0, 0); + text('Recording now! Click to stop.', 20, 20); + state++; + } else if (state === 1) { + recorder.stop(); // रिकॉर्डर को रोकें, और परिणाम को साउंडफाइल पर भेजें + + background(0, 255, 0); + text('Recording stopped. Click to play & save', 20, 20); + state++; + } else if (state === 2) { + soundFile.play(); // परिणाम खेलें! + saveSound(soundFile, 'mySound.wav'); // फाइल सुरक्षित करें + state++; + } +} diff --git a/dist/assets/examples/hi/33_Sound/21_FreqModulation.js b/dist/assets/examples/hi/33_Sound/21_FreqModulation.js new file mode 100644 index 0000000000..1fb84a8ea0 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/21_FreqModulation.js @@ -0,0 +1,148 @@ +/** + * @name फ़्रीक्वेंसी मॉडुलन + * @description

फ़्रीक्वेंसी मॉडुलन संश्लेषण का एक शक्तिशाली रूप है। + * अपने सरलतम रूप में, FM में दो ऑसिलेटर शामिल होते हैं, जिन्हें संदर्भित किया जाता है + * वाहक और न्यूनाधिक के रूप में। जैसा कि न्यूनाधिक का तरंग दोलन करता है + * कुछ न्यूनतम और अधिकतम आयाम मान के बीच, वह क्षणिक मान + * वाहक की आवृत्ति ("मॉड्यूलेट") में जोड़ा जाता है।

+ *

वाहक को आमतौर पर श्रव्य आवृत्ति पर दोलन करने के लिए सेट किया जाता है + * जिसे हम एक पिच के रूप में देखते हैं - इस मामले में, यह 220Hz पर एक साइन वेव थरथरानवाला है, + * "A3" नोट के बराबर। वाहक डिफ़ॉल्ट रूप से मास्टर आउटपुट से जुड़ा होता है + * (यह सभी p5.Oscillators के लिए मामला है)।

+ *

हम मास्टर आउटपुट से मॉड्यूलेटर को डिस्कनेक्ट करेंगे, + * और इसके बजाय वाहक की आवृत्ति से कनेक्ट करें: + * carrier.freq(modulator). यह के आउटपुट आयाम को जोड़ता है + * वाहक की आवृत्ति के लिए न्यूनाधिक।

+ *

+ * मॉड्यूलेशन गहराई बताती है कि वाहक आवृत्ति कितनी संशोधित करेगी। + * यह न्यूनाधिक के आयाम पर आधारित है। + * न्यूनाधिक आयाम मानों की एक सतत धारा उत्पन्न करता है जिसे हम जोड़ेंगे + * वाहक आवृत्ति के लिए। शून्य के आयाम का अर्थ है मौन, इसलिए मॉडुलन होगा + *कोई प्रभाव नहीं पड़ता। 1.0 का एक आयाम आउटपुट मानों की सीमा को मापता है + * +1.0 और -1.0 के बीच। ध्वनि के लिए यह मानक श्रेणी है जिसे भेजा जाता है + * आपके स्पीकर, लेकिन FM में हम इसके बजाय मॉड्यूलेटर के आउटपुट को कैरियर फ़्रीक्वेंसी पर भेज रहे हैं, + * जहां हम मुश्किल से +1Hz / -1Hz मॉडुलन को नोटिस करेंगे। + * तो हम आम तौर पर न्यूनाधिक के आयाम ("गहराई") को बढ़ाकर संख्याओं की तुलना में बहुत अधिक करेंगे + * हम अपने वक्ताओं को भेज सकते हैं।

+ *

मॉड्यूलेशन फ़्रीक्वेंसी मॉडुलन की गति है। जब मॉडुलन आवृत्ति कम होती है + * 20 हर्ट्ज से अधिक, हम इसकी आवृत्ति को पिच के रूप में सुनना बंद कर देते हैं, और इसे धड़कन की लय के रूप में सुनना शुरू कर देते हैं। + * उदाहरण के लिए, एक ऑपरेटिव गायक के "वाइब्रेटो" प्रभाव की नकल करने के लिए 20 की गहराई पर 7.5 हर्ट्ज़ आज़माएं। + * इसके लिए शब्द लो फ़्रीक्वेंसी ऑसिलेटर या एलएफओ है। उच्च आवृत्तियों पर सेट किए गए मॉड्यूलेटर कर सकते हैं + * दिलचस्प प्रभाव भी पैदा करते हैं, खासकर जब आवृत्ति का हार्मोनिक संबंध होता है + * वाहक संकेत के लिए। उदाहरण के लिए, सुनें कि क्या होता है जब न्यूनाधिक की आवृत्ति होती है + * वाहक का आधा या दोगुना। यह जॉन चाउनिंग द्वारा विकसित एफएम सिंथेसिस का आधार है + * 1960 के दशक में, जो 1980 के दशक में संश्लेषण में क्रांति लाने के लिए आया था और अक्सर इसका उपयोग संश्लेषण के लिए किया जाता है + * पीतल और घंटी जैसी आवाजें। + * + *

इस उदाहरण में,

+ * - माउसएक्स -150 से 150 तक मॉड्यूलेशन गहराई (मॉड्यूलेटर का आयाम) को नियंत्रित करता है। + * जब मॉड्यूलेटर का आयाम 0 (बीच में) पर सेट होता है, तो ध्यान दें कि मॉड्यूलेशन कैसे होता है + *कोई प्रभाव नहीं पड़ता। संख्या जितनी अधिक (पूर्ण मान) होगी, प्रभाव उतना ही अधिक होगा। + * यदि मॉड्यूलेटर तरंग एक वर्ग [] की तरह सममित है, तो साइन ~ + * या त्रिभुज /\, ऋणात्मक आयाम धनात्मक आयाम के समान होगा। + * लेकिन इस उदाहरण में, न्यूनाधिक एक विषम चूरा तरंग है, जिसका आकार इस प्रकार है /। + * जब हम इसे किसी ऋणात्मक संख्या से गुणा करते हैं, तो यह इस प्रकार पीछे की ओर जाती है। सबसे अच्छा के लिए + * अंतर देखें, आवृत्ति कम करने का प्रयास करें। + *

+ *

- MouseY न्यूनाधिक की आवृत्ति को 0 से 112 Hz तक नियंत्रित करता है। + * श्रव्य सीमा के नीचे मॉड्यूलेशन आवृत्तियों की तुलना करने का प्रयास करें (जो लगभग 20 हर्ट्ज से शुरू होता है), + * और इसके ऊपर, विशेष रूप से वाहक आवृत्ति के लिए एक हार्मोनिक संबंध में (जो कि 220hz है, इसलिए + * आधा प्रयास करें, 1/3, 1/4 आदि...)। + * + *

आपको इसमें शामिल करना होगा + * p5.sound लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए।

+ */ + +let carrier; // यह थरथरानवाला है जिसे हम सुनेंगे +let modulator; // यह थरथरानवाला वाहक की आवृत्ति को नियंत्रित करेगा + +let analyzer; // हम इसका उपयोग तरंग की कल्पना करेंगे + +// वाहक आवृत्ति पूर्व-मॉड्यूलेशन +let carrierBaseFreq = 220; + +// न्यूनाधिक के लिए न्यूनतम/अधिकतम रेंजmax +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); // आयाम सेट करें + carrier.freq(carrierBaseFreq); // आवृत्ति सेट करें + carrier.start(); // हिलना शुरू करें + + // प्रकार को 'वर्ग', 'साइन' या 'त्रिकोण' में बदलने का प्रयास करें + modulator = new p5.Oscillator('sawtooth'); + modulator.start(); + + // वाहक की आवृत्ति को संशोधित करने के लिए मॉड्यूलेटर का आउटपुट जोड़ें + modulator.disconnect(); + carrier.freq(modulator); + + // ऑडियो का विश्लेषण करने के लिए एक FFT बनाएं + analyzer = new p5.FFT(); + + // माउसओवर / टच स्टार्ट पर वाहक को अंदर / बाहर फीका करें + toggleAudio(cnv); +} + +function draw() { + background(30); + + // मैप माउसY अधिकतम और न्यूनतम आवृत्ति के बीच न्यूनाधिक आवृत्ति के लिए + let modFreq = map(mouseY, height, 0, modMinFreq, modMaxFreq); + modulator.freq(modFreq); + + // न्यूनाधिक के आयाम को बदलें + // नकारात्मक amp चूरा तरंग को उलट देता है, और टक्कर लगता है + // + let modDepth = map(mouseX, 0, width, modMinDepth, modMaxDepth); + modulator.amp(modDepth); + + // तरंग का विश्लेषण करें + waveform = analyzer.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); + // क्या हो रहा है इसके बारे में एक नोट जोड़ें + 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 + ); +} + +// ध्वनि को टॉगल करने के लिए सहायक कार्य +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); + }); +} diff --git a/dist/assets/examples/hi/33_Sound/22_AmplitudeModulation.js b/dist/assets/examples/hi/33_Sound/22_AmplitudeModulation.js new file mode 100644 index 0000000000..c9b15f7003 --- /dev/null +++ b/dist/assets/examples/hi/33_Sound/22_AmplitudeModulation.js @@ -0,0 +1,95 @@ +/** + * @name आयाम मॉडुलन + * @description

एम्पलीट्यूड मॉड्यूलेशन में दो ऑसिलेटर शामिल होते हैं, जिन्हें संदर्भित किया जाता है + * वाहक और न्यूनाधिक के रूप में, जहाँ न्यूनाधिक नियंत्रित करता है + * वाहक का आयाम।

+ * + *

वाहक आमतौर पर एक श्रव्य आवृत्ति (यानी 440 हर्ट्ज) पर सेट होता है + * और डिफ़ॉल्ट रूप से मास्टर आउटपुट से जुड़ा है। वाहक.amp है + * शून्य पर सेट करें क्योंकि हमारे पास मॉड्यूलेटर इसके आयाम को नियंत्रित करेगा।

+ * + *

मॉड्यूलेटर मास्टर आउटपुट से डिस्कनेक्ट हो गया है। इसके बजाय, यह जुड़ा हुआ है + * कैरियर के आयाम तक, इस तरह:वाहक.amp(मॉड्यूलेटर)।

+ * + *

इस उदाहरण में...

+ *

- MouseX न्यूनाधिक के आयाम को नियंत्रित करता है + * 0 से 1 तक। जब न्यूनाधिक का आयाम 0 पर सेट होता है, तो + * आयाम मॉडुलन का कोई प्रभाव नहीं पड़ता है।

+ * + *

- MouseY न्यूनाधिक की आवृत्ति को 0 से 20hz तक नियंत्रित करता है। + * यह रेंज मनुष्यों की तुलना में कम आवृत्तियों की है, और हम अनुभव करते हैं + * एक लय के रूप में मॉडुलन। यह श्रेणी ट्रेमोलो जैसे प्रभावों का अनुकरण कर सकती है। + * रिंग मॉड्यूलेशन एक प्रकार का एम्प्लीट्यूड मॉड्यूलेशन है जहां मूल + * वाहक संकेत मौजूद नहीं है, और अक्सर तेजी से मॉडुलन शामिल होता है + * आवृत्ति।

+ * + *

आपको इसमें शामिल करना होगा + * p5.sound लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए।

+ */ +let carrier; // यह थरथरानवाला है जिसे हम सुनेंगे +let modulator; // यह थरथरानवाला वाहक के आयाम को संशोधित करेगा +let fft; // हम तरंग की कल्पना करेंगे + +function setup() { + createCanvas(800, 400); + noFill(); + background(30); // अल्फा + + carrier = new p5.Oscillator(); // डिफ़ॉल्ट रूप से मास्टर आउटपुट से जुड़ता है + carrier.freq(340); + carrier.amp(0); + // वाहक का amp डिफ़ॉल्ट रूप से 0 है, हमारे न्यूनाधिक को कुल नियंत्रण देता है + + carrier.start(); + + modulator = new p5.Oscillator('triangle'); + modulator.disconnect(); // मास्टर आउटपुट से मॉड्यूलेटर को डिस्कनेक्ट करें + modulator.freq(5); + modulator.amp(1); + modulator.start(); + + // न्यूनाधिक के साथ वाहक के आयाम को संशोधित करें + // वैकल्पिक रूप से, हम सिग्नल को स्केल कर सकते हैं। + carrier.amp(modulator.scale(-1, 1, 1, -1)); + + // ऑडियो का विश्लेषण करने के लिए एक fft बनाएं + fft = new p5.FFT(); +} + +function draw() { + background(30, 30, 30, 100); // अल्फा + + // माउसY को 0 और 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); // चिकनी लुप्त होती के लिए 0.1 का फीका समय fade + + // तरंग का विश्लेषण करें + waveform = fft.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); +} diff --git a/dist/assets/examples/hi/35_Mobile/00_Acceleration_Ball_Bounce.js b/dist/assets/examples/hi/35_Mobile/00_Acceleration_Ball_Bounce.js new file mode 100644 index 0000000000..1f5c186208 --- /dev/null +++ b/dist/assets/examples/hi/35_Mobile/00_Acceleration_Ball_Bounce.js @@ -0,0 +1,58 @@ +/* + * @name एक्सेलेरेशन बॉल बाउंस + * @description त्वरणX और त्वरणY मानों के आधार पर एक दीर्घवृत्त को इधर-उधर घुमाएँ, और कैनवास के किनारे को छूने पर उछलता है। + */ + +// स्थिति चर +let x = 0; +let y = 0; + +// गति वेग +let vx = 0; +let vy = 0; + +// त्वरण +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; + + // कैनवास के किनारे को छूने पर उछलें + 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/dist/assets/examples/hi/35_Mobile/01_Simple_Draw.js b/dist/assets/examples/hi/35_Mobile/01_Simple_Draw.js new file mode 100644 index 0000000000..b558da7f27 --- /dev/null +++ b/dist/assets/examples/hi/35_Mobile/01_Simple_Draw.js @@ -0,0 +1,15 @@ +/* + * @name सिंपल ड्रा + * @description mouseX, mouseY, pmouseX, और pmouseY मानों का उपयोग करके स्क्रीन पर ड्रा करने के लिए स्पर्श करें। + */ + +function setup() { + createCanvas(displayWidth, displayHeight); + strokeWeight(10); + stroke(0); +} + +function touchMoved() { + line(mouseX, mouseY, pmouseX, pmouseY); + return false; +} diff --git a/dist/assets/examples/hi/35_Mobile/02_Acceleration_Color.js b/dist/assets/examples/hi/35_Mobile/02_Acceleration_Color.js new file mode 100644 index 0000000000..25ce60604f --- /dev/null +++ b/dist/assets/examples/hi/35_Mobile/02_Acceleration_Color.js @@ -0,0 +1,24 @@ +/* + * @name त्वरण रंग + * @description डिवाइस को घुमाए जाने का पता लगाने के लिए deviceMoved() का उपयोग करें। पृष्ठभूमि आरजीबी रंग मान एक्सेलेरेशन एक्स, एक्सेलेरेशन वाई, और एक्सेलेरेशन जेड मानों पर मैप किए जाते हैं। + */ + +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/dist/assets/examples/hi/35_Mobile/03_Shake_Ball_Bounce.js b/dist/assets/examples/hi/35_Mobile/03_Shake_Ball_Bounce.js new file mode 100644 index 0000000000..a2ccf26b51 --- /dev/null +++ b/dist/assets/examples/hi/35_Mobile/03_Shake_Ball_Bounce.js @@ -0,0 +1,114 @@ +/* + * @name शेक बॉल बाउंस + * @description एक बॉल क्लास बनाएं, कई ऑब्जेक्ट्स को इंस्टेंट करें, इसे स्क्रीन के चारों ओर घुमाएं, और कैनवास के किनारे को छूने पर बाउंस करें। + * त्वरणX और त्वरण में कुल परिवर्तन के आधार पर शेक घटना का पता लगाएं और पता लगाने के आधार पर वस्तुओं को गति दें या धीमा करें। + */ + +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/dist/assets/examples/hi/35_Mobile/04_Tilted_3D_Box.js b/dist/assets/examples/hi/35_Mobile/04_Tilted_3D_Box.js new file mode 100644 index 0000000000..45e5b29d63 --- /dev/null +++ b/dist/assets/examples/hi/35_Mobile/04_Tilted_3D_Box.js @@ -0,0 +1,15 @@ +/* + * @name झुका हुआ 3D बॉक्स + * @description बॉक्स को झुकाने के लिए मोबाइल का इस्तेमाल करें + */ +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/dist/assets/examples/hi/90_Hello_P5/01_shapes.js b/dist/assets/examples/hi/90_Hello_P5/01_shapes.js new file mode 100644 index 0000000000..7b7702c953 --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/01_shapes.js @@ -0,0 +1,28 @@ +/* + * @name सरल आकार + * @description इस उदाहरण में एक वृत्त, वर्ग, त्रिभुज और एक फूल शामिल है। + */ +function setup() { + // कैनवास बनाएं + createCanvas(720, 400); + background(200); + + // रंग सेट करें + fill(204, 101, 192, 127); + stroke(127, 63, 120); + + // एक चतुर्भुज + rect(40, 120, 120, 40); + // एक दीर्घवृत्त + ellipse(240, 240, 80, 80); + // एक त्रिभुज + triangle(300, 100, 320, 100, 310, 80); + + // एक साधारण फूल के लिए एक डिजाइन + translate(580, 200); + noStroke(); + for (let i = 0; i < 10; i ++) { + ellipse(0, 30, 20, 80); + rotate(PI/5); + } +} diff --git a/dist/assets/examples/hi/90_Hello_P5/02_interactivity.js b/dist/assets/examples/hi/90_Hello_P5/02_interactivity.js new file mode 100644 index 0000000000..9d2c07f1f3 --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/02_interactivity.js @@ -0,0 +1,40 @@ +/* + * @name अन्तरक्रियाशीलता 1 + * @frame 720,425 + * @description जब आप इस पर क्लिक करते हैं तो सर्कल का रंग बदल जाता है। + *

इस उदाहरण को स्थानीय रूप से चलाने के लिए, आपको इसकी आवश्यकता होगी + * p5.dom लाइब्रेरी। + *

+ */ + +// लाल, और रंग के रंग के लिए +let r, g, b; + +function setup() { + createCanvas(720, 400); + // बेतरतीब ढंग से रंग चुनें + r = random(255); + g = random(255); + b = random(255); +} + +function draw() { + background(127); + // एक चक्र बनाएं + strokeWeight(2); + stroke(r, g, b); + fill(r, g, b, 127); + ellipse(360, 200, 200, 200); +} + +// जब उपयोगकर्ता माउस पर क्लिक करता है +function mousePressed() { + // जांचें कि क्या माउस सर्कल के अंदर है + let d = dist(mouseX, mouseY, 360, 200); + if (d < 100) { + // नए यादृच्छिक रंग मान चुनें + r = random(255); + g = random(255); + b = random(255); + } +} diff --git a/dist/assets/examples/hi/90_Hello_P5/03_interactivity.js b/dist/assets/examples/hi/90_Hello_P5/03_interactivity.js new file mode 100644 index 0000000000..ffed52fa11 --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/03_interactivity.js @@ -0,0 +1,29 @@ +/* + * @name अन्तरक्रियाशीलता 2 + * @frame 720,425 + * @description जब आप स्लाइडर को घुमाते हैं तो वृत्त का रंग बदल जाता है। + * आपको शामिल करने की आवश्यकता होगी + * p5.dom लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए। + */ + +// एक HTML रेंज स्लाइडर +let slider; + +function setup() { + createCanvas(720, 400); + // रंग, संतृप्ति और चमक + colorMode(HSB, 255); + // स्लाइडर में 0 और 255 के बीच की सीमा होती है, जिसका शुरुआती मान 127 . होता है + slider = createSlider(0, 255, 127); +} + +function draw() { + background(127); + strokeWeight(2); + + // स्लाइडर के अनुसार रंग सेट करें + 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/dist/assets/examples/hi/90_Hello_P5/04_animate.js b/dist/assets/examples/hi/90_Hello_P5/04_animate.js new file mode 100644 index 0000000000..0657f9e729 --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/04_animate.js @@ -0,0 +1,33 @@ +/* + * @name एनिमेशन + * @description सर्कल चलता है। + */ +// सर्कल कहां है +let x, y; + +function setup() { + createCanvas(720, 400); + // बीच में शुरू होता है + x = width / 2; + y = height; +} + +function draw() { + background(200); + + // एक चक्र बनाएं + stroke(50); + fill(100); + ellipse(x, y, 24, 24); + + // क्षैतिज अक्ष पर बेतरतीब ढंग से झूलना + x = x + random(-1, 1); + // निरंतर गति से ऊपर जा रहा है + y = y - 1; + + // नीचे की ओर रीसेट करें + if (y < 0) { + y = height; + } +} + diff --git a/dist/assets/examples/hi/90_Hello_P5/04_flocking.js b/dist/assets/examples/hi/90_Hello_P5/04_flocking.js new file mode 100644 index 0000000000..8b3b5a9dfd --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/04_flocking.js @@ -0,0 +1,185 @@ +/* + * @name झुंड + * @description क्रेग रेनॉल्ड्स के "फ्लॉकिंग" व्यवहार का प्रदर्शन।
+ * (नियम: सामंजस्य, पृथक्करण, संरेखण।)
+ * natureofcode.com से। + */ +let boids = []; + +function setup() { + createCanvas(720, 400); + + // सिस्टम में बोलियों का एक प्रारंभिक सेट जोड़ें + for (let i = 0; i < 100; i++) { + boids[i] = new Boid(random(width), random(height)); + } +} + +function draw() { + background(51); + // सभी बोड्स चलाएं + for (let i = 0; i < boids.length; i++) { + boids[i].run(boids); + } +} + +// बोईड क्लास +// पृथक्करण, सामंजस्य, संरेखण के तरीके जोड़े गए +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; // अधिकतम गति + this.maxforce = 0.05; // अधिकतम स्टीयरिंग बल + } + + run(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); + } + + // बल त्वरण में जाते हैं + applyForce(force) { + this.acceleration.add(force); + } + + // हम हर बार तीन नियमों के आधार पर एक नया त्वरण जमा करते हैं + flock(boids) { + let sep = this.separate(boids); // पृथक्करण + let ali = this.align(boids); // संरेखण + let coh = this.cohesion(boids); // सामंजस्य + // मनमाने ढंग से इन ताकतों को तौलें + sep.mult(2.5); + ali.mult(1.0); + coh.mult(1.0); + // बल वैक्टर को त्वरण में जोड़ें + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); + } + + // स्थान अपडेट करने की विधि + update() { + // वेग अपडेट करें + this.velocity.add(this.acceleration); + // सीमा गति + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // प्रत्येक चक्र में त्वरण को 0 पर रीसेट करें + this.acceleration.mult(0); + } + + // एक विधि जो एक लक्ष्य की ओर एक स्टीयरिंग बल की गणना और लागू करती है + // स्टीयर = वांछित माइनस वेलोसिटी + seek(target) { + let desired = p5.Vector.sub(target, this.position); // स्थान से लक्ष्य की ओर इशारा करते हुए एक वेक्टर + // वांछित और स्केल को अधिकतम गति के लिए सामान्यीकृत करें + desired.normalize(); + desired.mult(this.maxspeed); + // संचालन = वांछित शून्य वेग + let steer = p5.Vector.sub(desired, this.velocity); + steer.limit(this.maxforce); // अधिकतम स्टीयरिंग बल तक सीमित करें + return steer; + } + + // एक सर्कल के रूप में बोइड ड्रा करें + render() { + fill(127, 127); + stroke(200); + ellipse(this.position.x, this.position.y, 16, 16); + } + + // चारों ओर लपेट दो + 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; + } + + // पृथक्करण + // विधि आस-पास के boids के लिए जाँच करता है और दूर चला जाता है + separate(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // सिस्टम में प्रत्येक बोड के लिए, जांचें कि क्या यह बहुत करीब है + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + // यदि दूरी 0 से अधिक है और मनमानी राशि से कम है (0 जब आप स्वयं हों) + if ((d > 0) && (d < desiredseparation)) { + // पड़ोसी से दूर की ओर इशारा करते हुए वेक्टर की गणना करें + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // दूरी से वजन + steer.add(diff); + count++; // कितने का ट्रैक रखें + } + } + // औसत -- कितने से विभाजित करें + if (count > 0) { + steer.div(count); + } + + // जब तक वेक्टर 0 . से बड़ा है + if (steer.mag() > 0) { + // रेनॉल्ड्स को लागू करें: संचालन = वांछित - वेग + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; + } + + // संरेखण + // सिस्टम में प्रत्येक आस-पास के बोड के लिए, औसत वेग की गणना करें + 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(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].position); // स्थान जोड़ना + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // स्थान की ओर बढ़ें + } else { + return createVector(0, 0); + } + } +} + diff --git a/dist/assets/examples/hi/90_Hello_P5/05_weather.js b/dist/assets/examples/hi/90_Hello_P5/05_weather.js new file mode 100644 index 0000000000..24f5f25472 --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/05_weather.js @@ -0,0 +1,73 @@ +/* + * @name मौसम + * @frame 720,280 + * @description यह उदाहरण apixu.com से JSON मौसम डेटा प्राप्त करता है। + * आपको शामिल करने की आवश्यकता होगी + * p5.dom लाइब्रेरी + * इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए। +*/ + +// एक हवा की दिशा वेक्टर +let wind; +// सर्कल की स्थिति +let position; + +function setup() { + createCanvas(720, 200); + // apixu.com से डेटा का अनुरोध करें + let url = 'https://api.apixu.com/v1/current.json?key=513d8003c8b348f1a2461629162106&q=NYC'; + loadJSON(url, gotWeather); + // सर्कल बीच में शुरू होता है + position = createVector(width/2, height/2); + // हवा शुरू होती है (0,0) + wind = createVector(); +} + +function draw() { + background(200); + + // यह खंड हवा की दिशा की ओर इशारा करते हुए एक तीर खींचता है + push(); + translate(32, height - 32); + // हवा के कोण से घुमाएं + 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(); + + // हवा की दिशा में आगे बढ़ें + 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 angle = radians(Number(weather.current.wind_degree)); + // हवा की गति प्राप्त करें + let windmag = Number(weather.current.wind_mph); + + // HTML तत्वों के रूप में प्रदर्शित करें + let temperatureDiv = createDiv(floor(weather.current.temp_f) + '°'); + let windDiv = createDiv("WIND " + windmag + " MPH"); + + // एक वेक्टर बनाएं + wind = p5.Vector.fromAngle(angle); +} diff --git a/dist/assets/examples/hi/90_Hello_P5/06_drawing.js b/dist/assets/examples/hi/90_Hello_P5/06_drawing.js new file mode 100644 index 0000000000..336fcde85a --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/06_drawing.js @@ -0,0 +1,132 @@ +/* +* @name ड्राइंग +* @description जनरेटिव पेंटिंग प्रोग्राम। +*/ + +// सभी पथ +let paths = []; +// क्या हम पेंटिंग कर रहे हैं? +let painting = false; +// अगले सर्कल तक कब तक +let next = 0; +// अब हम कहाँ हैं और हम कहाँ थे? +let current; +let previous; + +function setup() { + createCanvas(720, 400); + current = createVector(0,0); + previous = createVector(0,0); +}; + +function draw() { + background(200); + + // यदि यह एक नए बिंदु के लिए समय है + if (millis() > next && painting) { + + // माउस की स्थिति को पकड़ो + current.x = mouseX; + current.y = mouseY; + + // नए कण का बल माउस की गति पर आधारित होता है + let force = p5.Vector.sub(current, previous); + force.mult(0.05); + + // नया कण जोड़ें + paths[paths.length - 1].add(current, force); + + // अगले सर्कल को शेड्यूल करें + next = millis() + random(100); + + // माउस मूल्यों को स्टोर करें + previous.x = current.x; + previous.y = current.y; + } + + // सभी पथ बनाएं + for( let i = 0; i < paths.length; i++) { + paths[i].update(); + paths[i].display(); + } +} + +// इसे शुरू करो +function mousePressed() { + next = 0; + painting = true; + previous.x = mouseX; + previous.y = mouseY; + paths.push(new Path()); +} + +// रुकें +function mouseReleased() { + painting = false; +} + +// पथ कणों की एक सूची है +class Path { + constructor() { + this.particles = []; + this.hue = random(100); + } + + add(position, force) { + // स्थिति, बल और रंग के साथ एक नया कण जोड़ें + this.particles.push(new Particle(position, force, this.hue)); + } + + // डिस्प्ले प्लाथ + update() { + for (let i = 0; i < this.particles.length; i++) { + this.particles[i].update(); + } + } + + // डिस्प्ले प्लाथ + display() { + // पीछे की ओर से लूप करें + for (let i = this.particles.length - 1; i >= 0; i--) { + // अगर हम इसे हटा देते हैं + if (this.particles[i].lifespan <= 0) { + this.particles.splice(i, 1); + // अन्यथा, इसे प्रदर्शित करें + } else { + this.particles[i].display(this.particles[i+1]); + } + } + + } +} + +// पथ के साथ कण +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() { + // इसे हटाएं + this.position.add(this.velocity); + // इसे धीमा करें + this.velocity.mult(this.drag); + // इसे फीका करें + this.lifespan--; + } + + // कण ड्रा करें और इसे एक लाइन से कनेक्ट करें + // दूसरे के लिए एक रेखा खींचें + display(other) { + stroke(0, this.lifespan); + fill(0, this.lifespan/2); + ellipse(this.position.x,this.position.y, 8, 8); + // यदि हमें एक रेखा खींचने की आवश्यकता है + if (other) { + line(this.position.x, this.position.y, other.position.x, other.position.y); + } + } +} diff --git a/dist/assets/examples/hi/90_Hello_P5/07_song.js b/dist/assets/examples/hi/90_Hello_P5/07_song.js new file mode 100644 index 0000000000..6f4a741a26 --- /dev/null +++ b/dist/assets/examples/hi/90_Hello_P5/07_song.js @@ -0,0 +1,119 @@ +/* + * @name गीत + * @frame 720, 430 + * @description एक गाना बजाएं। + * आपको शामिल करने की आवश्यकता होगी + * p5.sound + * पुस्तकालय इस उदाहरण के लिए अपने स्वयं के प्रोजेक्ट में काम करने के लिए। + */ +// एक पैमाने के मिडी नोट +let notes = [ 60, 62, 64, 65, 67, 69, 71]; + +// स्वचालित रूप से गाना बजाने के लिए +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"); + // ट्रिगर स्वचालित रूप से खेल रहा है + button.mousePressed(function() { + if (!autoplay) { + index = 0; + autoplay = true; + } + }); + + // एक त्रिकोण थरथरानवाला + osc = new p5.TriOsc(); + // शुरू करें + osc.start(); + osc.amp(0); +} + +// एक नोट खेलने के लिए एक समारोह +function playNote(note, duration) { + osc.freq(midiToFreq(note)); + // इसे फीका करें + osc.fade(0.5,0.2); + + // यदि हम एक अवधि निर्धारित करते हैं, तो इसे फीका कर दें + if (duration) { + setTimeout(function() { + osc.fade(0,0.2); + }, duration-50); + } +} + +function draw() { + + // यदि हम ऑटोप्ले कर रहे हैं और यह अगले नोट के लिए समय है + if (autoplay && millis() > trigger){ + playNote(notes[song[index].note], song[index].duration); + trigger = millis() + song[index].duration; + // अगले नोट पर जाएं + index ++; + // हम अंत में हैं, ऑटोप्ले करना बंद करें। + } else if (index >= song.length) { + autoplay = false; + } + + + // एक कीबोर्ड बनाएं + + // प्रत्येक कुंजी की चौड़ाई + let w = width / notes.length; + for (let i = 0; i < notes.length; i++) { + let x = i * w; + // यदि माउस कुंजी के ऊपर है + if (mouseX > x && mouseX < x + w && mouseY < height) { + // अगर हम क्लिक कर रहे हैं + if (mouseIsPressed) { + fill(100,255,200); + // या बस लुढ़कना + } else { + fill(127); + } + } else { + fill(200); + } + + // या अगर हम गाना बजा रहे हैं, तो इसे भी हाइलाइट करें + if (autoplay && i === song[index-1].note) { + fill(100,255,200); + } + + // कुंजी ड्रा करें + rect(x, 0, w-1, height-1); + } + +} + +// जब हम क्लिक करते हैं +function mousePressed(event) { + if(event.button == 0 && event.clientX < width && event.clientY < height) { + // माउस को प्रमुख इंडेक्स पर मैप करें + let key = floor(map(mouseX, 0, width, 0, notes.length)); + playNote(notes[key]); + } +} + +// जब हम रिलीज करते हैं तो इसे फीका कर दें +function mouseReleased() { + osc.fade(0,0.5); +} diff --git a/dist/assets/examples/ko/00_Structure/00_Statements_and_Comments.js b/dist/assets/examples/ko/00_Structure/00_Statements_and_Comments.js new file mode 100644 index 0000000000..36a4d268b6 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/00_Statements_and_Comments.js @@ -0,0 +1,22 @@ +/* + * @name 스테이트멘트와 코멘트 + * @description 스테이트멘트는 프로그램을 형성하는 작은 단위의 문장입니다. 스테이트멘트의 끝은 ";" (세미콜론)를 사용합니다. + * 이 것을 "스테이트멘트 종결 기호" ("statement * terminator")이라고 합니다. 반면에 코멘트는 + * 더욱 편리한 이해를 위해 사용하는 일종의 메모입니다. 코멘트는 두 개의 슬래시 ("//")로 시작합니다. + * (https://processing.org/examples/statementscomments.html에서 옮김) + */ + +// createCanvas 함수는 컴퓨터에게 만들 윈도의 크기를 지정하는 함수 스테이트멘트입니다. +// 함수 스테이트멘트는 0개 이상의 인자 (parameter)가 있읍니다. +// 인자들는 함수에 사용되는 데이터며, 인자들의 값으로 컴퓨터의 행동을 지정합니다. + +function setup() { + createCanvas(710, 400); +} + +// background 함수는 컴퓨터에게 만들 위토의 배경색 (또는 회색도)를 +// 지정하는 함수 스테이트멘트입니다. +function draw() { + background(204, 153, 0); +} + diff --git a/dist/assets/examples/ko/00_Structure/01_Coordinates.js b/dist/assets/examples/ko/00_Structure/01_Coordinates.js new file mode 100644 index 0000000000..a356a75f66 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/01_Coordinates.js @@ -0,0 +1,34 @@ +/* + * @name 좌표 + * @description 모든 도형들은 좌표값으로 지정된 화면 위치에 나타납니다. + * 모든 좌표값은 원점으로부터의 거리를 픽셀 단위로 측정합니다. + * 원점 [0,0]는 화면 좌측 상단의 좌표이며, 우측 하단의 좌표는 [너비-1, 높이-1]에 해당합니다. + */ + +function setup() { + // 캔버스 크기를 너비 720픽셀, 높이 720픽셀로 설정 + createCanvas(720, 400); +} + +function draw() { + // 배경색을 검정색(0)으로 지정, noFill()로 면채우기 기능 해제 + background(0); + noFill(); + + // point()의 괄호 안 두 인수로 좌표값 지정 + // 첫번째 인수는 x값을, 두번째 인수는 y값 의미 + stroke(255); + point(width * 0.5, height * 0.5); + point(width * 0.5, height * 0.25); + + // 좌표를 활용해 점 뿐 아니라 모든 도형을 그릴 수 있습니다. + // 각 함수별 괄호에 적힌 매개변수들은 각기 다른 목적을 위해 사용됩니다. + // 예를들어 line()함수에 쓰인 처음 두 매개변수들은 각각 첫번째 그리고 두번째 끝점을 지정합니다. + stroke(0, 153, 255); + line(0, height * 0.33, width, height * 0.33); + + // rect()함수의 처음 두 매개변수는 상단 모서리의 좌표값을 의미하고, + // 그 다음 두 매개변수는 너비와 높이를 지정합니다. + stroke(255, 153, 0); + rect(width * 0.25, height * 0.1, width * 0.5, height * 0.8); +} diff --git a/dist/assets/examples/ko/00_Structure/02_Width_and_Height.js b/dist/assets/examples/ko/00_Structure/02_Width_and_Height.js new file mode 100644 index 0000000000..76eb7551a6 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/02_Width_and_Height.js @@ -0,0 +1,19 @@ +/* + * @name 너비와 높이 + * @description '너비(width)'와 '높이(height)' 변수들은 createCanvas() 함수에 따라 + * 정의된, 윈도우 화면의 너비 및 높이 값을 담습니다. + */ +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/dist/assets/examples/ko/00_Structure/03_Setup_and_Draw.js b/dist/assets/examples/ko/00_Structure/03_Setup_and_Draw.js new file mode 100644 index 0000000000..d91d046988 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/03_Setup_and_Draw.js @@ -0,0 +1,25 @@ +/* + * @name 설정하고 그리기 + * @description draw()함수 속의 코드들은 위에서 아래 방향으로 + * 실행되며, 프로그램이 멈출 때까지 계속해서 반복됩니다. + */ +let y = 100; + +// setup()함수 속 선언문은 프로그램 시작시 한번 실행됩니다. +function setup() { + // createCanvas가 그 첫 선언문입니다. + createCanvas(720, 400); + stroke(255); // 선색을 흰색(255)으로 지정 + frameRate(30); +} +// draw() 함수 속 선언문들은 프로그램이 멈출 때까지 계속해서 실행됩니다. +// 각 선언문은 위에서 아래 방향으로 순차적으로 실행되며, +// 마지막 선언문 실행을 마친 뒤에는 상단의 첫 선언문으로 되돌아갑니다. +function draw() { + background(0); // 배경색을 검정색(0)으로 지정 + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/ko/00_Structure/04_No_Loop.js b/dist/assets/examples/ko/00_Structure/04_No_Loop.js new file mode 100644 index 0000000000..2f50b6f2f5 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/04_No_Loop.js @@ -0,0 +1,28 @@ +/* + * @name 루프 중단 + * @description noLoop()함수는 draw()함수를 반복없이 단 한번만 실행되도록 합니다. + * noLoop()를 호출하지 않는다면 draw()함수는 계속해서 반복 실행될 것입니다. + */ +let y; + +// setup()함수 속 선언문은 프로그램 시작시 한번 실행됩니다. +function setup() { + // createCanvas가 그 첫 선언문입니다. + createCanvas(720, 400); + stroke(255); // 윤곽선을 흰색(255)으로 지정 + noLoop(); + + y = height * 0.5; +} + +// 아래의 draw()함수에 포함된 선언문들은 프로그램 실행이 멈출 때까지 계속해서 실행됩니다. +// 각 선언문은 위에서 아래 방향으로 순차적으로 실행되며, +// 마지막 선언문 실행을 마친 뒤에는 상단의 첫 선언문으로 되돌아갑니다. +function draw() { + background(0); // 배경색을 검정색(0)으로 지정 + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/ko/00_Structure/05_Loop.js b/dist/assets/examples/ko/00_Structure/05_Loop.js new file mode 100644 index 0000000000..bbf684de22 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/05_Loop.js @@ -0,0 +1,24 @@ +/* + * @name 루프 + * @description draw()함수 속 코드들은 위에서 아래 방향으로 + * 실행되며, 이는 프로그램이 멈출 때까지 계속해서 반복됩니다. + */ +let y = 100; + +// setup()함수 속 선언문은 프로그램 시작시 한번 실행됩니다. +function setup() { + createCanvas(720, 400); // 첫 선언문으로 캔버스 크기를 지정합니다. + stroke(255); // 선색을 흰색(255)로 지정 + frameRate(30); +} +// 아래의 draw()함수 속 선언문들은 프로그램 실행이 멈출 때까지 계속해서 실행됩니다. +// 각 선언문은 위에서 아래 방향으로 순차적으로 실행되며, +// 마지막 선언문 실행을 마친 뒤에는 상단의 첫 선언문으로 되돌아갑니다. +function draw() { + background(0); // 배경색을 검정색(0)으로 지정 + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/ko/00_Structure/06_Redraw.js b/dist/assets/examples/ko/00_Structure/06_Redraw.js new file mode 100644 index 0000000000..2fd28df755 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/06_Redraw.js @@ -0,0 +1,31 @@ +/* + * @name 다시 그리기 + * @description redraw()함수는 draw()함수를 재실행합니다. + * 이 예제에서 draw()는 마우스가 클릭될 때마다 매번 재실행됩니다. + */ + +let y; + +// setup()함수 속 선언문들은 프로그램 시작시 한번 실행됩니다. +function setup() { + createCanvas(720, 400); + stroke(255); + noLoop(); + y = height * 0.5; +} + +// 아래의 draw()함수에 포함된 선언문들은 프로그램 실행이 멈출 때까지 계속해서 실행됩니다. +// 각 선언문은 위에서 아래 방향으로 순차적으로 실행되며, +// 마지막 선언문 실행을 마친 뒤에는 상단의 첫 선언문으로 되돌아갑니다. +function draw() { + background(0); + y = y - 4; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} + +function mousePressed() { + redraw(); +} diff --git a/dist/assets/examples/ko/00_Structure/07_Functions.js b/dist/assets/examples/ko/00_Structure/07_Functions.js new file mode 100644 index 0000000000..47f31593aa --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/07_Functions.js @@ -0,0 +1,27 @@ +/* + *@name 그 외 함수들 + *@description 각 drawTarget()함수로 과녁판 형상의 도형 여러개를 쉽게 만들 수 있습니다. + *호출된 drawTarget()함수들은 각기 다른 과녁판 도형의 위치, 크기 그리고 고리 개수를 지정합니다. + */ + +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/dist/assets/examples/ko/00_Structure/08_Recursion.js b/dist/assets/examples/ko/00_Structure/08_Recursion.js new file mode 100644 index 0000000000..9833a01bae --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/08_Recursion.js @@ -0,0 +1,27 @@ +/* + *@name 재귀 함수 + *@description 재귀 함수는 자기 자신을 다시 호출하는 함수를 말합니다. + * drawCircle()함수가 블록 말미에 그 자신을 다시 호출하는 것을 볼 수 있습니다. + * 이 경우, drawCircle()함수의 변수인 "level"의 값이 1과 같아질 때까지 계속해서 재호출됩니다. + */ + +function setup() { + createCanvas(720, 400); + noStroke(); + noLoop(); +} + +function draw() { + drawCircle(width / 2, 280, 6); +} + +function drawCircle(x, radius, level) { + const tt = (126 * level) / 4.0; + fill(tt); + ellipse(x, height / 2, radius * 2, radius * 2); + if (level > 1) { + level = level - 1; + drawCircle(x - radius / 2, radius / 2, level); + drawCircle(x + radius / 2, radius / 2, level); + } +} diff --git a/dist/assets/examples/ko/00_Structure/09_Create_Graphics.js b/dist/assets/examples/ko/00_Structure/09_Create_Graphics.js new file mode 100644 index 0000000000..36b3ab0ae5 --- /dev/null +++ b/dist/assets/examples/ko/00_Structure/09_Create_Graphics.js @@ -0,0 +1,29 @@ +/* + * @name 그래픽 만들기 + * @description 새로운 p5.Renderer 객체를 만들고 반환합니다. + * 아래의 클래스는 특정 사각 스크린의 바깥 영역에 그래픽 버퍼를 만드는 데에 사용됩니다. + * 두 인수들은 사각 스크린의 너비와 높이값을 픽셀 단위로 각각 지정합니다. + */ + +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); + + //image() 선언문으로 사각 스크린 바깥에 위치한 그래픽 버퍼를 그립니다. + image(pg, 150, 75); +} diff --git a/dist/assets/examples/ko/01_Form/00_Points_and_Lines.js b/dist/assets/examples/ko/01_Form/00_Points_and_Lines.js new file mode 100644 index 0000000000..a7e1028623 --- /dev/null +++ b/dist/assets/examples/ko/01_Form/00_Points_and_Lines.js @@ -0,0 +1,36 @@ +/* + * @name 점과 선 + * @description 점과 선을 활용하여 기본적인 기하 형태를 그릴 수 있습니다. + * 도형의 크기 조정을 위해 변수인 'd'값을 바꿔보세요. + * 4개의 변수들은 d값을 기준으로 위치값을 설정합니다. + */ +function setup() { + let d = 70; + let p1 = d; + let p2 = p1 + d; + let p3 = p2 + d; + let p4 = p3 + d; + + // 캔버스 크기를 너비 720픽셀, 높이 720픽셀로 설정 + createCanvas(720, 400); + background(0); + noSmooth(); + + translate(140, 0); + + // 회색의 사각형 그리기 + stroke(153); + line(p3, p3, p2, p3); + line(p2, p3, p2, p2); + line(p2, p2, p3, p2); + line(p3, p2, p3, p3); + + // 흰색 점들 그리기 + stroke(255); + point(p1, p1); + point(p1, p3); + point(p2, p4); + point(p3, p1); + point(p4, p2); + point(p4, p4); +} diff --git a/dist/assets/examples/ko/01_Form/01_Shape_Primitives.js b/dist/assets/examples/ko/01_Form/01_Shape_Primitives.js new file mode 100644 index 0000000000..3a6a3d26e3 --- /dev/null +++ b/dist/assets/examples/ko/01_Form/01_Shape_Primitives.js @@ -0,0 +1,31 @@ +/* + * @name 기본 조형 + * @description 기본 조형을 그리는 함수로는 triangle(), + * rect(), quad(), ellipse(), 그리고 arc()가 있습니다. 사각형은 rect()로, + * 원형은 ellipse()로 만들 수 있습니다. 도형의 위치와 크기 조정을 위해 + * 각 함수들의 괄호 안 인수들을 반드시 지정해야합니다. + */ +function setup() { + // 캔버스 크기를 너비 720픽셀, 높이 720픽셀로 설정 + 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/dist/assets/examples/ko/01_Form/02_Pie_Chart.js b/dist/assets/examples/ko/01_Form/02_Pie_Chart.js new file mode 100644 index 0000000000..248006533f --- /dev/null +++ b/dist/assets/examples/ko/01_Form/02_Pie_Chart.js @@ -0,0 +1,33 @@ +/* + * @name 파이형 차트 + * @description arc()함수를 사용하여 배열에 저장된 데이터로 파이형 차트를 생성해보세요. + */ +let angles = [30, 10, 45, 35, 60, 38, 75, 67]; + +function setup() { + createCanvas(720, 400); + noStroke(); + noLoop(); // 프로그램 시작시 한 번 실행 뒤 멈추기 +} + +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/dist/assets/examples/ko/01_Form/03_Regular_Polygon.js b/dist/assets/examples/ko/01_Form/03_Regular_Polygon.js new file mode 100644 index 0000000000..0fd70871c0 --- /dev/null +++ b/dist/assets/examples/ko/01_Form/03_Regular_Polygon.js @@ -0,0 +1,42 @@ +/* + * @name 정다각형 + * @description 가장 좋아하는 정다각형이 있나요? 오각형? 육각형? 칠각형? 아니면, 이십각형은요? + * 이 예제에서 소개하는 polygon()함수는 그 어떠한 정다각형도 그릴 수 있습니다. + * draw()함수 내에 호출된 polygon() 안에 다양한 숫자를 넣어 탐구해보세요. + */ +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/dist/assets/examples/ko/01_Form/04_Star.js b/dist/assets/examples/ko/01_Form/04_Star.js new file mode 100644 index 0000000000..7e98f1d2b4 --- /dev/null +++ b/dist/assets/examples/ko/01_Form/04_Star.js @@ -0,0 +1,45 @@ +/* + * @name 별모양 + * @description 이 예제에서 소개하는 star()함수는 여러가지 다양한 모양을 그립니다. + * draw()함수 내에 호출된 polygon() 안에 다양한 숫자를 넣어 탐구해보세요. + */ +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/dist/assets/examples/ko/01_Form/05_Triangle_Strip.js b/dist/assets/examples/ko/01_Form/05_Triangle_Strip.js new file mode 100644 index 0000000000..62308eea3d --- /dev/null +++ b/dist/assets/examples/ko/01_Form/05_Triangle_Strip.js @@ -0,0 +1,38 @@ +/* + * @name 삼각형 고리 + * @description 이라 그린버그(Ira Greenberg) 제작 예제. vertex()함수와 + * beginShape(TRIANGLE_STRIP) 모드를 이용하여 닫힌 고리를 하나 생성하세요. + * outsideRadius와 insideRadius 변수를 이용하여 각 고리의 지름(radius)을 조정할 수 있습니다. + */ +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/dist/assets/examples/ko/01_Form/06_Bezier.js b/dist/assets/examples/ko/01_Form/06_Bezier.js new file mode 100644 index 0000000000..8e779bb045 --- /dev/null +++ b/dist/assets/examples/ko/01_Form/06_Bezier.js @@ -0,0 +1,26 @@ +/* + * @name 베지어 곡선 + * @description bezier()함수의 처음 두 매개변수들은 각각 곡선의 시작점과 끝점을 지정합니다. + * 중간의 인수들은 곡선의 모양을 조정하는 '조정점(control point)'들입니다. + */ +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/dist/assets/examples/ko/01_Form/07_3D_Primitives.js b/dist/assets/examples/ko/01_Form/07_3D_Primitives.js new file mode 100644 index 0000000000..06204637be --- /dev/null +++ b/dist/assets/examples/ko/01_Form/07_3D_Primitives.js @@ -0,0 +1,30 @@ +/* + * @name 3D 기본 조형 + * @frame 720,400 (optional) + * @description 3D 객체를 합성 공간 속에 수학적으로 배치하기. + * box()와 sphere()함수는 최소 한 개의 매개변수를 사용하여 객체의 크기를 조정합니다. + * 도형의 위치는 translate()함수를 통해 조정할 수 있습니다. + */ +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/dist/assets/examples/ko/01_Form/08_Trig_Wheels_and_Pie_Chart.js b/dist/assets/examples/ko/01_Form/08_Trig_Wheels_and_Pie_Chart.js new file mode 100644 index 0000000000..0f0b07a2fa --- /dev/null +++ b/dist/assets/examples/ko/01_Form/08_Trig_Wheels_and_Pie_Chart.js @@ -0,0 +1,85 @@ +/* + * @name 단위원과 파이 차트 + * @frame 400,400 + * @description 해리스 교수 ( + Prof WM Harris,)의 기고 예시, '삼각함수 컬러 휠 만드는 법과 인구 연령 데이터로 파이차트 그리기' + (How to create a trig color wheel and a visualization of a population age data as a pie chart). +
+ 켄바스 설정, 삼각함수 컬러 휠, 휠 조각 그리기와 파이차트를 위한 함수르 만듭니다. 컬러 휠 조각들의 크기와 + 색상범위 (color range)를 정합니다. 파이차트는 값에 따라 색깔로 나누어지는 반면, 삼각함수 컬러 휠은 조각의 수가 + 고정되어있고 색상 범위로 나누어집니다. +*/ + +function setup() { + createCanvas(400, 400); + colorMode(HSB); + angleMode(DEGREES); + + //색깔 컬러 휠 중점을 위한 + 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/dist/assets/examples/ko/02_Data/00_Variables.js b/dist/assets/examples/ko/02_Data/00_Variables.js new file mode 100644 index 0000000000..faeb3bc6c3 --- /dev/null +++ b/dist/assets/examples/ko/02_Data/00_Variables.js @@ -0,0 +1,36 @@ +/* + * @name 변수 + * @description 변수는 값을 저장하는 데에 사용됩니다. 예제의 변수값을 바꿔 구성을 바꿔보세요. + */ +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/dist/assets/examples/ko/02_Data/01_True_and_False.js b/dist/assets/examples/ko/02_Data/01_True_and_False.js new file mode 100644 index 0000000000..4ebc9f2224 --- /dev/null +++ b/dist/assets/examples/ko/02_Data/01_True_and_False.js @@ -0,0 +1,30 @@ +/* + * @name 참과 거짓 + * @description 불리언(Boolean) 변수는 오직 'true(참)'과 'false(거짓)'이라는 두 개의 값만 갖습니다. + * 불리언과 함께 제어문을 사용하여 프로그램의 흐름을 조정하는 것이 일반적인 방식입니다. + * 이 예제에서는, b값이 'true(참)'일 때 세로선들이 그려지고 + * b값이 'false(거짓)'일 때 가로선들이 그려집니다. + */ +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) { + // 세로선 + line(i, d, i, height - d); + } + + if (b === false) { + // 가로선 + line(middle, i - middle + d, width - d, i - middle + d); + } + } +} diff --git a/dist/assets/examples/ko/02_Data/03_Variable_Scope.js b/dist/assets/examples/ko/02_Data/03_Variable_Scope.js new file mode 100644 index 0000000000..a9cd27632c --- /dev/null +++ b/dist/assets/examples/ko/02_Data/03_Variable_Scope.js @@ -0,0 +1,45 @@ +/* + * @name 변수 범위 + * @description 변수는 '전역(global) 변수'로서 선언되거나, 그 적용 범위를 조정하여 '지역(local) 변수'로 사용할 수 있습니다. + * 예를 들어, setup() 및 draw()함수 안에 선언된 변수들은 해당 함수들의 범위 내에서만 사용되는 '지역 변수'가 됩니다. + * '전역 변수'의 경우, setup() 및 draw()함수 범위 외에서도 사용 가능합니다. + * 어떤 함수의 '지역 변수'가 '전역 변수'와 동일한 이름으로 선언된 경우, + * 이 변수는 해당 함수에 한해 지역 변수로서 처리됩니다. + */ +let a = 80; // 전역 변수 "a" 생성하기 + +function setup() { + createCanvas(720, 400); + background(0); + stroke(255); + noLoop(); +} + +function draw() { + // 전역 변수 a를 사용하여 선 그리기 + line(a, 0, a, height); + + // 반복문 안에 지역 변수 a를 사용하기 + for (let a = 120; a < 200; a += 3) { + line(a, 0, a, height); + } + + // 사용자가 만든 함수 drawAnotherLine() 호출하기 + drawAnotherLine(); + + // 사용자가 만든 함수 drawYetAnotherLine() 호출하기 + drawYetAnotherLine(); +} + +function drawAnotherLine() { + // 이 함수에 대한 지역 변수로서 새로운 a 선언하기 + let a = 320; + // 지역 변수 a를 사용하여 선 그리기 line(a, 0, a, height); + line(a, 0, a, height); +} + +function drawYetAnotherLine() { + // 새로운 지역 변수 a를 선언하지 않았으므로, + // 이 선은 위에서 선언된 전역 변수 a(값 80)를 사용하여 그려집니다. + line(a + 3, 0, a + 3, height); +} diff --git a/dist/assets/examples/ko/02_Data/04_Numbers.js b/dist/assets/examples/ko/02_Data/04_Numbers.js new file mode 100644 index 0000000000..43d081fa5f --- /dev/null +++ b/dist/assets/examples/ko/02_Data/04_Numbers.js @@ -0,0 +1,30 @@ +/* + * @name 숫자값 + * @frame 720,400 + * @description 숫자값은 소수점과 함께, 또는 소수점없이 사용할 수 있습니다. + * 보통 "int"라 불리는 정수(integer)는 소수점이 없는 숫자를 말합니다. + * "float"는 소수점 이하 자릿수를 갖는 부동소수점 숫자를 말합니다. + */ +let a = 0; // "a"를 숫자형 전역 변수로 선언 +let b = 0; // "b"를 숫자형 전역 변수로 선언 + +function setup() { + createCanvas(720, 400); + stroke(255); +} + +function draw() { + background(0); + + a = a + 1; // a를 정수 단위로 증가 + b = b + 0.2; // b를 부동소수점수 단위로 증가 + 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/dist/assets/examples/ko/03_Arrays/00_Array.js b/dist/assets/examples/ko/03_Arrays/00_Array.js new file mode 100644 index 0000000000..4f624aaaa8 --- /dev/null +++ b/dist/assets/examples/ko/03_Arrays/00_Array.js @@ -0,0 +1,42 @@ +/* + * @name 배열 + * @description 배열은 데이터의 리스트를 말합니다. 배열 속 각 데이터는 + * 배열에서의 위치를 나타내는 색인(index) 번호로 식별됩니다. 배열의 시작은 0을 기준으로 합니다. + * 따라서, 배열의 첫 번째 데이터는 [0]이고 두 번째 데이터는 [1]로 식별됩니다. + * 이 예제에서는 "coswave"라는 배열을 만들고, 이를 코사인 값으로 채웁니다. + * 데이터는 실행 화면상 세 가지의 다른 방법으로 표현됩니다. + */ +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/dist/assets/examples/ko/03_Arrays/01_Array_2d.js b/dist/assets/examples/ko/03_Arrays/01_Array_2d.js new file mode 100644 index 0000000000..1d7885502d --- /dev/null +++ b/dist/assets/examples/ko/03_Arrays/01_Array_2d.js @@ -0,0 +1,37 @@ +/* + * @name 2D 배열 + * @description 2차원(2D) 배열 작성을 위한 구문입니다. + * 2D 배열의 값은 두 개의 색인(index)값을 통해 가져올 수 있습니다. + * 2D 배열은 이미지를 저장하는 데에 유용합니다. + * 이 예제에서 각 점의 색상은 이미지 중심으로부터의 거리에 따라 지정됩니다. + */ +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] = []; // 중첩 배열 만들기 + 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(); // 한번 실행 후 멈추기 +} + +function draw() { + background(0); + // 이 함수에 내장된 반복문은 앞서 선언된 spacer변수에 따라 배열값 사이의 간격을 생성하게 됩니다. + // 따라서, 이 함수로 그려진 것보다 더 많은 값이 배열에 있는 셈입니다. + // spacer변수의 값을 변경하여 점들 간의 밀도를 조정해보세요. + 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/dist/assets/examples/ko/03_Arrays/02_Array_Objects.js b/dist/assets/examples/ko/03_Arrays/02_Array_Objects.js new file mode 100644 index 0000000000..70ba8f8073 --- /dev/null +++ b/dist/assets/examples/ko/03_Arrays/02_Array_Objects.js @@ -0,0 +1,71 @@ +/* + * @name 객체 배열 + * @description 사용자가 정의한 객체 배열을 만듭니다. + */ + +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; + } + + // 사용자 정의한 메소드를 통해 변수들을 업데이트합니다. + 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; + } + } + + // 사용자가 정의한 메소드를 통해 객체를 그립니다. + 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/dist/assets/examples/ko/03_Arrays/03_Walk_Over_2dArray.js b/dist/assets/examples/ko/03_Arrays/03_Walk_Over_2dArray.js new file mode 100644 index 0000000000..e5577e7383 --- /dev/null +++ b/dist/assets/examples/ko/03_Arrays/03_Walk_Over_2dArray.js @@ -0,0 +1,85 @@ +/* + * @name Walk Over 2dArray + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to display 2D array contents on the canvas +using regular for and for-of loops in multiple different ways.
+ A function is created for the canvas, the 2D + array (Friend Array) is initialized and walked over using nested + loops in different ways. Variables x and y are used to place the + array item on the canvas in the form of 2D array. + The final nested loop is used to initialize 2D + array (Fish Array) with random Integers (fish ages). +*/ + + +//"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/dist/assets/examples/ko/04_Control/00_Iteration.js b/dist/assets/examples/ko/04_Control/00_Iteration.js new file mode 100644 index 0000000000..7f96ebc7c7 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/00_Iteration.js @@ -0,0 +1,41 @@ +/* + * @name for 반복문 + * @description "for" 구조를 사용하여 반복 형식을 만듭니다. + */ +let y; +let num = 14; + +function setup() { + createCanvas(720, 360); + background(102); + noStroke(); + + // 흰색 막대기들 그리기 + fill(255); + y = 60; + for (let i = 0; i < num / 3; i++) { + rect(50, y, 475, 10); + y += 20; + } + + // 회색 막대기들 + 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; + } + + // 얇은 선들 + y = 45; + fill(0); + for (let i = 0; i < num - 1; i++) { + rect(120, y, 40, 1); + y += 20; + } +} diff --git a/dist/assets/examples/ko/04_Control/01_Embedded_Iteration.js b/dist/assets/examples/ko/04_Control/01_Embedded_Iteration.js new file mode 100644 index 0000000000..33c571bb01 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/01_Embedded_Iteration.js @@ -0,0 +1,21 @@ +/* + * @name for 내장 반복문 + * @description "for" 반복문 구조를 이중 사용하여 2차원 도형을 반복할 수 있습니다. + */ +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/dist/assets/examples/ko/04_Control/02_Conditionals_1.js b/dist/assets/examples/ko/04_Control/02_Conditionals_1.js new file mode 100644 index 0000000000..8de20977a9 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/02_Conditionals_1.js @@ -0,0 +1,24 @@ +/* + * @name 조건문 1 + * @description 조건문은 마치 질문과도 같습니다. + * 프로그램은 조건문이 던지는 질문이 참인지 거짓인지에 따라 + * 특정 선언문의 실행 여부를 결정합니다. + * 조건문으로 던지는 질문들은 언제나 논리 또는 관계 선언문의 형식을 갖습니다. + * 이 예제의 경우, 변수 i가 0이라는 조건이 충족될시 선이 그려집니다. + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 10; i < width; i += 10) { + // i가 20으로 나누어 떨어진다면, 첫번째 선을 그린다. + // 그렇지 않을 경우, 두번째 선을 그린다. + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + } else { + stroke(153); + line(i, 20, i, 180); + } + } +} diff --git a/dist/assets/examples/ko/04_Control/03_Conditionals_2.js b/dist/assets/examples/ko/04_Control/03_Conditionals_2.js new file mode 100644 index 0000000000..bde90ef016 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/03_Conditionals_2.js @@ -0,0 +1,27 @@ +/* + * @name 조건문 2 + * @description 조건문 1 예제에 "else"라는 키워드를 더해 조건문의 문법을 확장해봅시다. + * "else"를 사용하면 연속하여 2개 이상의 질문을 던질 수 있습니다. + * 이 때, 각각의 질문은 서로 다른 행위를 요청할 수 있습니다. + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 2; i < width - 2; i += 4) { + // i가 20으로 나누어 떨어질 경우 + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + // i가 10으로 나누어 떨어질 경우 + } else if (i % 10 === 0) { + stroke(153); + line(i, 20, i, 180); + // 위의 두 조건 모두 충족하지 않을 경우 + // 이 선을 그린다. + } else { + stroke(102); + line(i, height / 2, i, height - 20); + } + } +} diff --git a/dist/assets/examples/ko/04_Control/04_Logical_Operators.js b/dist/assets/examples/ko/04_Control/04_Logical_Operators.js new file mode 100644 index 0000000000..4f3436dce7 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/04_Logical_Operators.js @@ -0,0 +1,42 @@ +/* + * @name 논리적 연산자 + * @description 논리 연산자인 AND (&&) 와 OR (||) 는 + * 간단한 관계 선언문에 좀 더 복잡한 조건을 더할 때 쓰입니다. + * NOT (!) 연산자는 불리언 선언문을 부정할 때 쓰입니다. + */ +let test = false; + +function setup() { + createCanvas(720, 360); + background(126); + + for (let i = 5; i <= height; i += 5) { + // 논리적 연산자 AND + stroke(0); + if (i > 35 && i < 100) { + line(width / 4, i, width / 2, i); + test = false; + } + + // 논리적 연산자 OR + stroke(76); + if (i <= 35 || i >= 100) { + line(width / 2, i, width, i); + test = true; + } + + // 불리언 값이 참(true)인지 여부를 테스트 + // "if(test)"이 "if(test == true)"와 동일한지 여부를 확인 + if (test) { + stroke(0); + point(width / 3, i); + } + + // 불리언 값이 거짓(false)인지 여부를 테스트 + // "if(!test)"이 "if(test == false)"와 동일한지 여부를 확인 + if (!test) { + stroke(255); + point(width / 4, i); + } + } +} diff --git a/dist/assets/examples/ko/04_Control/05_Logical_Operators_2.js b/dist/assets/examples/ko/04_Control/05_Logical_Operators_2.js new file mode 100644 index 0000000000..2684feb956 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/05_Logical_Operators_2.js @@ -0,0 +1,91 @@ +/* + * @name Logical Operators 2 + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to create Xboxes with one global variable and create conditions with + boolean variables and boolean expressions by utilizing Boolean + operators ||, &&, and ! to do boundary checking.
+ Functions + are created for both the canvas set up as well as the creation of + the boxes. Background color is dependent on the location of the + boxes in the canvas space. When mouse button and key are pressed + simultaneously, the “where” text and box color changes to cyan, + but if the mouse button is clicked alone then the animation will + start. When q or Q are pressed the text “Did you type q or Q?” + will change to blue, else it will be purple. If the mouse is placed + within the orange box containing the text, “withinRect” then the + shape will turn pink. + */ + + +//1 coordinate for everything :) +let where = 0; //control boxes' positions + +function setup() { + createCanvas(400, 400); +} + +function draw() { + //similar to slide 4 use of OR, || + //to set bg color of canvas + if ((where < 0) || (where > height)) { + background("beige"); + } else { + background("chocolate"); + } + + //similar to slide 4 use of AND, && + //to set fill color of box & text + if (mouseIsPressed && keyIsPressed) { + fill("cyan"); + } else { + fill(255); + } + + //boxL + rect(where, where, 40); + + //boxR, pad x coordinate for size of box + rect(width - where - 40, where, 40); + + //Move the boxes + where = where + 1; + + //Show the value of where the boxes are + text("where is " + where, 150, 30); + + //testing not, ! and or, || operators + if (!(key === "q" || key === "Q")) { + fill("purple"); + } else { + fill("dodgerBlue"); + } + //Show the current key value + text("Did you type a q or Q? " + key, 150, 70); + + //*** Boundary checking *** + //Is the mouse within rect boundary? + //left, right, top, bottom + let withinRect = (mouseX >= 150) && + (mouseX <= 150 + 100) && + (mouseY >= 300) && + (mouseY <= 300 + 40); + //fill color based on value of withinRect + if (withinRect) { + fill("pink"); + } else { + fill("orange"); + } + //draw the rect + rect(150, 300, 100, 40); + //show withinRect value as label on rect + fill(0); + text("withinRect " + withinRect, 160, 320); +} + +//boxes restart +function mousePressed() { + //Reset boxes back up and above the canvas + where = -50; +} \ No newline at end of file diff --git a/dist/assets/examples/ko/04_Control/06_Conditional_Shapes.js b/dist/assets/examples/ko/04_Control/06_Conditional_Shapes.js new file mode 100644 index 0000000000..8d544e9081 --- /dev/null +++ b/dist/assets/examples/ko/04_Control/06_Conditional_Shapes.js @@ -0,0 +1,48 @@ +/* + * @name Conditional Shapes + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to draw different shapes mid canvas depending on the mouse position.
+ Functions + are created for the main canvas set up with the markers on the left and + right hand sides. One is also created for the location of the mouse + regarding the canvas and the markers. If the mouse is within the + outer left hand beige rectangle, then the shape of circle is drawn + down the center of the canvas. If the mouse is within the outer right + hand beige rectangle, then the shape of square is drawn down the + center of the canvas. +*/ +function setup() { + createCanvas(400, 400); + strokeWeight(3); + //center squares to match circles + rectMode(CENTER); + + //draw rects to mark far sides + noStroke(); + fill("beige"); + rect(5, height / 2, 10, height); + rect(width - 5, height / 2, 10, height); + fill("orange"); + stroke("brown"); + + } + + function draw() { + point(mouseX, mouseY); + + //if (test) {doThis; } + //test: mouseX on far left of canvas + //doThis: draw a circle at mouseY + if (mouseX < 10) { + circle(width / 2, mouseY, 20); + } + + //test: mouseX on far right of canvas + //doThis: draw a square at mouseY + if (mouseX > width - 10) { + square(width / 2, mouseY, 20); + } + + } diff --git a/dist/assets/examples/ko/05_Image/00_Load_and_Display_Image.js b/dist/assets/examples/ko/05_Image/00_Load_and_Display_Image.js new file mode 100644 index 0000000000..5111273db6 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/00_Load_and_Display_Image.js @@ -0,0 +1,19 @@ +/* + * @name 이미지 불러오기 및 보이기 + * @description 이미지를 실제 또는 다른 크기로 지정하여 화면상 불러오고 보이게 할 수 있습니다. + *

로컬 프로젝트에서 이 예제를 실행하려면, 이미지 파일을 준비하시고 + * 로컬 서버를 작동시키세요.

+ */ +let img; // 변수 'img' 선언 + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // 이미지 불러오기 +} + +function draw() { + // 이미지를 화면상 좌표 (0,0) 위치에 실제 크기로 보이게 한다. + image(img, 0, 0); + // 이미지를 화면상 좌표 (0,높이/2) 위치에 절반 크기로 보이게 한다. + image(img, 0, height / 2, img.width / 2, img.height / 2); +} diff --git a/dist/assets/examples/ko/05_Image/01_Background_Image.js b/dist/assets/examples/ko/05_Image/01_Background_Image.js new file mode 100644 index 0000000000..c261f4c2eb --- /dev/null +++ b/dist/assets/examples/ko/05_Image/01_Background_Image.js @@ -0,0 +1,30 @@ +/* + * @name 배경 이미지 + * @description 이 예제는 배경 이미지를 불러오는 가장 빠른 방법을 소개합니다. + * 이미지 파일을 배경으로 쓰기 위해선, 이미지의 너비와 높이를 + * 프로그램 화면 크기와 동일하게 맞추면 됩니다. + *

로컬 프로젝트에서 이 예제를 실행하려면, 이미지 파일을 준비하시고 + * 로컬 서버를 작동시키세요.

+ */ +let bg; +let y = 0; + +function setup() { + // 이미지 파일을 배경으로 쓰기 위해, createCanvas() 메소드의 인수에 + // 이미지 크기와 동일한 사이즈를 기입하면 됩니다. + // 이 예제의 경우, 이미지 크기는 720x400 픽셀입니다. + 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/dist/assets/examples/ko/05_Image/02_Transparency.js b/dist/assets/examples/ko/05_Image/02_Transparency.js new file mode 100644 index 0000000000..54e54acdb5 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/02_Transparency.js @@ -0,0 +1,23 @@ +/* + * @name 투명도 + * @description 마우스 포인터를 좌우로 움직여 이미지의 위치를 옮겨보세요. + * 이 예제의 경우, tint()함수로 알파값이 수정된 이미지를 원본 이미지에 위에 겹쳐 보여줍니다. + *

로컬 프로젝트에서 이 예제를 실행하려면, 이미지 파일을 준비하시고 + * 로컬 서버를 작동시키세요.

+ */ +let img; +let offset = 0; +let easing = 0.05; + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // 프로그램상 이미지 불러오기 +} + +function draw() { + image(img, 0, 0); // 이미지를 투명도 100%로 보이게하기 + let dx = mouseX - img.width / 2 - offset; + offset += dx * easing; + tint(255, 127); // 이미지를 투명도 50%로 보이게하기 + image(img, offset, 0); +} diff --git a/dist/assets/examples/ko/05_Image/03_Alpha_Mask.js b/dist/assets/examples/ko/05_Image/03_Alpha_Mask.js new file mode 100644 index 0000000000..ad500307c6 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/03_Alpha_Mask.js @@ -0,0 +1,26 @@ +/* + * @name 알파 마스크 + * @description 이미지 일부의 투명도를 설정하기 위해 마스크를 불러옵니다. + * 이미지와 마스크는 p5.Image의 mask() 메소드를 통해 합쳐집니다. + *

로컬 프로젝트에서 이 예제를 실행하려면, 이미지 파일을 준비하시고 + * 로컬 서버를 작동시키세요.

+ */ +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/dist/assets/examples/ko/05_Image/04_Create_Image.js b/dist/assets/examples/ko/05_Image/04_Create_Image.js new file mode 100644 index 0000000000..a051fcb02e --- /dev/null +++ b/dist/assets/examples/ko/05_Image/04_Create_Image.js @@ -0,0 +1,25 @@ +/* + * @name 이미지 만들기 + * @description createImage() 함수로 재밌는 픽셀 버퍼를 만들 수 있습니다. + * 이 예제는 그래디언트 이미지를 만듭니다. + */ +let img; // '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/dist/assets/examples/ko/05_Image/05_Pointillism.js b/dist/assets/examples/ko/05_Image/05_Pointillism.js new file mode 100644 index 0000000000..edd9562e6c --- /dev/null +++ b/dist/assets/examples/ko/05_Image/05_Pointillism.js @@ -0,0 +1,32 @@ +/* + * @name 점묘법 + * @description 제작: 다니엘 쉬프만(Dan Shiffman). 마우스의 가로 위치는 점의 크기를 조정합니다. + * 픽셀에 따라 색칠된 원형(ellipse)으로 간단한 점묘법 효과를 만듭니다. + *

로컬 프로젝트에서 이 예제를 실행하려면, 이미지 파일을 준비하시고 + * 로컬 서버를 작동시키세요.

+ */ +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/dist/assets/examples/ko/05_Image/06_Blur.js b/dist/assets/examples/ko/05_Image/06_Blur.js new file mode 100644 index 0000000000..2374bc0345 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/06_Blur.js @@ -0,0 +1,89 @@ +/* + * @name Blur + * @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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/ko/05_Image/07_EdgeDetection.js b/dist/assets/examples/ko/05_Image/07_EdgeDetection.js new file mode 100644 index 0000000000..5eff38c2d2 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/07_EdgeDetection.js @@ -0,0 +1,93 @@ +/* + * @name Edge Detection + * @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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/ko/05_Image/08_Brightness.js b/dist/assets/examples/ko/05_Image/08_Brightness.js new file mode 100644 index 0000000000..3c58a98876 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/08_Brightness.js @@ -0,0 +1,63 @@ +/* + * @name Brightness + * @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 + */ +// 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(); +} \ No newline at end of file diff --git a/dist/assets/examples/ko/05_Image/09_Convolution.js b/dist/assets/examples/ko/05_Image/09_Convolution.js new file mode 100644 index 0000000000..eb953c6729 --- /dev/null +++ b/dist/assets/examples/ko/05_Image/09_Convolution.js @@ -0,0 +1,91 @@ +/* + * @name Convolution + * @description 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.

+ */ + +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); +} \ No newline at end of file diff --git a/dist/assets/examples/ko/05_Image/10_Copy_Method.js b/dist/assets/examples/ko/05_Image/10_Copy_Method.js new file mode 100644 index 0000000000..2002d34dfe --- /dev/null +++ b/dist/assets/examples/ko/05_Image/10_Copy_Method.js @@ -0,0 +1,20 @@ +/* + * @name Copy() method + * @frame 600,400 + * @description An example of how to simulate coloring image with the copy() method. + */ +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/dist/assets/examples/ko/07_Color/00_Hue.js b/dist/assets/examples/ko/07_Color/00_Hue.js new file mode 100644 index 0000000000..3719823704 --- /dev/null +++ b/dist/assets/examples/ko/07_Color/00_Hue.js @@ -0,0 +1,25 @@ +/* + * @name 색조 + * @description 색조는 오브젝트에 반사되거나 이를 통해 전달된 색상을 말하며, + * 일반적으로 색상명(빨강, 파랑, 노랑 등)으로 불립니다. + * 마우스 커서를 세로축으로 움직여 막대기의 색조를 변경해 보세요. + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, height, height, height); + noStroke(); + background(0); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(mouseY, height, height); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/ko/07_Color/01_Saturation.js b/dist/assets/examples/ko/07_Color/01_Saturation.js new file mode 100644 index 0000000000..0e9cb3fff6 --- /dev/null +++ b/dist/assets/examples/ko/07_Color/01_Saturation.js @@ -0,0 +1,24 @@ +/* + * @name 채도 + * @description 채도는 회색이 차지하는 비율에 따른, 색조의 짙음 또는 맑음 정도를 말합니다. + * 포화된 색은 맑고, 불포화된 색은 높은 비율의 회색조를 갖습니다. + * 마우스 커서를 세로축으로 움직여 막대기의 채도를 변경해 보세요. + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, width, height, 100); + noStroke(); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(barX, mouseY, 66); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/ko/07_Color/02_Brightness.js b/dist/assets/examples/ko/07_Color/02_Brightness.js new file mode 100644 index 0000000000..7f7bcb99ed --- /dev/null +++ b/dist/assets/examples/ko/07_Color/02_Brightness.js @@ -0,0 +1,46 @@ +/* + * @name 밝기 + * @description 제작: 다니엘 쉬프만(Dan Shiffman). 마우스와 각 픽셀 간의 거리값을 + * 계산하여 이미지 일부의 밝기를 조정합니다. + *

로컬 컴퓨터에서 이 예제를 실행하려면, 이미지 파일을 준비하시고 + * 로컬 서버를 작동시키세요.

+ */ +let img; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 200); + pixelDensity(1); + img.loadPixels(); + loadPixels(); +} + +function draw() { + for (let x = 0; x < img.width; x++) { + for (let y = 0; y < img.height; y++) { + // 2D 그리드로부터 1차원 위치 계산 + let loc = (x + y * img.width) * 4; + // 이미지에서 R,G,B값 받기 + let r, g, b; + r = img.pixels[loc]; + // 마우스와의 거리에 따라 변경할 밝기 계산 + let maxdist = 50; + let d = dist(x, y, mouseX, mouseY); + let adjustbrightness = (255 * (maxdist - d)) / maxdist; + r += adjustbrightness; + // RGB의 색상 범위가 0-255에 국한되도록 설정 + r = constrain(r, 0, 255); + // 새로운 색상 생성 후 화면에 픽셀 위치 고정 + //color c = color(r, g, b); + let pixloc = (y * width + x) * 4; + pixels[pixloc] = r; + pixels[pixloc + 1] = r; + pixels[pixloc + 2] = r; + pixels[pixloc + 3] = 255; + } + } + updatePixels(); +} diff --git a/dist/assets/examples/ko/07_Color/03_Color_Variables.js b/dist/assets/examples/ko/07_Color/03_Color_Variables.js new file mode 100644 index 0000000000..5c3aa3d911 --- /dev/null +++ b/dist/assets/examples/ko/07_Color/03_Color_Variables.js @@ -0,0 +1,40 @@ +/* + * @name 색상 변수 + * @description (Albers에게 바칩니다.) 이 예제는 색상 조정을 위한 변수 생성 방법을 다룹니다. + * 이 때, 변수들은 숫자가 아닌 특정 명칭으로 지정됩니다. + */ +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); + + // 아래의 변수 선언문은 위의 선언문들과 동일합니다. + // 둘 중 원하는 형식을 사용하면 됩니다. + //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/dist/assets/examples/ko/07_Color/04_Relativity.js b/dist/assets/examples/ko/07_Color/04_Relativity.js new file mode 100644 index 0000000000..f54aef95d9 --- /dev/null +++ b/dist/assets/examples/ko/07_Color/04_Relativity.js @@ -0,0 +1,34 @@ +/* + * @name 상대성 + * @description 각 색상은 다른 색상과의 관계 속에서 인식됩니다. + * 상단과 하단의 막대기들은 둘 다 동일한 색상 요소들을 갖지만, + * 색상 요소들의 배열에 따라 마치 다른 색조를 갖는 듯 보입니다. + */ +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(); // 반복없이 한번만 그리기 +} + +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/dist/assets/examples/ko/07_Color/05_Linear_Gradient.js b/dist/assets/examples/ko/07_Color/05_Linear_Gradient.js new file mode 100644 index 0000000000..95c2feb2ca --- /dev/null +++ b/dist/assets/examples/ko/07_Color/05_Linear_Gradient.js @@ -0,0 +1,51 @@ +/* + * @name 선형 그래디언트 + * @description lerpColor() 함수는 두 가지 색상을 보간하는 데에 쓰입니다. + */ +// 상수 +const Y_AXIS = 1; +const X_AXIS = 2; +let b1, b2, c1, c2; + +function setup() { + createCanvas(710, 400); + + // 색상 정의하기 + b1 = color(255); + b2 = color(0); + c1 = color(204, 102, 0); + c2 = color(0, 102, 153); + + noLoop(); +} + +function draw() { + // 배경 + setGradient(0, 0, width / 2, height, b1, b2, X_AXIS); + setGradient(width / 2, 0, width / 2, height, b2, b1, X_AXIS); + // 전경 + 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) { + // 위에서 아래 방향 그래디언트 + 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) { + // 왼쪽에서 오른쪽 방향 그래디언트 + 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/dist/assets/examples/ko/07_Color/06_Radial_Gradient.js b/dist/assets/examples/ko/07_Color/06_Radial_Gradient.js new file mode 100644 index 0000000000..ce2df1dde5 --- /dev/null +++ b/dist/assets/examples/ko/07_Color/06_Radial_Gradient.js @@ -0,0 +1,32 @@ +/* + * @name 방사형 그래디언트 + * @description 동심원을 그려 한 색상이 다른 색상으로 퍼지는 듯한 효과를 만듭니다. + */ +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/dist/assets/examples/ko/07_Color/07_Lerp_Color.js b/dist/assets/examples/ko/07_Color/07_Lerp_Color.js new file mode 100644 index 0000000000..0c1324183f --- /dev/null +++ b/dist/assets/examples/ko/07_Color/07_Lerp_Color.js @@ -0,0 +1,49 @@ +/* + * @name 선형 보간(lerp) 색상 + * @description 무작위의 도형을 반복하고, + * 빨강색과 파란색을 선형적으로 보간합니다. + */ +function setup() { + createCanvas(720, 400); + background(255); + noStroke(); +} + +function draw() { + background(255); + from = color(255, 0, 0, 0.2 * 255); + to = color(0, 0, 255, 0.2 * 255); + c1 = lerpColor(from, to, 0.33); + c2 = lerpColor(from, to, 0.66); + for (let i = 0; i < 15; i++) { + fill(from); + quad( + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height) + ); + fill(c1); + quad( + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height) + ); + fill(c2); + quad( + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height) + ); + fill(to); + quad( + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height) + ); + } + frameRate(5); +} diff --git a/dist/assets/examples/ko/08_Math/00_incrementdecrement.js b/dist/assets/examples/ko/08_Math/00_incrementdecrement.js new file mode 100644 index 0000000000..2fa2db7120 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/00_incrementdecrement.js @@ -0,0 +1,42 @@ +/* + * @name 증가와 감소 + * @description "a++"는 "a = a + 1"와 같은 표현입니다. + * "a--"는 "a = a - 1"과 같은 표현입니다. + */ +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/dist/assets/examples/ko/08_Math/01_operatorprecedence.js b/dist/assets/examples/ko/08_Math/01_operatorprecedence.js new file mode 100644 index 0000000000..0f7e3a8028 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/01_operatorprecedence.js @@ -0,0 +1,51 @@ +/* + * @name 연산자 우선 순위 + * @description 연산자의 실행 순서를 명시하는 경우를 제외하고, 모든 선언문은 연산자 우선 순위에 따라 + * 처리됩니다. 예를 들어, 수식 "4+2*8"는 2에 8을 먼저 곱하고, 그 결과값에 4를 더합니다. + * 이는 "*"이 "+"보다 연산 우선 순위를 갖기 때문입니다. + * 혼동을 방지하기 위해 "4+(2*8)"라 쓰는 편을 권장하기도 합니다. + * 이처럼, 코드 내에 괄호를 사용하여 처리 순서를 명시할 수 있습니다. + * 연산자 우선 순위는 다음과 같습니다. + */ +// 처리 순위가 높은 연산자는 목록 상단에, +// 가장 낲은 연산자는 목록 하단에 적힙니다. +// 곱하기 연산자: * / % +// 증감 연산자: + - +// 비교 연산자: < > <= >= +// 등호 연산자: == != +// 논리 연산자 AND: && +// 논리 연산자 OR: || +// 할당 연산자: = += -= *= /= %= +function setup() { + createCanvas(710, 400); + background(51); + noFill(); + stroke(51); + + stroke(204); + for (let i = 0; i < width - 20; i += 4) { + // 70이 30을 더한 결과값이 + // 현재 "i"값보다 큰 지의 여부를 평가 + // 처리 순서를 명확히하고자 "if (i > (30 + 70)) {"로 작성 + if (i > 30 + 70) { + line(i, 0, i, 50); + } + } + + stroke(255); + // 2와 8을 곱한 뒤, 그 결과값에 4를 더함 + // 처리 순서를 명확히하고자, "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) { + // 비교 선언문을 가장 먼저 처리한 뒤, + // 다음으로 논리 연산자 AND, 마지막으로 논리 연산자 OR 순으로 처리. + // 처리 순서를 명확히하고자 다음과 같이 작성: + // "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/dist/assets/examples/ko/08_Math/02_distance1d.js b/dist/assets/examples/ko/08_Math/02_distance1d.js new file mode 100644 index 0000000000..36e93c6904 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/02_distance1d.js @@ -0,0 +1,64 @@ +/* + * @name 1D 거리 + * @description 마우스를 좌우로 움직여, 화면 속 도형의 움직임 속도와 방향을 조정해보세요. + */ +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/dist/assets/examples/ko/08_Math/03_distance2d.js b/dist/assets/examples/ko/08_Math/03_distance2d.js new file mode 100644 index 0000000000..3fa5d7efa0 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/03_distance2d.js @@ -0,0 +1,24 @@ +/* + * @name 2D 거리 + * @description 이미지 위로 마우스를 움직여, 매트릭스를 흐리게 또는 뚜렷하게 만들어보세요. + * 각 타원과 마우스 간의 거리에 비례하여 원형의 크기가 조정됩니다. + */ +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/dist/assets/examples/ko/08_Math/04_sine.js b/dist/assets/examples/ko/08_Math/04_sine.js new file mode 100644 index 0000000000..6f55c094fe --- /dev/null +++ b/dist/assets/examples/ko/08_Math/04_sine.js @@ -0,0 +1,27 @@ +/* + * @name 사인 + * @description sin() 함수로 도형의 크기를 부드럽게 조정합니다. + */ +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/dist/assets/examples/ko/08_Math/05_sincosine.js b/dist/assets/examples/ko/08_Math/05_sincosine.js new file mode 100644 index 0000000000..431daec574 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/05_sincosine.js @@ -0,0 +1,43 @@ +/* + * @name 사인 코사인 + * @description sin()와 cos() 함수를 이용한 선형적 움직임입니다. + * 0과 PI*2 사이의 숫자(TWO_PI의 경우, 약 6.28)를 위의 함수에 넣으면 + * -1과 1 사이의 값이 반환됩니다. + * 이러한 반환값은 더 큰 움직임을 만드는 한 척도로서 쓰입니다. + */ +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/dist/assets/examples/ko/08_Math/06_sinewave.js b/dist/assets/examples/ko/08_Math/06_sinewave.js new file mode 100644 index 0000000000..a3dbc919b5 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/06_sinewave.js @@ -0,0 +1,47 @@ +/* + * @name 사인파 + * @description 간단한 사인파를 만듭니다. + * 원본 제작: 다니엘 쉬프만(Daniel Shiffman) + */ + +let xspacing = 16; // 각 도형들 간의 가로 거리 +let w; // 전체 파형의 너비 +let theta = 0.0; // 시작 각도 0 +let amplitude = 75.0; // 파형의 높이 +let period = 500.0; // 파형이 반복되기 전까지 생성되는 픽셀 개수 +let dx; // x 증가값 +let yvalues; // 파형의 최고 높이를 저장하기 위한 배열 + +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() { + // 세타값(theta) 증가 (다른 값을 넣어 각속도를 조정해보세요) + theta += 0.02; + + // 매 x값마다 싸인 함수를 이용해 y값을 계산 + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = sin(x) * amplitude; + x += dx; + } +} + +function renderWave() { + noStroke(); + fill(255); + // 각 위치에 지정된 타원형으로 파형을 그릴 수 있는 간단한 방법 + for (let x = 0; x < yvalues.length; x++) { + ellipse(x * xspacing, height / 2 + yvalues[x], 16, 16); + } +} diff --git a/dist/assets/examples/ko/08_Math/07_additivewave.js b/dist/assets/examples/ko/08_Math/07_additivewave.js new file mode 100644 index 0000000000..4efea302ea --- /dev/null +++ b/dist/assets/examples/ko/08_Math/07_additivewave.js @@ -0,0 +1,67 @@ +/* + * @name 파형 추가 + * @description 두 개의 파형을 합쳐 좀 더 복잡한 파도 모양을 만듭니다. + * 원본 제작: 다니엘 쉬프만(Daniel Shiffman) + */ +let xspacing = 8; // 각 타원 간 가로 거리 +let w; // 전체 파형의 너비 +let maxwaves = 4; // 더해진 파형들의 전체 개수 + +let theta = 0.0; +let amplitude = new Array(maxwaves); // 파형의 높이 +// X를 증가하는 값으로, period와 xspacing로 계산됨 +let dx = new Array(maxwaves); +// 파형의 최고 높이를 저장하기 위한 배열 (반드시 필요한 건 아님) +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); // 파형이 반복되기 전까지 생성되는 픽셀 갯수 + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new Array(floor(w / xspacing)); +} + +function draw() { + background(0); + calcWave(); + renderWave(); +} + +function calcWave() { + // 세타값(theta) 증가 (다른 값을 넣어 각속도를 조정해보세요) + theta += 0.02; + + // 모든 높이값을 0으로 설정 + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // 파형 높이값 축적하기 + for (let j = 0; j < maxwaves; j++) { + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + // 매번 모든 파형들은 싸인 대신 코싸인으로 처리 + if (j % 2 == 0) yvalues[i] += sin(x) * amplitude[j]; + else yvalues[i] += cos(x) * amplitude[j]; + x += dx[j]; + } + } +} + +function renderWave() { + // 각 위치에 지정된 타원형으로 파형을 그릴 수 있는 간단한 방법 + 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/dist/assets/examples/ko/08_Math/08_polartocartesian.js b/dist/assets/examples/ko/08_Math/08_polartocartesian.js new file mode 100644 index 0000000000..834cad7159 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/08_polartocartesian.js @@ -0,0 +1,44 @@ +/* + * @name 극좌표를 직교 좌표로 + * @description 극좌표(지름 r, 세타 theta)를 직교 좌표(x,y)로 변환 + * : x = rcos(theta) y = rsin(theta) + * 원본 제작: 다니엘 쉬프만(Daniel Shiffman) + */ +let r; + +// 각도, 각속도, 가속 +let theta; +let theta_vel; +let theta_acc; + +function setup() { + createCanvas(710, 400); + + // 모든값 초기화 + r = height * 0.45; + theta = 0; + theta_vel = 0; + theta_acc = 0.0001; +} + +function draw() { + background(0); + + // 원점을 화면 중간 위치에 해당하는 좌표값으로 설정 + translate(width / 2, height / 2); + + // 극좌표를 직교 좌표로 변환 + let x = r * cos(theta); + let y = r * sin(theta); + + // 직교 좌표에서 타원 그리기 + ellipseMode(CENTER); + noStroke(); + fill(200); + ellipse(x, y, 32, 32); + + // 가속도와 속도를 각도에 적용하기 + // (이 예제에서 r은 고정됩니다.) + theta_vel += theta_acc; + theta += theta_vel; +} diff --git a/dist/assets/examples/ko/08_Math/09_arctangent.js b/dist/assets/examples/ko/08_Math/09_arctangent.js new file mode 100644 index 0000000000..21c053b7fd --- /dev/null +++ b/dist/assets/examples/ko/08_Math/09_arctangent.js @@ -0,0 +1,45 @@ +/* + * @name 아크탄젠트 + * @description 마우스를 움직여 눈의 방향을 바꿔보세요.
atan2()함수는 마우스 커서와 눈의 각도를 계산합니다. + */ +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(); + }; +} diff --git a/dist/assets/examples/ko/08_Math/10_Interpolate.js b/dist/assets/examples/ko/08_Math/10_Interpolate.js new file mode 100644 index 0000000000..1659c1ce3c --- /dev/null +++ b/dist/assets/examples/ko/08_Math/10_Interpolate.js @@ -0,0 +1,32 @@ +/* + * @name 선형 보간법 + * @frame 720, 400 + * @description 화면 위로 마우스를 움직이면 타원이 따라옵니다. + * 애니메이션의 매 프레임 사이에, 타원은 현재 위치에서 커서를 향해 지정된 거리(0.05)의 일부만큼 움직입니다. + * 이는 lerp() 함수를 사용하여 구현된 것입니다. + * 이 예제는 이징(Easing) 예제와 동일한 효과를 만들지만, lerp()만으로 구현한다는 점에서 다릅니다. + */ + +let x = 0; +let y = 0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(51); + + // lerp()는 특정 값만큼 증가하는 두 개의 숫자로부터 그 결과값을 계산합니다. + // amt인수는 이 두 개의 숫자를 선형적으로 결정하는데, + // 0.0은 처음 위치, 0.1은 첫번째 점과 아주 가까운 위치, 0.5는 앞의 두 점의 중간 위치인 식입니다. + + // 매 프레임마다 마우스 위치를 향해 5%의 거리를 움직이도록 합니다. + x = lerp(x, mouseX, 0.05); + y = lerp(y, mouseY, 0.05); + + fill(255); + stroke(255); + ellipse(x, y, 66, 66); +} diff --git a/dist/assets/examples/ko/08_Math/11_doubleRandom.js b/dist/assets/examples/ko/08_Math/11_doubleRandom.js new file mode 100644 index 0000000000..de03e23121 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/11_doubleRandom.js @@ -0,0 +1,24 @@ +/* + * @name 이중 랜덤 + * @frame 720,400 (optional) + * @description random() 호출과 point()함수를 이중으로 사용하여 + * 불규칙한 톱니 모양의 선을 만듭니다. + * 원본 제작: 이라 그린버그(Ira Greenberg) + */ +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/dist/assets/examples/ko/08_Math/12_random.js b/dist/assets/examples/ko/08_Math/12_random.js new file mode 100644 index 0000000000..558f3beebf --- /dev/null +++ b/dist/assets/examples/ko/08_Math/12_random.js @@ -0,0 +1,19 @@ +/* + * @name 랜덤 + * @description 난수(random number)에 근간을 둔 이미지입니다. + * 프로그램이 불러오기될 때마다 결과가 달라집니다. + */ +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/dist/assets/examples/ko/08_Math/13_noise1D.js b/dist/assets/examples/ko/08_Math/13_noise1D.js new file mode 100644 index 0000000000..5ef5783292 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/13_noise1D.js @@ -0,0 +1,31 @@ +/* + * @name 1D 노이즈 + * @description 1차원 펄린 노이즈를 사용해 위치를 지정합니다. + */ +let xoff = 0.0; +let xincrement = 0.01; + +function setup() { + createCanvas(710, 400); + background(0); + noStroke(); +} + +function draw() { + // 알파값이 섞인 배경 생성 + fill(0, 10); + rect(0, 0, width, height); + + //let n = random(0,width); // 노이즈 대신 이 코드를 사용할 수 있습니다. + + // xoff로 노이즈값을 지정하고 + // 화면의 너비에 따라 크기 조정 + let n = noise(xoff) * width; + + // 매 사이클마다 xoff만큼 증가 + xoff += xincrement; + + // 펄린 노이즈가 생성한 값으로 타원 그리기 + fill(200); + ellipse(n, height / 2, 64, 64); +} diff --git a/dist/assets/examples/ko/08_Math/14_noisewave.js b/dist/assets/examples/ko/08_Math/14_noisewave.js new file mode 100644 index 0000000000..557ef533c1 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/14_noisewave.js @@ -0,0 +1,42 @@ +/* + * @name 노이즈 파형 + * @description 펄린 노이즈를 사용하여 파도같은 패턴을 만듭니다. + * 원본 제작: 다니엘 쉬프만(Daniel Shiffman) + */ +let yoff = 0.0; // 펄린 노이즈의 2차원 + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(51); + + fill(255); + // 파형의 점들을 이용한 다각형 그리기 + beginShape(); + + let xoff = 0; // 옵션 #1: 2D 노이즈 + // let xoff = yoff; // 옵션 #2: 1D 노이즈 + + // 가로 픽셀들에 반복 + for (let x = 0; x <= width; x += 10) { + // y값을 노이즈에 따라 계산, 다음에 매핑(map)하기 + + // 옵션 #1: 2D 노이즈 + let y = map(noise(xoff, yoff), 0, 1, 200, 300); + + // 옵션 #2: 1D 노이즈 + // let y = map(noise(xoff), 0, 1, 200,300); + + // 버텍스 설정하기 + vertex(x, y); + // 노이즈의 x차원 증가하기 + xoff += 0.05; + } + // 노이즈의 y차원 증가하기 + yoff += 0.01; + vertex(width, height); + vertex(0, height); + endShape(CLOSE); +} diff --git a/dist/assets/examples/ko/08_Math/15_Noise2D.js b/dist/assets/examples/ko/08_Math/15_Noise2D.js new file mode 100644 index 0000000000..cba42f1384 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/15_Noise2D.js @@ -0,0 +1,42 @@ +/* + * @name 2D 노이즈 + * @frame 710,400 (선택 사항) + * @description 여러 인수를 사용하여 2D 노이즈를 만들어보세요. + * + */ + +let noiseVal; +let noiseScale = 0.02; + +function setup() { + createCanvas(640, 360); +} + +function draw() { + background(0); + // 이미지의 좌측 절반 그리기 + for (let y = 0; y < height - 30; y++) { + for (let x = 0; x < width / 2; x++) { + // noiceDetail, 픽셀 옥타브와 번짐 정도 + noiseDetail(2, 0.2); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // 이미지의 우측 절반 그리기 + for (let y = 0; y < height - 30; y++) { + for (let x = width / 2; x < width; x++) { + // noiceDetail, 픽셀 옥타브와 번짐 정도 + noiseDetail(5, 0.5); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + //두 화면의 디테일 구성하기 + textSize(18); + fill(255, 255, 255); + text('2옥타브와 0.2 번짐 정도의 2D 노이즈', 10, 350); + text('1옥타브와 0.7 번짐 정도의 2D 노이즈', 330, 350); +} diff --git a/dist/assets/examples/ko/08_Math/16_Noise3D.js b/dist/assets/examples/ko/08_Math/16_Noise3D.js new file mode 100644 index 0000000000..d060e0311b --- /dev/null +++ b/dist/assets/examples/ko/08_Math/16_Noise3D.js @@ -0,0 +1,48 @@ +/* + * @name 3D 노이즈 + * @frame 710,400 (선택 사항) + * @description 3D 노이즈를 사용하여 간단한 동적 텍스처를 만듭니다. + */ + +let noiseVal; +//x를 0.01씩 증가 +let x_increment = 0.01; +//draw()함수 사이클마다 z를 0.02씩 증가 +let z_increment = 0.02; + +//Offset values +let z_off, y_off, x_off; + +function setup() { + //캔버스 만들기 + createCanvas(640, 360); + //프레임 속도 조정 + frameRate(20); + //z_off의 초기값 + z_off = 0; +} + +function draw() { + x_off = 0; + y_off = 0; + //배경을 검정색으로 설정 + background(0); + //노이즈 디테일 조정 + noiseDetail(8, 0.65); + + //매 x,y마다 노이즈값 계산 + for (let y = 0; y < height; y++) { + x_off += x_increment; + y_off = 0; + + for (let x = 0; x < width; x++) { + //각 픽셀을 계산하고 그리기 + 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/dist/assets/examples/ko/08_Math/17_Randomchords.js b/dist/assets/examples/ko/08_Math/17_Randomchords.js new file mode 100644 index 0000000000..a77fad280a --- /dev/null +++ b/dist/assets/examples/ko/08_Math/17_Randomchords.js @@ -0,0 +1,35 @@ +/* + * @name 랜덤 선들 + * @description 원형을 그리는 무작위의 선들을 축적합니다. + * 불투명하게 처리된 선들이 축적될수록 마치 명암이 적용된 구처럼 보입니다. + * 기여: 애티쉬 바티아(Aatish Bhatia), 앤더스 호프(Anders Hoff)로부터 영감을 받음. + */ + +function setup() { + createCanvas(400, 400); + background(255, 255, 255); + + // 알파값을 활용하여 선의 불투명도를 조정 + stroke(0, 0, 0, 15); +} + +function draw() { + // 매 프레임마다 두 개의 선을 무작위로 그리기 + randomChord(); + randomChord(); +} + +function randomChord() { + // 원형 위 점 하나를 무작위로 찾기 + let angle1 = random(0, 2 * PI); + let xpos1 = 200 + 200 * cos(angle1); + let ypos1 = 200 + 200 * sin(angle1); + + // 원형 위 또다른 점 하나를 무작위로 찾기 + let angle2 = random(0, 2 * PI); + let xpos2 = 200 + 200 * cos(angle2); + let ypos2 = 200 + 200 * sin(angle2); + + // 둘 사이에 선을 긋기 + line(xpos1, ypos1, xpos2, ypos2); +} diff --git a/dist/assets/examples/ko/08_Math/18_Map.js b/dist/assets/examples/ko/08_Math/18_Map.js new file mode 100644 index 0000000000..df4f840974 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/18_Map.js @@ -0,0 +1,21 @@ +/* + * @name 매핑(map) + * @description map()함수를 통해 그 어떠한 숫자든 여러분의 프로젝트에 더 많은 도움을 줄 + * 숫자로 매핑할 수 있습니다. + * 예를 들어, 마우스 위치값을 사용하여 도형의 크기와 색상을 조정할 수 있습니다. + * 이 예제에서는 마우스의 x 좌표(0과 360사이의 숫자)가 원형의 색상과 크기를 정의하는 새로운 숫자들로 처리됩니다. + */ +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(0); + // 0부터 720에 이르는 mouseX 값을 0부터 175의 범위로 조정 + let c = map(mouseX, 0, width, 0, 175); + // 0부터 720에 이르는 mouseX 값을 40부터 300의 범위로 조정 + let d = map(mouseX, 0, width, 40, 300); + fill(255, c, 0); + ellipse(width/2, height/2, d, d); +} diff --git a/dist/assets/examples/ko/08_Math/19_parametricEquation.js b/dist/assets/examples/ko/08_Math/19_parametricEquation.js new file mode 100644 index 0000000000..553b4ea135 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/19_parametricEquation.js @@ -0,0 +1,43 @@ +/* + * @name 매개변수 방정식 + * @description 매개변수 방정식은 x와 y 좌표값이 다른 문자로서 표기된 식을 말합니다. + * 이러한 문자를 매개변수라 부르며, 일반적으로 t 또는 θ로 표기됩니다. + * 알렉산더 밀러(Alexander Miller)의 유투브 채널로부터 영감을 얻었습니다. + */ + +function setup(){ + createCanvas(720,400); +} + +// x와 y의 매개변수는 일반적으로 세타(theta)를 뜻하는 't' 또는 그 기호(θ)로 표기됩니다. +let t = 0; +function draw(){ + background('#fff'); + translate(width/2,height/2); + stroke('#0f0f0f'); + strokeWeight(1.5); + //100개의 선 추가를 위한 반복문 + 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; +} +// 선의 초기 x 좌표값을 변경하는 함수 +function x1(t){ + return sin(t/10)*125+sin(t/20)*125+sin(t/30)*125; +} + +// 선의 초기 y 좌표값을 변경하는 함수 +function y1(t){ + return cos(t/10)*125+cos(t/20)*125+cos(t/30)*125; +} + +// 선의 최종 x 좌표값을 변경하는 함수 +function x2(t){ + return sin(t/15)*125+sin(t/25)*125+sin(t/35)*125; +} + +// 선의 최종 y 좌표값을 변경하는 함수 +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/dist/assets/examples/ko/08_Math/20_Graphing2DEquations.js b/dist/assets/examples/ko/08_Math/20_Graphing2DEquations.js new file mode 100644 index 0000000000..af71814bbb --- /dev/null +++ b/dist/assets/examples/ko/08_Math/20_Graphing2DEquations.js @@ -0,0 +1,52 @@ +/** + * @name Graphing 2D Equations + * @frame 710, 400 + * @description Graphics the following equation: sin(n cos(r) + 5θ) where n is a function of horizontal mouse location. Original by Daniel Shiffman + */ +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/dist/assets/examples/ko/08_Math/21_parametricEquation.js b/dist/assets/examples/ko/08_Math/21_parametricEquation.js new file mode 100644 index 0000000000..83c1a3c336 --- /dev/null +++ b/dist/assets/examples/ko/08_Math/21_parametricEquation.js @@ -0,0 +1,44 @@ +/* + * @name Parametric Equations + * @description 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. + */ + +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/dist/assets/examples/ko/09_Simulate/00_Forces.js b/dist/assets/examples/ko/09_Simulate/00_Forces.js new file mode 100644 index 0000000000..ee8b1df54a --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/00_Forces.js @@ -0,0 +1,147 @@ +/* + * @name 힘 + * @description 바디 객체에 작용하는 여러가지 물리학적 힘 + * (natureofcode.com) + */ +// 바디에 적용되는 여러가지 물리학적 힘(Mover 클래스) +// 바디는 중력을 끊임없이 경험합니다. +// 바디는 물 속에서 유체 저항을 경험합니다. + +// 5개의 움직이는 형체 +let movers = []; + +// Liquid +let liquid; + +function setup() { + createCanvas(640, 360); + reset(); + // liquid(액체) 객체 생성 + liquid = new Liquid(0, height / 2, width, height / 2, 0.1); +} + +function draw() { + background(127); + + // 물 그리기 + liquid.display(); + + for (let i = 0; i < movers.length; i++) { + + // Mover가 액체인가요? + if (liquid.contains(movers[i])) { + // 항력 계산하기 + let dragForce = liquid.calculateDrag(movers[i]); + // Mover에 항력 적용하기 + movers[i].applyForce(dragForce); + } + + // 중력은 여기서 mass(질량)에 따라 결정됩니다! + let gravity = createVector(0, 0.1 * movers[i].mass); + // 중력 적용하기 + movers[i].applyForce(gravity); + + // 업데이트하고 화면에 보이기(display) + movers[i].update(); + movers[i].display(); + movers[i].checkEdges(); + } + +} + + +function mousePressed() { + reset(); +} + +// 모든 Mover 오브젝트들을 무작위로 재시작하기 +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; +}; + +// Mover가 액체인가요? +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; +}; + +// 항력 계산하기 +Liquid.prototype.calculateDrag = function(m) { + // Magnitue(크기) = 계수 * speed(속도)의 제곱 + let speed = m.velocity.mag(); + let dragMagnitude = this.c * speed * speed; + + // 방향은 속도와 반대쪽으로 + let dragForce = m.velocity.copy(); + dragForce.mult(-1); + + // 힘의 크기에 따라 조정하기 + // 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)의 두번째 법칙: F = M * A +// 또는 A = F / M +Mover.prototype.applyForce = function(force) { + let f = p5.Vector.div(force, this.mass); + this.acceleration.add(f); +}; + +Mover.prototype.update = function() { + // 가속도에 따라 변하는 속도 + this.velocity.add(this.acceleration); + // 속도에 따라 변하는 위치 + this.position.add(this.velocity); + // 매 프레임마다 가속도 초기화 + 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); +}; + +// 바닥면에서 튀어오르기 +Mover.prototype.checkEdges = function() { + if (this.position.y > (height - this.mass * 8)) { + // 바닥면에 닿을 때 약간의 완충 현상 발생 + this.velocity.y *= -0.9; + this.position.y = (height - this.mass * 8); + } +}; + + + + + + + + diff --git a/dist/assets/examples/ko/09_Simulate/01_ParticleSystem.js b/dist/assets/examples/ko/09_Simulate/01_ParticleSystem.js new file mode 100644 index 0000000000..81ea5dd585 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/01_ParticleSystem.js @@ -0,0 +1,69 @@ +/* + * @name 파티클 시스템 + * @description 이 예제는 기초적인 파티클 시스템을 다룹니다. + * (natureofcode.com) + */ +let system; + +function setup() { + createCanvas(720, 400); + system = new ParticleSystem(createVector(width / 2, 50)); +} + +function draw() { + background(51); + system.addParticle(); + system.run(); +} + +// 간단한 파티클 클래스 +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(); +}; + +// 위치 업데이트를 위한 메소드 +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// 화면에 보이기 위한 메소드 +Particle.prototype.display = function() { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// 파티클이 여전히 쓸만한가요? +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/dist/assets/examples/ko/09_Simulate/02_Flocking.js b/dist/assets/examples/ko/09_Simulate/02_Flocking.js new file mode 100644 index 0000000000..55fa0b262b --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/02_Flocking.js @@ -0,0 +1,229 @@ +/* + * @name 플로킹 + * @description 크레이그 레이놀즈(Craig Reynolds)의 "군집(Flocking)" 행위를 묘사합니다. + * 참고: http://www.red3d.com/cwr/ + * 규칙: 응집, 분리, 정렬 + * (출처: natureofcode.com). + * 마우스를 드래그하여 시스템에 개체(boid)를 더해보세요. + */ + + +let flock; + +function setup() { + createCanvas(640, 360); + createP("Drag the mouse to generate new boids."); + + flock = new Flock(); + // 시스템에 초기 개체(boid) 더하기 + for (let i = 0; i < 100; i++) { + let b = new Boid(width / 2,height / 2); + flock.addBoid(b); + } +} + +function draw() { + background(51); + flock.run(); +} + +// 시스템에 새로운 개체 더하기 +function mouseDragged() { + flock.addBoid(new Boid(mouseX, mouseY)); +} + +// The Nature of Code +// 다니엘 쉬프만(Daniel Shiffman) +// http://natureofcode.com + +// Flock 객체는 +// 모든 개체(boid)의 배열을 관리하는, 간단한 작업을 수행합니다. + +function Flock() { + // 모든 개체의 배열 + this.boids = []; // 배열 초기화 +} + +Flock.prototype.run = function() { + for (let i = 0; i < this.boids.length; i++) { + this.boids[i].run(this.boids); // 전체 보이즈 개체 목록을 각 개체에 보내기 + } +} + +Flock.prototype.addBoid = function(b) { + this.boids.push(b); +} + +// The Nature of Code +// 다니엘 쉬프만(Daniel Shiffman) +// http://natureofcode.com + +// Boid(개체) 클래스 +// 응집(cohesion), 분리(seperation), 정렬(alignment)을 위한 메소드 추가 + +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; // 최대 속도 + this.maxforce = 0.05; // 최대 조타력 +} + +Boid.prototype.run = function(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); +} + +Boid.prototype.applyForce = function(force) { + // A = F / M 으로 계산하고 싶다면, 여기에 질량을 더하면 됩니다. + this.acceleration.add(force); +} + +// 3가지 규칙에 따라 매번 새로운 가속도를 만듭니다. +Boid.prototype.flock = function(boids) { + let sep = this.separate(boids); // 분리 + let ali = this.align(boids); // 정렬 + let coh = this.cohesion(boids); // 응집 + // 세 힘들을 임의로 가중하기 + sep.mult(1.5); + ali.mult(1.0); + coh.mult(1.0); + // 가속도에 force 벡터 더하기 + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); +} + +// 위치 업데이트를 위한 메소드 +Boid.prototype.update = function() { + // 속도 업데이트 + this.velocity.add(this.acceleration); + // 속도 제한 + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // 매 사이클마다 가속도를 0으로 리셋 + this.acceleration.mult(0); +} + +// 특정 목표점을 향한 조타력을 계산하고 적용하는 메소드 +// STEER(조타력) = DESIRED(목표점) - VELOCITY(속도) +Boid.prototype.seek = function(target) { + let desired = p5.Vector.sub(target,this.position); // 현위치에서 목표점을 가리키는 벡터 + // desired를 표준화하고 최대 속도로 조정 + desired.normalize(); + desired.mult(this.maxspeed); + // Steering = Desired minus Velocity + let steer = p5.Vector.sub(desired,this.velocity); + steer.limit(this.maxforce); // 최대 조타력으로 제한 + return steer; +} + +Boid.prototype.render = function() { + // 속도의 방향에 따라 회전하는 삼각형 그리기 + 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; +} + +// 분리 Seperation +// 인근의 개체를 확인하고 이로부터 거리를 유지하며 조타하게 만드는 메소드 +Boid.prototype.separate = function(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // 매 개체가 시스템에 생성될 때마다, 서로 너무 가까운 위치에 있는지 여부를 확인 + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position,boids[i].position); + // 만약 그 거리가 0보다 크고 임의의 값보다 작다면(0은 개체의 현위치) + if ((d > 0) && (d < desiredseparation)) { + // 인근의 개체로부터 떨어진 지점을 향하는 벡터 계산 + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // 거리에 따른 가중 + steer.add(diff); + count++; // 개체수 카운트 + } + } + // 평균 -- 얼마로 나눌 것인가 + if (count > 0) { + steer.div(count); + } + + // 벡터가 0보다 크다면, + if (steer.mag() > 0) { + // 레이놀즈의 공식 Steering = Desired - Velocity을 적용한다. + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; +} + +// 배열 Alignment +// 서로 인근에 있는 모든 개체에 대한 평균 속도 계산 +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 +// 서로 인근에 있는 모든 개체의 평균 위치값(예: 중앙)에 대해, 이 지점을 향한 조타 벡터값 계산 +Boid.prototype.cohesion = 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].position); // 위치 추가 + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // 해당 위치를 향해 조타 + } else { + return createVector(0, 0); + } +} + + diff --git a/dist/assets/examples/ko/09_Simulate/03_WolframCA.js b/dist/assets/examples/ko/09_Simulate/03_WolframCA.js new file mode 100644 index 0000000000..6472f7d97f --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/03_WolframCA.js @@ -0,0 +1,73 @@ +/* + * @name 울프램 셀룰러 오토마타 + * @description 1차원 셀룰러 오토마타(cellular automata) 간단하게 구현하기. + * (natureofcode.com) + */ + +let w = 10; +// 0과 1들의 배열 +let cells; + + // "1"의 상태를 갖는 중간 셀과 함께 시작합니다. +let generation = 0; + +// {0,1,1,0,1,1,0,1}과 같은 규칙 묶음(ruleset)을 저장하는 배열 +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(); + } +} + +// 새로운 세대(generation) 생성 과정 +function generate() { + // 먼저, 새로운 값을 위한 빈 배열을 만듭니다. + let nextgen = Array(cells.length); + // 매 셀마다 현재 상태를 확인하여 새로운 상태를 결정하고 이 둘을 이웃하게 만듭니다. + // 모서리에 위치하여 한 개의 이웃만을 가진 상태는 무시합니다. + for (let i = 1; i < cells.length-1; i++) { + let left = cells[i-1]; // 좌측 이웃 상태 + let me = cells[i]; // 현재 상태 + let right = cells[i+1]; // 우측 이웃 상태 + nextgen[i] = rules(left, me, right); // 다음 세대 상태를 규칙 묶음(ruleset)에 의거하여 계산 + } + // 현재 상태가 새로운 세대가 됩니다. + cells = nextgen; + generation++; +} + + +// 울프램 규칙 구현하기 +// 더 향상되거나 간결해질 수도 있지만, 여기서 각 사례별로 어떤 일이 일어나는지 명확히 볼 수 있습니다. +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/dist/assets/examples/ko/09_Simulate/04_GameOfLife.js b/dist/assets/examples/ko/09_Simulate/04_GameOfLife.js new file mode 100644 index 0000000000..d203b1a791 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/04_GameOfLife.js @@ -0,0 +1,95 @@ +/* + * @name 라이프 게임 + * @description 존 콘웨이(John Conway)의 라이프 게임 셀룰러 오토마타 + * (Game of Life Cellular Automata)의 기초적 구현 + * (natureofcode.com) + */ + +let w; +let columns; +let rows; +let board; +let next; + +function setup() { + createCanvas(720, 400); + w = 20; + // 행렬 계산하기 + columns = floor(width / w); + rows = floor(height / w); + // JS를 사용하여 요상한 2D 배열 만들기 + board = new Array(columns); + for (let i = 0; i < columns; i++) { + board[i] = new Array(rows); + } + // 복수의 2D 배열을 만들고 바꾸기 + 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); + } + } + +} + +// 마우스 버튼 클릭시 보드 리셋하기 +function mousePressed() { + init(); +} + +// 무작위로 보드 채우기 +function init() { + for (let i = 0; i < columns; i++) { + for (let j = 0; j < rows; j++) { + // 0으로 모서리 테두리 그리기 + if (i == 0 || j == 0 || i == columns-1 || j == rows-1) board[i][j] = 0; + // 나머지는 무작위로 채우기 + else board[i][j] = floor(random(2)); + next[i][j] = 0; + } + } +} + +// 새로운 세대 생성하는 과정 +function generate() { + + // 2D 배열 상 모든 셀들을 걸쳐 반복하며 각 셀별 이웃 확인하기 + for (let x = 1; x < columns - 1; x++) { + for (let y = 1; y < rows - 1; y++) { + // 3x3의 주변 그리드에 모든 상태들을 더하여 넣기 + let neighbors = 0; + for (let i = -1; i <= 1; i++) { + for (let j = -1; j <= 1; j++) { + neighbors += board[x+i][y+j]; + } + } + + // 위의 반복을 통해 모든 셀들의 현재 상태를 계산해 넣었으므로, + // 이 계산을 빼주는 요령 + neighbors -= board[x][y]; + // 라이프 규칙 + if ((board[x][y] == 1) && (neighbors < 2)) next[x][y] = 0; // 외로움 + else if ((board[x][y] == 1) && (neighbors > 3)) next[x][y] = 0; // 인구과잉 + else if ((board[x][y] == 0) && (neighbors == 3)) next[x][y] = 1; // 재생산 + else next[x][y] = board[x][y]; // 균형 + } + } + + // 바꾸기! + let temp = board; + board = next; + next = temp; +} + diff --git a/dist/assets/examples/ko/09_Simulate/05_MultipleParticleSystems.js b/dist/assets/examples/ko/09_Simulate/05_MultipleParticleSystems.js new file mode 100644 index 0000000000..2c7cb25c9d --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/05_MultipleParticleSystems.js @@ -0,0 +1,137 @@ +/* + * @name 멀티플 파티클 시스템 + * @description 마우스를 클릭한 위치에서 파티클이 폭발적으로 생성되도록 만들어보세요.
매 폭발은 Particle 클래스의 하위 클래스인 Particles와 CrazyParticles + * 의 한 인스턴스에 해당합니다.
클래스 상속과 다형 사용에 대한 방법을 확인해보세요.
+ * 원본 제작: 다니엘 쉬프만(Daniel Shiffman) + */ +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); +} + +// 간단한 파티클 클래스 +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(); +}; + +// 위치 업데이트를 위한 메소드 +Particle.prototype.update = function(){ + this.velocity.add(this.acceleration); + this.position.add(this.velocity); + this.lifespan -= 2; +}; + +// 화면에 보이기 위한 메소드 +Particle.prototype.display = function () { + stroke(200, this.lifespan); + strokeWeight(2); + fill(127, this.lifespan); + ellipse(this.position.x, this.position.y, 12, 12); +}; + +// 파티클이 여전히 쓸만한가요? +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 () { + // Particle 또는 CrazyParticle을 시스템에 더하기 + 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); + } + } +}; + +// Particle의 하위 클래스 + +function CrazyParticle(origin) { + // 부모 생성자(constructor) 만들기 + // 이 때, Function#call을 사용하여 "this"가 올바르게 설정되었는지 확인합니다. + Particle.call(this, origin); + + // 더해진 속성들 초기화하기 + this.theta = 0.0; +}; + +// Particle.prototype을 상속하는 Crazy.prototype 오브젝트 만들기 +// 주의: 여기서 자주 발생하는 실수는, Crazy.prototype을 만들기 위해 새로운 "particle()"함수를 쓰는 것입니다. +// 이는 여러가지 이유로 적당하지 않은데, 특히 Particle에 "origin" 인수를 제공할 게 없다는 점에서 그렇습니다. +// Particle은 위와 같이 Crazy에서 호출하면 됩니다. +CrazyParticle.prototype = Object.create(Particle.prototype); // 아래의 주석을 보세요. + +// "constructor(생성자)" 속성이 CrazyParticle을 참조하게 설정하기 +CrazyParticle.prototype.constructor = CrazyParticle; + +// 여기서 우리는 run()메소드를 쓰지 않습니다. Particle로부터 상속되었기 때문입니다. + +// 이 update() 메소드는 부모 클래스의 update() 메소드를 오버라이드합니다. +CrazyParticle.prototype.update=function() { + Particle.prototype.update.call(this); + // 가로 속도에 따라 회전값 증가하기 + this.theta += (this.velocity.x * this.velocity.mag()) / 10.0; +} + +// 이 display() 메소드는 부모 클래스의 display() 메소드를 오버라이드합니다. +CrazyParticle.prototype.display=function() { + // 타원형을 일반적인 파티클처럼 렌더링하기 + Particle.prototype.display.call(this); + // 그 다음, 회전하는 선들 더하기 + push(); + translate(this.position.x, this.position.y); + rotate(this.theta); + stroke(255, this.lifespan); + line(0, 0, 25, 0); + pop(); +} diff --git a/dist/assets/examples/ko/09_Simulate/06_Spirograph.js b/dist/assets/examples/ko/09_Simulate/06_Spirograph.js new file mode 100644 index 0000000000..bdbb38b12e --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/06_Spirograph.js @@ -0,0 +1,73 @@ + +/* + * @name 스피로그래프 + * @description 일명 싸인이라 불리는 서로 맞물린 원형들을 이용하여, + * 스피로그래프와 같은 효과를 만드는 간단한 변형 예제를 소개합니다. + * 스페이스바를 눌러 스피로그래프 화면이나, 이것의 기하 궤도 추적 화면으로 전환해보세요.
+ * 이 예제는 R. Luke DuBois가 제작하였습니다.
+ * http://en.wikipedia.org/wiki/Spirograph + */ +let NUMSINES = 20; // 얼마나 싸인을 많은 동시에 그릴 건가요? +let sines = new Array(NUMSINES); // 현재 각도들을 모두 저장하는 배열 +let rad; // 중심 싸인의 초기 반지름값 +let i; // 카운터 변수 + +// 아래의 값들을 갖고 놀며 어떤 일이 일어나는 건지 감잡아 보세요! +let fund = 0.005; // 중심 싸인의 속도 +let ratio = 1; // 더해진 각 싸인은 속도에 몇을 곱하나요? +let alpha = 50; // 궤도 추적 시스템의 투명도 + +let trace = false; // 추적 중인가요? + +function setup() { + createCanvas(710, 400); + + rad = height / 4; // 중심 원의 반지름 계산 + background(204); // 화면 비우기 + + for (let i = 0; i + * 제작: R. Luke DuBois
+ * https://en.wikipedia.org/wiki/L-system + */ +// 거북이: +let x, y; // 거북이의 현재 위치 +let currentangle = 0; // 거북이가 가리키는 방향w +let step = 20; // 매 'F'마다 거북이가 움직이는 크기 +let angle = 90; // '-' 또는 '+'에 따라 거북이가 회전하는 크기 + +// 린덴마이어 시스템(L-SYSTEMS) +let thestring = 'A'; // 공리, 또는 문자열의 시작 +let numloops = 5; // 전처리할 반복문 개수 +let therules = []; // 규칙 배열 +therules[0] = ['A', '-BF+AFA+FB-']; // 첫 번째 규칙 +therules[1] = ['B', '+AF-BFB-FA+']; // 두 번째 규칙 + +let whereinstring = 0; // L-시스템 상 현재 위치? + +function setup() { + createCanvas(710, 400); + background(255); + stroke(0, 0, 0, 255); + + // 좌측 하단 코너에서 x와 y 위치 시작 + x = 0; + y = height-1; + + // L-시스템 처리하기 + for (let i = 0; i < numloops; i++) { + thestring = lindenmayer(thestring); + } +} + +function draw() { + + // 현재의 문자를 문자열로 그리기: + drawIt(thestring[whereinstring]); + + // 문자열을 읽는 지점 증가하기 + // 마지막에 wrap around + whereinstring++; + if (whereinstring > thestring.length-1) whereinstring = 0; + +} + +// L-시스템 해석하기 +function lindenmayer(s) { + let outputstring = ''; // 빈 출력 문자열 시작하기 + + // 'therules'를 반복하여 일치하는 기호 찾기: + for (let i = 0; i < s.length; i++) { + let ismatch = 0; // 기본값으로, 일치하는 기호 없음 + for (let j = 0; j < therules.length; j++) { + if (s[i] == therules[j][0]) { + outputstring += therules[j][1]; // 대체내용 작성 + ismatch = 1; // 일치하는 기호가 있으므로 복사하지 않음 + break; // for() 반복문 나오기 + } + } + // 일치하는 기호가 없으면 복사 + if (ismatch == 0) outputstring+= s[i]; + } + + return outputstring; // 수정된 문자열 전송 +} + +// 아래는 거북이를 그리는 사용자 정의 함수입니다. +function drawIt(k) { + + if (k=='F') { // 앞으로 그리기 + // step과 currentangle을 기준으로, 극좌표에서 직교 좌표로 변환하기: + let x1 = x + step*cos(radians(currentangle)); + let y1 = y + step*sin(radians(currentangle)); + line(x, y, x1, y1); // 이전의 것과 새로운 것을 연결 + + // 거북이의 위치 업데이트: + x = x1; + y = y1; + } else if (k == '+') { + currentangle += angle; // 왼쪽으로 돌기 + } else if (k == '-') { + currentangle -= angle; // 오른쪽으로 돌기 + } + + // 무작위의 색상값을 주세요: + let r = random(128, 255); + let g = random(0, 192); + let b = random(0, 50); + let a = random(50, 100); + + // 반지름에 대한 가우스 분포(D&D) 선택하기: + let radius = 0; + radius += random(0, 15); + radius += random(0, 15); + radius += random(0, 15); + radius = radius / 3; + + // 그리기: + fill(r, g, b, a); + ellipse(x, y, radius, radius); +} \ No newline at end of file diff --git a/dist/assets/examples/ko/09_Simulate/08_Spring.js b/dist/assets/examples/ko/09_Simulate/08_Spring.js new file mode 100644 index 0000000000..6338d32ea5 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/08_Spring.js @@ -0,0 +1,92 @@ +/* + * @name 용수철 + * @frame 710, 400 + * @description 수평 막대를 클릭하고 드래그한 뒤 놓으면 용수철 효과를 볼 수 있습니다. + */ +// 상단의 막대기를 위한 용수철(spring) 그리기 +let springHeight = 32, + left, + right, + maxHeight = 200, + minHeight = 100, + over = false, + move = false; + +// 용수철 시뮬레이션 상수들 +let M = 0.8, // Mass(질량) + K = 0.2, // 용수철(spring) 상수 + D = 0.92, // Damping(감쇠) + R = 150; // Rest Position(놓인 위치) + +// 용수철 시뮬레이션 변수들 +let ps = R, // 위치 + vs = 0.0, // 속도 + as = 0, // 가속도 + f = 0; // 힘 + +function setup() { + createCanvas(710, 400); + rectMode(CORNERS); + noStroke(); + left = width / 2 - 100; + right = width / 2 + 100; +} + +function draw() { + background(102); + updateSpring(); + drawSpring(); +} + +function drawSpring() { + // 바탕 그리기 + fill(0.2); + let baseWidth = 0.5 * ps + -8; + rect(width / 2 - baseWidth, ps + springHeight, width / 2 + baseWidth, height); + + // 상단 막대기의 색상 설정하고 그리기 + if (over || move) { + fill(255); + } else { + fill(204); + } + + rect(left, ps, right, ps + springHeight); +} + +function updateSpring() { + // 용수철(spring) 위치 업데이트 + if ( !move ) { + f = -K * ( ps - R ); // f=-ky + as = f / M; // 가속도 설정, f=ma == a=f/m + vs = D * (vs + as); // 속도 설정 + ps = ps + vs; // 업데이트된 위치 + } + + if (abs(vs) < 0.1) { + vs = 0.0; + } + + // 마우스가 상단 막대기 위에 있는지 여부 테스트 + if (mouseX > left && mouseX < right && mouseY > ps && mouseY < ps + springHeight) { + over = true; + } else { + over = false; + } + + // 상단 막대기의 위치 설정 및 제한 + if (move) { + ps = mouseY - springHeight / 2; + ps = constrain(ps, minHeight, maxHeight); + } +} + +function mousePressed() { + if (over) { + move = true; + } +} + +function mouseReleased() { + move = false; +} diff --git a/dist/assets/examples/ko/09_Simulate/09_Springs.js b/dist/assets/examples/ko/09_Simulate/09_Springs.js new file mode 100644 index 0000000000..bca9c5c5c5 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/09_Springs.js @@ -0,0 +1,148 @@ +/* + * @name 용수철들 + * @frame 710,400 + * @description 마우스로 원형 하나를 클릭해 재배치해보세요. + * 마우스 클릭을 놓으면 원위치로 되돌아갑니다. + * 각 원형은 조금씩 다른 행동을 보입니다. + * (https://processing.org/examples/springs.html에서 옮김) + */ +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) 클래스 +function Spring (_x, _y, _s, _d, _m, _k_in, _others, _id) { + // 화면상 위치값들 + // 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; + + // 용수철 시뮬레이션 상수들 + this.mass = _m; // Mass(질량) + this.k = 0.2; // Spring constant + this.k = _k_in; + this.damp = _d; // Damping(감쇠) + this.rest_posx = _x; // 놓인 위치 X + this.rest_posy = _y; // 놓인 위치 Y + + // 용수철 시뮬레이션 변수들 + //float pos = 20.0; // 위치 + this.velx = 0.0; // X 속도 + this.vely = 0.0; // Y 속도 + this.accel = 0; // 가속도 + this.force = 0; // 힘 + + 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; // 가속도 설정하기, f=ma == a=f/m + this.vely = this.damp * (this.vely + this.accel); // 속도 설정하기 + this.y_pos = this.y_pos + this.vely; // 업데이트된 위치 + + + this.force = -this.k * (this.x_pos - this.rest_posx); // f=-ky + this.accel = this.force / this.mass; // 가속도 설정하기, f=ma == a=f/m + this.velx = this.damp * (this.velx + this.accel); // 속도 설정하기 + this.x_pos = this.x_pos + this.velx; // 업데이트된 위치 + + + + if ((this.overEvent() || this.move) && !(this.otherOver()) ) { + this.over = true; + } else { + this.over = false; + } + } + + // 마우스가 이 용수철 위에 있는지의 여부 테스트 + 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; + } + } + + // 다른 용수철이 움직이지 않도록 처리 + 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; + } +}; \ No newline at end of file diff --git a/dist/assets/examples/ko/09_Simulate/10_SoftBody.js b/dist/assets/examples/ko/09_Simulate/10_SoftBody.js new file mode 100644 index 0000000000..48d8eebeab --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/10_SoftBody.js @@ -0,0 +1,110 @@ +/* + * @name 소프트 바디 + * @description 원본 제작: 이라 그린버그(Ira Greenberg) + *

curveVertex() 와 curveTightness()를 사용한 소프트 바디 역학 시뮬레이션. + */ +// 중심점 +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; + +// 모서리의 노드들 +let nodes = 5; + +// 빈 배열 +let nodeStartX = []; +let nodeStartY = []; +let nodeX = []; +let nodeY = []; +let angle = []; +let frequency = []; + +// 소프트 바디 역학 +let organicConstant = 1.0; + +function setup() { + createCanvas(710, 400); + + // 화면상의 중심 도형 + centerX = width / 2; + centerY = height / 2; + + // 배열을 0으로 초기화 + for (let i = 0; i < nodes; i++){ + nodeStartX[i] = 0; + nodeStartY[i] = 0; + nodeY[i] = 0; + nodeY[i] = 0; + angle[i] = 0; + } + + // 모서리 노드들의 빈도수 초기화 + for (let i = 0; i < nodes; i++){ + frequency[i] = random(5, 12); + } + + noStroke(); + frameRate(30); +} + +function draw() { + // 배경 사라지게하기 + fill(0, 100); + rect(0, 0, width, height); + drawShape(); + moveShape(); +} + +function drawShape() { + // 노드 시작 위치 계산 + 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; + } + + // 다각형 그리기 + 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() { + // 중심점 옮기기 + deltaX = mouseX - centerX; + deltaY = mouseY - centerY; + + // 스프링같은 효과 만들기 + deltaX *= springing; + deltaY *= springing; + accelX += deltaX; + accelY += deltaY; + + // 프레데터(predator)의 중심 옮기기 + centerX += accelX; + centerY += accelY; + + // 스프링같은 효과 감쇠하기 + accelX *= damping; + accelY *= damping; + + // 커브의 탄성 바꾸기 + organicConstant = 1 - ((abs(accelX) + abs(accelY)) * 0.1); + + // 노드 옮기기 + 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]; + } +} diff --git a/dist/assets/examples/ko/09_Simulate/11_SmokeParticleSystem.js b/dist/assets/examples/ko/09_Simulate/11_SmokeParticleSystem.js new file mode 100644 index 0000000000..1a2c3168f2 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/11_SmokeParticleSystem.js @@ -0,0 +1,182 @@ +/* + * @name 연기 파티클 + * @description 다니엘 쉬프만(Dan Shiffman)이 프로세싱(Processing)을 위해 제작한 + * 연기 파티클 시스템(SmokeParticleSystem) 예제를 옮겨왔습니다. + * 마치 연기와 같은 파티클을 만들어볼까요 :p + */ + +// 파티클 텍스쳐 +let particle_texture = null; + +// 파티클 시스템을 담는 변수 +let ps = null; + +function preload() { + particle_texture = loadImage("assets/particle_texture.png"); +} + +function setup() { + + // 캔버스 사이즈 설정 + createCanvas(640, 360); + + // 파티클 시스템 초기화 + 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(); + } + + // 바람의 힘을 뜻하는 화살표 그리기 + drawVector(wind, createVector(width / 2, 50, 0), 500); +} + +/** + * 이 함수는 "wind(바람)"이 부는 방향을 나타낸 화살표를 그립니다. + */ +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(); +} +//========= 파티클 시스템 =========== + +/** + * 기본적인 파티클 시스템 클래스 + * @param num 파티클 개수를 나타내는 매개 변수 + * @param v 파티클 시스템의 원점을 나타내는 매개 변수 + * @param img_ 시스템 상 각 파티클의 텍스쳐를 나타내는 매개 변수 + * @constructor 생성자 + */ +let ParticleSystem = function(num, v, img_) { + + this.particles = []; + this.origin = v.copy(); // 실수로 원래 벡터값(origin)을 바꾼 경우를 대비하여, 벡터값을 복사합니다. + this.img = img_ + for(let i = 0; i < num; ++i){ + this.particles.push(new Particle(this.origin, this.img)); + } +}; + +/** + * 이 함수는 전체 파티클 시스템을 실행합니다. + */ +ParticleSystem.prototype.run = function() { + + // 변수들에 반복할, 숨겨진 배열 길이 + // for 반복문에 .length가 표시 될 수 있지만, 매 반복마다 그 길이가 + // 다시 계산되기 때문에 여기에 숨깁니다. + let len = this.particles.length; + + //파티클 반복 및 실행 + for (let i = len - 1; i >= 0; i--) { + let particle = this.particles[i]; + particle.run(); + + // 파티클이 죽을 경우, 제거(remove)합니다. + // 자바스크립트의 배열에는 "remove" 기능이 없지만, + // 대신 동일한 기능을 수행하는 "splice"를 사용할 수 있습니다. + // 제거를 시작할 지점에 인덱스를 넣고, 해당 지점부터 몇 개를 제거할 지 넣을 수 있습니다. + if (particle.isDead()) { + this.particles.splice(i, 1); + } + } +} + +/** + * 현재 시스템의 존재하는 모든 파티클에 힘 벡터를 추가하는 메소드 + * @param dir 힘의 방향을 묘사하는 p5.Vector 매개 변수 + */ +ParticleSystem.prototype.applyForce = function(dir) { + let len = this.particles.length; + for(let i = 0; i < len; ++i){ + this.particles[i].applyForce(dir); + } +} + +/** + * 본래 지정된 텍스쳐와 동일한 텍스쳐의 파티클을 시스템 원점에 추가 + */ +ParticleSystem.prototype.addParticle = function() { + this.particles.push(new Particle(this.origin, this.img)); +} + + +//========= 파티클 =========== +/** + * 파티클을 이미지로 렌더링하는 간단한 파티클 클래스 + */ +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_; +} + +/** + * 파티클을 업데이트하는 동시에 보이게 하기 + */ +Particle.prototype.run = function() { + this.update(); + this.render(); +} + +/** + * 파티클을 화면에 보이게하는 메소드 + */ +Particle.prototype.render = function() { + imageMode(CENTER); + tint(255, this.lifespan); + image(this.texture, this.loc.x, this.loc.y); +} + +/** + * 파티클에 힘 벡터를 적용하는 메소드 + */ +Particle.prototype.applyForce = function(f) { + this.acc.add(f); +} + +/** + * 파티클의 lifespan(수명)이 끝나가는지 여부를 확인하는 메소드 + * 만약 끝나간다면 true(참)을, 그렇지 않다면 false(거짓)을 반환 + */ +Particle.prototype.isDead = function () { + if (this.lifespan <= 0.0) { + return true; + } else { + return false; + } +} + +/** + * 파티클의 위치를 업데이트하는 메소드 + */ +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/dist/assets/examples/ko/09_Simulate/12_BrownianMotion.js b/dist/assets/examples/ko/09_Simulate/12_BrownianMotion.js new file mode 100644 index 0000000000..a9f1959558 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/12_BrownianMotion.js @@ -0,0 +1,46 @@ +/* + * @name 브라운 운동 + * @description 무작위의 움직임을 연속된 선으로서 기록합니다. + * 프로세싱(Processing) 공식 웹사이트의 '예제' 페이지상 원본 예제를 p5.js로 옮겨왔습니다. + */ + +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); + + // 모든 요소들을 좌측으로 1자리 이동 + for ( let i = 1; i < num; i++ ) { + ax[i - 1] = ax[i]; + ay[i - 1] = ay[i]; + } + + // 배열의 끝에 새로운 값 넣기 + ax[num - 1] += random(-range, range); + ay[num - 1] += random(-range, range); + + // 모든 점들을 화면에 제한 + ax[num - 1] = constrain(ax[num - 1], 0, width); + ay[num - 1] = constrain(ay[num - 1], 0, height); + + // 점들을 잇는 선 그리기 + 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/dist/assets/examples/ko/09_Simulate/13_Chain.js b/dist/assets/examples/ko/09_Simulate/13_Chain.js new file mode 100644 index 0000000000..3a1aa01fa2 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/13_Chain.js @@ -0,0 +1,56 @@ +/* + * @name 사슬 + * @description 한 도형은 마우스 커서 위치에, 다른 하나는 이 도형의 위치에 붙어 따라옵니다. + * 화면에는 중력이 작용하여 두 도형을 아래 방향으로 끌어당깁니다. + * 프로세싱(Processing) 공식 웹사이트의 '예제' 페이지상 원본 예제를 p5.js로 옮겨왔습니다. + */ +let s1, s2; +let gravity = 9.0; +let mass = 2.0; + +function setup() { + createCanvas(720, 400); + fill(255, 126); + // 입력: 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;// x 와 y 좌표 + this.y = ypos; + this.vx = 0; // x축과 y축 속도 + 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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/ko/09_Simulate/14_SnowflakeParticleSystem.js b/dist/assets/examples/ko/09_Simulate/14_SnowflakeParticleSystem.js new file mode 100644 index 0000000000..0b33293e32 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/14_SnowflakeParticleSystem.js @@ -0,0 +1,63 @@ +/* + * @name 눈송이 파티클 + * @description 이 파티클 시스템은 마치 떨어지는 눈송이같은 모션을 시뮬레이션합니다. + * 눈송이 파티클을 담는 객체 배열을 사용합니다. + * 기여: 애티쉬 바티아(Aatish Bhatia) + */ + +let snowflakes = []; // 눈송이 객체를 담는 배열 + +function setup() { + createCanvas(400, 600); + fill(240); + noStroke(); +} + +function draw() { + background('brown'); + let t = frameCount / 60; // 시간 업데이트 + + // 매 프라임마다 무작위 개수의 눈송이 생성 + for (let i = 0; i < random(5); i++) { + snowflakes.push(new snowflake()); // 눈송이 객체 추가 + } + + // for 반복문을 사용하여 눈송이 반복 + for (let flake of snowflakes) { + flake.update(t); // 눈송이 위치 업데이트 + flake.display(); // 눈송이 그리기 + } +} + +// snowflake 클래스 +function snowflake() { + // 좌표값 초기화 + this.posX = 0; + this.posY = random(-50, 0); + this.initialangle = random(0, 2 * PI); + this.size = random(2, 5); + + // 방사형 눈송이의 반지름 + // 눈송이를 화면에 고루 퍼뜨리기 위해 선택 + this.radius = sqrt(random(pow(width / 2, 2))); + + this.update = function(time) { + // 원형을 따라다니는 x 위치 + let w = 0.6; // 각속도 + let angle = w * time + this.initialangle; + this.posX = width / 2 + this.radius * sin(angle); + + // 크기가 다른 눈송이가 미묘하게 다른 y 속도로 떨어집니다. + this.posY += pow(this.size, 0.5); + + // 화면 하단을 지나친 눈송이는 삭제 + 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/dist/assets/examples/ko/09_Simulate/15_penrose_tiles.js b/dist/assets/examples/ko/09_Simulate/15_penrose_tiles.js new file mode 100644 index 0000000000..71c5f5bd0b --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/15_penrose_tiles.js @@ -0,0 +1,125 @@ +/* + * @name 펜로즈 타일 + * @frame 710,400 + * @description 이 예제는 데이비드 블리츠(David Blitz)가 processing.org/examples의 "펜로즈 타일(Penrose Tile)" 예제를 p5.js로 옮겨온 것입니다. + */ + +let ds; + +function setup() { + createCanvas(710, 400); + ds = new PenroseLSystem(); + //다음의 줄과 함께 놀아보세요! + ds.simulate(5); +} + +function draw() { + background(0); + ds.render(); +} + +function PenroseLSystem() { + this.steps = 0; + + //아래는 펜로즈 마름모 L-시스템의 공리와 규칙들입니다. + //레퍼런스가 있다면 좋겠지만, 좋은 사례를 찾지 못했습니다. + 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"; + + //아래의 두 줄과 함께 놀아보세요! + this.startLength = 460.0; + this.theta = TWO_PI / 10.0; //36도, 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; + } + +//대체 규칙을 적용하여, 문자열의 새로운 반복 생성 +PenroseLSystem.prototype.iterate = function() { + let newProduction = ""; + + for(let i=0; i < this.production.length; ++i) { + let step = this.production.charAt(i); + // 현재 문자가 'W'이면, + // 이 현재 문자를 규칙에 맞게 대체합니다. + 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 { + // 모든 'F'를 drop 삭제하되, + // 여타 문자들(예. '+', '-', '[', ']')은 건들지 않는다. + if (step != 'F') { + newProduction = newProduction + step; + } + } + } + + this.drawLength = this.drawLength * 0.5; + this.generations++; + this.production = newProduction; +} + +//문자열을 거북이 그래픽으로 변환 +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재귀 나무 예제 에서 p5.js로 옮겨왔습니다. + */ +let theta; + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(0); + frameRate(30); + stroke(255); + // 마우스 위치에 따라 0부터 90도 중 각도 한 개를 골라볼까요! + let a = (mouseX / width) * 90; + // 이를 라디안 값으로 전환합니다. + theta = radians(a); + // 화면 하단에서 나무 시작하기 + translate(width/2,height); + // 120픽셀 길이의 선 그리기 + line(0,0,0,-120); + // 위의 선의 끝 지점으로 이동하기 + translate(0,-120); + // 나뭇가지의 재귀적 분기 시작하기! + branch(120); + +} + +function branch(h) { + // 각각의 나뭇가지 크기는 이전 가지의 2/3에 해당합니다. + h *= 0.66; + + // 모든 재귀 함수에는 종료(exit) 조건이 있어야합니다!!! + // 이 예제의 경우, 나뭇 가지의 길이가 2픽셀과 같거나 적을 때 입니다. + if (h > 2) { + push(); // 현재의 변형 상태를 저장 (즉, 현재 상태) + rotate(theta); // theta(세타)값으로 회전하기 + line(0, 0, 0, -h); // 나뭇가지 그리기 + translate(0, -h); // 나뭇가지의 끝 지점으로 이동하기 + branch(h); // 자, 이제 자기 자신을 호출하여 2개의 새로운 나뭇가지를 그릴게요! + pop(); // 이 지점에 도달할 때 마다, 이전 매트릭스 상태를 복원하기 위해 "pop(팝)"합니다. + + // 같은 내용을 반복하되, 이번에는 "왼쪽"으로만 가지가 분기하도록 만듭니다! + push(); + rotate(-theta); + line(0, 0, 0, -h); + translate(0, -h); + branch(h); + pop(); + } +} diff --git a/dist/assets/examples/ko/09_Simulate/17_Mandelbrot.js b/dist/assets/examples/ko/09_Simulate/17_Mandelbrot.js new file mode 100644 index 0000000000..6b41ae6ab4 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/17_Mandelbrot.js @@ -0,0 +1,86 @@ +/* + * @name 망델브로 집합 + * @description 망델브로(Mandelbrot) 집합을 간단히 렌더링합니다. + * 다니엘 쉬프만(Daniel Shiffman)의 프로세싱(Processing)을 위한 망델브로 예제에서 옮겨왔습니다. + */ + +function setup() { + createCanvas(710, 400); + pixelDensity(1); + noLoop(); +} + +function draw() { + background(0); + + // 복잡한 평면 위에서 값의 범위를 설정 + // 설정된 범위에 따라 프랙탈을 줌인 또는 줌아웃할 수 있습니다. + + // 모든 것은 너비값에서 시작합니다. 더 크거나 적은 값을 시도해보세요. + const w = 4; + const h = (w * height) / width; + + // 너비와 높이의 음의 절반에서 시작 + const xmin = -w/2; + const ymin = -h/2; + + // pixels[] 배열에 쓸 수 있는지 확인합니다. + // 다른 드로잉을 하지 않으므로, 이 작업은 한번만 수행합니다. + loadPixels(); + + // 복잡한 평면 위의 각 점마다 반복할 수 있는 최대 횟수 + const maxiterations = 100; + + // x는 xmin에서 xmax로 이동 + const xmax = xmin + w; + // y는 ymin에서 ymax로 이동 + const ymax = ymin + h; + + // 각 픽셀마다 x,y를 증가하는 양 계산 + const dx = (xmax - xmin) / (width); + const dy = (ymax - ymin) / (height); + + // y 시작 + let y = ymin; + for (let j = 0; j < height; j++) { + // x 시작 + let x = xmin; + for (let i = 0; i < width; i++) { + + // 이제, 우리가 z = z^2 + cm 를 반복 할 때 z가 무한대로 향하나요? + 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; + // 이 유한한 세상에서의 무한대 개념은 간단합니다. 여기서는 그냥 16이라 설정하지요. + if (dist(aa, bb, 0, 0) > 16) { + break; + } + n++; + } + + // 무한대에 도달하기까지 걸리는 시간을 기준으로 각 픽셀에 색상을 지정합니다. + // 도달하지 못할 경우, 검정색으로 지정합니다. + 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 { + // 원한다면 여기서 좀 더 화려한 색상을 만들 수 있습니다. + pixels[pix + 0] = bright; + pixels[pix + 1] = bright; + pixels[pix + 2] = bright; + pixels[pix + 3] = 255; + } + x += dx; + } + y += dy; + } + updatePixels(); +} diff --git a/dist/assets/examples/ko/09_Simulate/18_Koch.js b/dist/assets/examples/ko/09_Simulate/18_Koch.js new file mode 100644 index 0000000000..3b36472477 --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/18_Koch.js @@ -0,0 +1,141 @@ +/* + * @name 코흐 곡선 + * @description 간단한 코흐 곡선 즉, 눈송이형 프랙탈을 만듭니다. + * 각각의 재귀 단계는 순차적으로 그려집니다. + * 제작: 다니엘 쉬프만(Daniel Shiffman) + */ + +let k; + +function setup() { + createCanvas(710, 400); + frameRate(1); // 천천히 움직이기 + k = new KochFractal(); +} + +function draw() { + background(0); + // 눈송이 그리기! + k.render(); + // 반복하기 + k.nextLevel(); + // 5회를 초과하진 않습니다... + if (k.getCount() > 5) { + k.restart(); + } +} + +// 선 하나를 프랙탈로 표현해주는 클래스 +// midp5.Vectors가 코크 알고리즘에 의거하여 선을 계산하는 메소드를 포함합니다. + +class KochLine { + constructor(a,b) { + // 두개의 p5.Vectors, + // 시작은 "왼쪽" p5.Vector이고 + // 끝은 "오른쪽" 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(); + } + + // 쉽지요? 여기까지 전체 내용의 1/3을 진행했어요. + kochB() { + let v = p5.Vector.sub(this.end, this.start); + v.div(3); + v.add(this.start); + return v; + } + + // 약간 복잡한데요, 이 p5의 위치를 알아내기 위해 약간의 삼각법을 사용합니다! + 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); // 점 B로 이동하기 + v.rotate(-PI/3); // 60도 회전하기 + a.add(v); // 점 C로 이동하기 + return a; + } + + // 쉽지요? 여기까지 전체 내용의 2/3을 진행했어요. + 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(); + } +} + +//눈송이 패턴을 갖는 선분들을 배열로 관리하는 클래스입니다. +class KochFractal { + constructor() { + this.start = createVector(0,height-20); // 시작점 p5.Vector + this.end = createVector(width,height-20); // 끝점 p5.Vector + this.lines = []; // 모든 선분을 추적하는 배열 + this.count = 0; + this.restart(); + } + + nextLevel() { + // 배열에 담긴 각각의 선분들에 대해 + // 4개의 선분들을 추가한, 새로운 배열을 만듭니다. + this.lines = this.iterate(this.lines); + this.count++; + } + + restart() { + this.count = 0; // 카운트 리셋하기 + this.lines = []; // 배열 비우기 + this.lines.push(new KochLine(this.start,this.end)); // 초기 선분 더하기(하나의 끝점 p5.Vector에서 다른 p5.Vector로) + } + + getCount() { + return this.count; + } + + // 이 부분도 쉽습니다. 모든 선들을 그리는 함수이지요. + render() { + for(let i = 0; i < this.lines.length; i++) { + this.lines[i].display(); + } + } + + // 이제부터 **마법**이 시작됩니다. + // 1단계: 빈 배열 목록을 새로 생성합니다. + // 2단계: 배열 목록에 현재 담긴 모든 선들에 대하여, + // - 코흐 알고리즘에 따라 선분 4개를 계산하고, + // - 이 4개의 선분들을 모두 새로운 배열 목록에 더합니다. + // 3단계: 새로운 배열 목록이 반환되고, 이 새 목록은 전체 구조의 선분들에 대한 목록이 됩니다. + + // 위의 단계를 반복하면, 모든 선들이 4개의 다른 선으로 분할되고, 또 그 선들은 다시 4개의 선들로 끊임없이 분할되는 식입니다. + iterate(before) { + let now = []; // 빈 배열 생성하기 + for(let i = 0; i < this.lines.length; i++) { + let l = this.lines[i]; + // 5개의 코흐 p5.Vector 계산 (선 객체를 통해 계산) + let a = l.kochA(); + let b = l.kochB(); + let c = l.kochC(); + let d = l.kochD(); + let e = l.kochE(); + // 모든 p5.Vector 사이에 선분을 만들고 추가하기 + 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/dist/assets/examples/ko/09_Simulate/19_Bubblesort.js b/dist/assets/examples/ko/09_Simulate/19_Bubblesort.js new file mode 100644 index 0000000000..bff2f5a7bf --- /dev/null +++ b/dist/assets/examples/ko/09_Simulate/19_Bubblesort.js @@ -0,0 +1,66 @@ +/* + * @name 버블 정렬 + * @description 전체 정렬 과정을 시뮬레이션하면서, + * 무작위로 분포된 막대들을 그 높이에 따라 오름차순으로 정렬합니다. + * 코딩 트레인(Coding Train)의 코딩 챌린지(Coding Challenge)를 참조하였습니다. + */ + +let values = []; +let i = 0; +let j = 0; + +// setup() 함수 속 명령문들은 +// 프로그램 시작시 한 번 실행됩니다. +// 배열은 setup()함수를 통해 임의의 값들로 채워집니다. +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(); + } + } +} + +// simulateSorting() 함수는 버블 정렬 알고리즘에 +// 애니메이션을 적용합니다. +// 이 함수는 배열의 값을 사각형 길이로 치환해 +// 사각형을 그립니다. +function simulateSorting(){ + for(let i = 0;i= 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'); +} + +// 두 개의 사각형을 각각 +// 흰색과 검정색으로 지정 +let brick1 = new Brick("white",100); +let brick2 = new Brick("black",250); + +// +brick1.setSpeed(); +brick2.setSpeed(); + +function draw () { + background(0); + if(mouseIsPressed){ + background(50); + } + brick1.createBrick(); + brick1.moveBrick(); + if(!mouseIsPressed){ + createBars(); + } + brick2.createBrick(); + brick2.moveBrick(); +} + +// 이 함수로 화면에 +// 검정색 및 흰색 막대기들을 생성하기 +function createBars() { + let len = 12; + for(let i = 0;i width) + this.xSpeed*=-1; + if(this.y < 0 || this.y > height) + this.ySpeed*=-1; + this.x+=this.xSpeed; + this.y+=this.ySpeed; + } + +// 이 함수는 특정 거리 안쪽에 위치한 파티클들 사이에 연결선을 만듭니다. + joinParticles(paraticles) { + 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); + } + }); + } +} + +// 복수의 파티클들을 추가하기 위한 배열 +let particles = []; + +function setup() { + createCanvas(720, 400); + for(let i = 0;i
+ * 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
+ */ + +// 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)); +} \ No newline at end of file diff --git a/dist/assets/examples/ko/10_Interaction/10_Tickle.js b/dist/assets/examples/ko/10_Interaction/10_Tickle.js new file mode 100644 index 0000000000..829b9276fd --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/10_Tickle.js @@ -0,0 +1,48 @@ +/* + * @name 간질간질 + * @description 마우스 커서를 "tickle"에 올리면, 마치 간지럼을 타는듯 떨립니다. + * 너무 간지럽히면 화면 밖으로 튀어나갈 수도 있습니다 >_< + */ +let message = 'tickle', + font, + bounds, // 텍스트의 바운딩 박스에 대한 x, y, w, h값 + fontsize = 60, + x, + y; // 텍스트의 x 와 y 좌표 + +function preload() { + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // 폰트 설정 + textFont(font); + textSize(fontsize); + + // 초기화시 중앙 정렬을 위해 텍스트의 너비 및 높이값 받아오기 + bounds = font.textBounds(message, 0, 0, fontsize); + x = width / 2 - bounds.w / 2; + y = height / 2 - bounds.h / 2; +} + +function draw() { + background(204, 120); + + // 텍스트를 검정색으로 쓰고, 그 바운딩 박스 받아오기 + fill(0); + text(message, x, y); + bounds = font.textBounds(message, x, y, fontsize); + + // 마우스가 바운딩 박스 안에 있는지 확인하고, 안에 있다면 간질간질! + 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/dist/assets/examples/ko/10_Interaction/11_WeightLine.js b/dist/assets/examples/ko/10_Interaction/11_WeightLine.js new file mode 100644 index 0000000000..a455dcb781 --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/11_WeightLine.js @@ -0,0 +1,55 @@ +/* + * @name Weight Line + * @frame 710,400 + * @description contributed by + Prof WM Harris, using the random function with events to color/weight a line
+ How to use the random function with events to color/ weight a line + dependent on mouse location, left mouse button clicks, character key types, and + random key releases.
+ Functions are created for both the canvas set up as well as the creation of + the line. Depending on the action taken by the user the line can + vary in width and color. Left mouse button clicks result in a color + change to blue, while the typing of any character key will change + the color to turquoise, each resulting in a variable stroke weight; + the width of the former will be between 0 – 1 while the width of + the latter will be 0 – 5. The release of any key will result in a + random hue, saturation, and brightness change to the line. + */ + + +function setup() { + createCanvas(400, 400); + background("beige"); + colorMode(HSB); + } + + function draw() { + //Line from prev pt to current pt + //of mouse position + line(mouseX, mouseY, pmouseX, pmouseY); + } + + //listen when we click the mouse + function mouseClicked() { + //weights 0 to 1 + stroke("slateBlue"); + strokeWeight(random()); + + //what if want weights 0 to .4? + //strokeWeight( random(.4) ); + } + + //listen when we release *any* key + function keyReleased() { + //color hue values between 20 and 145 + //saturation 0 to 100 + //brightness 80 to 100 + stroke(random(20, 145), random(100), random(80, 100)); + } + + //listen for only character keys + function keyTyped() { + //weights 0 to 5 + stroke("turquoise"); + strokeWeight(random(5)); + } \ No newline at end of file diff --git a/dist/assets/examples/ko/10_Interaction/20_Follow1.js b/dist/assets/examples/ko/10_Interaction/20_Follow1.js new file mode 100644 index 0000000000..c5b35b3a13 --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/20_Follow1.js @@ -0,0 +1,37 @@ +/* + * @name 따라다니기 1 + * @frame 710,400 + * @description 마우스 커서로 선분을 밀고 당깁니다. + * 이 예제는 키스 피터스(Keith Peters)가 제작한 코드를 기반으로 합니다. + */ +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/dist/assets/examples/ko/10_Interaction/21_Follow2.js b/dist/assets/examples/ko/10_Interaction/21_Follow2.js new file mode 100644 index 0000000000..276ebaa52b --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/21_Follow2.js @@ -0,0 +1,39 @@ +/* + * @name 따라다니기 2 + * @frame 710,400 + * @description 팔 형상의 두 선분이 마우스 커서의 위치를 따라다닙니다. + * 선분들 사이의 상대 각도는 atan2()로, 그 위치는 sin()과 cos()로 계산됩니다. + * 이 예제는 키스 피터스(Keith Peters)가 제작한 코드를 기반으로 합니다. + */ +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/dist/assets/examples/ko/10_Interaction/22_Follow3.js b/dist/assets/examples/ko/10_Interaction/22_Follow3.js new file mode 100644 index 0000000000..7f585e572b --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/22_Follow3.js @@ -0,0 +1,47 @@ +/* + * @name 따라다니기 3 + * @frame 710,400 + * @description 선분이 마우스를 따라다닙니다. 한 선분의 다음 선분에 대한 상대 각도는 atan2()로, + * 다음 선분의 위치는 sin()과 cos()로 계산됩니다. + * 이 예제는 키스 피터스(Keith Peters)가 제작한 코드를 기반으로 합니다. + */ +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/dist/assets/examples/ko/10_Interaction/23_snake.js b/dist/assets/examples/ko/10_Interaction/23_snake.js new file mode 100644 index 0000000000..10422434f6 --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/23_snake.js @@ -0,0 +1,168 @@ +/* + * @name 스네이크 게임 + * @description 그 유명한 스네이크 게임입니다! 실행(run)을 누르고, + * 검은 화면 위 아무 지점을 클릭한 뒤, i,j,k,l 키로 뱀을 조종할 수 있습니다. + * 뱀이 벽이나 자신의 몸에 닿지 않도록 하세요!
+ * 예제 제작: 프라샨트 굽타(Prashant Gupta) + */ + +// 뱀의 형상은 작은 조각(segment)들로 구성되는데, +// 이는 매 'draw' 호출에서 그려지고 수정됩니다. +let numSegments = 10; +let direction = 'right'; + +const xStart = 0; // 뱀의 시작 x좌표 +const yStart = 250; // 뱀의 시작 y좌표 +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(); +} + +/* + 뱀의 방향에 따라, 뱀의 형상을 구성하는 작은 조각(segment)들의 위치가 업데이트됩니다. + 0에서 n-1까지의 모든 조각들은 n에 도달할 때까지 그 다음 조각의 위치를 복사합니다. + 예를 들어, segment 0은 segment 1의 값을 받고, segment 1은 segment 2의 값을 받습니다. 뱀은 이러한 과정을 통해 움직이는 것입니다. + 이 때, 마지막 조각(segment)은 뱀이 가는 방향에 따라 추가됩니다. + 뱀이 좌우로 움직일 때 가장 마지막 조각의 x값은, 마지막에서 두번째 조각의 x값보다 'diff'값만큼 증가합니다. + 뱀이 상하로 움직일 때는 가장 마지막 조각의 y값이 증가하는 식입니다. +*/ +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; + } +} + +/* + 전 항상 뱀의 머리 위치인 xCor[xCor.length - 1]와 + yCor[yCor.length - 1]를 확인하여 뱀이 화면 경계나 자신의 몸에 닿는지를 본답니다. +*/ +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); + } +} + +/* + 뱀이 자신의 몸에 닿았다는건 다시말해, 뱀의 머리의 (x,y)좌표가 + 조각(segment)들 중 한 (x,y)좌표와 일치한다는 것입니다. +*/ +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; + } + } +} + +/* + 뱀이 과일을 먹을 때마다 조각의 수가 증가하고, 배열의 시작에 꼬리 조각이 다시 삽입되도록 설정했습니다.(기본적으로, 마지막 조각을 꼬리 부분에 추가하여 꼬리를 늘리는 식이지요.) +*/ +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() { + /* + 여기서 복잡한 연산 논리가 추가된 이유는 + 뱀이 10의 배수 단위로 움직이도록 설정했기 때문입니다. + 점을 너비 100과 -100 사이에 있도록 하고, + 그 위치값이 가장 가까운 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/dist/assets/examples/ko/10_Interaction/24_Wavemaker.js b/dist/assets/examples/ko/10_Interaction/24_Wavemaker.js new file mode 100644 index 0000000000..340cce3b3b --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/24_Wavemaker.js @@ -0,0 +1,38 @@ +/* + * @name 파도 만들기 + * @description 이 예제는 특정 위치에서 진동하는 파티클로 파도를 만드는 법을 다룹니다. + * 마우스를 움직여 파도의 방향을 바꿔보세요. + * 기여: 애티쉬 바티아(Aatish Bhatia), 제작: 댄 와이트(Dan Whyte) Orbiters + * 로부터 영감을 받았습니다. + */ + +let t = 0; // 시간 변수 + +function setup() { + createCanvas(600, 600); + noStroke(); + fill(40, 200, 40); +} + +function draw() { + background(10, 10); // 불투명한 배경화면(파티클의 꼬리 만들기) + + // 타원형으로 구성된 x와 y 그리드 만들기 + for (let x = 0; x <= width; x = x + 30) { + for (let y = 0; y <= height; y = y + 30) { + // 각 타원의 시작 점은 마우스 위치에 따라 달라집니다. + const xAngle = map(mouseX, 0, width, -4 * PI, 4 * PI, true); + const yAngle = map(mouseY, 0, height, -4 * PI, 4 * PI, true); + // 또, 파티클의 위치에 따라 달라집니다. + const angle = xAngle * (x / width) + yAngle * (y / height); + + // 각 파티클은 동그라미를 그리며 움직입니다. + const myX = x + 20 * cos(2 * PI * t + angle); + const myY = y + 20 * sin(2 * PI * t + angle); + + ellipse(myX, myY, 10); // 파티클로 그리기 + } + } + + t = t + 0.01; // 시간 업데이트 +} diff --git a/dist/assets/examples/ko/10_Interaction/25_reach1.js b/dist/assets/examples/ko/10_Interaction/25_reach1.js new file mode 100644 index 0000000000..483283d3da --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/25_reach1.js @@ -0,0 +1,57 @@ +/* + * @name 팔닿기 1 + * @frame 710,400 + * @description 팔 모양이 마우스 위치를 따라다닙니다. 팔의 각도는 atan2()로 계산됩니다. + * 이 예제는 키스 피터스(Keith Peters)가 제작한 코드를 기반으로 합니다. + */ +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/dist/assets/examples/ko/10_Interaction/26_reach2.js b/dist/assets/examples/ko/10_Interaction/26_reach2.js new file mode 100644 index 0000000000..d6b1ae8272 --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/26_reach2.js @@ -0,0 +1,65 @@ +/* + * @name 팔닿기 2 + * @frame 710,400 + * @description 팔 모양이 마우스 위치를 따라다닙니다. 팔의 각도는 atan2()로 계산됩니다. + * 이 예제는 키스 피터스(Keith Peters)가 제작한 코드를 기반으로 합니다. + */ +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; // 기본 x좌표 설정 + y[x.length - 1] = height; // 기본 y좌표 설정 +} + +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/dist/assets/examples/ko/10_Interaction/27_reach3.js b/dist/assets/examples/ko/10_Interaction/27_reach3.js new file mode 100644 index 0000000000..fdf58bc952 --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/27_reach3.js @@ -0,0 +1,81 @@ +/* + * @name 팔닿기 3 + * @frame 710,400 + * @description 팔모양이 공의 위치를 따라다닙니다. 팔의 각도는 atan2()로 계산됩니다. + * 이 예제는 키스 피터스(Keith Peters)가 제작한 코드를 기반으로 합니다. + */ +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; // 기본 x좌표 설정 + y[x.length - 1] = height; // 기본 y좌표 설정 +} + +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/dist/assets/examples/ko/10_Interaction/28_ArduinoSensor.js b/dist/assets/examples/ko/10_Interaction/28_ArduinoSensor.js new file mode 100644 index 0000000000..b4b1195d1b --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/28_ArduinoSensor.js @@ -0,0 +1,38 @@ +/* + * @name 웹잭과 아두이노 센서 데이터 + * @description 웹잭(WebJack)은 오디오를 사용하여 아두이노와 + * 다른 소스들로부터 데이터를 읽어오는 한 방식입니다. + * 기본적으로, 아두이노를 오디오 모뎀으로 변환합니다. + * + * https://github.com/publiclab/webjack + * + * 주의: 이 예제를 로컬 프로젝트에서 실행하려면, index.html 파일에 WebJack과 p5-webjack 라이브러리를 다음과같이 추가해야 합니다: + *
<script src="https://webjack.io/dist/webjack.js"></script>
+ *
<script src="https://jywarren.github.io/p5-webjack/lib.js"></script>
+ * + * 작동 예시: https://editor.p5js.org/jywarren/sketches/rkztwSt8M + * + * 오디오 테스팅: https://www.youtube.com/watch?v=GtJW1Dlt3cg + * 이 스케치를 아두이노로 불러오세요: + * https://create.arduino.cc/editor/jywarren/023158d8-be51-4c78-99ff-36c63126b554/preview + * 아두이노가 pin 3 + ground로부터 오디오를 출력할 것입니다. 마이크나 오디오 케이블을 사용하세요. + */ + +function setup() { + createCanvas(400, 400); + noStroke(); + fill('#ff00aa22'); + receiveSensorData(handleData); +} + +function handleData(data, connection) { + + console.log(data); // 값을 로그에 출력 + // data[0] = 첫번째 값, data[1] = 두번째 값 ... + + // 그려보세요! 참고: http://p5js.org/reference/ + background('#ddd'); + ellipse(100, 200, data[0]+10, data[0]+10); + + // connection.send('아두이노가 오디오리스닝 중이라면 아두이노로 데이터를 다시 전송하기'); +} diff --git a/dist/assets/examples/ko/10_Interaction/29_kaleidoscope.js b/dist/assets/examples/ko/10_Interaction/29_kaleidoscope.js new file mode 100644 index 0000000000..56b1b24cb7 --- /dev/null +++ b/dist/assets/examples/ko/10_Interaction/29_kaleidoscope.js @@ -0,0 +1,76 @@ +/* + * @name 만화경 + * @description +436/5000 +만화경은 두 개 이상의 반사면이 서로를 향해 비스듬히 기울어진 광학 기기를 말합니다. +이 예제는 만화경의 작동 원리를 복제하고 재현합니다. "대칭(symmetry)" 변수를 통해 반사 횟수를 조정하고 화면 위에 그림을 그려보세요. +슬라이더를 사용하여 브러시 크기를 조정할 수 있습니다. "clearButton"은 화면을 지웁니다. "saveButton" 버튼은 사용자가 만든 작품을 .jpg 파일로 다운로드합니다. +*/ +// 반사 횟수에 따른 대칭을 설정합니다. 반사 횟수를 조정해보세요. +let symmetry = 6; + +let angle = 360 / symmetry; +let saveButton, clearButton, mouseButton, keyboardButton; +let slider; + +function setup() { + createCanvas(710, 710); + angleMode(DEGREES); + background(127); + + // 파일 저장을 위한 saveButton 생성하기 + saveButton = createButton('save'); + saveButton.mousePressed(saveFile); + + // 화면 지우기를 위한 claerButton 생성하기 + clearButton = createButton('clear'); + clearButton.mousePressed(clearScreen); + + // 전체 화면 보기를 위한 fullscreenButton 생성하기 + fullscreenButton = createButton('Full Screen'); + fullscreenButton.mousePressed(screenFull); + + // 브러시 두께 조정을 위한 슬라이더 설정하기 + brushSizeSlider = createButton('Brush Size Slider'); + sizeSlider = createSlider(1, 32, 4, 0.1); +} + +// 파일 저장 함수 +function saveFile() { + save('design.jpg'); +} + +// 화면 지우기 함수 +function clearScreen() { + background(127); +} + +// 전체 화면 보기 함수 +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/dist/assets/examples/ko/11_Objects/01_Objects.js b/dist/assets/examples/ko/11_Objects/01_Objects.js new file mode 100644 index 0000000000..cffbe8d85c --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/01_Objects.js @@ -0,0 +1,39 @@ +/* + * @name 객체 + * @description Jitter 클래스를 만들고, 객체를 인스턴스화하여 + * 화면 안에서 움직여보세요. 캐시 리스(Casey Reas) & 벤 프라이(Ben Fry) 저 Getting Started with + * Processing에서 옮김. + */ + +let bug; // 객체 선언하기 + +function setup() { + createCanvas(710, 400); + // 객체 생성하기 + bug = new Jitter(); +} + +function draw() { + background(50, 89, 100); + bug.move(); + bug.display(); +} + +// Jitter 클래스 +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/dist/assets/examples/ko/11_Objects/02_Multiple_Objects.js b/dist/assets/examples/ko/11_Objects/02_Multiple_Objects.js new file mode 100644 index 0000000000..8a0a96a3f4 --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/02_Multiple_Objects.js @@ -0,0 +1,50 @@ +/* + * @name 복수 객체 + * @description Jitter 클래스를 만들고, 복수의 객체를 인스턴스화하여 + * 화면 안에서 움직여보세요. + */ + +let bug1; // 객체들 선언하기 +let bug2; +let bug3; +let bug4; + +function setup() { + createCanvas(710, 400); + // 객체 생성하기 + 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 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/dist/assets/examples/ko/11_Objects/03_Objects_Array.js b/dist/assets/examples/ko/11_Objects/03_Objects_Array.js new file mode 100644 index 0000000000..2fac9f60b8 --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/03_Objects_Array.js @@ -0,0 +1,42 @@ +/* + * @name 객체 배열 + * @description Jitter 클래스를 만들고, 객체 배열을 인스턴스화하여 + * 화면 안에서 움직여보세요. + */ + +let bugs = []; // Jitter 객체들의 배열 + +function setup() { + createCanvas(710, 400); + // 객체들 생성하기 + 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 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/dist/assets/examples/ko/11_Objects/03_Objects_Optional_Arguments.js b/dist/assets/examples/ko/11_Objects/03_Objects_Optional_Arguments.js new file mode 100644 index 0000000000..25ffa5e70a --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/03_Objects_Optional_Arguments.js @@ -0,0 +1,65 @@ +/* + * @name 객체 2 + * @description hbarragan 제작 예제에서 옮김. 이미지 위로 마우스를 움직여 + * 기하의 속도와 위치를 바꿔보세요. MRect 클래스가 선들의 군상을 정의합니다. + * defines a group of lines. + */ + +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; // 막대기 한 개 너비 + this.xpos = ixp; // rect의 x위치 + this.h = ih; // rect의 높이 + this.ypos = iyp; // rect의 y위치 + this.d = id; // 막대기 간 거리 + this.t = it; // 막대기 개수 + } + + 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/dist/assets/examples/ko/11_Objects/04_Inheritance.js b/dist/assets/examples/ko/11_Objects/04_Inheritance.js new file mode 100644 index 0000000000..ab5a51bafa --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/04_Inheritance.js @@ -0,0 +1,70 @@ +/* @name 상속 + * @description 다른 클래스에 기초하여 클래스를 정의할 수 있습니다. + * 객체 지향 프로그래밍 언어에서, 한 클래스는 다른 클래스의 필드와 메소드를 상속할 수 있습니다. + * 이처럼 다른 객체로부터 상속받는 객체를 하위 클래스라 하고, + * 상속하는 객체를 상위 클래스라고 합니다. + * 하위 클래스는 상위 클래스를 확장합니다. + */ +let spots, arm; + +function setup() { + createCanvas(640, 360); + arm = new SpinArm(width/2, height/2, 0.01); + spots = new SpinSpots(width/2, height/2, -0.02, 90.0); +} + +function draw() { + background(204); + arm.update(); + arm.display(); + spots.update(); + spots.display(); +} + +class Spin { + constructor(x, y, s) { + this.x = x; + this.y = y; + this.speed = s; + this.angle = 0.0; + } + + update() { + this.angle += this.speed; + } +} + +class SpinArm extends Spin { + constructor(x, y, s) { + super(x, y, s) + } + + display() { + strokeWeight(1); + stroke(0); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + line(0, 0, 165, 0); + pop(); + } +} + +class SpinSpots extends Spin { + constructor(x, y, s, d) { + super(x, y, s) + this.dim = d; + } + + display() { + noStroke(); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + ellipse(-this.dim/2, 0, this.dim, this.dim); + ellipse(this.dim/2, 0, this.dim, this.dim); + pop(); + } +} \ No newline at end of file diff --git a/dist/assets/examples/ko/11_Objects/05_Composite_Objects.js b/dist/assets/examples/ko/11_Objects/05_Composite_Objects.js new file mode 100644 index 0000000000..b1872b76bd --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/05_Composite_Objects.js @@ -0,0 +1,98 @@ +/* @name 합성 객체 + * @description 한 객체는 여러 개의 다른 객체들을 담을 수 있습니다. + * 합성 객체를 생성하면 모듈화 원칙들을 활용하거나, 또 높은 수준의 추상을 구축하기에 좋습니다. + */ +let er1, er2; + +function setup() { + createCanvas(640, 360); + er1 = new EggRing(width*0.45, height*0.5, 0.1, 120); + er2 = new EggRing(width*0.65, height*0.8, 0.05, 180); +} + +function draw() { + background(0); + er1.transmit(); + er2.transmit(); +} + +class Egg { + constructor(xpos, ypos, t, s) { + this.x = xpos; + this.y = ypos; + this.tilt = t; + this.scalar = s / 100.0; + this.angle = 0.0; + } + + wobble() { + this.tilt = cos(this.angle) / 8; + this.angle += 0.1; + } + + display() { + noStroke(); + fill(255); + push(); + translate(this.x, this.y); + rotate(this.tilt); + scale(this.scalar); + beginShape(); + vertex(0, -100); + bezierVertex(25, -100, 40, -65, 40, -40); + bezierVertex(40, -15, 25, 0, 0, 0); + bezierVertex(-25, 0, -40, -15, -40, -40); + bezierVertex(-40, -65, -25, -100, 0, -100); + endShape(); + pop(); + } +} + +class Ring { + start(xpos, ypos) { + this.x = xpos; + this.y = ypos; + this.on = true; + this.diameter = 1; + } + + grow() { + if (this.on == true) { + this.diameter += 0.5; + if (this.diameter > width*2) { + this.diameter = 0.0; + } + } + } + + display() { + if (this.on == true) { + noFill(); + strokeWeight(4); + stroke(155, 153); + ellipse(this.x, this.y, this.diameter, this.diameter); + } + } +} + +class EggRing { + constructor(x, y, t, sp) { + this.x = x; + this.y = y; + this.t = t; + this.sp = sp; + this.circle = new Ring(); + this.ovoid = new Egg(this.x, this.y, this.t, this.sp); + this.circle.start(this.x, this.y - this.sp/2); + } + + transmit() { + this.ovoid.wobble(); + this.ovoid.display(); + this.circle.grow(); + this.circle.display(); + if (circle.on == false) { + circle.on = true; + } + } +} diff --git a/dist/assets/examples/ko/11_Objects/06_Car_Instances.js b/dist/assets/examples/ko/11_Objects/06_Car_Instances.js new file mode 100644 index 0000000000..1966f9c8e3 --- /dev/null +++ b/dist/assets/examples/ko/11_Objects/06_Car_Instances.js @@ -0,0 +1,82 @@ +/* + * @name Car Instances + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create three instances of Car Class and +invoke class methods.
+ A function is created for the canvas setup, and +3 car instances are initialized with different colors and canvas +positions. The speed of each car is set by passing value to the +instance’s start method. A second function calls class methods to +display and move the cars. +*/ +class Car { + /* Constructor expects parameters for + fill color, x and y coordinates that + will be used to initialize class properties. + */ + constructor(cColor, x, y) { + this.color = cColor; + this.doors = 4; + this.isConvertible = false; + this.x = x; + this.y = y; + this.speed = 0; + } + + start(speed) { // method expects parameter! + this.speed = speed; + } + + display() { // method! + fill(this.color); + rect(this.x, this.y, 20, 10); + } + + move() { // method! + this.x += this.speed; + // Wrap x around boundaries + if (this.x < -20) { + this.x = width; + } else if (this.x > width) { + this.x = -20; + } + } +} //end class Car + +let rav4; +let charger; +let nova; + +function setup() { + createCanvas(200, 400); + /* Construct the 3 Cars */ + //constructor expects cColor, x, y + rav4 = new Car("silver", 100, 300); + charger = new Car("gold", 0, 200); + nova = new Car("blue", 200, 100); + nova.doors = 2; //update nova's doors property + + console.log("rav4", rav4); + console.log("charger", charger); + console.log("nova", nova); + + //call start methods of Car instances + //the start method expects a number for speed + rav4.start(2.3); + charger.start(-4); + nova.start(random(-1, 1)); +} + +function draw() { + background("beige"); + + //display and move all 3 Cars + rav4.display(); + charger.display(); + nova.display(); + + rav4.move(); + charger.move(); + nova.move(); +} diff --git a/dist/assets/examples/ko/12_Lights/02_Directional.js b/dist/assets/examples/ko/12_Lights/02_Directional.js new file mode 100644 index 0000000000..2e09a2c792 --- /dev/null +++ b/dist/assets/examples/ko/12_Lights/02_Directional.js @@ -0,0 +1,28 @@ +/* + * @name 디렉셔널 라이트 + * @frame 710,400 + * @description 마우스를 움직여 조명의 방향을 바꿔보세요. + * 디렉셔널 라이트는 한 방향에서 비롯되며 + * 표면에 직각으로 닿을 때 강한 빛을, + * 부드러운 각도로 닿았을 때 약한 빛을 보입니다. + * 디렉셔널 라이트는 표면에 닿으면 그 빛이 모든 방향으로 흩어집니다. + */ +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/dist/assets/examples/ko/12_Lights/05_Mixture.js b/dist/assets/examples/ko/12_Lights/05_Mixture.js new file mode 100644 index 0000000000..d01c872f70 --- /dev/null +++ b/dist/assets/examples/ko/12_Lights/05_Mixture.js @@ -0,0 +1,26 @@ +/* + * @name 혼합 라이트 + * @frame 710,400 (optional) + * @description 세 개의 다른 조명과 함께 박스를 보여줍니다. + */ +function setup() { + createCanvas(710, 400, WEBGL); + noStroke(); +} + +function draw() { + background(0); + + // 우측에서 비추는 오렌지색 포인트 라이트 + pointLight(150, 100, 0, 500, 0, 200); + + // 좌측에서 비추는 파랑색 디렉셔널 라이트 + directionalLight(0, 102, 255, -1, 0, 0); + + // 정면에서 비추는 노랑색 스포트라이트 + pointLight(255, 255, 109, 0, 0, 300); + + rotateY(map(mouseX, 0, width, 0, PI)); + rotateX(map(mouseY, 0, height, 0, PI)); + box(200); +} diff --git a/dist/assets/examples/ko/13_Motion/01_non_orthogonal_reflection.js b/dist/assets/examples/ko/13_Motion/01_non_orthogonal_reflection.js new file mode 100644 index 0000000000..028d28ef51 --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/01_non_orthogonal_reflection.js @@ -0,0 +1,110 @@ +/* + * @name 비직각 반사 + * @frame 710,400 (optional) + * @description 이 예제는 processing.org/examples의 "Reflection 1" 예제를 데이비드 블리츠(David Blitz)가 옮긴 것입니다. + */ + +// 바닥의 왼쪽 위치 +let base1; + +// 바닥의 오른쪽 위치 +let base2; +// 바닥의 길이 +//let baseLength; + +// 움직이는 공에 대한 변수들 +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(); + + // 화면 중앙의 상단에서 타원형 시작 + position = createVector(width / 2, 0); + + // 초기 임의 속도 계산 + velocity = p5.Vector.random2D(); + velocity.mult(speed); +} + +function draw() { + // 배경 그리기 + fill(0, 12); + noStroke(); + rect(0, 0, width, height); + + // base(밑바닥) 그리기 + fill(200); + quad(base1.x, base1.y, base2.x, base2.y, base2.x, height, 0, height); + + // base(밑바닥) 상단의 normal(표준) 계산하기 + let baseDelta = p5.Vector.sub(base2, base1); + baseDelta.normalize(); + let normal = createVector(-baseDelta.y, baseDelta.x); + let intercept = p5.Vector.dot(base1, normal); + + // ellipse(타원) 그리기 + noStroke(); + fill(255); + ellipse(position.x, position.y, r * 2, r * 2); + + // 타원 움직이기 + position.add(velocity); + + // 표준화된 투사 벡터 + incidence = p5.Vector.mult(velocity, -1); + incidence.normalize(); + + // 밑바닥과의 충돌 감지하고 조정하기 + if (p5.Vector.dot(normal, position) > intercept) { + //투사 벡터와 밑바닥 상단의 dot(점) 계산 + let dot = incidence.dot(normal); + + // 반사 벡터 계산 + // 반사 벡터를 방향 벡터에 지정 + velocity.set( + 2 * normal.x * dot - incidence.x, + 2 * normal.y * dot - incidence.y, + 0 + ); + velocity.mult(speed); + + // 충돌 지점에서 밑바닥 상단 표준 그리기 + stroke(255, 128, 0); + line( + position.x, + position.y, + position.x - normal.x * 100, + position.y - normal.y * 100 + ); + } + //} + + // 경계면 충돌 감지 + // 우측 + if (position.x > width - r) { + position.x = width - r; + velocity.x *= -1; + } + // 좌측 + if (position.x < r) { + position.x = r; + velocity.x *= -1; + } + // 상단 + if (position.y < r) { + position.y = r; + velocity.y *= -1; + + // 밑바닥의 상단 임의화하기 + base1.y = random(height - 100, height); + base2.y = random(height - 100, height); + } +} diff --git a/dist/assets/examples/ko/13_Motion/02_Linear_Motion.js b/dist/assets/examples/ko/13_Motion/02_Linear_Motion.js new file mode 100644 index 0000000000..454e13377a --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/02_Linear_Motion.js @@ -0,0 +1,24 @@ +/* + * @name 선형 + * @frame 720,400 + * @description 변수를 바꿔 움직이는 선을 만들어보세요. + * 선이 화면 상단 밖으로 나가면 변수는 0이 되어 + * 선의 위치를 화면의 하단으로 되돌립니다. + */ + +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/dist/assets/examples/ko/13_Motion/03_Bounce.js b/dist/assets/examples/ko/13_Motion/03_Bounce.js new file mode 100644 index 0000000000..c1a6b9ae7f --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/03_Bounce.js @@ -0,0 +1,44 @@ +/* + * @name 바운스 + * @frame 720,400 + * @description 도형이 화면의 모서리에 닿으면 반대 방향으로 움직입니다. + */ + +let rad = 60; // 도형의 너비 +let xpos, ypos; // 도형의 시작점 + +let xspeed = 2.8; // 도형의 속도 +let yspeed = 2.2; // 도형의 속도 + +let xdirection = 1; // 왼쪽 또는 오른쪽 +let ydirection = 1; // 위 또는 아래 + +function setup() { + createCanvas(720, 400); + noStroke(); + frameRate(30); + ellipseMode(RADIUS); + // 도형의 시작점 설정 + xpos = width / 2; + ypos = height / 2; +} + +function draw() { + background(102); + + // 도형의 위치 업데이트 + xpos = xpos + xspeed * xdirection; + ypos = ypos + yspeed * ydirection; + + // 도형이 화면 경계를 넘어가는 지 테스트 + // 넘어갈 경우, -1을 곱하여 방향을 반대로 돌린다. + if (xpos > width - rad || xpos < rad) { + xdirection *= -1; + } + if (ypos > height - rad || ypos < rad) { + ydirection *= -1; + } + + // 도형 그리기 + ellipse(xpos, ypos, rad, rad); +} diff --git a/dist/assets/examples/ko/13_Motion/04_Bouncy_Bubbles.js b/dist/assets/examples/ko/13_Motion/04_Bouncy_Bubbles.js new file mode 100644 index 0000000000..108b83b8ba --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/04_Bouncy_Bubbles.js @@ -0,0 +1,95 @@ +/* + * @name 버블 바운스 + * @frame 720,400 + * @description 이 예제는 키스 피터스(Keith Peters)가 제작한 복수-객체 충돌(Multiple-object collision) 예제 코드를 기반으로 합니다. + */ + +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; + let vx = 0; + let 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; + vx -= ax; + vy -= ay; + this.others[i].vx += ax; + this.others[i].vy += ay; + } + } + } + + move() { + vy += gravity; + this.x += vx; + this.y += vy; + if (this.x + this.diameter / 2 > width) { + this.x = width - this.diameter / 2; + vx *= friction; + } else if (this.x - this.diameter / 2 < 0) { + this.x = this.diameter / 2; + vx *= friction; + } + if (this.y + this.diameter / 2 > height) { + this.y = height - this.diameter / 2; + vy *= friction; + } else if (this.y - this.diameter / 2 < 0) { + this.y = this.diameter / 2; + vy *= friction; + } + } + + display() { + ellipse(this.x, this.y, this.diameter, this.diameter); + } +} diff --git a/dist/assets/examples/ko/13_Motion/05_Morph.js b/dist/assets/examples/ko/13_Motion/05_Morph.js new file mode 100644 index 0000000000..6a950d7d97 --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/05_Morph.js @@ -0,0 +1,92 @@ +/* + * @name 변형(morph) + * @frame 720,400 + * @description 버텍스를 보간하여 한 모양에서 다른 모양으로 바꾸기 + */ + +// 두 도형의 버텍스들을 저장하는 두 개의 배열 리스트(ArrayList) +// 이 예제는 두 도형이 동일한 개수의 버텍스를 갖고 있다는 것을 전제합니다. +// 즉, 배열 리스트가 동일하다는 뜻입니다. +let circle = []; +let square = []; + +// 3번째 버텍스 묶음 저장을 위한 배열 리스트 +// 화면상 그려집니다. +let morph = []; + +// 이 불리언 변수는 원형이나 사각형으로 변형할지 여부를 결정합니다. +let state = false; + +function setup() { + createCanvas(720, 400); + + // 중심을 가리키는 벡터를 사용하여 원 그리기 + for (let angle = 0; angle < 360; angle += 9) { + // 주의: 원의 이동 경로와 상응하기 위해, 0에서 시작하지 않습니다. + let v = p5.Vector.fromAngle(radians(angle - 135)); + v.mult(100); + circle.push(v); + // morph 배열 리스트를 빈 PVector로 채웁니다. + morph.push(createVector()); + } + + // 사각형은 직선을 따라 이어진 여러 개의 버텍스입니다. + // 사각형 상단 + for (let x = -50; x < 50; x += 10) { + square.push(createVector(x, -50)); + } + // 사각형 우측 + for (let y = -50; y < 50; y += 10) { + square.push(createVector(50, y)); + } + // 사각형 하단 + for (let x = 50; x > -50; x -= 10) { + square.push(createVector(x, 50)); + } + // 사각형 좌측 + for (let y = 50; y > -50; y -= 10) { + square.push(createVector(-50, y)); + } +} + +function draw() { + background(51); + + // 이 버텍스들이 목표 대상으로부터 얼마나 멀리 있는지 확인 + let totalDistance = 0; + + // 각 버텍스 확인 + for (let i = 0; i < circle.length; i++) { + let v1; + // 원형이나 사각형으로 선형 보간합니까? + if (state) { + v1 = circle[i]; + } else { + v1 = square[i]; + } + // 그려질 버텍스 가져오기 + let v2 = morph[i]; + // 대상을 향해 선형 보간하기 + v2.lerp(v1, 0.1); + // 목표 대상으로부터 얼마나 멀리 있는지 확인 + totalDistance += p5.Vector.dist(v1, v2); + } + + // 모든 버텍스들이 가까워지면, 모양 전환 + if (totalDistance < 0.1) { + state = !state; + } + + // 중심을 기준으로 그리기 + translate(width / 2, height / 2); + strokeWeight(4); + // 모든 버텍스를 구성하는 다각형 그리기 + beginShape(); + noFill(); + stroke(255); + + morph.forEach(v => { + vertex(v.x, v.y); + }); + endShape(CLOSE); +} diff --git a/dist/assets/examples/ko/13_Motion/06_Moving_On_Curves.js b/dist/assets/examples/ko/13_Motion/06_Moving_On_Curves.js new file mode 100644 index 0000000000..0a65c143f6 --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/06_Moving_On_Curves.js @@ -0,0 +1,47 @@ +/* + * @name 곡선 위 움직이기 + * @frame 720,400 + * @description 이 예제에서, 원들은 y = x^4 곡선을 따라 움직입니다. + * 마우스를 클릭하여 새로운 위치로 움직이도록 해보세요. + */ + +let beginX = 20.0; // 초기 x 좌표 +let beginY = 10.0; // 초기 y 좌표 +let endX = 570.0; // 최종 x 좌표 +let endY = 320.0; // 최종 y 좌표 +let distX; // 이동할 X축 거리 +let distY; // 이동할 Y축 거리 +let exponent = 4; // 곡선 결정 +let x = 0.0; // 현재 x 좌표 +let y = 0.0; // 현재 y 좌표 +let step = 0.01; // 경로를 따른 각 단계별 움직임 크기 +let pct = 0.0; // 이동 거리 비율 (0.0과 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/dist/assets/examples/ko/13_Motion/07_Circle_Collision.js b/dist/assets/examples/ko/13_Motion/07_Circle_Collision.js new file mode 100644 index 0000000000..876bc23d6e --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/07_Circle_Collision.js @@ -0,0 +1,145 @@ +/* + * @name Circle Collision + * @frame 710,400 (optional) + * @description This is a port of the "Circle Collision" example from processing.org/examples
This example uses vectors for better visualization of physical Quantity + */ +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]); + } +} diff --git a/dist/assets/examples/ko/13_Motion/08_Moving_On_Curves.js b/dist/assets/examples/ko/13_Motion/08_Moving_On_Curves.js new file mode 100644 index 0000000000..4c347c7e00 --- /dev/null +++ b/dist/assets/examples/ko/13_Motion/08_Moving_On_Curves.js @@ -0,0 +1,47 @@ +/* + * @name Moving On Curves + * @frame 720,400 + * @description In this example, the circles moves along the curve y = x^4. + * Click the mouse to have it move to a new position. + */ + +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/dist/assets/examples/ko/15_Instance_Mode/01_Instantiating.js b/dist/assets/examples/ko/15_Instance_Mode/01_Instantiating.js new file mode 100644 index 0000000000..2f5f4ae97a --- /dev/null +++ b/dist/assets/examples/ko/15_Instance_Mode/01_Instantiating.js @@ -0,0 +1,35 @@ +/* + * @name 인스턴스화 + * @description p5 인스턴스를 만들어, 해당 페이지의 모든 변수들이 + * 전역 범위에서 사용되지 않도록 합니다. + */ +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); + +// "전역 모드(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/dist/assets/examples/ko/15_Instance_Mode/02_Instance_Container.js b/dist/assets/examples/ko/15_Instance_Mode/02_Instance_Container.js new file mode 100644 index 0000000000..b5d6647f6e --- /dev/null +++ b/dist/assets/examples/ko/15_Instance_Mode/02_Instance_Container.js @@ -0,0 +1,92 @@ +/* + * @norender + * @name 인스턴스 컨테이너 + * @description 캔버스에 기본 컨테이너를 지정하거나, + * 두번째 인수로 추가될 수 있는 모든 요소를 지정할 수 있습니다. + * HTML의 요소 id나 HTML 노드 그 자체도 지원됩니다. + * 컨테이너 DOM 요소를 지정하는 세 가지 다른 방법이 있습니다. + * p5로 만들어진 모든 DOM 요소(캔버스, 버튼, div 등)는 + * p5()함수 호출시 두 번째 인수로 지정된 DOM 요소에 담기게 됩니다. + */ + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dist/assets/examples/ko/16_Dom/03_Input_Button.js b/dist/assets/examples/ko/16_Dom/03_Input_Button.js new file mode 100644 index 0000000000..76549e0e51 --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/03_Input_Button.js @@ -0,0 +1,41 @@ +/* + * @name 입력과 버튼 + * @description 로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리 + * 를 추가하면 됩니다.

+ * 텍스트를 입력하고 버튼을 클릭하면 어떤 효과가 캔버스에 나타나는지 보세요. + */ +let input, button, greeting; + +function setup() { + // 캔버스 생성하기 + 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/dist/assets/examples/ko/16_Dom/04_Slider.js b/dist/assets/examples/ko/16_Dom/04_Slider.js new file mode 100644 index 0000000000..551a4687c4 --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/04_Slider.js @@ -0,0 +1,33 @@ +/* + * @name 슬라이더 + * @description 로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리 + * 를 추가하면 됩니다.

+ * 슬라이더를 움직여 배경색의 R,G,B값을 조정해보세요. + */ +let rSlider, gSlider, bSlider; + +function setup() { + // 캔버스 생성하기 + createCanvas(710, 400); + textSize(15); + noStroke(); + + // 슬라이더 생성하기 + 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/dist/assets/examples/ko/16_Dom/07_Modify_DOM.js b/dist/assets/examples/ko/16_Dom/07_Modify_DOM.js new file mode 100644 index 0000000000..dfbd9b7325 --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/07_Modify_DOM.js @@ -0,0 +1,55 @@ +/* + * @name DOM 변경 + * @frame 710,300 + * @description

DOM 요소를 만들고 draw()함수가 매번 호출될 때마다 + * 그 속성들을 변경해보세요. 로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리 + * 를 추가하면 됩니다.

+ */ +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() { + // 이 단락은 위의 주요 코드 블록의 부록으로서 작성됩니다. + // 아래의 코드들은 요소의 생성과 지정 기능을 구분합니다. + // 지정된 요소들은 p5js로 별도 생성될 필요가 없으며, + // 일반적인 HTML처럼 쓰일 수 있습니다. + createP( + 'I learn in this Letter, that Don Peter of Aragon, ' + + ' comes this night to Messina' + ).addClass('text').hide(); + + // 이 줄은 금방 생성된 '단락'을 받지만, + // 동시에 HTML 페이지상 'text' 클래스를 가진 다른 요소들을 받아오기도 합니다. + 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/dist/assets/examples/ko/16_Dom/08_Video.js b/dist/assets/examples/ko/16_Dom/08_Video.js new file mode 100644 index 0000000000..76996c8430 --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/08_Video.js @@ -0,0 +1,30 @@ +/* + * @name 비디오 + * @frame 710,250 + * @description

다양한 형식의 비디오를 불러오고 버튼을 눌러 재생 또는 일시 정지를 합니다. + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 비디오 파일이 필요하고, + * p5.dom 라이브러리를 추가하면 됩니다.

+ */ +let playing = false; +let fingers; +let button; + +function setup() { + noCanvas(); + // 여러 브라우저 지원을 위해 다양한 비디오 형식 지정 + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + button = createButton('play'); + button.mousePressed(toggleVid); // 버튼 리스너 붙이기 +} + +// 현재 상태에 따라 비디오를 재생 또는 일시 정지 +function toggleVid() { + if (playing) { + fingers.pause(); + button.html('play'); + } else { + fingers.loop(); + button.html('pause'); + } + playing = !playing; +} diff --git a/dist/assets/examples/ko/16_Dom/09_Video_Canvas.js b/dist/assets/examples/ko/16_Dom/09_Video_Canvas.js new file mode 100644 index 0000000000..02b9727715 --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/09_Video_Canvas.js @@ -0,0 +1,27 @@ +/* + * @name 비디오 캔버스 + * @description

비디오를 다양한 형식으로 불러와 캔버스 위에 그릴 수 있도록 합니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 비디오 파일이 필요하고, + * p5.dom 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +let fingers; + +function setup() { + createCanvas(710, 400); + // 여러 브라우저 지원을 위해 다양한 비디오 형식 지정 + fingers = createVideo(['assets/fingers.mov', 'assets/fingers.webm']); + fingers.hide(); // 기본값으로, 비디오는 별개의 DOM 요소로 나타납니다. + // 이를 우선 숨긴 뒤, 캔버스에 그릴 수 있도록 해볼까요 +} + +function draw() { + background(150); + image(fingers, 10, 10); // 캔버스에 비디오 프레임 그리기 + filter(GRAY); + image(fingers, 150, 150); // 캔버스에 두번째 사본 그리기 +} + +function mousePressed() { + fingers.loop(); // 반복 재생 설정 및 비디오 재생 +} diff --git a/dist/assets/examples/ko/16_Dom/10_Video_Pixels.js b/dist/assets/examples/ko/16_Dom/10_Video_Pixels.js new file mode 100644 index 0000000000..10bd28beef --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/10_Video_Pixels.js @@ -0,0 +1,33 @@ +/* + * @name 비디오 픽셀 + * @frame 320,240 + * @description

비디오를 불러와 픽셀을 조정하고 캔버스에 그려보세요. + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 비디오 파일이 필요하고, + * p5.dom 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +let fingers; + +function setup() { + createCanvas(320, 240); + // 여러 브라우저 지원을 위해 다양한 비디오 형식 지정 + 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/dist/assets/examples/ko/16_Dom/11_Capture.js b/dist/assets/examples/ko/16_Dom/11_Capture.js new file mode 100644 index 0000000000..4c3457e2a3 --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/11_Capture.js @@ -0,0 +1,25 @@ +/* + * @name 실시간 비디오 + * @frame 710,240 + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 비디오 파일이 필요하고, + * p5.dom 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.



+ * 웹캠을 통해 보여지는 실시간 비디오 화면을 캔버스 위에 그릴 수 있습니다. + * 반전 효과 필터도 적용할 수 있습니다. + * 실시간 비디오 화면은 기본값으로 캔버스 위에 나타납니다. + * 아래의 코드 중 capture.hide()의 주석 처리(//)를 해제하면 이 실시간 비디오 화면을 숨길 수 있습니다. + */ +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/dist/assets/examples/ko/16_Dom/12_Drop.js b/dist/assets/examples/ko/16_Dom/12_Drop.js new file mode 100644 index 0000000000..c3541c6d1f --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/12_Drop.js @@ -0,0 +1,36 @@ +/* + * @name 드롭 기능 + * @description 여러분의 로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리 + * 를 추가하면 됩니다.

+ * 이미지 파일을 캔버스에 드래그 & 드롭하여 화면에 보이는지 확인해보세요. + */ + +function setup() { + // 캔버스 생성 + const c = createCanvas(710, 400); + background(100); + // 캔버스에 이미지 파일이 드롭될 때 이벤트 추가 + 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 (file.type === 'image') { + // 이미지 DOM 요소를 생성하되, 화면엔 띄우지 않는다. + const img = createImg(file.data).hide(); + // 이미지를 캔버스에 그린다. + image(img, 0, 0, width, height); + } else { + console.log('Not an image file!'); + } +} diff --git a/dist/assets/examples/ko/16_Dom/13_DOM_Form_Elements.js b/dist/assets/examples/ko/16_Dom/13_DOM_Form_Elements.js new file mode 100644 index 0000000000..d83dfdc13e --- /dev/null +++ b/dist/assets/examples/ko/16_Dom/13_DOM_Form_Elements.js @@ -0,0 +1,152 @@ +/* + * @name DOM Form Elements + * @frame 600,400 + * @description contributed by + Prof WM Harris, How to use p5 DOM form elements to create a slider, +button, checkbox, radio group, select menu, and entry field.
+Functions are created that include: the canvas +setup, checkbox creation with text, text box with text that projects +typed text onto canvas, slider with button, three selections which +project a rectangle in different areas on the canvas depending on +selection, and a drop down menu with font change. +*/ + +/* global variables */ +//p5 DOM form elements +let slider1; +let button1; +let checkbox1; +let radio1; +let select1; +let entry1; + +function setup() { + createCanvas(200, 200); + background("beige"); + + checkbox1 = createCheckbox("Check me"); + + createP(); //spacer with

tag + + createSpan("What's your name? "); //label for entry1 + // createInput([value], [type]) + // type: "text" (default), "number", + // "date", "password", "email", etc. + entry1 = createInput(); + //If text in the entry field changes, call + //the entryCallback function. + entry1.changed(entryCallback); + + createP(); //spacer with

tag + + //createSlider(min, max, [value], [step]) + slider1 = createSlider(10, 200); + + button1 = createButton("Press me"); //, "pressed"); + //Assign callback fcn for button1 + //when user clicks mouse on it + button1.mouseClicked(button1Clicked); + + createP(); //spacer with

tag + + radio1 = createRadio(); + + //.option([value], [contentLabel]) + //If 1 param, it's both content AND + //value. Values treated as strings. + radio1.option(1, "cranberries"); + radio1.option(2, "almonds"); + radio1.option(3, "gouda"); + + radio1.value("1"); //set init value + + createP(); //spacer with

tag + + select1 = createSelect(); + //.option([contentValue],[value]) + //If 1 param, it's both content AND + //value. Values treated as strings. + select1.option("Sans-serif"); + select1.option("Serif"); + select1.option("Fantasy"); + //If changed, call select1Changed + select1.changed(select1Changed); +} + +function draw() { + //get value from slider 1 + let gray = slider1.value(); + fill(gray); + + //If mouse in corner, turn on checkbox1 + if ((mouseX < width / 3) && + (mouseY < height / 3)) { + checkbox1.checked(true); + } + //Is checkbox1 checked? Say so. + if (checkbox1.checked()) { + text("CHECKED", 20, 40); + } + + switch (radio1.value()) { + //radio value is always a string + case "1": + rect(0, 0, width, 50); + break; + case "2": + rect(0, 70, width, 50); + break; + case "3": + rect(0, 140, width, 50); + break; + } +} + +//callback fcn for button1 +function button1Clicked() { + //reset slider value to 200 + slider1.value(200); +} + + +//callback fcn for select1 +function select1Changed() { + switch (select1.value()) { + case "Sans-serif": + textFont("sans-serif"); + break; + case "Serif": + textFont("serif"); + break; + case "Fantasy": + textFont("fantasy"); + break; + } +} + +//callback function for entry1 +function entryCallback() { + for (let i = 0; i < 25; i++) { + text(entry1.value(), random(width), + random(height)); + } + +} + +function mouseClicked() { + console.log("button1?", button1.value()); + console.log("checkbox1?", checkbox1.value()); + //Update .value of either? No visible change + //to a button or checkbox + checkbox1.value("Check again"); + button1.value("clicked?"); +} + +function keyTyped() { + switch (key) { + case "r": + //move slider1 value to 100 + slider1.value(100); + break; + } +} diff --git a/dist/assets/examples/ko/17_Drawing/00_Continuous_Lines.js b/dist/assets/examples/ko/17_Drawing/00_Continuous_Lines.js new file mode 100644 index 0000000000..aa89265d1d --- /dev/null +++ b/dist/assets/examples/ko/17_Drawing/00_Continuous_Lines.js @@ -0,0 +1,15 @@ +/* + * @name 연속된 선 + * @description 마우스를 클릭하고 드래그하여 선을 그려보세요. + */ +function setup() { + createCanvas(710, 400); + background(102);ㅌ +} + +function draw() { + stroke(255); + if (mouseIsPressed === true) { + line(mouseX, mouseY, pmouseX, pmouseY); + } +} diff --git a/dist/assets/examples/ko/17_Drawing/01_Pattern.js b/dist/assets/examples/ko/17_Drawing/01_Pattern.js new file mode 100644 index 0000000000..c1db5a64fd --- /dev/null +++ b/dist/assets/examples/ko/17_Drawing/01_Pattern.js @@ -0,0 +1,26 @@ +/* + * @name 패턴 + * @description 캔버스 위로 마우스를 움직여 드로잉할 수 있는 소프트웨어 툴입니다. + * 이 때, 드로잉은 마우스의 속도에 반응합니다. + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + // variableEllipse()메소드를 호출하고, 여기에 + // 마우스의 현재 및 이전 위치를 담은 매개 변수를 보냅니다. + variableEllipse(mouseX, mouseY, pmouseX, pmouseY); +} + +// 이 간단한 메소드 variableEllipse()는 이 프로그램을 위해 +// 작성되었습니다. 메소드는 마우스의 속도를 계산하는데, +// 마우스가 천천히 움직이면 작은 타원을, +// 마우스가 빨리 움직이면 큰 타원을 그립니다. + +function variableEllipse(x, y, px, py) { + let speed = abs(x - px) + abs(y - py); + stroke(speed); + ellipse(x, y, speed, speed); +} diff --git a/dist/assets/examples/ko/17_Drawing/02_Pulses.js b/dist/assets/examples/ko/17_Drawing/02_Pulses.js new file mode 100644 index 0000000000..3b2e77f82d --- /dev/null +++ b/dist/assets/examples/ko/17_Drawing/02_Pulses.js @@ -0,0 +1,30 @@ +/* + * @name 율동 + * @description 드로잉 스포트웨어는 특정 리듬이나, 그려진 제스쳐로부터 독립된 규칙을 따를 수 있습니다. + * 이 예제의 경우, 협업 드로잉으로도 볼 수 있습니다. + * 사용자가 이미지의 일부를 조정하면 소프트웨어가 다른 일부를 조정하는 식입니다. + */ +let angle = 0; + +function setup() { + createCanvas(710, 400); + background(102); + noStroke(); + fill(0, 102); +} + +function draw() { + // 마우스가 클릭될 때만 그리기 + 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/dist/assets/examples/ko/18_Transform/00_Translate.js b/dist/assets/examples/ko/18_Transform/00_Translate.js new file mode 100644 index 0000000000..e535237377 --- /dev/null +++ b/dist/assets/examples/ko/18_Transform/00_Translate.js @@ -0,0 +1,39 @@ +/* + * @name 위치 이동(Translate) + * @description translate() 함수는 객체를 화면 내 어떤 위치로든 이동하게 합니다. + * 그 첫 번째 매개변수는 x축의 오프셋(offset)을, + * 두 번째 매개변수는 y축의 오프셋을 지정합니다. + * 이 예제는 이러한 이동들이 축적되는 것을 보여줍니다. + */ + +let x = 0; +let y = 0; +let dim = 80.0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(102); + // x값을 증가시켜 움직이게 만들기 + x = x + 0.8; + // 도형이 캔버스 밖으로 나가면, 위치를 리셋한다. + if (x > width + dim) { + x = -dim; + } + + // rect 명령어는 원점을 중심점으로 삼는 도형을 그리지만, + // translate(이동)은 이를 새로운 x와 y 위치로 옮깁니다. + translate(x, height / 2 - dim / 2); + fill(255); + rect(-dim / 2, -dim / 2, dim, dim); + + // translate(이동)은 축적됩니다. 이 rect가 다른 rect와 + // 동일한 x축값 매개변수를 가졌음에도 + // 두 배로 빠르게 움직이는 걸 볼 수 있습니다. + translate(x, dim); + fill(0); + rect(-dim / 2, -dim / 2, dim, dim); +} diff --git a/dist/assets/examples/ko/18_Transform/01_Scale.js b/dist/assets/examples/ko/18_Transform/01_Scale.js new file mode 100644 index 0000000000..0bfa5be461 --- /dev/null +++ b/dist/assets/examples/ko/18_Transform/01_Scale.js @@ -0,0 +1,45 @@ +/* + * @name 크기 조정(Scale) + * @description scale()함수의 매개변수는 10진수 백분율로 표현됩니다. + * 예를 들어, scale(2.0) 메소드 호출은 도형의 차원을 200 퍼센트 증가시킵니다. + * 오브젝트의 크기는 항상 원점을 기준으로 조정됩니다. + * 이 예제는 그러한 변형이 누적되는 양상과, 순서에 따라 scale과 translate이 + * 상호작용하는 것을 보여줍니다. + */ + +let a = 0.0; +let s = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + // 드로잉 시작 기본 위치인 상단 좌측 코너가 아닌, + // 화면 중앙에서 직사각형이 그려지도록 합니다. + rectMode(CENTER); +} + +function draw() { + background(102); + + // 'a'를 천천히 증가시킨 다음 'a'의 코사인을 찾아, + // 's'에 부드럽고 주기적인 애니메이션 효과를 줍니다. + a = a + 0.04; + s = cos(a) * 2; + + // 사각형의 위치를 원점에서 캔버스 중간으로 이동(translate)한 다음, + // 's'로 크기를 조정합니다. + translate(width / 2, height / 2); + scale(s); + fill(51); + rect(0, 0, 50, 50); + + // 위치 이동과 크기 조정은 누적됩니다. + // 따라서 이동된 두 번째 사각형은 첫 번째 사각형보다 + // 조금 더 오른쪽으로 이동하게 되고, 그 크기는 두배가 됩니다. + // 한편, 코사인은 's'가 음수와 양수를 오가도록 하는데, + // 이에 따라 사각형이 왼쪽과 오른쪽을 순환하게 됩니다. + translate(75, 0); + fill(255); + scale(s); + rect(0, 0, 50, 50); +} diff --git a/dist/assets/examples/ko/18_Transform/02_Rotate.js b/dist/assets/examples/ko/18_Transform/02_Rotate.js new file mode 100644 index 0000000000..d25d8de8f9 --- /dev/null +++ b/dist/assets/examples/ko/18_Transform/02_Rotate.js @@ -0,0 +1,42 @@ +/* + * @name 회전(Rotate) + * @description Z축을 기준으로 사각형 회전시킵니다. + * 원하는 결과를 얻기 위해, 0부터 PI*2(즉, TWO_PI, 약 6.28)에 해당하는, + * rotate 함수 속 각도 매개 변수를 보냅니다. + * 각도를 도(0-360) 단위로 표현하고 싶다면, radians() 메소드를 통해 변환하면 됩니다. + * 예: scale(radians(90))은 선언문 scale(PI/2)과 동일합니다. + * 이 예제에서, 모든 짝수 초마다 jitter(떨림)가 회전에 더해집니다. + * 홀수 초에는 마지막 jitter값으로 결정된 속도에 따라 + * 시계 방향 또는 반시계 방향으로 회전합니다. + */ + +let angle = 0.0; +let jitter = 0.0; + +function setup() { + createCanvas(720, 400); + noStroke(); + fill(255); + //중심으로부터 사각형을 그리고, + //사각형이 중심을 기준으로 회전하도록 만들기 + rectMode(CENTER); +} + +function draw() { + background(51); + + // 짝수 초(0, 2, 4, 6...)동안 회전에 + // jitter(떨림) 더하기 + if (second() % 2 === 0) { + jitter = random(-0.1, 0.1); + } + // 가장 마지막 jitter값을 사용해 각도값 증가시키기 + angle = angle + jitter; + // 떨림이 없는 경우, 코싸인을 사용해 부드러운 시계 방향 및 반시계 방향 모션 받기 + let c = cos(angle); + //도형을 캔버스의 중앙으로 이동시키기 + translate(width / 2, height / 2); + //최종 회전 적용하기 + rotate(c); + rect(0, 0, 180, 180); +} diff --git a/dist/assets/examples/ko/18_Transform/03_Arm.js b/dist/assets/examples/ko/18_Transform/03_Arm.js new file mode 100644 index 0000000000..b62f1dac02 --- /dev/null +++ b/dist/assets/examples/ko/18_Transform/03_Arm.js @@ -0,0 +1,47 @@ +/* + * @name 팔모양 + * @description 이 예제는 변형 행렬을 사용하여 팔모양을 만듭니다. + * 각 선분의 각도는 mouseX 및 mouseY 위치로 조정됩니다. + * 첫 번째 선분에 적용된 변형은 두 번째 선분에도 적용됩니다. + * 두 선분 모두 동일한 push() 및 pop() 행렬 그룹에 속하기 때문입니다. + */ + +let x, y; +let angle1 = 0.0; +let angle2 = 0.0; +let segLength = 100; + +function setup() { + createCanvas(720, 400); + strokeWeight(30); + + // 반투명한 선 그리기 + stroke(255, 160); + + // 팔의 "어깨" 위치를 캔버스 중앙에 위치시키기 + x = width * 0.5; + y = height * 0.5; +} + +function draw() { + background(0); + + // 마우스 위치에 따라 선분의 각도 바꾸기 + angle1 = (mouseX / float(width) - 0.5) * -TWO_PI; + angle2 = (mouseY / float(height) - 0.5) * PI; + + // push와 pop을 사용해 변형을 담기 + // 사용자 정의 함수를 사용해 선분을 그려도 + // 변형 내용이 축적되는 걸 볼 수 있습니다. + push(); + segment(x, y, angle1); + segment(segLength, 0, angle2); + pop(); +} + +// 선분을 그리기 위한 사용자 정의 함수 +function segment(x, y, a) { + translate(x, y); + rotate(a); + line(0, 0, segLength, 0); +} diff --git a/dist/assets/examples/ko/19_Typography/00_Letters.js b/dist/assets/examples/ko/19_Typography/00_Letters.js new file mode 100644 index 0000000000..b965b233bc --- /dev/null +++ b/dist/assets/examples/ko/19_Typography/00_Letters.js @@ -0,0 +1,64 @@ +/* + * @name 글자 + * @description 폰트를 불러와 글자 속성을 정하면, 화면에 글자를 그릴 수 있습니다. + * 이 예제에서는 for 반복문과 유니코드 참조 번호를 사용하여, + * 그리드 속 글자들로 캔버스를 자동으로 채웁니다. + * 이 중, 모음들에만 특정 색상이 부여됩니다. + */ +let font, + fontsize = 32; + +function preload() { + // setup()과 draw()를 호출하기에 앞서, + // assets 파일 경로에 .ttf 또는 .otf 폰트가 저장 및 로드되었는지 확인하세요. + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // 텍스트 속성 설정 + textFont(font); + textSize(fontsize); + textAlign(CENTER, CENTER); +} + +function draw() { + background(160); + + // 글자 간, 그리고 글자와 좌측 및 상단 간의 margin(여백) 설정 + let gap = 52; + let margin = 10; + translate(margin * 4, margin * 4); + + // 원하는 글자에서 시작하도록 카운터 설정 + // 이 예제에서는 유니코드 35, 즉 # 기호입니다. + let counter = 35; + + // 캔버스에 공간이 확보되는 한 반복하기 + for (let y = 0; y < height - gap; y += gap) { + for (let x = 0; x < width - gap; x += gap) { + // 카운터를 사용해 유니코드 번호로 개별 글자를 검색 + let letter = char(counter); + + // 모음과 기타 글자들에 각각 다른 색상 더하기 + if ( + letter === 'A' || + letter === 'E' || + letter === 'I' || + letter === 'O' || + letter === 'U' + ) { + fill('#ed225d'); + } else { + fill(255); + } + + // 화면에 글자 그리기 + text(letter, x, y); + + // 카운터 증가시키기 + counter++; + } + } +} diff --git a/dist/assets/examples/ko/19_Typography/01_Words.js b/dist/assets/examples/ko/19_Typography/01_Words.js new file mode 100644 index 0000000000..725cb82229 --- /dev/null +++ b/dist/assets/examples/ko/19_Typography/01_Words.js @@ -0,0 +1,58 @@ +/* + * @name 단어 + * @description text()함수는 화면에 단어를 쓸 때 사용됩니다. + * textAlign()함수로 단어들을 왼쪽, 가운데, 또는 오른쪽 정렬할 수 있으며, + * 도형과 마찬가지로, 단어들 역시 fill()로 그 색을 채울 수 있습니다. + */ +let font, + fontsize = 40; + +function preload() { + // setup()과 draw()를 호출하기에 앞서, + // assets 파일 경로에 .ttf 또는 .otf 폰트가 저장 및 로드되었는지 확인하세요. + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // 텍스트 속성 설정 + textFont(font); + textSize(fontsize); + textAlign(CENTER, CENTER); +} + +function draw() { + background(160); + + // 텍스트를 오른쪽 정렬하고 + // 캔버스의 좌측 1/3 영역에서 drawWords() 실행하기 + textAlign(RIGHT); + drawWords(width * 0.25); + + // 텍스트를 가운데 정렬하고 + // 캔버스의 가운데 영역에서 drawWords() 실행하기 + textAlign(CENTER); + drawWords(width * 0.5); + + // 텍스트를 왼쪽 정렬하고 + // 캔버스의 우측 1/3 영역에서 drawWords() 실행하기 + textAlign(LEFT); + drawWords(width * 0.75); +} + +function drawWords(x) { + // text() 함수에는 세 개의 매개 변수가 필요합니다: + // 그려질 텍스트, 가로 위치, 그리고 세로 위치 + 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/dist/assets/examples/ko/19_Typography/02_Text_Rotation.js b/dist/assets/examples/ko/19_Typography/02_Text_Rotation.js new file mode 100644 index 0000000000..5d6904eafe --- /dev/null +++ b/dist/assets/examples/ko/19_Typography/02_Text_Rotation.js @@ -0,0 +1,62 @@ +/* + * @name 텍스트 회전 + * @description 스크린에 글자를 그린 후, 다양한 각도로 회전시킵니다. + * (https://processing.org/examples/textrotation.html에서 옮김) + */ + +let font, +fontsize = 32; + +let angleRotate = 0.0; + +function setup() { + createCanvas(710, 400); + background(0); + + // setup()함수와 draw()함수를 부르기 전에 .ttf 또는 .otf 파일이 'assets' 주소에 + // 있을 것을 확안합니다 + font = loadFont('assets/SourceSansPro-Regular.otf'); + + // 텍스트의 특징을 정합니다 + textFont(font); +} + +function draw() { + background(0); + + strokeWeight(1); + stroke(153); + + push(); + let angle1 = radians(45); + translate(100, 180); + rotate(angle1); + // 스크린에 글짜를 그립니다 + text("45 DEGREES", 0, 0); + line(0, 0, 150, 0); + pop(); + + push(); + let angle2 = radians(270); + translate(200, 180); + rotate(angle2); + // 스크린에 글짜를 그립니다 + 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); +} diff --git a/dist/assets/examples/ko/20_3D/00_geometries.js b/dist/assets/examples/ko/20_3D/00_geometries.js new file mode 100644 index 0000000000..59a9b03459 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/00_geometries.js @@ -0,0 +1,60 @@ +/* + * @name 기하 + * @description 현재 p5에는 여섯 개의 3D 기초 조형이 있습니다. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + + translate(-240, -100, 0); + normalMaterial(); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + plane(70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(70, 70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cylinder(70, 70); + pop(); + + translate(-240 * 2, 200, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cone(70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + torus(70, 20); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + sphere(70); + pop(); +} diff --git a/dist/assets/examples/ko/20_3D/01_sine_cosine_in_3D.js b/dist/assets/examples/ko/20_3D/01_sine_cosine_in_3D.js new file mode 100644 index 0000000000..832ea9b8ff --- /dev/null +++ b/dist/assets/examples/ko/20_3D/01_sine_cosine_in_3D.js @@ -0,0 +1,28 @@ +/* + * @name 3D속 사인 코사인 + * @description 사인, 코사인, 그리고 push / pop 함수는 3D에도 적용됩니다. + */ +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/dist/assets/examples/ko/20_3D/02_multiple_lights.js b/dist/assets/examples/ko/20_3D/02_multiple_lights.js new file mode 100644 index 0000000000..1491c79a43 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/02_multiple_lights.js @@ -0,0 +1,30 @@ +/* + * @name 복수의 조명들 + * @description 한 스케치 위에 여러 종류의 조명을 사용할 수 있습니다. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + ambientLight(50); + directionalLight(255, 0, 0, 0.25, 0.25, 0); + 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, 64); +} diff --git a/dist/assets/examples/ko/20_3D/03_materials.js b/dist/assets/examples/ko/20_3D/03_materials.js new file mode 100644 index 0000000000..571219eee0 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/03_materials.js @@ -0,0 +1,65 @@ +/* + * @name 재질(Materials) + * @description 지원되는 재질은 다섯 가지 입니다. + * 각각은 조명에 다르게 반응합니다. + * 마우스를 움직여 빛의 위치를 바꿔보세요. + */ +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/dist/assets/examples/ko/20_3D/04_textures.js b/dist/assets/examples/ko/20_3D/04_textures.js new file mode 100644 index 0000000000..54aafba4a6 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/04_textures.js @@ -0,0 +1,40 @@ +/* + * @name 텍스처 + * @description 이미지와 비디오가 텍스처를 지원합니다. + */ +// 비디오 출처: 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); + //이미지를 텍스처로 전달하기 + 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/dist/assets/examples/ko/20_3D/05_ray_casting.js b/dist/assets/examples/ko/20_3D/05_ray_casting.js new file mode 100644 index 0000000000..ac4fc40e06 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/05_ray_casting.js @@ -0,0 +1,100 @@ +/* + * @name 레이 캐스팅 + * @description 예제 원본: 조나단 왓슨(Jonathan Watson) 제작 + *

광선 투사(ray casting) 기능으로 3D 공간 속 마우스의 위치를 감지합니다. + */ +const objects = []; +let eyeZ; + +function setup() { + createCanvas(710, 400, WEBGL); + + eyeZ = height / 2 / tan((30 * PI) / 180); // 카메라가 원점에서 떨어진 기본 위치 + + objects.push(new IntersectPlane(1, 0, 0, -100, 0, 0)); // 왼쪽 벽 + objects.push(new IntersectPlane(1, 0, 0, 100, 0, 0)); // 오른쪽 벽 + objects.push(new IntersectPlane(0, 1, 0, 0, -100, 0)); // 바닥 + objects.push(new IntersectPlane(0, 1, 0, 0, 100, 0)); // 천장 + objects.push(new IntersectPlane(0, 0, 1, 0, 0, 0)); // 뒷면 벽 + + noStroke(); + ambientMaterial(250); +} + +function draw() { + background(0); + + // 조명들 + pointLight(255, 255, 255, 0, 0, 400); + ambientLight(244, 122, 158); + + // 왼쪽 벽 + push(); + translate(-100, 0, 200); + rotateY((90 * PI) / 180); + plane(400, 200); + pop(); + + // 오른쪽 벽 + push(); + translate(100, 0, 200); + rotateY((90 * PI) / 180); + plane(400, 200); + pop(); + + // 바닥 + push(); + translate(0, 100, 200); + rotateX((90 * PI) / 180); + plane(200, 400); + pop(); + + // 천장 + push(); + translate(0, -100, 200); + rotateX((90 * PI) / 180); + plane(200, 400); + pop(); + + plane(200, 200); // 뒷면 벽 + + const x = mouseX - width / 2; + const y = mouseY - height / 2; + + const Q = createVector(0, 0, eyeZ); // 광선 위의 점과 카메라의 기본 위치 + const v = createVector(x, y, -eyeZ); // 광선의 방향 벡터 + + let intersect; // 광선과 벽면의 교차점 + let closestLambda = eyeZ * 10; // 거리 그리기 + + for (let x = 0; x < objects.length; x += 1) { + let object = objects[x]; + let lambda = object.getLambda(Q, v); // 광선과 객체 간 교차점의 람다값 + + if (lambda < closestLambda && lambda > 0) { + // 광선과 객체의 교차점 위치 찾기 + intersect = p5.Vector.add(Q, p5.Vector.mult(v, lambda)); + closestLambda = lambda; + } + } + + // 커서 + push(); + translate(intersect); + fill(237, 34, 93); + sphere(10); + pop(); +} + +// 무한대로 확장하는 벽면 생성을 위한 클래스 +class IntersectPlane { + constructor(n1, n2, n3, p1, p2, p3) { + this.normal = createVector(n1, n2, n3); // 면의 기본 벡터 + this.point = createVector(p1, p2, p3); // 면 위의 점 + this.d = this.point.dot(this.normal); + } + + getLambda(Q, v) { + return (-this.d - this.normal.dot(Q)) / this.normal.dot(v); + } +} diff --git a/dist/assets/examples/ko/20_3D/07_orbit_control.js b/dist/assets/examples/ko/20_3D/07_orbit_control.js new file mode 100644 index 0000000000..7c45043100 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/07_orbit_control.js @@ -0,0 +1,36 @@ +/* + * @name 궤도 제어 + * @description 궤도 제어(Orbit Control)를 사용해 월드를 드래그하거나 움직일 수 있습니다. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + let radius = width * 1.5; + + //월드를 움직이도록 드래그 + orbitControl(); + + normalMaterial(); + translate(0, 0, -600); + 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/dist/assets/examples/ko/20_3D/08_basic_shader.js b/dist/assets/examples/ko/20_3D/08_basic_shader.js new file mode 100644 index 0000000000..f335a266f8 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/08_basic_shader.js @@ -0,0 +1,27 @@ +/* + * @name 셰이더 기초 + * @description p5.js에 셰이더를 불러오는 방법을 설명하는 기본 예제입니다. + *
p5.js로 셰이더를 사용하는 방법에 대해 더 알고 싶다면: p5.js Shaders + */ + +// 이 변수는 셰이더 객체를 담습니다. +let theShader; + +function preload(){ + // 셰이더 불러오기 + theShader = loadShader('assets/basic.vert', 'assets/basic.frag'); +} + +function setup() { + // 셰이더를 작동하기 위해 WEBGL 모드가 필요합니다. + createCanvas(710, 400, WEBGL); + noStroke(); +} + +function draw() { + // shader()는 활성화 셰이더를 theShader로 설정합니다. + shader(theShader); + + // rect()함수로 화면에 기하 추가하기 + rect(0,0,width, height); +} diff --git a/dist/assets/examples/ko/20_3D/09_shader_as_a_texture.js b/dist/assets/examples/ko/20_3D/09_shader_as_a_texture.js new file mode 100644 index 0000000000..3e12f552c7 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/09_shader_as_a_texture.js @@ -0,0 +1,68 @@ +/* + * @name 셰이더로 텍스처 만들기 + * @description 셰이더는 2D/3D 도형에 텍스처로서 적용될 수 있습니다. + *
p5.js로 셰이더를 사용하는 방법에 대해 더 알고 싶다면: p5.js Shaders + */ + + // 이 변수는 셰이더 객체를 담습니다. + let theShader; + // 이 변수는 createGraphics 레이어를 담습니다. + let shaderTexture; + + let theta = 0; + + let x; + let y; + let outsideRadius = 200; + let insideRadius = 100; + + function preload(){ + // 셰이더 불러오기 + theShader = loadShader('assets/texture.vert','assets/texture.frag'); + } + + function setup() { + // 셰이더를 작동하기 위해 WEBGL 모드가 필요합니다. + createCanvas(710, 400, WEBGL); + noStroke(); + + // createGraphics 레이어 초기화하기 + shaderTexture = createGraphics(710, 400, WEBGL); + + // createGraphics 레이어의 테두리 없애기 + shaderTexture.noStroke(); + + x = -50; + y = 0; + } + + function draw() { + + // theShader를 활성화 셰이더로 설정하는 대신, createGraphics 레이어로 보냅니다. + shaderTexture.shader(theShader); + + // setUniform()를 사용하여 유니폼을 theShader로 보냅니다. + theShader.setUniform("resolution", [width, height]); + theShader.setUniform("time", millis() / 1000.0); + theShader.setUniform("mouse", [mouseX, map(mouseY, 0, height, height, 0)]); + + // shaderTexture 레이어 위 기하 형상의 렌더링을 위한 설정 + shaderTexture.rect(0,0,width,height); + + background(255); + + // 셰이더를 텍스쳐로서 설정하기 + 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(); + + // 5번째 매개변수를 3D 상의 부드러운 모서리 처리를 위한 값으로 보내기 + ellipse(260,0,200,200,100); + } diff --git a/dist/assets/examples/ko/20_3D/10_passing_shader_uniforms.js b/dist/assets/examples/ko/20_3D/10_passing_shader_uniforms.js new file mode 100644 index 0000000000..3b274aef49 --- /dev/null +++ b/dist/assets/examples/ko/20_3D/10_passing_shader_uniforms.js @@ -0,0 +1,34 @@ +/* + * @name 셰이더 유니폼 + * @description 유니폼(Uniform)을 통해 p5에서 셰이더로 정보를 전송합니다. + *
p5.js로 셰이더를 사용하는 방법에 대해 더 알고 싶다면: p5.js Shaders + */ + + // 이 변수는 셰이더 객체를 담습니다. + let theShader; + + function preload(){ + // 셰이더 불러오기 + theShader = loadShader('assets/uniforms.vert', 'assets/uniforms.frag'); + } + + function setup() { + // 셰이더를 작동하기 위해 WEBGL 모드가 필요합니다. + createCanvas(710, 400, WEBGL); + noStroke(); + } + + function draw() { + // shader()는 활성화 셰이더를 theShader로 설정합니다. + shader(theShader); + + // 마우스 + 데이터 수정 시간을 보내기에 앞서, + // 해상도, 마우스, 시간을 셰이더에 보냅니다. + // 이렇게 하면 셰이더에서 사용하기가 더 쉬워집니다. + theShader.setUniform('resolution', [width, height]); + theShader.setUniform('mouse', map(mouseX, 0, width, 0, 7)); + theShader.setUniform('time', frameCount * 0.01); + + // rect()함수로 화면에 기하 형상 추가하기 + rect(0,0,width, height); + } diff --git a/dist/assets/examples/ko/20_3D/11_shader_using_webcam.js b/dist/assets/examples/ko/20_3D/11_shader_using_webcam.js new file mode 100644 index 0000000000..0763b93fac --- /dev/null +++ b/dist/assets/examples/ko/20_3D/11_shader_using_webcam.js @@ -0,0 +1,37 @@ +/* + * @name 웹캠을 사용한 셰이더 + * @description 웹캠을 텍스처로서 셰이더에 보낼 수 있습니다. + *
p5.js로 셰이더를 사용하는 방법에 대해 더 알고 싶다면: p5.js Shaders + */ + + // 이 변수는 셰이더 객체를 담습니다. + let theShader; + // 이 변수는 웹캠 비디오를 담습니다. + let cam; + + function preload(){ + // 셰이더 불러오기 + theShader = loadShader('assets/webcam.vert', 'assets/webcam.frag'); + } + + function setup() { + // 셰이더 작동을 위해 WEBGL 모드가 필요합니다. + createCanvas(710, 400, WEBGL); + noStroke(); + + cam = createCapture(VIDEO); + cam.size(710, 400); + + cam.hide(); + } + + function draw() { + // shader()는 활성화 셰이더를 theShader로 설정합니다. + shader(theShader); + + // cam을 텍스처로 보내기 + theShader.setUniform('tex0', cam); + + // rect()함수로 화면에 기하 추가하기 + rect(0,0,width,height); + } diff --git a/dist/assets/examples/ko/21_Input/00_Clock.js b/dist/assets/examples/ko/21_Input/00_Clock.js new file mode 100644 index 0000000000..7d9b53c902 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/00_Clock.js @@ -0,0 +1,62 @@ +/* + * @name 시계 + * @description second(), minute(), 그리고 hour()함수를 사용하여 + * 현재 시간을 읽어올 수 있습니다. + * 이 예제에서는 sin()과 cos()값이 시침, 분침, 초침의 위치를 정합니다. + */ +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); + + // 시계 배경 그리기 + noStroke(); + fill(244, 122, 158); + ellipse(cx, cy, clockDiameter + 25, clockDiameter + 25); + fill(237, 34, 93); + ellipse(cx, cy, clockDiameter, clockDiameter); + + // sin()과 cos()의 각도는 3시 정각에서 시작; + // HALF_PI를 뺄셈하여 상단에서부터 시작하도록 설정 + 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; + + // 시계침들 그리기 + 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); + + // 분침 그리기 + 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/dist/assets/examples/ko/21_Input/01_Constrain.js b/dist/assets/examples/ko/21_Input/01_Constrain.js new file mode 100644 index 0000000000..5aff15a043 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/01_Constrain.js @@ -0,0 +1,36 @@ +/* + * @name 제한 + * @description 화면 위로 마우스를 움직이면 동그라미가 움직이지만, + * 박스 안에서만 움직이도록 제한되어 있습니다. + */ +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/dist/assets/examples/ko/21_Input/02_Easing.js b/dist/assets/examples/ko/21_Input/02_Easing.js new file mode 100644 index 0000000000..d84bae3c2a --- /dev/null +++ b/dist/assets/examples/ko/21_Input/02_Easing.js @@ -0,0 +1,28 @@ +/* + * @name 이징(Easing) + * @description 화면 위로 마우스 커서를 움직이면 기호가 따라옵니다. + * 애니메이션의 매 프레임 사이에, 프로그램은 기호와 마우스 커서 간의 거리를 계산합니다. + * 만약 그 거리가 1픽셀보다 크다면, 기호는 현재 위치로부터 커서의 위치를 향해 + * 일정 거리(0.05)를 이동합니다. + */ +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/dist/assets/examples/ko/21_Input/03_Keyboard.js b/dist/assets/examples/ko/21_Input/03_Keyboard.js new file mode 100644 index 0000000000..643e11c539 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/03_Keyboard.js @@ -0,0 +1,38 @@ +/* + * @name 키보드 + * @description 이미지를 클릭하여 포커스를 주고 + * 키보드 입력을 통해 화면에 모양을 만듭니다. + * 각 자판은 고유의 식별 번호를 갖습니다. + * 이 번호들은 도형의 화면 상 위치를 정합니다. + */ +let rectWidth; + +function setup() { + createCanvas(720, 400); + noStroke(); + background(230); + rectWidth = width / 4; +} + +function draw() { + // draw()를 여기에 작성하여 키보드 입력을 기다리는 동안 반복되게 합니다. +} + +function keyPressed() { + let keyIndex = -1; + if (key >= 'a' && key <= 'z') { + keyIndex = key.charCodeAt(0) - 'a'.charCodeAt(0); + } + if (keyIndex === -1) { + // 글자 자판이 아닐 경우, 화면을 비웁니다. + background(230); + } else { + // 글자 자판일 경우, 사각면을 채웁니다. + 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/dist/assets/examples/ko/21_Input/04_Mouse1D.js b/dist/assets/examples/ko/21_Input/04_Mouse1D.js new file mode 100644 index 0000000000..0ca0d20e8e --- /dev/null +++ b/dist/assets/examples/ko/21_Input/04_Mouse1D.js @@ -0,0 +1,23 @@ +/* + * @name 1D 마우스 + * @description 마우스를 좌우로 움직여 균형점을 이동해보세요. + * mouseX 변수로 사각형의 크기와 색상 모두를 조정할 수 있습니다. + */ +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/dist/assets/examples/ko/21_Input/05_Mouse2D.js b/dist/assets/examples/ko/21_Input/05_Mouse2D.js new file mode 100644 index 0000000000..72f1513be4 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/05_Mouse2D.js @@ -0,0 +1,19 @@ +/* + * @name 2D 마우스 + * @description 마우스를 움직이면 각 상자의 위치와 크기가 바뀝니다. + */ +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/dist/assets/examples/ko/21_Input/06_MouseIsPressed.js b/dist/assets/examples/ko/21_Input/06_MouseIsPressed.js new file mode 100644 index 0000000000..b29e306fec --- /dev/null +++ b/dist/assets/examples/ko/21_Input/06_MouseIsPressed.js @@ -0,0 +1,20 @@ +/* + * @name 마우스 버튼 + * @description 마우스를 움직여 도형의 위치를 바꿔보세요. + * 마우스 버튼을 눌러 색을 반전시킬 수 있습니다. + */ +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/dist/assets/examples/ko/21_Input/07_Mouse_Functions.js b/dist/assets/examples/ko/21_Input/07_Mouse_Functions.js new file mode 100644 index 0000000000..659b8e8e27 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/07_Mouse_Functions.js @@ -0,0 +1,66 @@ +/* + * @name 마우스 함수 + * @description 상자를 클릭한 뒤 화면 위에서 드래그 해보세요. + */ +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); + + // 상자 위에 커서가 있는지를 테스트 + 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; + } + + // 상자 그리기 + 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/dist/assets/examples/ko/21_Input/08_Mouse_Signals.js b/dist/assets/examples/ko/21_Input/08_Mouse_Signals.js new file mode 100644 index 0000000000..694d9e8aae --- /dev/null +++ b/dist/assets/examples/ko/21_Input/08_Mouse_Signals.js @@ -0,0 +1,51 @@ +/* + * @name 마우스 신호 + * @description 마우스를 움직이고 클릭하여 신호를 만들어보세요. + * 상단의 행은 "mouseX", 가운데 행은 "mouseY", + * 하단의 행은 "mouseIsPressed"에 대한 신호입니다. + */ +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]; + } + // 배열의 마지막에 새로운 값들 더하기 + 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/dist/assets/examples/ko/21_Input/09_Storing_Input.js b/dist/assets/examples/ko/21_Input/09_Storing_Input.js new file mode 100644 index 0000000000..ea88476c2f --- /dev/null +++ b/dist/assets/examples/ko/21_Input/09_Storing_Input.js @@ -0,0 +1,36 @@ +/* + * @name 입력값 저장 + * @description 화면 위로 마우스를 움직여 원들의 위치를 바꿔보세요. + * 마우스의 위치값들은 배열에 기록되고 매 프레임마다 재생됩니다. + * 각 프레임이 재생되는 사이, 가장 새로운 값이 배열의 마지막에 더해지고 + * 가장 오래된 값은 삭제됩니다. + */ +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); + + // 각 프레임마다 다른 입력값을 이용해 배열을 순환 + // 이처럼 모듈로(%)를 사용하면 모든 값들을 이동시키는 것보다 빠릅니다. + let which = frameCount % num; + mx[which] = mouseX; + my[which] = mouseY; + + for (let i = 0; i < num; i++) { + // which+1은 가장 작은 값 (동시에, 배열에서 가장 오래된 값) + let index = (which + 1 + i) % num; + ellipse(mx[index], my[index], i, i); + } +} diff --git a/dist/assets/examples/ko/21_Input/10_Rollover.js b/dist/assets/examples/ko/21_Input/10_Rollover.js new file mode 100644 index 0000000000..b5a6cf50c9 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/10_Rollover.js @@ -0,0 +1,79 @@ +/* + * @name 롤오버 (Rollover) + * @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 + */ +let squareX, squareY; // 정사각형 버튼의 위치 +let circleX, circleY; // 원형 버튼의 위치 +let squareSize = 90; // 정사각형의 너비와 높이 +let circleSize = 93; // 원의 지름 + +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; + } +} \ No newline at end of file diff --git a/dist/assets/examples/ko/21_Input/11_Storing_Input.js b/dist/assets/examples/ko/21_Input/11_Storing_Input.js new file mode 100644 index 0000000000..563ff80759 --- /dev/null +++ b/dist/assets/examples/ko/21_Input/11_Storing_Input.js @@ -0,0 +1,38 @@ +/* + * @name Storing Input + * @description 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. + */ +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/dist/assets/examples/ko/22_Advanced_Data/00_Load_Saved_JSON.js b/dist/assets/examples/ko/22_Advanced_Data/00_Load_Saved_JSON.js new file mode 100644 index 0000000000..e6eeba00c9 --- /dev/null +++ b/dist/assets/examples/ko/22_Advanced_Data/00_Load_Saved_JSON.js @@ -0,0 +1,104 @@ +/* + * @name 저장된 JSON 불러오기 + * @description Bubble 클래스를 만들고, JSON 파일의 데이터를 사용해 버블 여러 개를 인스턴스화합니다. + * 그리고, 그 결과물을 화면에 띄웁니다. + * 웹 브라우저마다 파일 저장 위치가 다르기 때문에, + * 프로세싱(Processing)의 예제와는 달리 saveJSON을 사용하지 않습니다.

+ * 다니엘 쉬프만(Daniel Shiffman) 제작 프로세싱(Processing)의 LoadSaveJSON 예제 참고 + */ + +// Bubble 클래스 +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; + } + + // 마우스가 버블 위에 있는지 확인 + rollover(px, py) { + let d = dist(px, py, this.x, this.y); + this.over = d < this.radius; + } + + // 버블을 화면에 보이기 + 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 = {}; // loadJSON 호출의 결과물을 담는 전역 객체 +let bubbles = []; // 모든 버블 객체를 담는 전역 배열 + +// 비동기 데이터 로딩을 preload에 담아 setup이 실행되기 전 완료시킴 +function preload() { + data = loadJSON('assets/bubbles.json'); +} + +// 저장된 Bubble 데이터를 Bubble 객체로 전환 +function loadData() { + let bubbleData = data['bubbles']; + for (let i = 0; i < bubbleData.length; i++) { + // 배열 속 각 객체 받아오기 + let bubble = bubbleData[i]; + // position 객체 받아오기 + let position = bubble['position']; + // 위치로부터 x,y 받아오기 + let x = position['x']; + let y = position['y']; + + // Get diameter and label + let diameter = bubble['diameter']; + let label = bubble['label']; + + // 배열에 객체 담기 + bubbles.push(new Bubble(x, y, diameter, label)); + } +} + +// 마우스가 클릭될 때마다 새로운 Bubble 만들기 +function mousePressed() { + // Bubble에 지름과 레이블 더하기 + let diameter = random(40, 80); + let label = 'New Label'; + + // 배열에 새로운 JSON bubble 객체 더하기 + bubbles.push(new Bubble(mouseX, mouseY, diameter, label)); + + // 버블이 너무 많을 경우 개수 제거하기 + if (bubbles.length > 10) { + bubbles.shift(); // 배열의 첫 번째 항목 제거하기 + } +} + +function setup() { + createCanvas(640, 360); + loadData(); +} + +function draw() { + background(255); + + // 모든 버블들 화면에 보이기 + for (let i = 0; i < bubbles.length; i++) { + bubbles[i].display(); + bubbles[i].rollover(mouseX, mouseY); + } + + // 하단에서의 레이블 방향들 + textAlign(LEFT); + fill(0); + text('Click to add bubbles.', 10, height - 10); +} diff --git a/dist/assets/examples/ko/22_Advanced_Data/01_Load_Saved_Table.js b/dist/assets/examples/ko/22_Advanced_Data/01_Load_Saved_Table.js new file mode 100644 index 0000000000..8536abcccc --- /dev/null +++ b/dist/assets/examples/ko/22_Advanced_Data/01_Load_Saved_Table.js @@ -0,0 +1,110 @@ +/* + * @name Load Saved Table + * @description Create a Bubble class, instantiate multiple bubbles using data from + * a csv file, and display results on the screen. + * Because the web browsers differ in where they save files, we do not make use of + * + * Based on Daniel Shiffman's LoadSaveTable Example for Processing. + */ + +// 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); +} diff --git a/dist/assets/examples/ko/33_Sound/00_Load_and_Play_Sound.js b/dist/assets/examples/ko/33_Sound/00_Load_and_Play_Sound.js new file mode 100644 index 0000000000..c497516da3 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/00_Load_and_Play_Sound.js @@ -0,0 +1,25 @@ +/* + * @name 사운드 불러오기/재생 + * @description preload()중 사운드 불러오기. 캔버스가 클릭될 때마다 소리를 재생합니다. + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.



+ */ +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()은 불리언 값을 반환합니다. + song.stop(); + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/ko/33_Sound/01_Preload_Sound.js b/dist/assets/examples/ko/33_Sound/01_Preload_Sound.js new file mode 100644 index 0000000000..38120ffaaa --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/01_Preload_Sound.js @@ -0,0 +1,35 @@ +/* + * @name 사운드 파일 미리 불러오기 + * @description preload()에서 loadSound()를 호출하여, + * setup()이 호출되기 전에 미리 사운드 파일을 불러오도록 합니다. + * 이 때, preload()에서 loadSound()를 호출하는 것이 가장 좋은 방법입니다. + * 그렇지 않을 경우, 스케치에서 사운드 재생을 원하는 시점에 파일이 불러지지 않을 수 있습니다. + * + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ + +let song; + +function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + song.loop(); // 이제 노래 파일이 setup()에서 재생될 준비가 되었습니다. + //preload에서 이미 한 차례 불러왔기 때문입니다. + background(0, 255, 0); +} + +function mousePressed() { + if (song.isPlaying()) { + // .isPlaying()은 불리언 값을 반환합니다. + song.pause(); // .play()는 .pause() 지점에서 다시 시작합니다. + background(255, 0, 0); + } else { + song.play(); + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/ko/33_Sound/02_soundFormats.js b/dist/assets/examples/ko/33_Sound/02_soundFormats.js new file mode 100644 index 0000000000..0cf8a92cdc --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/02_soundFormats.js @@ -0,0 +1,50 @@ +/** + * @name 사운드 파일 형식 + * @description

특허 문제로 인해, 모든 웹 브라우저가 지원하는 + * 단일의 사운드 파일 형식은 존재하지 않습니다. + * 예를 들어, + * mp3의 경우, OSX나 윈도우즈의 + * 주요 브라우저 최신 버전에서 지원하긴 하지만, 일부 운영 체제나 브라우저에서는 + * 사용하지 못할 수 있습니다.

+ * + *

사운드 파일의 완전한 호환성을 보장하기 위해, 동일한 사운드 파일을 + * 여러가지 형식으로 스케치에 포함시킬 수 있습니다. 'sound.mp3'나 'sound.ogg'가 그 예입니다. + * (Ogg는 mp3의 대안형 오픈 소스입니다.) media.io + * 에서 오디오 파일을 웹-친화적인 형식으로 무료 변환할 수 있습니다.

. + * + *

soundFormats() 메소드는 현재 스케치에 포함된 사운드 파일의 형식들을 loadSound에게 지정합니다. + * 그러면, loadSound는 지정된 형식들 중 클라이언트의 웹 브라우저가 지원하는 + * 첫번째 형식을 불러오도록 시도할 것입니다.

+ * + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

*/ +let song; + +function preload() { + // .ogg와 .mp3 파일 모두를 스케치에 포함시키기 + soundFormats('ogg', 'mp3'); + + // 만약 mp3를 이 브라우저가 지원하지 않는다면, + // loadSound는 스케치에 포함된 형식인 ogg 파일을 불러옵니다. + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + + // preload()중에 사운드 파일을 미리 불러와, setup()에서 재생할 수 있도록 준비 + song.play(); + background(0, 255, 0); +} + +function mousePressed() { + if (song.isPlaying()) { + // .isPlaying()은 불리언 값을 반환합니다. + song.pause(); + background(255, 0, 0); + } else { + song.play(); // playback은 pause(일시정지) 지점에서 다시 재생합니다. + background(0, 255, 0); + } +} diff --git a/dist/assets/examples/ko/33_Sound/03_Play_Mode.js b/dist/assets/examples/ko/33_Sound/03_Play_Mode.js new file mode 100644 index 0000000000..accdf51bc2 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/03_Play_Mode.js @@ -0,0 +1,42 @@ +/* + * @name 재생 모드 + * @description + *

'sustain' 모드에서는 사운드가 겹쳐서 재생됩니다. + * 'restart' 모드에서는 사운드가 멈췄다가 다시 재생합니다. + * 마우스 클릭으로 사운드 파일을 재생해보세요. + * 동시에 여러 사운드를 재생해보세요! 아무 자판을 눌러 재생 모드를 변경합니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +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/dist/assets/examples/ko/33_Sound/04_Pan_SoundFile.js b/dist/assets/examples/ko/33_Sound/04_Pan_SoundFile.js new file mode 100644 index 0000000000..0f07dd1a6a --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/04_Pan_SoundFile.js @@ -0,0 +1,34 @@ +/* + * @name 사운드 패닝 + * @description

마우스를 클릭해 사운드를 재생하세요. + * 공의 위치는 마우스의 위치와 더불어, 사운드의 패닝과도 관련됩니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ * + */ +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() { + // 공의 x 위치를 패닝 각도에 맵핑하기 + // -1.0 (좌) 과 1.0 (우) 사이 + let panning = map(ball.x, 0, width, -1.0, 1.0); + soundFile.pan(panning); + soundFile.play(); +} diff --git a/dist/assets/examples/ko/33_Sound/05_Sound_Effect.js b/dist/assets/examples/ko/33_Sound/05_Sound_Effect.js new file mode 100644 index 0000000000..7f9b5e65a3 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/05_Sound_Effect.js @@ -0,0 +1,68 @@ +/* + * @name 사운드 효과 + * @description

마우스로 원 안쪽을 누르면 사운드 효과가 재생됩니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +// 다니엘 쉬프만(Daniel Shiffman)의 Learning Processing을 적용 +// http://www.learningprocessing.com +// 초인종 샘플 출처: freesound.org에서 Corsica_S 제작, +// Creative Commons BY 3.0 + +// "doorbell(초인종)"을 설명하는 클래스 (실제로 버튼처럼 작동) +class Doorbell { + constructor(x_, y_, r_) { + // 위치와 크기 + this.x = x_; + this.y = y_; + this.r = r_; + } + // doorbell 안에 마우스 점이 있나요? (마우스 롤오버 등에 사용) + contains(mx, my) { + return dist(mx, my, this.x, this.y) < this.r; + } + + // doorbell을 보여주세요. (색상 부분은 하드코딩이네요. 더 나은 방법이 있을거에요.) + display(mx, my) { + if (this.contains(mx, my)) { + fill(100); + } else { + fill(175); + } + stroke(0); + strokeWeight(4); + ellipse(this.x, this.y, this.r, this.r); + } +} + +// 사운드 파일 객체 +let dingdong; + +// 초인종 객체 (사운드를 트리거) +let doorbell; + +function setup() { + createCanvas(200, 200); + + // 사운드 파일 불러오기 + // 스케치에 MP3와 OGG 버전을 포함시킵니다. + soundFormats('mp3', 'ogg'); + dingdong = loadSound('assets/doorbell.mp3'); + + // 새로운 초인종 만들기 + doorbell = new Doorbell(width / 2, height / 2, 64); +} + +function draw() { + background(255); + // 초인종 보이기 + doorbell.display(mouseX, mouseY); +} + +function mousePressed() { + // 사용자가 초인종을 클릭하면, 사운드 재생하기! + if (doorbell.contains(mouseX, mouseY)) { + dingdong.play(); + } +} diff --git a/dist/assets/examples/ko/33_Sound/06_Manipulate_Sound.js b/dist/assets/examples/ko/33_Sound/06_Manipulate_Sound.js new file mode 100644 index 0000000000..5edc06eb21 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/06_Manipulate_Sound.js @@ -0,0 +1,48 @@ +/* + * @name 재생 속도 + * @description

사운드 파일을 불러와 재생 속도와 볼륨을 mouseY에 맵핑합니다. + * 여기서 재생 속도란, 웹 오디오가 사운드 파일 정보를 처리하는 속도를 말합니다. + * 재생 속도가 느리면 사운드의 지속 시간을 늘릴 뿐 아니라, + * 느린 주파수에서 재생되어 음고(pitch)를 감소시킵니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +// 사운드 파일 객체 +let song; + +function preload() { + // 사운드 파일 불러오기 + song = loadSound('assets/Damscray_DancingTiger.mp3'); +} + +function setup() { + createCanvas(710, 400); + + // 사운드 무한 반복하기 + // (뭐, 적어도 stop()이 호출되기 전까지요) + song.loop(); +} + +function draw() { + background(200); + + // 볼륨 범위를 0 과 1.0 사이로 설정 + let volume = map(mouseX, 0, width, 0, 1); + volume = constrain(volume, 0, 1); + song.amp(volume); + + // 재생 속도 범위를 0.1 과 4 사이로 설정 + // 재생 속도를 변경하면 음고 또한 달라집니다. + let speed = map(mouseY, 0.1, height, 0, 2); + speed = constrain(speed, 0.01, 4); + song.rate(speed); + + // 원을 그려 어떤 일이 일어나는지 확인하기 + stroke(0); + fill(51, 100); + ellipse(mouseX, 100, 48, 48); + stroke(0); + fill(51, 100); + ellipse(100, mouseY, 48, 48); +} diff --git a/dist/assets/examples/ko/33_Sound/07_Amplitude_Analysis.js b/dist/assets/examples/ko/33_Sound/07_Amplitude_Analysis.js new file mode 100644 index 0000000000..91c2e4e994 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/07_Amplitude_Analysis.js @@ -0,0 +1,47 @@ +/** + * @name 진폭 측정 + * @description

p5.Amplitude로 사운드의 진폭을 분석합니다.

+ * + *

진폭(amplitude)은 진동의 크기를 말합니다. + * 사운드는 진동이므로, 볼륨/음량과 밀접한 관계를 갖습니다.

+ * + *

getLevel() 메소드는 짧은 시간 동안 수집된 + * 진폭값(1024 샘플)을 배열에 담습니다. + * 그 다음, 이 값들의 제곱 평균 제곱근(RMS)을 반환합니다.

+ * + *

디지털 오디오의 본래 진폭값은 -1.0과 1.0 사이입니다. + * 하지만, RMS는 제곱이므로 항상 양수입니다. + * 또한, RMS는 초당 44,000배의 속도에서 샘플링된 순간 진폭 판독값을 사용하는 대신 + * 시간에 따른 평균값(이 경우, 1024 샘플)을 사용하여, 진폭을 듣는 방식을 더욱 잘 나타냅니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +let song, analyzer; + +function preload() { + song = loadSound('assets/lucky_dragons_-_power_melody.mp3'); +} + +function setup() { + createCanvas(710, 200); + song.loop(); + + // 새로운 진폭 분석기 생성 + analyzer = new p5.Amplitude(); + + // 볼륨 분석기에 입력값 패치하기 + analyzer.setInput(song); +} + +function draw() { + background(255); + + // 평균 진폭값(RMS) 받아오기 + let rms = analyzer.getLevel(); + fill(127); + stroke(0); + + // 볼륨과 비례한 크기의 타원 그리기 + ellipse(width / 2, height / 2, 10 + rms * 200, 10 + rms * 200); +} diff --git a/dist/assets/examples/ko/33_Sound/08_Noise_Envelope.js b/dist/assets/examples/ko/33_Sound/08_Noise_Envelope.js new file mode 100644 index 0000000000..2132861e7d --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/08_Noise_Envelope.js @@ -0,0 +1,50 @@ +/** + * @name 노이즈 드럼 엔벨로프 + * @description

 화이트 노이즈는 주파수 영역의 모든 부분에서 + * 동일한 에너지를 갖는, 임의의 오디오 신호입니다

+ *

엔벨로프(envelope)는 시간/값의 쌍으로 정의되는 + * 일련의 페이드를 말합니다.

+ *

이 예제에서는, p5.Env로 출력된 진폭을 제어하여 + * p5.Noise를 마치 드럼처럼 "재생"합니다. + * p5.Amplitude는 스케치에 포함된 모든 사운드들의 레벨을 가져오며, + * 작동 중인 엔벨로프를 이 값으로서 초록색 사각형으로 표현합니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 됩니다.

+ */ +let noise, env, analyzer; + +function setup() { + createCanvas(710, 200); + noise = new p5.Noise(); // 그 외 타입들은 '갈색'과 '분홍'을 포함 + noise.start(); + + // 노이즈 볼륨에 0 곱하기 + // (노이즈 재생 전까지 조용하기 위해서요!) + noise.amp(0); + + env = new p5.Env(); + // 어택 시간, 감쇠 시간, 지속 속도, 릴리즈 시간 설정 + env.setADSR(0.001, 0.1, 0.2, 0.1); + // 어택 레벨, 릴리즈 레벨 설정 + env.setRange(1, 0); + + // setInput()메소드로 입력값을 지정하지 않는 이상, + // p5.Amplitude는 스케치에 포함된 모든 사운드를 분석할 것입니다. + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // p5.Amplitude analyzer(분석 장치)로부터 볼륨 판독값 받아오기 + let level = analyzer.getLevel(); + + // 레벨값을 사용하여 초록색 사각형 그리기 + 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/dist/assets/examples/ko/33_Sound/09_Note_Envelope.js b/dist/assets/examples/ko/33_Sound/09_Note_Envelope.js new file mode 100644 index 0000000000..853814b982 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/09_Note_Envelope.js @@ -0,0 +1,59 @@ +/** + * @name 음계 엔벨로프 + * @description

엔벨로프(envelope)는 시간/값의 쌍으로 정의되는 + * 일련의 페이드를 말합니다. + * 이 예제에서 엔벨로프는 오실레이터의 출력 진폭을 제어하여 + * 음계를 "재생"하는 데 사용됩니다.

+ * p5.Oscillator은 내부 웹 오디오 GainNode(p5.Oscillator.output) + * 를 거쳐 그 출력 내용을 전송합니다. + * 이 노드는 기본값으로 상수 0.5를 갖는데, osc.amp()메소드로 재설정할 수 있습니다. + * 또는 이 예제에서처럼, 엔벨로프가 직접 노드를 제어하여 + * 마치 볼륨을 조정하듯 진폭을 조정할 수 있습니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 됩니다.

+ */ +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(); + + // 엔벨로프 인스턴스화 + envelope = new p5.Env(); + + // 어택 시간, 감쇠 시간, 지속 속도, 릴리즈 시간 설정 + envelope.setADSR(0.001, 0.5, 0.1, 0.5); + + // 어택 레벨, 릴리즈 레벨 설정 + 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; + } + + // 캔버스에 FFT.analyze() 주파수 분석 내용 기입 + 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/dist/assets/examples/ko/33_Sound/10_Oscillator_Waveform.js b/dist/assets/examples/ko/33_Sound/10_Oscillator_Waveform.js new file mode 100644 index 0000000000..434bd0a2b1 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/10_Oscillator_Waveform.js @@ -0,0 +1,39 @@ +/* + * @name 오실레이터 주파수 + * @description

FFT를 사용하여 오실레이터를 제어하고 그 파형을 봅니다. + * MouseX는 주파수에, mouseY는 진폭에 매핑됩니다.

+ *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 됩니다.

+ */ +let osc, fft; + +function setup() { + createCanvas(720, 256); + + osc = new p5.TriOsc(); // 주파수와 종류 설정 + osc.amp(0.5); + + fft = new p5.FFT(); + osc.start(); +} + +function draw() { + background(255); + + let waveform = fft.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(); + + // 오실레이터 주파수를 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/dist/assets/examples/ko/33_Sound/11_Live_Input.js b/dist/assets/examples/ko/33_Sound/11_Live_Input.js new file mode 100644 index 0000000000..dc3fefa8e4 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/11_Live_Input.js @@ -0,0 +1,33 @@ +/** + * @name 마이크 입력 + * @description

컴퓨터의 마이크를 통해 오디오 입력을 받습니다. + * 마이크에 소리를 내어 타원이 떠오르게 해보세요.

+ *

주의: p5.AudioIn에는 p5.Amplitude 객체가 포함되어, 별도의 + * p5.Amplitude를 생성하지 않고도 p5.AudioIn에서 getLevel을 호출할 수 있습니다.

+ * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

*/ +let mic; + +function setup() { + createCanvas(710, 200); + + // 오디오 입력 생성하기 + mic = new p5.AudioIn(); + + // 오디오 입력 시작하기 + // 그 기본값은 .connect()(즉, 컴퓨터 스피커에 연결)되지 "않은" 상태입니다. + mic.start(); +} + +function draw() { + background(200); + + // 전체 볼륨(0과 1.0 사이) 받아오기 + let vol = mic.getLevel(); + fill(127); + stroke(0); + + // 마이크 소리의 볼륨에 따라 떠있는 높이가 변하는 타원 그리기 + let h = map(vol, 0, 1, height, 0); + ellipse(width / 2, h - 25, 50, 50); +} diff --git a/dist/assets/examples/ko/33_Sound/12_FFT_Spectrum.js b/dist/assets/examples/ko/33_Sound/12_FFT_Spectrum.js new file mode 100644 index 0000000000..488985b5be --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/12_FFT_Spectrum.js @@ -0,0 +1,30 @@ +/** + * @name 주파수 스펙트럼 + * @description

실시간 오디오 입력을 통해 주파수 스펙트럼을 시각화합니다.

+ *

To run this example locally, you will need the + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +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/dist/assets/examples/ko/33_Sound/13_Mic_Threshold.js b/dist/assets/examples/ko/33_Sound/13_Mic_Threshold.js new file mode 100644 index 0000000000..46e98c93d5 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/13_Mic_Threshold.js @@ -0,0 +1,48 @@ +/** + * @name 마이크 임계값 + * @description

입력된 오디오의 볼륨이 임계값을 초과하면 + * 특정 이벤트(이 경우, 사각형 그리기)가 발생합니다.

+ * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +// 다니엘 쉬프만(Daniel Shiffman)저 Learning Processing을 적용 +// learningprocessing.com +let input; +let analyzer; + +function setup() { + createCanvas(710, 200); + background(255); + + // 오디오 입력 생성하기 + input = new p5.AudioIn(); + + input.start(); +} + +function draw() { + // 전체 볼륨(0과 1.0 사이) 받아오기 + let volume = input.getLevel(); + + // 만약 볼륨 > 0.1 이라면, 임의의 위치에 사각형 한 개가 그려집니다. + // 볼륨이 커질수록, 사각형도 커집니다. + let threshold = 0.1; + if (volume > threshold) { + stroke(0); + fill(0, 100); + rect(random(40, width), random(height), volume * 50, volume * 50); + } + + // 전체 볼륨 범위를 막대 그래프로 나타내고 임계값의 위치에는 선 하나 긋기 + let y = map(volume, 0, 1, height, 0); + let ythreshold = map(threshold, 0, 1, height, 0); + + noStroke(); + fill(175); + rect(0, 0, 20, height); + // 그 다음, 볼륨값을 보여주는 검정 사각형을 그래프 위에 그리기 + fill(0); + rect(0, y, 20, y); + stroke(0); + line(0, ythreshold, 19, ythreshold); +} diff --git a/dist/assets/examples/ko/33_Sound/14_Filter_LowPass.js b/dist/assets/examples/ko/33_Sound/14_Filter_LowPass.js new file mode 100644 index 0000000000..2b9f7f7c09 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/14_Filter_LowPass.js @@ -0,0 +1,59 @@ +/* + * @name 로우패스 필터 + * @description p5.SoundFile에 p5.LowPass 필터를 적용합니다. + * FFT를 사용해 사운드를 시각화해보세요. + * mouseX를 필터의 차단 주파수에, mouseY를 밴드패스 필터의 울림/폭에 맵핑합니다. + *

로컬 프로젝트에서 이 예제를 실행하려면 + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +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); + + // 사운드 파일 불러오기 + soundFile.loop(); + + filter = new p5.LowPass(); + + // 마스터 출력으로부터 사운드 파일 연결 해제 + // 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); + + // mouseX를 FFT 스펙트럼 가청 범위(10Hz-22050Hz)에 해당하는 밴드패스 주파수에 맵핑하기 + filterFreq = map(mouseX, 0, width, 10, 22050); + + // mouseY를 울림/폭에 맵핑하기 + filterRes = map(mouseY, 0, height, 15, 5); + + // 필터 매개 변수들 설정 + filter.set(filterFreq, filterRes); + + // FFT 스펙트럼 분석 중 x와 h가 아래와 같은 모든 값들 그리기: + // x = 최저(10Hz)~최고(22050Hz) 주파수, + // h = 해당 주파수에서의 에너지 / 진폭 + 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/dist/assets/examples/ko/33_Sound/15_Filter_BandPass.js b/dist/assets/examples/ko/33_Sound/15_Filter_BandPass.js new file mode 100644 index 0000000000..37ad52651f --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/15_Filter_BandPass.js @@ -0,0 +1,51 @@ +/* + * @name 밴드패스 필터 + * @description 화이트 노이즈에 p5.BandPass 필터를 적용합니다. + * FFT를 사용해 사운드를 시각화해보세요. + * mouseX를 필터의 밴드패스(대역) 주파수에, mouseY를 밴드패스 필터의 울림/폭에 맵핑합니다. + *

로컬 프로젝트에서 이 예제를 실행하려면 + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +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(); // 마스터 출력과 사운드 파일 연결 해제... + filter.process(noise); // ...그리고 필터에 연결하여 밴드패스만 들리게하기 + + noise.start(); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + + // mouseX를 FFT 가청 스펙트럼 범위(10Hz-22050Hz)에 해당하는 밴드패스 주파수에 맵핑하기 + filterFreq = map(mouseX, 0, width, 10, 22050); + // mouseY를 울림/폭에 맵핑하기 + filterWidth = map(mouseY, 0, height, 0, 90); + // 필터 매개 변수들 설정 + filter.set(filterFreq, filterWidth); + + // FFT 스펙트럼 분석 중 x와 h가 아래와 같은 모든 값들 그리기: + // x = 최저(10Hz)~최고(22050Hz) 주파수, + // h = 해당 주파수에서의 에너지 / 진폭 + + 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/dist/assets/examples/ko/33_Sound/16_Delay.js b/dist/assets/examples/ko/33_Sound/16_Delay.js new file mode 100644 index 0000000000..f18120992f --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/16_Delay.js @@ -0,0 +1,56 @@ +/** + * @name 딜레이 필터 + * @description + * 마우스를 클릭하여 p5.Delay로 처리된 사운드 파일을 들어보세요. + * MouseX는 p5.Delay필터의 주파수를 조정합니다. + * MouseY는 p5.Delay필터의 시간과 울림 정도를 조정합니다. + * Amplitude(진폭) 객체로 출력된 사운드의 볼륨을 시각화해보세요. + * + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ + +let soundFile, analyzer, delay; + +function preload() { + soundFormats('ogg', 'mp3'); + soundFile = loadSound('assets/beatbox.mp3'); +} + +function setup() { + createCanvas(710, 400); + + soundFile.disconnect(); // 여기선 딜레이만 들을 수 있습니다. + + delay = new p5.Delay(); + delay.process(soundFile, 0.12, 0.7, 2300); + delay.setType('pingPong'); // 스테레오 효과 + + analyzer = new p5.Amplitude(); +} + +function draw() { + background(0); + + // p5.Amplitude 분석 장치의 볼륨 판독 내용 받아오기 + let level = analyzer.getLevel(); + + // 레벨을 사용하여 초록색 사각형 그리기 + 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/dist/assets/examples/ko/33_Sound/17_Reverb.js b/dist/assets/examples/ko/33_Sound/17_Reverb.js new file mode 100644 index 0000000000..eefb7b69ad --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/17_Reverb.js @@ -0,0 +1,36 @@ +/* + * @name 리버브 + * @description 리버브(reverb)는 사운드에 깊이감과 공간감을 더합니다. + * 이 예제에서 노이즈는 reverb로 처리됩니다. + * + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +let sound, reverb; + +function preload() { + soundFormats('mp3', 'ogg'); + soundFile = loadSound('assets/Damscray_DancingTiger'); + + // 기본값으로 설정된 연결 상태를 해제하여 + // reverb.process를 통해서만 사운드를 들을 수 있도록 처리합니다. + soundFile.disconnect(); +} + +function setup() { + createCanvas(720, 100); + background(0); + + reverb = new p5.Reverb(); + + // 6초의 reverbTime(리버브 시간)과 0.2%의 decayRate(감쇠 속도)를 갖는 + // 리버브에 사운드 파일 연결하기 + reverb.process(soundFile, 6, 0.2); + + reverb.amp(4); // 턴잇업! +} + +function mousePressed() { + soundFile.play(); +} diff --git a/dist/assets/examples/ko/33_Sound/18_Convolution_Reverb.js b/dist/assets/examples/ko/33_Sound/18_Convolution_Reverb.js new file mode 100644 index 0000000000..91205a1cee --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/18_Convolution_Reverb.js @@ -0,0 +1,84 @@ +/* + * @name 컨볼루션 리버브 + * @description

The p5.Convolver + * p5.Convolver는 컨볼루션을 사용하여 실제 공간 사운드를 재현합니다. + * 컨볼루션은 임펄스 응답(즉, 반향하는 공간의 사운드)으로 해당 공간의 사운드를 재생성합니다. + * 컨볼루션으로 처리된 소리를 재생하려면 클릭하세요. + * 매번 클릭할 때마다, 서로 다른 임펄스 응답으로 재생성된 사운드를 들을 수 있습니다. + * 임펄스 응답만 재생하려면 아무 키나 누르세요. + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ * 컨볼루션 샘플들은 + * recordinghopkins가 제작한 크리에이티브 커먼즈(CC)입니다.

+ */ +let sound, env, cVerb, fft; +let currentIR = 0; +let rawImpulse; + +function preload() { + // 모든 임펄스/사운드들의 MP3 및 OGG 버전을 이 스케치에 포함시킵니다. + soundFormats('ogg', 'mp3'); + + // p5.Convolver 생성하기 + cVerb = createConvolver('assets/bx-spring'); + + // bx-spring에 더해, cVerb.impulses 배열에 임펄스 응답 추가하기 + cVerb.addImpulse('assets/small-plate'); + cVerb.addImpulse('assets/drum'); + cVerb.addImpulse('assets/beatbox'); + cVerb.addImpulse('assets/concrete-tunnel'); + + // p5.ConvultionReverb로 처리될 사운드 불러오기 + sound = loadSound('assets/Damscray_DancingTiger'); +} + +function setup() { + createCanvas(710, 400); + rawImpulse = loadSound('assets/' + cVerb.impulses[currentIR].name); + + // 마스터 출력으로부터 연결 해제하고... + sound.disconnect(); + // ... cVerb로 처리하여 + // 오직 리버브만 들을 수 있도록 합니다. + cVerb.process(sound); + + fft = new p5.FFT(); +} + +function draw() { + background(30); + fill(0, 255, 40); + + let spectrum = fft.analyze(); + + // frequencySpectrum 배열에 있는 모든 값들을 사각형으로 그리기 + 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() { + // cVerb.impulses 배열 반복하기 + currentIR++; + if (currentIR >= cVerb.impulses.length) { + currentIR = 0; + } + cVerb.toggleImpulse(currentIR); + + // 임펄스를 거쳐 사운드 재생하기 + sound.play(); + + // 현재 임펄스 응답 이름 보이기(파일 경로) + println('Convolution Impulse Response: ' + cVerb.impulses[currentIR].name); + + rawImpulse.setPath('assets/' + cVerb.impulses[currentIR].name); +} + +// 임펄스 재생하기(컨볼루션 없이) +function keyPressed() { + rawImpulse.play(); +} diff --git a/dist/assets/examples/ko/33_Sound/19_Record_Save.js b/dist/assets/examples/ko/33_Sound/19_Record_Save.js new file mode 100644 index 0000000000..e694f0c482 --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/19_Record_Save.js @@ -0,0 +1,57 @@ +/** + * @name 오디오 녹음/저장 + * @description + * 사운드를 녹음하고 재생한 뒤, 클라이언트 컴퓨터에 .wav 파일로 저장하세요. + * 이 예제에서는 총 세 개의 객체가 필요합니다: p5.AudioIn(마이크/사운드 소스), + * p5.SoundRecorder(사운드 녹음), 그리고 p5.SoundFile(재생/저장) + *

로컬 프로젝트에서 이 예제를 실행하려면 적어도 한 개의 사운드 파일이 필요하고, + * p5.sound 라이브러리를 추가해야 되며, + * 로컬 서버를 작동시켜야 합니다.

+ */ +let mic, recorder, soundFile; + +let state = 0; // 마우스 버튼이 눌리면 녹음, 정지, 재생 순으로 상태가 변합니다. + +function setup() { + createCanvas(400, 400); + background(200); + fill(0); + text('Enable mic and click the mouse to begin recording', 20, 20); + + // AudioIn 생성하기 + mic = new p5.AudioIn(); + + // 녹음 기능을 제대로 작동시키려면, 사용자가 브라우저 마이크를 수동으로 활성화해야 됩니다! + mic.start(); + + // 사운드 녹음기 생성하기 + recorder = new p5.SoundRecorder(); + + // 마이크를 녹음기에 연결 + recorder.setInput(mic); + + // 녹음된 사운드를 재생할 빈 사운드 파일 생성 + soundFile = new p5.SoundFile(); +} + +function mousePressed() { + // '.enabled' 불리언을 사용하여 사용자의 마이크 활성화 여부 확인(그렇지 않을 경우, 침묵 상태를 녹음하게 됩니다!) + if (state === 0 && mic.enabled) { + // p5.SoundFile에 녹음하라고 녹음기에 지시하기. 이 파일은 녹음 사운드를 재생하는 데에 쓰입니다. + recorder.record(soundFile); + + background(255, 0, 0); + text('Recording now! Click to stop.', 20, 20); + state++; + } else if (state === 1) { + recorder.stop(); // 녹음기를 멈추고, 결과물을 soundFile에 보내기 + + background(0, 255, 0); + text('Recording stopped. Click to play & save', 20, 20); + state++; + } else if (state === 2) { + soundFile.play(); // 결과물 재생하기! + saveSound(soundFile, 'mySound.wav'); // 파일 저장하기 + state++; + } +} diff --git a/dist/assets/examples/ko/33_Sound/21_FreqModulation.js b/dist/assets/examples/ko/33_Sound/21_FreqModulation.js new file mode 100644 index 0000000000..27140d9a8f --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/21_FreqModulation.js @@ -0,0 +1,142 @@ +/** + * @name 주파수 변조(FM) + * @description

주파수 변조(Frequancy Modulator, FM)는 강력한 합성 방식입니다. + * 아주 간단히 말하자면, FM은 반송파와 변조기라는 두 개의 오실레이터를 포함합니다. + * 변조기의 파형이 최소 및 최대 진폭 값 사이에서 진동하면, 그 순간의 값이 반송파 주파수에 추가(즉, "변조")됩니다

+ *

반송파는, 우리가 일반적으로 음고(pitch)라 부르는, 가청 주파수에서 진동합니다. + * 이 예제의 경우, "A3"음과 동일한 220Hz의 사인파 오실레이터입니다. + * 모든 p5.Oscillator들은 그 기본값으로 반송파가 마스터 출력에 연결되어 있습니다. + *

이 예제에서 우리는 변조기를 마스터 출력과 연결 해제하고, + * 대신 다음을 사용하여 반송파 주파수에 연결합니다: carrier.freq(modulator). + * 이는 변조기의 출력 진폭을 반송파 주파수에 추가합니다.

+ *

+ * 변조 깊이는 반송파 주파수가 변조된 정도를 묘사합니다. + * 이는 변조기의 진폭을 기반으로 합니다. + * 변조기는 반송파 주파수에 추가될, 진폭 값들의 연속적인 스트림을 생성합니다. + * 진폭이 0이면 묵음이 발생하므로 변조가 적용되지 않습니다. + * 진폭이 1.0이면 출력값의 범위가 +1.0과 -1.0 사이로 조정됩니다. + * 이는 스피커로 전송되는 사운드의 표준 범위이기도 합니다. + * 하지만, FM에서는 변조기의 출력을 반송파 주파수로 전송하는데, + * 반송파 주파수에서는 + 1Hz / -1Hz 변조를 거의 찾아보기 힘듭니다. + * 따라서, 변조기의 진폭("깊이")을 스피커로 보내는 값보다 훨씬 높은 숫자로 증가시키는 게 일반적입니다.

+ *

변조 주파수는 변조 속도를 나타냅니다. + * 변조 주파수가 20Hz보다 낮으면, 우리는 주파수를 음고가 아닌 비트와 리듬으로서 듣게 됩니다. + * 예를 들어, 오페라 보컬의 "비브라토" 효과를 따라하고자, 깊이 20에서 7.5Hz를 시도해보세요. + * 이를 위한 용어는 저주파수 오실레이터(Low Frequency Oscillator, LFO)입니다. + * 더 높은 주파수로 설정된 변조기는 여러가지 흥미로운 효과들을 만들 수 있습니다. + * 특히, 주파수가 반송파 신호와 화음을 이룰 경우 그렇습니다. + * 그 예로, 변조기의 주파수가 반송파 주파수의 절반 또는 두 배일 때 발생하는 사운드를 들어세요. + * 이는 존 차우닝(John Chowning)이 1960년대에 개발한 "FM 합성" 개념의 근간이기도 합니다. + * FM 합성은 1980년대에 이르러 사운드 합성을 변혁시킨 바 있으며, 놋쇠나 종소리를 합성하는 데에 자주 사용됩니다. * + * + *

이 예제에서는,

+ * - MouseX가 변조 깊이(즉, 변조기의 진폭)를 -150부터 150까지 조정합니다. + * 변조기 진폭이 0(즉, 가운데)으로 설정되면, 아무런 변조 효과가 발생하지 않습니다. + * 숫자의 절대값이 커질수록, 효과가 커집니다. + * 변조기 파형이 마치 사각형 [], 싸인 ~ + * 또는 삼각형 /\과 같이 대칭일 경우, 음수의 진폭과 양수의 진폭은 동일합니다. + * 하지만 이 예제 속 변조기는 마치 이러한 모양 / 의 톱니처럼 생긴 비대칭적인 파형을 갖습니다. + * 여기에 음수를 곱하면, 파형이 마치 이러한 모양 \ 처럼 반대로 바뀝니다. + * 그 차이를 명확히 관찰하려면, 주파수를 낮춰보세요. + *

+ *

- MouseY는 변조기의 주파수를 0부터 112Hz까지 조정합니다. + * 가청 범위(약 20hz에서 시작) 이하 및 이상 영역에서의 변조기 주파수를 비교해보세요. + * 특히, 반송파 주파수(220hz이므로 1/2, 1/3, 1/4 등으로 나눠보세요)와 화음을 이루는 상태에서요! * + * + *

로컬 프로젝트에서 이 예제를 실행하려면, + * p5.sound 라이브러리 + * 를 추가해야 됩니다.

+ */ + +let carrier; // 이것이 바로 우리가 듣게될 오실레이터입니다. +let modulator; // 이 오실레이터가 반송파 주파수를 변조할 것입니다. + +let analyzer; // 이것을 사용해 파형을 시각화합니다. + +// 반송파 주파수 사전 변조 +let carrierBaseFreq = 220; + +// 변조기의 최저/최고 범위 +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); // 진폭 설정 + carrier.freq(carrierBaseFreq); // 주파수 설정 + carrier.start(); // 오실레이팅 시작 + + // 종류를 'square(사각형)', 'sine(싸인)' 또는 'triangle(삼각형)'으로 바꿔보세요! + modulator = new p5.Oscillator('sawtooth'); + modulator.start(); + + // 반송파 주파수를 변조하기 위해 변조기의 출력값 더하기 + modulator.disconnect(); + carrier.freq(modulator); + + // 오디오 분석을 위해 FFT 생성하기 + analyzer = new p5.FFT(); + + // 마우스 오버 / 스타트 터치 시, 반송파 페이드 인/아웃 + toggleAudio(cnv); +} + +function draw() { + background(30); + + // 최대 및 최소 주파수 사이의 변조기 주파수에 mouseY를 매핑하기 + let modFreq = map(mouseY, height, 0, modMinFreq, modMaxFreq); + modulator.freq(modFreq); + + // 변조기의 진폭 바꾸기 + // 음수의 amp는 톱니 파형을 반대로 뒤집고, 두드리는 듯한 사운드를 만듭니다. + // + let modDepth = map(mouseX, 0, width, modMinDepth, modMaxDepth); + modulator.amp(modDepth); + + // 파형 분석하기 + waveform = analyzer.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); + // 어떤 일이 일어나는 지에 대한 설명을 추가합니다. + 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 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); + }); +} diff --git a/dist/assets/examples/ko/33_Sound/22_AmplitudeModulation.js b/dist/assets/examples/ko/33_Sound/22_AmplitudeModulation.js new file mode 100644 index 0000000000..a45481d22d --- /dev/null +++ b/dist/assets/examples/ko/33_Sound/22_AmplitudeModulation.js @@ -0,0 +1,91 @@ +/** + * @name 진폭 변조(AM) + * @description

진폭 변조(Amplitude Modulation, AM)은 + * 반송파와 변조기라는 두 개의 오실레이터를 포함하고, 이는 반송파의 진폭을 조정합니다.

+ * + *

반송파는 일반적으로 가청 주파수(예. 440Hz)에 설정됩니다. + * 그리고, 그 기본값으로 마스터 출력에 연결되어 있습니다.a + * carrier.amp는 0으로 설정되어 있는데, 이는 변조기로 진폭을 조정하기 위해서입니다.

+ * + *

이 예제에서 변조기는 마스터 출력과 연결이 해제되어 있습니다. + * 대신, 다음을 통해 반송파의 진폭에 연결되어 있습니다: carrier.amp(변조기).

+ * + *

이 예제에서는,

+ *

- MouseX가 변조기의 진폭을 0부터 1까지 조정합니다. + * 변조기 진폭이 0으로 설정되면, 아무런 변조 효과가 발생하지 않습니다.

+ * + *

- MouseY는 변조기의 주파수를 0부터 20hz까지 조정합니다. + * 이 범위는 인간이 들을 수 있는 주파수보다 낮으므로, 우리는 변조 사운드를 리듬으로서 듣게됩니다. + * 이 범위를 사용해 마치 풍금 소리와같은 효과를 만들 수 있습니다. + * 링 변조는 진폭 변조의 한 종류로, 원본 반송파 신호가 존재하지 않고, 더 빠른 주파수를 변조합니다.

+ * + *

로컬 프로젝트에서 이 예제를 실행하려면, + * p5.sound 라이브러리 + * 를 추가해야 됩니다.

+ */ +let carrier; // 이것이 바로 우리가 듣게될 오실레이터입니다. +let modulator; // 이 오실레이터가 반송파 주파수를 변조할 것입니다. +let fft; // 이것을 사용해 파형을 시각화합니다. + +function setup() { + createCanvas(800, 400); + noFill(); + background(30); // 알파값 + + carrier = new p5.Oscillator(); // 기본값으로, 마스터 출력에 연결된 상태입니다. + carrier.freq(340); + carrier.amp(0); + // 반송파의 amp는 기본값으로 0을 가져, 변조기에게 완전한 제어 권한을 부여합니다. + + carrier.start(); + + modulator = new p5.Oscillator('triangle'); + modulator.disconnect(); // 변조기를 마스터 출력과 연결 해제합니다. + modulator.freq(5); + modulator.amp(1); + modulator.start(); + + // 변조기를 사용해 반송파의 진폭을 변조하기 + // 추가적으로, 신호도 조정할 수 있습니다. + carrier.amp(modulator.scale(-1, 1, 1, -1)); + + // 오디오 분석을 위해 FFT 생성하기 + fft = new p5.FFT(); +} + +function draw() { + background(30, 30, 30, 100); // 알파값 + + // 0과 20hz 사이의 변조기 주파수에 mouseY를 매핑하기 + let modFreq = map(mouseY, 0, height, 20, 0); + modulator.freq(modFreq); + + let modAmp = map(mouseX, 0, width, 0, 1); + modulator.amp(modAmp, 0.01); // 페이드 타임을 0.1로 조정하여 페이딩을 부드럽게 만들기 + + // 파형 분석하기 + waveform = fft.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); +} diff --git a/dist/assets/examples/ko/35_Mobile/00_Acceleration_Ball_Bounce.js b/dist/assets/examples/ko/35_Mobile/00_Acceleration_Ball_Bounce.js new file mode 100644 index 0000000000..83902a3de1 --- /dev/null +++ b/dist/assets/examples/ko/35_Mobile/00_Acceleration_Ball_Bounce.js @@ -0,0 +1,58 @@ +/* + * @name 가속도와 바운스 + * @description accelerationX와 accelerationY 값을 활용해 타원을 움직이고, 캔버스의 경계에 닿았을 때 튕기도록 만듭니다. + */ + +// 위치 변수들 +let x = 0; +let y = 0; + +// 속도 변수들 +let vx = 0; +let vy = 0; + +// 가속 변수들 +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; + + // 캔버스의 경계에 닿았을 때 튕기기 + 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/dist/assets/examples/ko/35_Mobile/01_Simple_Draw.js b/dist/assets/examples/ko/35_Mobile/01_Simple_Draw.js new file mode 100644 index 0000000000..de4f128884 --- /dev/null +++ b/dist/assets/examples/ko/35_Mobile/01_Simple_Draw.js @@ -0,0 +1,15 @@ +/* + * @name 간단한 드로잉 + * @description mouseX, mouseY, pmouseX, pmouseY 값을 사용하여 스크린을 터치했을 때 그려지도록 합니다. + */ + +function setup() { + createCanvas(displayWidth, displayHeight); + strokeWeight(10); + stroke(0); +} + +function touchMoved() { + line(mouseX, mouseY, pmouseX, pmouseY); + return false; +} diff --git a/dist/assets/examples/ko/35_Mobile/02_Acceleration_Color.js b/dist/assets/examples/ko/35_Mobile/02_Acceleration_Color.js new file mode 100644 index 0000000000..cecd1bed76 --- /dev/null +++ b/dist/assets/examples/ko/35_Mobile/02_Acceleration_Color.js @@ -0,0 +1,24 @@ +/* + * @name 가속도 색상 + * @description deviceMoved()를 사용해 모바일 기기의 회전을 감지합니다. 배경의 RGB 색상값은 각각 accelerationX, accelerationY, accelerationZ 값에 매핑됩니다. + */ + +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/dist/assets/examples/ko/35_Mobile/03_Shake_Ball_Bounce.js b/dist/assets/examples/ko/35_Mobile/03_Shake_Ball_Bounce.js new file mode 100644 index 0000000000..404fae8810 --- /dev/null +++ b/dist/assets/examples/ko/35_Mobile/03_Shake_Ball_Bounce.js @@ -0,0 +1,116 @@ +/* + * @name 흔들기와 바운스 + * @description Ball 클래스를 생성하고 복수의 객체를 인스턴스화한 뒤, 화면 위에서 움직여보세요. + * 공이 캔버스의 경계에 닿으면 튕깁니다. + * accelerationX와 accelerationY의 총 변화를 기반으로 흔들림을 감지하고, + * 그러한 감지를 기반으로 객체의 속도를 높이거나 줄입니다. + */ + +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() { + // accelerationX와 accelerationY의 총 변화 계산 + accChangeX = abs(accelerationX - pAccelerationX); + accChangeY = abs(accelerationY - pAccelerationY); + accChangeT = accChangeX + accChangeY; + // 만약 흔들린다면, + if (accChangeT >= threshold) { + for (let i = 0; i < balls.length; i++) { + balls[i].shake(); + balls[i].turn(); + } + } + // 만약 흔들리지 않는다면, + else { + for (let i = 0; i < balls.length; i++) { + balls[i].stopShake(); + balls[i].turn(); + balls[i].move(); + } + } +} + +// Ball 클래스 +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; + } + + // 캔버스 경계에 닿았을 때 공 튀기기 + 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; + } + } + + // accerlerationX 값의 변화를 기반으로 + // xspeed와 yspeed에 더하기 + shake() { + this.xspeed += random(5, accChangeX / 3); + this.yspeed += random(5, accChangeX / 3); + } + + // 점점 느려지기 + 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/dist/assets/examples/ko/35_Mobile/04_Tilted_3D_Box.js b/dist/assets/examples/ko/35_Mobile/04_Tilted_3D_Box.js new file mode 100644 index 0000000000..7479b4c77c --- /dev/null +++ b/dist/assets/examples/ko/35_Mobile/04_Tilted_3D_Box.js @@ -0,0 +1,15 @@ +/* + * @name 기울어진 3D상자 + * @description 모바일 기기를 이용해 상자를 기울게 만듭니다. + */ +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/dist/assets/examples/ko/90_Hello_P5/01_shapes.js b/dist/assets/examples/ko/90_Hello_P5/01_shapes.js new file mode 100644 index 0000000000..308d10ed3e --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/01_shapes.js @@ -0,0 +1,28 @@ +/* + * @name 간단한 도형들 + * @description 이 예제는 원, 사각형, 삼각형, 그리고 꽃 모양을 포함합니다. + */ +function setup() { + // 캔버스 만들기 + createCanvas(720, 400); + background(200); + + // 색상 설정하기 + fill(204, 101, 192, 127); + stroke(127, 63, 120); + + // 사각형 한 개 + rect(40, 120, 120, 40); + // 타원 한 개 + ellipse(240, 240, 80, 80); + // 삼각형 한 개 + triangle(300, 100, 320, 100, 310, 80); + + // 간단한 꽃 그리기 + translate(580, 200); + noStroke(); + for (let i = 0; i < 10; i ++) { + ellipse(0, 30, 20, 80); + rotate(PI/5); + } +} diff --git a/dist/assets/examples/ko/90_Hello_P5/02_interactivity.js b/dist/assets/examples/ko/90_Hello_P5/02_interactivity.js new file mode 100644 index 0000000000..95c1733fec --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/02_interactivity.js @@ -0,0 +1,40 @@ +/* + * @name 인터랙티비티 1 + * @frame 720,425 + * @description 원을 클릭하면 색상이 바뀝니다. + *

로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리. + * 를 추가해야 됩니다.

+ */ + +// 빨강(r), 초록(g), 파랑(b) 색상값들 +let r, g, b; + +function setup() { + createCanvas(720, 400); + // 임의의 색상 고르기 + r = random(255); + g = random(255); + b = random(255); +} + +function draw() { + background(127); + // 원 그리기 + strokeWeight(2); + stroke(r, g, b); + fill(r, g, b, 127); + ellipse(360, 200, 200, 200); +} + +// 사용자가 마우스를 클릭했을 때, +function mousePressed() { + // 마우스가 원의 안쪽에 있는지 확인하기 + let d = dist(mouseX, mouseY, 360, 200); + if (d < 100) { + // 새로운 임의의 색상 고르기 + r = random(255); + g = random(255); + b = random(255); + } +} diff --git a/dist/assets/examples/ko/90_Hello_P5/03_interactivity.js b/dist/assets/examples/ko/90_Hello_P5/03_interactivity.js new file mode 100644 index 0000000000..6a64eec90a --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/03_interactivity.js @@ -0,0 +1,29 @@ +/* + * @name 인터랙티비티 2 + * @frame 720,425 + * @description 슬라이더를 움직이면 원의 색상이 바뀝니다. + * 로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리 + * 를 추가해야 됩니다. + */ + +// HTML 범위 슬라이더 +let slider; + +function setup() { + createCanvas(720, 400); + // 색조(H), 채도(S), 밝기(B) + colorMode(HSB, 255); + // 슬라이더의 범위를 0부터 255까지로, 그 시작값을 127로 설정하기 + slider = createSlider(0, 255, 127); +} + +function draw() { + background(127); + strokeWeight(2); + + // 슬라이더에 따라 채도 설정하기 + 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/dist/assets/examples/ko/90_Hello_P5/04_animate.js b/dist/assets/examples/ko/90_Hello_P5/04_animate.js new file mode 100644 index 0000000000..f746dd15ea --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/04_animate.js @@ -0,0 +1,33 @@ +/* + * @name 애니메이션 + * @description 원이 움직입니다. + */ +// 원의 위치를 알기 위해 +let x, y; + +function setup() { + createCanvas(720, 400); + // 화면 가운데에서 시작하기 + x = width / 2; + y = height; +} + +function draw() { + background(200); + + // 원 그리기 + stroke(50); + fill(100); + ellipse(x, y, 24, 24); + + // 가로축에서 무작위로 흔들리기 + x = x + random(-1, 1); + // 일정 속도로 위를 향해 움직이기 + y = y - 1; + + // 화면 하단으로 리셋 + if (y < 0) { + y = height; + } +} + diff --git a/dist/assets/examples/ko/90_Hello_P5/04_flocking.js b/dist/assets/examples/ko/90_Hello_P5/04_flocking.js new file mode 100644 index 0000000000..a5b5c9600b --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/04_flocking.js @@ -0,0 +1,186 @@ +/* + * @name 플로킹 + * @description 크레이그 레이놀즈(Craig Reynolds)의 + * "군집(Flocking)" 행위를 묘사합니다.
+ * (규칙: 응집, 분리, 정렬)
+ * (출처: natureofcode.com). + */ +let boids = []; + +function setup() { + createCanvas(720, 400); + + // 시스템에 초기 개체(boid) 더하기 + for (let i = 0; i < 100; i++) { + boids[i] = new Boid(random(width), random(height)); + } +} + +function draw() { + background(51); + // 모든 개체 실행하기 + for (let i = 0; i < boids.length; i++) { + boids[i].run(boids); + } +} + +// Boid 클래스 +// Separation(분리), Cohesion(응집), Alignment(정렬)을 위한 메소드 추가하기 +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; // 최고 속도 + this.maxforce = 0.05; // 최고 조타력 + } + + run(boids) { + this.flock(boids); + this.update(); + this.borders(); + this.render(); + } + + // Force는 acceleration에 담깁니다. + applyForce(force) { + this.acceleration.add(force); + } + + // 세 가지 규칙을 기반으로 새로운 accerlation(가속도)를 축적합니다. + flock(boids) { + let sep = this.separate(boids); // 분리 + let ali = this.align(boids); // 정렬 + let coh = this.cohesion(boids); // 응집 + // 세 힘들을 임의로 가중하기 + sep.mult(2.5); + ali.mult(1.0); + coh.mult(1.0); + // 가속도에 force 벡터 더하기 + this.applyForce(sep); + this.applyForce(ali); + this.applyForce(coh); + } + + // 위치 업데이트를 위한 메소드 + update() { + // 속도 업데이트 + this.velocity.add(this.acceleration); + // 속도 제한 + this.velocity.limit(this.maxspeed); + this.position.add(this.velocity); + // 매 사이클마다 acceleration을 0으로 리셋하기 + this.acceleration.mult(0); + } + + // 목표점을 향한 조타력을 계산하고 적용하는 메소드 + // STEER(조타력) = DESIRED(목표점) - VELOCITY(속도) + seek(target) { + let desired = p5.Vector.sub(target, this.position); // A vector pointing from the location to the target + // desired를 표준화하고 최대 속도로 조정 + desired.normalize(); + desired.mult(this.maxspeed); + // Steering = Desired minus Velocity + let steer = p5.Vector.sub(desired, this.velocity); + steer.limit(this.maxforce); // 최대 조타력으로 제한 + return steer; + } + + // 개체(boid)를 원형으로 그리기 + 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; + } + + // 분리 Seperation + // 인근의 개체를 확인하고 이로부터 거리를 유지하며 조타하게 만드는 메소드 + separate(boids) { + let desiredseparation = 25.0; + let steer = createVector(0, 0); + let count = 0; + // 매 개체가 시스템에 생성될 때마다, 서로 너무 가까운 위치에 있는지 여부를 확인 + for (let i = 0; i < boids.length; i++) { + let d = p5.Vector.dist(this.position, boids[i].position); + // 만약 그 거리가 0보다 크고 임의의 값보다 작다면(0은 개체의 현위치) + if ((d > 0) && (d < desiredseparation)) { + // 인근의 개체로부터 떨어진 지점을 향하는 벡터 계산 + let diff = p5.Vector.sub(this.position, boids[i].position); + diff.normalize(); + diff.div(d); // 거리에 따른 가중 + steer.add(diff); + count++; // 개체수 카운트 + } + } + // 평균 -- 얼마로 나눌 것인가 + if (count > 0) { + steer.div(count); + } + + // 벡터가 0보다 크다면, + if (steer.mag() > 0) { + // 레이놀즈의 공식 Steering = Desired - Velocity을 적용한다. + steer.normalize(); + steer.mult(this.maxspeed); + steer.sub(this.velocity); + steer.limit(this.maxforce); + } + return steer; + } + + // 배열 Alignment + // 서로 인근에 있는 모든 개체에 대한 평균 속도 계산 + 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 + // 서로 인근에 있는 모든 개체의 평균 위치값(예: 중앙)에 대해, 이 지점을 향한 조타 벡터값 계산 + cohesion(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].position); // 위치 추가 + count++; + } + } + if (count > 0) { + sum.div(count); + return this.seek(sum); // 해당 위치를 향해 조타 + } else { + return createVector(0, 0); + } + } +} + diff --git a/dist/assets/examples/ko/90_Hello_P5/05_weather.js b/dist/assets/examples/ko/90_Hello_P5/05_weather.js new file mode 100644 index 0000000000..c37e41879a --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/05_weather.js @@ -0,0 +1,73 @@ +/* + * @name 날씨 + * @frame 720,280 + * @description 이 예제는 www.metaweather.com로부터 JSON 날씨 데이터를 받아옵니다. + * 로컬 프로젝트에서 이 예제를 실행하려면, + * p5.dom 라이브러리 + * 를 추가해야 됩니다. +*/ + +// 풍향 벡터 +let wind; +// 원의 위치 +let position; + +function setup() { + createCanvas(720, 200); + // www.metaweather.com에 데이터 요청하기 + let url = 'https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/2459115/'; + loadJSON(url, gotWeather); + // 화면의 가운데에서 원그리기 시작 + position = createVector(width/2, height/2); + // 바람은 (0,0)에서 시작 + wind = createVector(); +} + +function draw() { + background(200); + + // 이 섹션에서는 풍향을 나타내는 화살표를 그립니다. + push(); + translate(32, height - 32); + // 바람의 각도에 따라 회전하기 + 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(); + + // 풍향에 따라 움직이기 + 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] + // 각도 받아오기 (래디언으로 변환) + let angle = radians(Number(weather_today.wind_direction)); + // 풍속 받아오기 + let windmag = Number(weather_today.wind_speed); + + // HTML요소로 화면에 보이기 + let temperatureDiv = createDiv(floor(weather_today.the_temp) + '°C'); + let windDiv = createDiv("WIND " + windmag + " MPH"); + + // 벡터 생성하기 + wind = p5.Vector.fromAngle(angle); +} diff --git a/dist/assets/examples/ko/90_Hello_P5/06_drawing.js b/dist/assets/examples/ko/90_Hello_P5/06_drawing.js new file mode 100644 index 0000000000..db309cbd67 --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/06_drawing.js @@ -0,0 +1,132 @@ +/* +* @name 드로잉 +* @description 제너레이티브 페인팅 프로그램입니다. +*/ + +// 모든 경로 +let paths = []; +// 지금 페인팅을 하고 있나요? +let painting = false; +// 다음 원까지 걸리는 시간 +let next = 0; +// 현재 및 이전 위치 +let current; +let previous; + +function setup() { + createCanvas(720, 400); + current = createVector(0,0); + previous = createVector(0,0); +}; + +function draw() { + background(200); + + // 새로운 점을 만들어 봅시다. + if (millis() > next && painting) { + + // 마우스 위치 받아오기 + current.x = mouseX; + current.y = mouseY; + + // 새로운 파티클의 힘은 마우스의 움직임에 기반을 둡니다. + let force = p5.Vector.sub(current, previous); + force.mult(0.05); + + // 새로운 파티클 더하기 + paths[paths.length - 1].add(current, force); + + // 다음 원의 시간 정하기 + next = millis() + random(100); + + // 더 많은 마우스값 저장하기 + previous.x = current.x; + previous.y = current.y; + } + + // 모든 경로 그리기 + for( let i = 0; i < paths.length; i++) { + paths[i].update(); + paths[i].display(); + } +} + +// 시작하기 +function mousePressed() { + next = 0; + painting = true; + previous.x = mouseX; + previous.y = mouseY; + paths.push(new Path()); +} + +// 정지 +function mouseReleased() { + painting = false; +} + +// Path(경로)는 파티클들의 목록입니다. +class Path { + constructor() { + this.particles = []; + this.hue = random(100); + } + + add(position, force) { + // 새로운 파티클을 그 위치, 힘, 색조값과 함께 추가하기 + this.particles.push(new Particle(position, force, this.hue)); + } + + // 파티클 길이 화면에 보이기 + update() { + for (let i = 0; i < this.particles.length; i++) { + this.particles[i].update(); + } + } + + // 파티클 길이 화면에 보이기 + display() { + // 뒤로 반복하기 + for (let i = this.particles.length - 1; i >= 0; i--) { + // 만약 제거해야 된다면, + if (this.particles[i].lifespan <= 0) { + this.particles.splice(i, 1); + // 그렇지 않다면, 화면에 보이기 + } else { + this.particles[i].display(this.particles[i+1]); + } + } + + } +} + +// 경로 위 파티클들 +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--; + } + + // 파티클을 그리고 선으로 잇기 + // 다른 파티클을 향해 선그리기 + display(other) { + stroke(0, this.lifespan); + fill(0, this.lifespan/2); + ellipse(this.position.x,this.position.y, 8, 8); + // 선을 그려야 한다면, + if (other) { + line(this.position.x, this.position.y, other.position.x, other.position.y); + } + } +} diff --git a/dist/assets/examples/ko/90_Hello_P5/07_song.js b/dist/assets/examples/ko/90_Hello_P5/07_song.js new file mode 100644 index 0000000000..2c3bbd65ab --- /dev/null +++ b/dist/assets/examples/ko/90_Hello_P5/07_song.js @@ -0,0 +1,118 @@ +/* + * @name 노래 + * @frame 720, 430 + * @description 노래를 재생하세요. + *

로컬 프로젝트에서 이 예제를 실행하려면, + * p5.Sound 라이브러리. + * 를 추가해야 됩니다.

+ */ +// MIDI 음계의 음표들 +let notes = [ 60, 62, 64, 65, 67, 69, 71]; + +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"); + // 자동 재생 트리거하기 + button.mousePressed(function() { + if (!autoplay) { + index = 0; + autoplay = true; + } + }); + + // 삼각형 오실레이터 + osc = new p5.TriOsc(); + // 무음 시작 + osc.start(); + osc.amp(0); +} + +// 음표를 재생하기 위한 함수 +function playNote(note, duration) { + osc.freq(midiToFreq(note)); + // 음표를 페이드인하기 + osc.fade(0.5,0.2); + + // 만약 재생 시간을 설정한다면, 페이드 아웃 + if (duration) { + setTimeout(function() { + osc.fade(0,0.2); + }, duration-50); + } +} + +function draw() { + + // 만약 현재 자동 재생 중이고 다음 음표를 재생할 때가 되었다면, + if (autoplay && millis() > trigger){ + playNote(notes[song[index].note], song[index].duration); + trigger = millis() + song[index].duration; + // 다음 음표로 이동하기 + index ++; + // 끝에 다다랐다면, 자동 재생 중지 + } else if (index >= song.length) { + autoplay = false; + } + + + // 키보드 그리기 + + // 각 건반의 너비 + let w = width / notes.length; + for (let i = 0; i < notes.length; i++) { + let x = i * w; + // 마우스가 건반 위에 있다면, + if (mouseX > x && mouseX < x + w && mouseY < height) { + // 마우스를 클릭 중이라면, + if (mouseIsPressed) { + fill(100,255,200); + // 또는 마우스가 건반 위를 롤오버 중이라면, + } else { + fill(127); + } + } else { + fill(200); + } + + // 또는, 노래가 재생 중이라면 하이라이트를 줍니다. + if (autoplay && i === song[index-1].note) { + fill(100,255,200); + } + + // 건반 그리기 + rect(x, 0, w-1, height-1); + } + +} + +// 클릭하면, +function mousePressed(event) { + if(event.button == 0 && event.clientX < width && event.clientY < height) { + // 건반 인덱스에 마우스를 매핑하기 + let key = floor(map(mouseX, 0, width, 0, notes.length)); + playNote(notes[key]); + } +} + +// 마우스 버튼을 놓으면 페이드 아웃하기 +function mouseReleased() { + osc.fade(0,0.5); +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/00_Statements_and_Comments.js b/dist/assets/examples/zh-Hans/00_Structure/00_Statements_and_Comments.js new file mode 100644 index 0000000000..8469f369b7 --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/00_Statements_and_Comments.js @@ -0,0 +1,19 @@ +/* + * @name Comments and Statements + * @description Statements are the elements that make up programs. The ";" (semi-colon) symbol is used to end statements. It is called the "statement * terminator". Comments are used for making notes to help people better understand programs. A comment begins with two forward slashes ("//"). (ported from https://processing.org/examples/statementscomments.html) + */ +// The createCanvas function is a statement that tells the computer +// how large to make the window. +// Each function statement has zero or more parameters. +// Parameters are data passed into the function +// and are used as values for telling the computer what to do. +function setup() { + createCanvas(710, 400); +} + +// The background function is a statement that tells the computer +// which color (or gray value) to make the background of the display window +function draw() { + background(204, 153, 0); +} + diff --git a/dist/assets/examples/zh-Hans/00_Structure/01_Coordinates.js b/dist/assets/examples/zh-Hans/00_Structure/01_Coordinates.js new file mode 100644 index 0000000000..5c58c6200a --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/01_Coordinates.js @@ -0,0 +1,29 @@ +/* + * @name 坐标 + * @description 绘制到屏幕上的所有形状都有一个指定为坐标的位置。所有的坐标都是以像素为单位,以距原点的距离来衡量的。原点 [0,0] 是窗口左上角的坐标,右下角的坐标是 [宽度-1, 高度-1] 。 + */ +function setup() { + // 制作一个 720 像素宽 400 像素高的画布。 + createCanvas(720, 400); +} + +function draw() { + // 将背景设置为黑色,关闭填色功能。 + background(0); + noFill(); + + // point() 函数的两个参数分别为指定的坐标。 + // 第一个参数是 x 坐标,第二个参数是 y 。 + stroke(255); + point(width * 0.5, height * 0.5); + point(width * 0.5, height * 0.25); + + // 坐标用于绘制所有形状,而不仅仅是点。 + // 不同功能的参数用于不同的目的。例如,line() 的前两个参数指定第一个端点的坐标,后两个参数指定第二个端点的坐标。 + stroke(0, 153, 255); + line(0, height * 0.33, width, height * 0.33); + + // 默认情况下,rect() 的前两个参数是左上角的坐标,后两个参数是宽度和高度。 + stroke(255, 153, 0); + rect(width * 0.25, height * 0.1, width * 0.5, height * 0.8); +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/02_Width_and_Height.js b/dist/assets/examples/zh-Hans/00_Structure/02_Width_and_Height.js new file mode 100644 index 0000000000..5f1a891658 --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/02_Width_and_Height.js @@ -0,0 +1,18 @@ +/* + * @name Width 和 Height + * @description 'width'(宽度)和 'height'(高度)变量包含 createCanvas() 函数中定义的显示窗口的宽度和高度。 + */ +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/dist/assets/examples/zh-Hans/00_Structure/03_Setup_and_Draw.js b/dist/assets/examples/zh-Hans/00_Structure/03_Setup_and_Draw.js new file mode 100644 index 0000000000..db3ea56aff --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/03_Setup_and_Draw.js @@ -0,0 +1,22 @@ +/* + * @name Setup 与 Draw + * @description draw() 函数中的代码从上到下连续运行,直到程序停止。 + */ +let y = 100; + +// 程序开始时,setup() 函数中的语句执行一次。 +function setup() { + // createCanvas 必须是第一条语句 + createCanvas(720, 400); + stroke(255); // 将线条绘制颜色设置为白色 + frameRate(30); +} +// draw() 中的语句一直执行到程序停止为止。每个语句都按顺序执行,并且在读取最后一行之后,将再次执行第一行。 +function draw() { + background(0); // 将背景设置为黑色 + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/04_No_Loop.js b/dist/assets/examples/zh-Hans/00_Structure/04_No_Loop.js new file mode 100644 index 0000000000..eccf5f6987 --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/04_No_Loop.js @@ -0,0 +1,26 @@ +/* + * @name No Loop + * @description noLoop() 函数使 draw() 只执行一次。 + *如果不调用 noLoop() ,draw() 内的代码会持续运行。 + */ +let y; + +// 程序开始时,setup() 函数中的语句执行一次。 +function setup() { + // createCanvas 必须是第一条语句 + createCanvas(720, 400); + stroke(255); // 线条绘制颜色设置为白色 + noLoop(); + + y = height * 0.5; +} + +// draw() 中的语句一直执行到程序停止为止。每个语句都按顺序执行,并且在读取最后一行之后,将再次执行第一行。 +function draw() { + background(0); // 将背景设置为黑色 + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/05_Loop.js b/dist/assets/examples/zh-Hans/00_Structure/05_Loop.js new file mode 100644 index 0000000000..df288c8847 --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/05_Loop.js @@ -0,0 +1,21 @@ +/* + * @name Loop + * @description draw() 函数中的代码从上到下连续运行,直到程序停止。 + */ +let y = 100; + +// 程序开始时,setup() 函数中的语句执行一次。 +function setup() { + createCanvas(720, 400); // createCanvas 必须是第一条语句 + stroke(255); // 线条绘制颜色设置为白色 + frameRate(30); +} +// draw() 中的语句一直执行到程序停止为止。每个语句都按顺序执行,并且在读取最后一行之后,将再次执行第一行。 +function draw() { + background(0); // 将背景设置为黑色 + y = y - 1; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/06_Redraw.js b/dist/assets/examples/zh-Hans/00_Structure/06_Redraw.js new file mode 100644 index 0000000000..39b74e9afd --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/06_Redraw.js @@ -0,0 +1,28 @@ +/* + * @name Redraw + * @description redraw() 函数使 draw() 执行一次。在这个例子中,draw() 将在每次点击鼠标时执行一次。 + */ + +let y; + +// 程序开始时,setup() 函数中的语句执行一次。 +function setup() { + createCanvas(720, 400); + stroke(255); + noLoop(); + y = height * 0.5; +} + +// draw() 中的语句一直执行到程序停止为止。每个语句都按顺序执行,并且在读取最后一行之后,将再次执行第一行。. +function draw() { + background(0); + y = y - 4; + if (y < 0) { + y = height; + } + line(0, y, width, y); +} + +function mousePressed() { + redraw(); +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/07_Functions.js b/dist/assets/examples/zh-Hans/00_Structure/07_Functions.js new file mode 100644 index 0000000000..de8f29d43a --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/07_Functions.js @@ -0,0 +1,26 @@ +/* + *@name 函数 + *@description drawTarget() 函数可以很容易绘制许多不同的目标。每次调用 drawTarget() 都会为每个目标指定环的位置,大小和数量。 + */ + +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/dist/assets/examples/zh-Hans/00_Structure/08_Recursion.js b/dist/assets/examples/zh-Hans/00_Structure/08_Recursion.js new file mode 100644 index 0000000000..6d5a4a36f0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/08_Recursion.js @@ -0,0 +1,27 @@ +/* + *@name 递归 + *@description 递归的一个演示,递归指的的是函数可以调用自身。 + * 注意 drawCircle() 函数是如何在代码块的末尾调用它自身的。 + * 它将继续这样执行直到变量 “level” 等于1。 + */ + +function setup() { + createCanvas(720, 560); + noStroke(); + noLoop(); +} + +function draw() { + drawCircle(width / 2, 280, 6); +} + +function drawCircle(x, radius, level) { + let tt = (126 * level) / 4.0; + fill(tt); + ellipse(x, height / 2, radius * 2, radius * 2); + if (level > 1) { + level = level - 1; + drawCircle(x - radius / 2, radius / 2, level); + drawCircle(x + radius / 2, radius / 2, level); + } +} diff --git a/dist/assets/examples/zh-Hans/00_Structure/09_Create_Graphics.js b/dist/assets/examples/zh-Hans/00_Structure/09_Create_Graphics.js new file mode 100644 index 0000000000..0c341efccc --- /dev/null +++ b/dist/assets/examples/zh-Hans/00_Structure/09_Create_Graphics.js @@ -0,0 +1,27 @@ +/* + * @name Create Graphics + * @description 创建并返回一个新的 p5.Renderer 对象。如果你需要绘制到屏幕外的图形缓冲区,请使用这个种类。这两个参数以像素为单位定义宽度和高度。 + */ + +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); + + //使用 image() 将屏幕外的缓冲区绘制到屏幕上 + image(pg, 150, 75); +} diff --git a/dist/assets/examples/zh-Hans/01_Form/00_Points_and_Lines.js b/dist/assets/examples/zh-Hans/01_Form/00_Points_and_Lines.js new file mode 100644 index 0000000000..5344d4bf32 --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/00_Points_and_Lines.js @@ -0,0 +1,35 @@ +/* + * @name Points 与 Lines + * @description Points 与 lines 可用于绘制基本几何。 + * 更改变量 'd' 的值以缩放外形。这四个变量根据 'd' 的值设置位置。 + */ +function setup() { + let d = 70; + let p1 = d; + let p2 = p1 + d; + let p3 = p2 + d; + let p4 = p3 + d; + + // 将屏幕设置为720像素宽,400像素高 + createCanvas(720, 400); + background(0); + noSmooth(); + + translate(140, 0); + + // 绘制灰色的方块 + stroke(153); + line(p3, p3, p2, p3); + line(p2, p3, p2, p2); + line(p2, p2, p3, p2); + line(p3, p2, p3, p3); + + // 绘制白色的点 + stroke(255); + point(p1, p1); + point(p1, p3); + point(p2, p4); + point(p3, p1); + point(p4, p2); + point(p4, p4); +} diff --git a/dist/assets/examples/zh-Hans/01_Form/01_Shape_Primitives.js b/dist/assets/examples/zh-Hans/01_Form/01_Shape_Primitives.js new file mode 100644 index 0000000000..c53599d3f7 --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/01_Shape_Primitives.js @@ -0,0 +1,30 @@ +/* + * @name 基本形状 + * @description 基本形状的原始函数包括 triangle()、 + * rect(), quad()、ellipse() 和 arc()。 方块是通过 rect() 绘制, + * 圆形是通过 ellipse() 来绘制。每个功能都需要一些参数来确定形状的位置和大小。 + */ +function setup() { + // 将屏幕设置为720像素宽,400像素高 + 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/dist/assets/examples/zh-Hans/01_Form/02_Pie_Chart.js b/dist/assets/examples/zh-Hans/01_Form/02_Pie_Chart.js new file mode 100644 index 0000000000..3d22c015b2 --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/02_Pie_Chart.js @@ -0,0 +1,33 @@ +/* + * @name 饼状图 + * @description 使用 arc() 函数,将储存在数组中的数据生成一个饼状图。 + */ +let angles = [30, 10, 45, 35, 60, 38, 75, 67]; + +function setup() { + createCanvas(720, 400); + noStroke(); + noLoop(); // 执行一次之后停止 +} + +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/dist/assets/examples/zh-Hans/01_Form/03_Regular_Polygon.js b/dist/assets/examples/zh-Hans/01_Form/03_Regular_Polygon.js new file mode 100644 index 0000000000..fd5c1b36fc --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/03_Regular_Polygon.js @@ -0,0 +1,41 @@ +/* + * @name 正多边形 + * @description 你最喜欢什么形状?五边形?六边形?七边形?都不对?那二十边形呢? + * 因此创建的 polygon() 函数能够绘制任何正多边形。在 draw() 内部,尝试将不同的数字放入 polygon() 以进行探索。 + */ +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/dist/assets/examples/zh-Hans/01_Form/04_Star.js b/dist/assets/examples/zh-Hans/01_Form/04_Star.js new file mode 100644 index 0000000000..083b8a6b44 --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/04_Star.js @@ -0,0 +1,45 @@ +/* + * @name Star + * @description 此范例中创建的 star() 函数能够绘制各种不同的形式。 + * 在 draw() 内部,尝试将不同的数字放入 star() 以进行探索。 + */ +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/dist/assets/examples/zh-Hans/01_Form/05_Triangle_Strip.js b/dist/assets/examples/zh-Hans/01_Form/05_Triangle_Strip.js new file mode 100644 index 0000000000..651ee3f8e6 --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/05_Triangle_Strip.js @@ -0,0 +1,37 @@ +/* + * @name Triangle Strip + * @description 由 Ira Greenberg 提供的范例。使用 vertex() 函数和 beginShape(TRIANGLE_STRIP) 模式生成闭环。 + * 这个 outsideRadius 和 insideRadius 变量分别控制环的内外半径。 + */ +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/dist/assets/examples/zh-Hans/01_Form/06_Bezier.js b/dist/assets/examples/zh-Hans/01_Form/06_Bezier.js new file mode 100644 index 0000000000..c5a9db14c0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/06_Bezier.js @@ -0,0 +1,26 @@ +/* + * @name Bezier + * @description bezier() 函数的前两个参数指定曲线中的第一个点,后两个参数指定最后一个点。 + * 中间的参数设置定义曲线形状的控制点。 + */ +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/dist/assets/examples/zh-Hans/01_Form/07_3D_Primitives.js b/dist/assets/examples/zh-Hans/01_Form/07_3D_Primitives.js new file mode 100644 index 0000000000..65740511da --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/07_3D_Primitives.js @@ -0,0 +1,30 @@ +/* + * @name 基本 3D 形状 + * @frame 720,400 (可选的) + * @description 将数学上的 3D 形体放置在合成空间中。 + * box() 和 sphere() 函数至少使用一个参数来指定它们的大小。 + * 这些形状的位置是由 translate() 函数来定义的。 + */ +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/dist/assets/examples/zh-Hans/01_Form/08_Trig_Wheels_and_Pie_Chart.js b/dist/assets/examples/zh-Hans/01_Form/08_Trig_Wheels_and_Pie_Chart.js new file mode 100644 index 0000000000..20597a112e --- /dev/null +++ b/dist/assets/examples/zh-Hans/01_Form/08_Trig_Wheels_and_Pie_Chart.js @@ -0,0 +1,88 @@ +/* + * @name Trig Wheels and Pie Chart + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create +a trig color wheel and a visualization of a population age data as a +pie chart.
+ Functions are +created for the canvas setup, trig color wheel, drawslice, and pie +chart. The size of the slices are determined as well as their color +range. The pie chart is separated by definitive color per value +whereas the trig color wheel has a fixed slice amount with a range +color fill. +*/ + +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/dist/assets/examples/zh-Hans/02_Data/00_Variables.js b/dist/assets/examples/zh-Hans/02_Data/00_Variables.js new file mode 100644 index 0000000000..eb20a466c4 --- /dev/null +++ b/dist/assets/examples/zh-Hans/02_Data/00_Variables.js @@ -0,0 +1,36 @@ +/* + * @name 变量 + * @description 变量用于存储数值。在此示例中,更改变量的值以影响图形构成。 + */ +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/dist/assets/examples/zh-Hans/02_Data/01_True_and_False.js b/dist/assets/examples/zh-Hans/02_Data/01_True_and_False.js new file mode 100644 index 0000000000..43076b8f90 --- /dev/null +++ b/dist/assets/examples/zh-Hans/02_Data/01_True_and_False.js @@ -0,0 +1,29 @@ +/* + * @name True 和 False + * @description 布尔变量只有两个可能的值: true 或者 false。 + * 使用控制语句与布尔值来确定程序的流程是很常见的。 + * 在这个范例中, 当布尔值 “b” 为 true 时,绘制垂直线,当布尔值 “b” 为 false 时,绘制水平线。 + */ +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) { + // 垂直线 + line(i, d, i, height - d); + } + + if (b === false) { + // 水平线 + line(middle, i - middle + d, width - d, i - middle + d); + } + } +} diff --git a/dist/assets/examples/zh-Hans/02_Data/03_Variable_Scope.js b/dist/assets/examples/zh-Hans/02_Data/03_Variable_Scope.js new file mode 100644 index 0000000000..6ede5cf65b --- /dev/null +++ b/dist/assets/examples/zh-Hans/02_Data/03_Variable_Scope.js @@ -0,0 +1,46 @@ +/* + * @name 变量范围 + * @description 变量具有全局或函数“范围”。 + * 例如,在 setup() 或 draw() 函数中声明的变量只能在该函数内使用。 + * 全局变量,在 setup() 和 draw() 之外声明的变量,可以在程序中的任何地方使用。 + * 如果声明的函数变量与全局变量同名,那么程序将使用当前范围内所声明的函数变量进行计算。 + */ +let a = 80; // 创建一个全局变量"a" + +function setup() { + createCanvas(720, 400); + background(0); + stroke(255); + noLoop(); +} + +function draw() { + // 使用全局变量 “a” 绘制一条线 + line(a, 0, a, height); + + for (let a = 120; a < 200; a += 3) { + line(a, 0, a, height); + } + + let a = 300; + // 使用新的本地变量 “a” 画一条线 + line(a, 0, a, height); + + // 调用自定义函数 drawAnotherLine() + drawAnotherLine(); + + // 调用自定义函数 drawYetAnotherLine() + drawYetAnotherLine(); +} + +function drawAnotherLine() { + // 在此函数的本地创建一个新变量 “a” + let a = 320; + // 使用本地变量 “a” 画一条线 + line(a, 0, a, height); +} + +function drawYetAnotherLine() { + // 因为没有设置新的本地变量 “a”,所以该线使用设置为值 20 的原始全局变量 “a” 进行绘制 + line(a + 3, 0, a + 3, height); +} diff --git a/dist/assets/examples/zh-Hans/02_Data/04_Numbers.js b/dist/assets/examples/zh-Hans/02_Data/04_Numbers.js new file mode 100644 index 0000000000..527b88a06f --- /dev/null +++ b/dist/assets/examples/zh-Hans/02_Data/04_Numbers.js @@ -0,0 +1,31 @@ +/* + * @name Numbers + * @frame 720,400 + * @description 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. + */ +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/dist/assets/examples/zh-Hans/03_Arrays/00_Array.js b/dist/assets/examples/zh-Hans/03_Arrays/00_Array.js new file mode 100644 index 0000000000..b9fc89fe59 --- /dev/null +++ b/dist/assets/examples/zh-Hans/03_Arrays/00_Array.js @@ -0,0 +1,40 @@ +/* + * @name 数组 + * @description 数组是数据列表。数组中的每条数据由表示其在数组中的位置的索引号标识。 + * 数组基于零,这意味着数组中的第一个元素是[0],第二个元素是[1],依此类推。 + * 在此示例中,一个名为 “coswave” 的数组被创建并使用余弦值填充。此数据在屏幕上以三种不同的方式显示。 + */ +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/dist/assets/examples/zh-Hans/03_Arrays/01_Array_2d.js b/dist/assets/examples/zh-Hans/03_Arrays/01_Array_2d.js new file mode 100644 index 0000000000..7dc0479a56 --- /dev/null +++ b/dist/assets/examples/zh-Hans/03_Arrays/01_Array_2d.js @@ -0,0 +1,33 @@ +/* + * @name 2D 数组 + * @description 演示创建二维(2D)数组的句法。 2D 数组中的值是通过两个索引值来访问的。 + * 2D 阵列特别适用于对于存储图像。在该示例中,每个点是通过其相对于距图像中心的距离来进行着色的。 + */ +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] = []; // 创建嵌套数组 + 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(); // 执行一次之后停止 +} + +function draw() { + background(0); + // 这个嵌入式循环基于 spacer 变量跳过数组中的值,因此数组中的值多于此处绘制的值。更改 spacer 变量的值可以更改点的密度 + 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/dist/assets/examples/zh-Hans/03_Arrays/02_Array_Objects.js b/dist/assets/examples/zh-Hans/03_Arrays/02_Array_Objects.js new file mode 100644 index 0000000000..8197341d8e --- /dev/null +++ b/dist/assets/examples/zh-Hans/03_Arrays/02_Array_Objects.js @@ -0,0 +1,71 @@ +/* + * @name 数组对象 + * @description 演示创建自定义对象数组的句法。 + */ + +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/dist/assets/examples/zh-Hans/03_Arrays/03_Walk_Over_2dArray.js b/dist/assets/examples/zh-Hans/03_Arrays/03_Walk_Over_2dArray.js new file mode 100644 index 0000000000..e5577e7383 --- /dev/null +++ b/dist/assets/examples/zh-Hans/03_Arrays/03_Walk_Over_2dArray.js @@ -0,0 +1,85 @@ +/* + * @name Walk Over 2dArray + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to display 2D array contents on the canvas +using regular for and for-of loops in multiple different ways.
+ A function is created for the canvas, the 2D + array (Friend Array) is initialized and walked over using nested + loops in different ways. Variables x and y are used to place the + array item on the canvas in the form of 2D array. + The final nested loop is used to initialize 2D + array (Fish Array) with random Integers (fish ages). +*/ + + +//"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/dist/assets/examples/zh-Hans/04_Control/00_Iteration.js b/dist/assets/examples/zh-Hans/04_Control/00_Iteration.js new file mode 100644 index 0000000000..8b159065a0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/00_Iteration.js @@ -0,0 +1,41 @@ +/* + * @name 迭代 + * @description 用 “for” 结构迭代来构造重复的形式。 + */ +let y; +let num = 14; + +function setup() { + createCanvas(720, 360); + background(102); + noStroke(); + + // 画白条 + fill(255); + y = 60; + for (let i = 0; i < num / 3; i++) { + rect(50, y, 475, 10); + y += 20; + } + + // 灰条 + 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; + } + + // 细线 + y = 45; + fill(0); + for (let i = 0; i < num - 1; i++) { + rect(120, y, 40, 1); + y += 20; + } +} diff --git a/dist/assets/examples/zh-Hans/04_Control/01_Embedded_Iteration.js b/dist/assets/examples/zh-Hans/04_Control/01_Embedded_Iteration.js new file mode 100644 index 0000000000..5d6f06b7a9 --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/01_Embedded_Iteration.js @@ -0,0 +1,21 @@ +/* + * @name 嵌入式迭代 + * @description 嵌入 “for” 结构允许在两个维度上进行重复。 + */ +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/dist/assets/examples/zh-Hans/04_Control/02_Conditionals_1.js b/dist/assets/examples/zh-Hans/04_Control/02_Conditionals_1.js new file mode 100644 index 0000000000..7b18dd559f --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/02_Conditionals_1.js @@ -0,0 +1,22 @@ +/* + * @name 条件 1 + * @description 条件就像问题。 + * 如果问题的答案为真值,它们允许程序决定采取一个动作;如果问题的答案为假值,则允许程序执行另一个动作。 + * 程序中提出的问题始终是逻辑或关系语句。例如,如果变量 'i' 等于零,则绘制一条线。 + */ +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/dist/assets/examples/zh-Hans/04_Control/03_Conditionals_2.js b/dist/assets/examples/zh-Hans/04_Control/03_Conditionals_2.js new file mode 100644 index 0000000000..07b7949161 --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/03_Conditionals_2.js @@ -0,0 +1,25 @@ +/* + * @name 条件 2 + * @description 我们通过添加关键字 “else” 来扩展前一个示例中的条件语言。 + * 这允许条件连续提出两个或更多个问题,每个问题都有不同的操作。 + */ +function setup() { + createCanvas(720, 360); + background(0); + + for (let i = 2; i < width - 2; i += 4) { + // 如果 'i' 除以 20 而没有余数 + if (i % 20 === 0) { + stroke(255); + line(i, 80, i, height / 2); + // 如果 'i' 除以 10 而没有余数 + } else if (i % 10 === 0) { + stroke(153); + line(i, 20, i, 180); + // 如果上述两个条件都不满足,则绘制这条线 + } else { + stroke(102); + line(i, height / 2, i, height - 20); + } + } +} diff --git a/dist/assets/examples/zh-Hans/04_Control/04_Logical_Operators.js b/dist/assets/examples/zh-Hans/04_Control/04_Logical_Operators.js new file mode 100644 index 0000000000..f4b5d1394c --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/04_Logical_Operators.js @@ -0,0 +1,41 @@ +/* + * @name 逻辑操作符 + * @description AND(&&)和 OR(||)的逻辑操作符被用于将简单的关系语句组合成更复杂的表达式 + * NOT (!) 操作符被用于否定布尔语句。 + */ +let test = false; + +function setup() { + createCanvas(720, 360); + background(126); + + for (let i = 5; i <= height; i += 5) { + // 逻辑 AND + stroke(0); + if (i > 35 && i < 100) { + line(width / 4, i, width / 2, i); + test = false; + } + + // 逻辑 OR + stroke(76); + if (i <= 35 || i >= 100) { + line(width / 2, i, width, i); + test = true; + } + + // 测试布尔值是否为 “true” + // 表达式 “if(test)” 等同于 "if(test == true)" + if (test) { + stroke(0); + point(width / 3, i); + } + + // 测试布尔值是否为 "false" + // 表达式 “if(test)” 等同于 "if(test == false)" + if (!test) { + stroke(255); + point(width / 4, i); + } + } +} diff --git a/dist/assets/examples/zh-Hans/04_Control/05_Logical_Operators_2.js b/dist/assets/examples/zh-Hans/04_Control/05_Logical_Operators_2.js new file mode 100644 index 0000000000..2684feb956 --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/05_Logical_Operators_2.js @@ -0,0 +1,91 @@ +/* + * @name Logical Operators 2 + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to create Xboxes with one global variable and create conditions with + boolean variables and boolean expressions by utilizing Boolean + operators ||, &&, and ! to do boundary checking.
+ Functions + are created for both the canvas set up as well as the creation of + the boxes. Background color is dependent on the location of the + boxes in the canvas space. When mouse button and key are pressed + simultaneously, the “where” text and box color changes to cyan, + but if the mouse button is clicked alone then the animation will + start. When q or Q are pressed the text “Did you type q or Q?” + will change to blue, else it will be purple. If the mouse is placed + within the orange box containing the text, “withinRect” then the + shape will turn pink. + */ + + +//1 coordinate for everything :) +let where = 0; //control boxes' positions + +function setup() { + createCanvas(400, 400); +} + +function draw() { + //similar to slide 4 use of OR, || + //to set bg color of canvas + if ((where < 0) || (where > height)) { + background("beige"); + } else { + background("chocolate"); + } + + //similar to slide 4 use of AND, && + //to set fill color of box & text + if (mouseIsPressed && keyIsPressed) { + fill("cyan"); + } else { + fill(255); + } + + //boxL + rect(where, where, 40); + + //boxR, pad x coordinate for size of box + rect(width - where - 40, where, 40); + + //Move the boxes + where = where + 1; + + //Show the value of where the boxes are + text("where is " + where, 150, 30); + + //testing not, ! and or, || operators + if (!(key === "q" || key === "Q")) { + fill("purple"); + } else { + fill("dodgerBlue"); + } + //Show the current key value + text("Did you type a q or Q? " + key, 150, 70); + + //*** Boundary checking *** + //Is the mouse within rect boundary? + //left, right, top, bottom + let withinRect = (mouseX >= 150) && + (mouseX <= 150 + 100) && + (mouseY >= 300) && + (mouseY <= 300 + 40); + //fill color based on value of withinRect + if (withinRect) { + fill("pink"); + } else { + fill("orange"); + } + //draw the rect + rect(150, 300, 100, 40); + //show withinRect value as label on rect + fill(0); + text("withinRect " + withinRect, 160, 320); +} + +//boxes restart +function mousePressed() { + //Reset boxes back up and above the canvas + where = -50; +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/04_Control/06_Conditional_Shapes.js b/dist/assets/examples/zh-Hans/04_Control/06_Conditional_Shapes.js new file mode 100644 index 0000000000..8d544e9081 --- /dev/null +++ b/dist/assets/examples/zh-Hans/04_Control/06_Conditional_Shapes.js @@ -0,0 +1,48 @@ +/* + * @name Conditional Shapes + * @frame 400,400 + * @description contributed by + Prof WM Harris, How + to draw different shapes mid canvas depending on the mouse position.
+ Functions + are created for the main canvas set up with the markers on the left and + right hand sides. One is also created for the location of the mouse + regarding the canvas and the markers. If the mouse is within the + outer left hand beige rectangle, then the shape of circle is drawn + down the center of the canvas. If the mouse is within the outer right + hand beige rectangle, then the shape of square is drawn down the + center of the canvas. +*/ +function setup() { + createCanvas(400, 400); + strokeWeight(3); + //center squares to match circles + rectMode(CENTER); + + //draw rects to mark far sides + noStroke(); + fill("beige"); + rect(5, height / 2, 10, height); + rect(width - 5, height / 2, 10, height); + fill("orange"); + stroke("brown"); + + } + + function draw() { + point(mouseX, mouseY); + + //if (test) {doThis; } + //test: mouseX on far left of canvas + //doThis: draw a circle at mouseY + if (mouseX < 10) { + circle(width / 2, mouseY, 20); + } + + //test: mouseX on far right of canvas + //doThis: draw a square at mouseY + if (mouseX > width - 10) { + square(width / 2, mouseY, 20); + } + + } diff --git a/dist/assets/examples/zh-Hans/05_Image/00_Load_and_Display_Image.js b/dist/assets/examples/zh-Hans/05_Image/00_Load_and_Display_Image.js new file mode 100644 index 0000000000..59b19f0c9e --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/00_Load_and_Display_Image.js @@ -0,0 +1,20 @@ +/* + * @name 加载(Load)和显示(Display)图像 + * @description 图像可以以原图大小或自定义大小被加载和显示。 + *

要在本地运行此范例,您需要一个图像文件,并运行在 + * 本地伺服器上。

+ + */ +let img; // 声明变量 'img' + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // 加载图像 +} + +function draw() { + // 在坐标(0, 0),显示原图大小的图像 + image(img, 0, 0); + // 在坐标(0, 高度/2),显示一半原图大小的图像 + image(img, 0, height / 2, img.width / 2, img.height / 2); +} diff --git a/dist/assets/examples/zh-Hans/05_Image/01_Background_Image.js b/dist/assets/examples/zh-Hans/05_Image/01_Background_Image.js new file mode 100644 index 0000000000..56961d73b8 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/01_Background_Image.js @@ -0,0 +1,28 @@ +/* + * @name 背景图像 + * @description 此范例展示了最快加载背景图像的方法。 + * 若需将一张图像作为背景,它必须和程序有相同的宽度和高度。 + *

要在本地运行此示例,您需要一个图像文件,并运行在 + * 本地伺服器上。

+ */ +let bg; +let y = 0; + +function setup() { + // 背景图像的大小必须和 createCanvas() 函数中的参数一样。 + // 该图像大小为 720x400 像素。 + 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/dist/assets/examples/zh-Hans/05_Image/02_Transparency.js b/dist/assets/examples/zh-Hans/05_Image/02_Transparency.js new file mode 100644 index 0000000000..db8141aa46 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/02_Transparency.js @@ -0,0 +1,23 @@ +/* + * @name 透明度 + * @description 左右移动指针(光标)来改变图像位置 + * 此程序为一张图像叠加在另一张上,通过tint() 函数来改变它的透明度值(alpha value)。 + *

要在本地运行此范例,您需要一个图像文件,并运行在 + * 本地伺服器上。

+ */ +let img; +let offset = 0; +let easing = 0.05; + +function setup() { + createCanvas(720, 400); + img = loadImage('assets/moonwalk.jpg'); // 加载图像 +} + +function draw() { + image(img, 0, 0); // 完全不透明 + let dx = mouseX - img.width / 2 - offset; + offset += dx * easing; + tint(255, 127); // 半透明 + image(img, offset, 0); +} diff --git a/dist/assets/examples/zh-Hans/05_Image/03_Alpha_Mask.js b/dist/assets/examples/zh-Hans/05_Image/03_Alpha_Mask.js new file mode 100644 index 0000000000..6e9f5ab201 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/03_Alpha_Mask.js @@ -0,0 +1,28 @@ +/* + * @name 透明度遮罩 (Alpha Mask) + * @description 在图像上加载一个遮罩来改变图像中不同位置的透明度。 + * 通过拍p5.Image 中的mask() 函数来混合两张图像(图像和遮罩)。 + *

要在本地运行此范例,您需要一个图像文件,并运行在 + * 本地伺服器上。

+ */ +let img; +let imgMask; + +function preload() { + // 加载图像及图像遮罩 + img = loadImage('assets/moonwalk.jpg'); + imgMask = loadImage('assets/mask.png'); +} + +function setup() { + createCanvas(720, 400); + // mask() 函数将图像遮罩覆盖在图像上 + img.mask(imgMask); + imageMode(CENTER); +} + +function draw() { + background(0, 102, 153); + image(img, width / 2, height / 2); + image(img, mouseX, mouseY); +} diff --git a/dist/assets/examples/zh-Hans/05_Image/04_Create_Image.js b/dist/assets/examples/zh-Hans/05_Image/04_Create_Image.js new file mode 100644 index 0000000000..f9e6a1ee0e --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/04_Create_Image.js @@ -0,0 +1,30 @@ +/* + * @name 创建图像 + * @description createImage() 函数能让我们巧妙地操控一个像素缓冲区。 此范例创建了一个渐变图像。 + */ +let img; // 声明变量 'img' + +function setup() { + createCanvas(720, 400); + // 设置图像大小 230x230 像素 + img = createImage(230, 230); + + // 将显示窗口的像素资料加载到 pixels[] 数组里 + // 这函数必须在读写 pixels[] 之前被调用 + 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); + // 使用 set() 设置该位置像素的颜色 + img.set(x, y, [0, 153, 204, a]); + } + } + // 使用 set() 后,必须调用updatePixels() 以使改变生效 + img.updatePixels(); +} + +function draw() { + background(0); + image(img, 90, 80); + image(img, mouseX - img.width / 2, mouseY - img.height / 2); +} diff --git a/dist/assets/examples/zh-Hans/05_Image/05_Pointillism.js b/dist/assets/examples/zh-Hans/05_Image/05_Pointillism.js new file mode 100644 index 0000000000..3e524f4276 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/05_Pointillism.js @@ -0,0 +1,43 @@ +/* + * @name 点画(Pointillism) + * @description 作者:Dan Shiffman。 + * 鼠标水平位置控制点的大小,由左到右对应由小到大的点。 + * 通过带有原图像素颜色的椭圆创建出一副简单的点画。 + *

要在本地运行此范例,您需要一个图像文件,并运行在 + * 本地伺服器上。

+ */ +// 声明变量 'img', 'smallPoint', 'largePoing' +let img; +let smallPoint, largePoint; + +function preload() { + // 加载图像 + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 400); + // 设置最小点宽度为 4,最大点宽度为 40 + smallPoint = 4; + largePoint = 40; + imageMode(CENTER); + noStroke(); + // 设置背景颜色为白色 + background(255); + img.loadPixels(); +} + +function draw() { + // map() 函数根据鼠标水平位置, + // 将其在 [0, 画布宽度] 的数值对应到 [最小点宽度, 最大点宽度] ([4,40]) 之中, + // 对应的数值即为点的大小 + let pointillize = map(mouseX, 0, width, smallPoint, largePoint); + // 随机生成坐标 (x, y) + let x = floor(random(img.width)); + let y = floor(random(img.height)); + // 得到图像中坐标 (x, y) 的颜色 + let pix = img.get(x, y); + // fill(灰度值,透明度值) + fill(pix, 128); + ellipse(x, y, pointillize, pointillize); +} diff --git a/dist/assets/examples/zh-Hans/05_Image/06_Blur.js b/dist/assets/examples/zh-Hans/05_Image/06_Blur.js new file mode 100644 index 0000000000..2374bc0345 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/06_Blur.js @@ -0,0 +1,89 @@ +/* + * @name Blur + * @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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/05_Image/07_EdgeDetection.js b/dist/assets/examples/zh-Hans/05_Image/07_EdgeDetection.js new file mode 100644 index 0000000000..2c0509d44b --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/07_EdgeDetection.js @@ -0,0 +1,93 @@ +/* + * @name Edge Detection + * @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 + */ +// 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); +} diff --git a/dist/assets/examples/zh-Hans/05_Image/08_Brightness.js b/dist/assets/examples/zh-Hans/05_Image/08_Brightness.js new file mode 100644 index 0000000000..3c58a98876 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/08_Brightness.js @@ -0,0 +1,63 @@ +/* + * @name Brightness + * @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 + */ +// 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(); +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/05_Image/09_Convolution.js b/dist/assets/examples/zh-Hans/05_Image/09_Convolution.js new file mode 100644 index 0000000000..eb953c6729 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/09_Convolution.js @@ -0,0 +1,91 @@ +/* + * @name Convolution + * @description 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.

+ */ + +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); +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/05_Image/10_Copy_Method.js b/dist/assets/examples/zh-Hans/05_Image/10_Copy_Method.js new file mode 100644 index 0000000000..0e7f9431e5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/05_Image/10_Copy_Method.js @@ -0,0 +1,20 @@ +/* + * @name Copy() 函数 + * @frame 600,400 + * @description 一个如何使用 copy() 函数模拟为图像着色的范例。 + */ +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/dist/assets/examples/zh-Hans/07_Color/00_Hue.js b/dist/assets/examples/zh-Hans/07_Color/00_Hue.js new file mode 100644 index 0000000000..68cc84c57c --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/00_Hue.js @@ -0,0 +1,25 @@ +/* + * @name 色调 + * @description 色调是从物件反射或透过物件传播得到的颜色, + * 通常指颜色的名字(红色,蓝色,黄色等)。 + * 将光标在每个条形上垂直移动以更改其色调。 + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, height, height, height); + noStroke(); + background(0); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(mouseY, height, height); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/zh-Hans/07_Color/01_Saturation.js b/dist/assets/examples/zh-Hans/07_Color/01_Saturation.js new file mode 100644 index 0000000000..da8c42c364 --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/01_Saturation.js @@ -0,0 +1,24 @@ +/* + * @name 饱和度 + * @description 饱和度是颜色的强度或者纯度,代表与色调成比例的灰色量。 + * “饱和”的颜色是纯色;“不饱和”的颜色含有很大比例的灰色。 + * 将光标在每个条形上垂直移动以更改其饱和度。 + */ +const barWidth = 20; +let lastBar = -1; + +function setup() { + createCanvas(720, 400); + colorMode(HSB, width, height, 100); + noStroke(); +} + +function draw() { + let whichBar = mouseX / barWidth; + if (whichBar !== lastBar) { + let barX = whichBar * barWidth; + fill(barX, mouseY, 66); + rect(barX, 0, barWidth, height); + lastBar = whichBar; + } +} diff --git a/dist/assets/examples/zh-Hans/07_Color/02_Brightness.js b/dist/assets/examples/zh-Hans/07_Color/02_Brightness.js new file mode 100644 index 0000000000..41a66e8ad9 --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/02_Brightness.js @@ -0,0 +1,48 @@ +/* + * @name 亮度 + * @description 作者 Dan Shiffman。 + * 此程序通过计算每个像素距离光标的距离调整图像的局部亮度。 + *

+ * 要在本地运行此范例,您需要至少一个图像文件,并运行在 + * + * 本地伺服器 上。

+ */ +let img; + +function preload() { + img = loadImage('assets/moonwalk.jpg'); +} + +function setup() { + createCanvas(720, 200); + pixelDensity(1); + img.loadPixels(); + loadPixels(); +} + +function draw() { + for (let x = 0; x < img.width; x++) { + for (let y = 0; y < img.height; y++) { + // 通过 2D 网格计算1D位置 + let loc = (x + y * img.width) * 4; + // 从图像里获取 R,G,B 数值 + let r, g, b; + r = img.pixels[loc]; + // 根据距离光标的距离计算亮度改变的量 + let maxdist = 50; + let d = dist(x, y, mouseX, mouseY); + let adjustbrightness = (255 * (maxdist - d)) / maxdist; + r += adjustbrightness; + // 限制 RGB 以确保它们在 0-255 的颜色范围内 + r = constrain(r, 0, 255); + // 创建一个新颜色,并在窗口里设置像素 + //color c = color(r, g, b); + let pixloc = (y * width + x) * 4; + pixels[pixloc] = r; + pixels[pixloc + 1] = r; + pixels[pixloc + 2] = r; + pixels[pixloc + 3] = 255; + } + } + updatePixels(); +} diff --git a/dist/assets/examples/zh-Hans/07_Color/03_Color_Variables.js b/dist/assets/examples/zh-Hans/07_Color/03_Color_Variables.js new file mode 100644 index 0000000000..25d8149693 --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/03_Color_Variables.js @@ -0,0 +1,40 @@ +/* + * @name 颜色变量 + * @description (向 Albers 致敬。) 此范例为颜色们建立了变量。 + * 这样它们可以在程序中以名字指代,而非数字。 + */ +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); + + // 以下语句与上面的语句等效。 + // 程序员可以选择他们喜欢的格式。 + //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/dist/assets/examples/zh-Hans/07_Color/04_Relativity.js b/dist/assets/examples/zh-Hans/07_Color/04_Relativity.js new file mode 100644 index 0000000000..ea4a4f9fc6 --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/04_Relativity.js @@ -0,0 +1,34 @@ +/* + * @name 相对性 + * @description 我们对每个颜色的感知都是相对于其他颜色而言的。 + * 上半部分和下半部分的条形具有相同的颜色构成,但是他们呈现每个颜色的顺序不同, + * 让同一个颜色看起来也不一样。 + */ +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(); // 只画一次 +} + +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/dist/assets/examples/zh-Hans/07_Color/05_Linear_Gradient.js b/dist/assets/examples/zh-Hans/07_Color/05_Linear_Gradient.js new file mode 100644 index 0000000000..2593d790c2 --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/05_Linear_Gradient.js @@ -0,0 +1,51 @@ +/* + * @name 线性渐变 + * @description lerpColor() 函数可用于在两个颜色之间插值。 + */ +// 常量 +const Y_AXIS = 1; +const X_AXIS = 2; +let b1, b2, c1, c2; + +function setup() { + createCanvas(710, 400); + + // 定义颜色 + b1 = color(255); + b2 = color(0); + c1 = color(204, 102, 0); + c2 = color(0, 102, 153); + + noLoop(); +} + +function draw() { + // 背景 + setGradient(0, 0, width / 2, height, b1, b2, X_AXIS); + setGradient(width / 2, 0, width / 2, height, b2, b1, X_AXIS); + // 前景 + 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) { + // 从上到下的渐变 + 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) { + // 从左到右的渐变 + 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/dist/assets/examples/zh-Hans/07_Color/06_Radial_Gradient.js b/dist/assets/examples/zh-Hans/07_Color/06_Radial_Gradient.js new file mode 100644 index 0000000000..bde099a6ff --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/06_Radial_Gradient.js @@ -0,0 +1,32 @@ +/* + * @name 径向渐变 + * @description 绘制一系列同心圆,创造出从一个颜色到另一个颜色到渐变效果。 + */ +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/dist/assets/examples/zh-Hans/07_Color/07_Lerp_Color.js b/dist/assets/examples/zh-Hans/07_Color/07_Lerp_Color.js new file mode 100644 index 0000000000..2cbb6ffc8d --- /dev/null +++ b/dist/assets/examples/zh-Hans/07_Color/07_Lerp_Color.js @@ -0,0 +1,48 @@ +/* + * @name 插值颜色 + * @description 随机循环形状,颜色从红色到蓝色。 + */ +function setup() { + createCanvas(720, 400); + background(255); + noStroke(); +} + +function draw() { + background(255); + from = color(255, 0, 0, 0.2 * 255); + to = color(0, 0, 255, 0.2 * 255); + c1 = lerpColor(from, to, 0.33); + c2 = lerpColor(from, to, 0.66); + for (let i = 0; i < 15; i++) { + fill(from); + quad( + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height), + random(-40, 220), random(height) + ); + fill(c1); + quad( + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height), + random(140, 380), random(height) + ); + fill(c2); + quad( + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height), + random(320, 580), random(height) + ); + fill(to); + quad( + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height), + random(500, 760), random(height) + ); + } + frameRate(5); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/00_incrementdecrement.js b/dist/assets/examples/zh-Hans/08_Math/00_incrementdecrement.js new file mode 100644 index 0000000000..abf5b039ff --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/00_incrementdecrement.js @@ -0,0 +1,41 @@ +/* + * @name 增量/减量 + * @description "a++" 等于 "a = a + 1"。 "a--" 等于 "a = a - 1"。 + */ +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/dist/assets/examples/zh-Hans/08_Math/01_operatorprecedence.js b/dist/assets/examples/zh-Hans/08_Math/01_operatorprecedence.js new file mode 100644 index 0000000000..57fd22bf21 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/01_operatorprecedence.js @@ -0,0 +1,48 @@ +/* + * @name 操作符优先级 + * @description 如果没有明确地指明表达式求值的次序,表达式将根据操作符的优先级来求值。 + * 例如,在 "4+2*8" 的语句中, 2 会先乘 8,其结果再加上 4。 + * 这是因为 "*" 的优先级比 "+" 的高。 + * 为了避免读取程序时的模凌两可,建议将该语句写成 "4+(2*8)"。 + * 在代码中加上括号可以控制求值的次序。 + * 以下是操作符优先级列表。 + */ +// 最高级(最先执行)的位于列表上方,最低级(最后执行)的位于下方。 +// 乘法: * / % +// 加法: + - +// 比较: < > <= >= +// 相等: == != +// 逻辑与 (AND): && +// 逻辑或 (OR): || +// 赋值: = += -= *= /= %= +function setup() { + createCanvas(710, 400); + background(51); + noFill(); + stroke(51); + + stroke(204); + for (let i = 0; i < width - 20; i += 4) { + // 30 和 70 先相加,其结果再和现在的 i 值比较大小 + // 更清楚的写法是:"if (i > (30 + 70)) {" + if (i > 30 + 70) { + line(i, 0, i, 50); + } + } + + stroke(255); + // 2 和 8 先相乘,其结果再加 4 + // 更清楚的写法是:"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) { + // 先算关系表达式,再是逻辑与 (AND),最后是逻辑或 (OR) + // 更清楚的写法是: + // "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/dist/assets/examples/zh-Hans/08_Math/02_distance1d.js b/dist/assets/examples/zh-Hans/08_Math/02_distance1d.js new file mode 100644 index 0000000000..c75eabd6c5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/02_distance1d.js @@ -0,0 +1,64 @@ +/* + * @name 一维间距 + * @description 左右移动鼠标来控制移动形状的速度和方向。 + */ +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/dist/assets/examples/zh-Hans/08_Math/03_distance2d.js b/dist/assets/examples/zh-Hans/08_Math/03_distance2d.js new file mode 100644 index 0000000000..c9c956d931 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/03_distance2d.js @@ -0,0 +1,24 @@ +/* + * @name 二维间距 + * @description 在图片上移动鼠标来遮盖并显示矩阵。 + * 测量鼠标到每个正方形的距离,并按比例设置大小。 + */ +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/dist/assets/examples/zh-Hans/08_Math/04_sine.js b/dist/assets/examples/zh-Hans/08_Math/04_sine.js new file mode 100644 index 0000000000..9ddbef561c --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/04_sine.js @@ -0,0 +1,27 @@ +/* + * @name 正弦 + * @description 使用 sin() 函数平滑地缩放大小。 + */ +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/dist/assets/examples/zh-Hans/08_Math/05_sincosine.js b/dist/assets/examples/zh-Hans/08_Math/05_sincosine.js new file mode 100644 index 0000000000..900df8b666 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/05_sincosine.js @@ -0,0 +1,42 @@ +/* + * @name 正弦余弦 + * @description sin() 函数和 cos() 函数的线性运动。 + * 将 0 到 PI*2 (TWO_PI 的角度大致是 6.28) 之间的数字放进这些函数将返回 -1 到 1 之间的数字。 + * 然后这些数字将缩放以产生更大的运动。 + */ +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/dist/assets/examples/zh-Hans/08_Math/06_sinewave.js b/dist/assets/examples/zh-Hans/08_Math/06_sinewave.js new file mode 100644 index 0000000000..a1dd4fb4de --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/06_sinewave.js @@ -0,0 +1,47 @@ +/* + * @name 正弦波 + * @description 渲染一个简单的正弦波。 + * 作者:Daniel Shiffman + */ + +let xspacing = 16; // 每个水平位置的距离 +let w; // 波的宽度 +let theta = 0.0; // 初始角度为 0 +let amplitude = 75.0; // 波的高度 +let period = 500.0; // 波在重复前的像素个数 +let dx; // x 的增量 +let yvalues; // 保存波的高度的数组 + +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() { + // theta 增量(尝试赋予 ‘角速度’ 不同的数值) + theta += 0.02; + + // 对于每一个 x 值,使用正弦函数计算 y 值 + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = sin(x) * amplitude; + x += dx; + } +} + +function renderWave() { + noStroke(); + fill(255); + // 在波上的每个位置画椭圆 + for (let x = 0; x < yvalues.length; x++) { + ellipse(x * xspacing, height / 2 + yvalues[x], 16, 16); + } +} diff --git a/dist/assets/examples/zh-Hans/08_Math/07_additivewave.js b/dist/assets/examples/zh-Hans/08_Math/07_additivewave.js new file mode 100644 index 0000000000..bf14652432 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/07_additivewave.js @@ -0,0 +1,67 @@ +/* + * @name 加性波 + * @description 通过相加两个波来绘制一个更复杂的波。 + * 作者:Daniel Shiffman + */ +let xspacing = 8; // 每个水平位置的距离 +let w; // 波的宽度 +let maxwaves = 4; // 相加的波的总数 + +let theta = 0.0; +let amplitude = new Array(maxwaves); // 波的高度 +// x 的增量值,根据周期和水平位置距离来计算 +let dx = new Array(maxwaves); +// 用数组保存波的高度(不完全需要) +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); // 波在重复前的像素个数 + dx[i] = (TWO_PI / period) * xspacing; + } + + yvalues = new Array(floor(w / xspacing)); +} + +function draw() { + background(0); + calcWave(); + renderWave(); +} + +function calcWave() { + // theta 增量(尝试赋予 ‘角速度’ 不同的数值) + theta += 0.02; + + // 所有高度设为 0 + for (let i = 0; i < yvalues.length; i++) { + yvalues[i] = 0; + } + + // 累积波的高度 + for (let j = 0; j < maxwaves; j++) { + let x = theta; + for (let i = 0; i < yvalues.length; i++) { + // 正弦余弦交替 + if (j % 2 === 0) yvalues[i] += sin(x) * amplitude[j]; + else yvalues[i] += cos(x) * amplitude[j]; + x += dx[j]; + } + } +} + +function renderWave() { + // 在波上的每个位置画椭圆 + 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/dist/assets/examples/zh-Hans/08_Math/08_polartocartesian.js b/dist/assets/examples/zh-Hans/08_Math/08_polartocartesian.js new file mode 100644 index 0000000000..c1116d3121 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/08_polartocartesian.js @@ -0,0 +1,43 @@ +/* + * @name PolarToCartesian + * @description 转换极坐标 (r,theta) 到笛卡尔坐标 (x,y): x = rcos(theta) y = rsin(theta)。 + * 作者:Daniel Shiffman + */ +let r; + +// 角度,角速度,角加速度 +let theta; +let theta_vel; +let theta_acc; + +function setup() { + createCanvas(710, 400); + + // 初始化所有值 + r = height * 0.45; + theta = 0; + theta_vel = 0; + theta_acc = 0.0001; +} + +function draw() { + background(0); + + // 将原点设为屏幕中心 + translate(width/2, height/2); + + // 转换极坐标到笛卡尔坐标 + let x = r * cos(theta); + let y = r * sin(theta); + + // 在笛卡尔坐标系上画椭圆 + ellipseMode(CENTER); + noStroke(); + fill(200); + ellipse(x, y, 32, 32); + + // 应用加速度和速度到角度上 + // (此示例中 r 保持静态) + theta_vel += theta_acc; + theta += theta_vel; +} diff --git a/dist/assets/examples/zh-Hans/08_Math/09_arctangent.js b/dist/assets/examples/zh-Hans/08_Math/09_arctangent.js new file mode 100644 index 0000000000..493f0426f9 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/09_arctangent.js @@ -0,0 +1,46 @@ +/* + * @name 反正切 + * @description 移动鼠标来改变眼球的方向。
+ * atan2() 函数计算每个眼球到鼠标的角度。 + */ +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(); + }; +} diff --git a/dist/assets/examples/zh-Hans/08_Math/10_Interpolate.js b/dist/assets/examples/zh-Hans/08_Math/10_Interpolate.js new file mode 100644 index 0000000000..eefc644450 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/10_Interpolate.js @@ -0,0 +1,31 @@ +/* + * @name 线性插值 + * @frame 720, 400 + * @description 在屏幕上移动鼠标,圆会跟着移动。 + * 在动画绘制的每一帧之间,lerp() 函数会使圆从其当前位置向光标移动一部分距离(0.05)。 + * 这和在 Input 中的 Easing 范例一样,只是使用了 lerp() 函数。 + */ + +let x = 0; +let y = 0; + +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(51); + + // lerp() 函数计算在特定增量下两个数值之间的数字 + // amt 参数为两个值之间的插值量 + // 0.0 为第一个值,0.1 为非常接近第一个值,0.5 为两者之间,等等 + + // 这里我们每帧移动 5% 至鼠标的距离 + x = lerp(x, mouseX, 0.05); + y = lerp(y, mouseY, 0.05); + + fill(255); + stroke(255); + ellipse(x, y, 66, 66); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/11_doubleRandom.js b/dist/assets/examples/zh-Hans/08_Math/11_doubleRandom.js new file mode 100644 index 0000000000..2fcc2a7752 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/11_doubleRandom.js @@ -0,0 +1,23 @@ +/* + * @name 双重随机 + * @frame 720,400 (optional) + * @description 调用两个 random() 函数和一个 point() 函数来绘制一个不规则的锯齿线。 + * 作者:Ira Greenberg + */ +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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/08_Math/12_random.js b/dist/assets/examples/zh-Hans/08_Math/12_random.js new file mode 100644 index 0000000000..a66b9bcdb6 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/12_random.js @@ -0,0 +1,20 @@ +/* + * @name 随机 + * @description 随机数创建了此图像的基础。 + * 每次加载程序将产生不同的结果。 + */ +function setup() { + createCanvas(710, 400); + background(0); + strokeWeight(20); + frameRate(2); +} + +function draw() { + for (let i = 0; i < width; i++) { + // 随机在 0-255 之间取数 + let r = random(255); + stroke(r); + line(i, 0, i, height); + } +} diff --git a/dist/assets/examples/zh-Hans/08_Math/13_noise1D.js b/dist/assets/examples/zh-Hans/08_Math/13_noise1D.js new file mode 100644 index 0000000000..d2e34e578e --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/13_noise1D.js @@ -0,0 +1,31 @@ +/* + * @name 一维噪声 (Noise1D) + * @description 调用一维柏林噪声来指定位置。 + */ +let xoff = 0.0; +let xincrement = 0.01; + +function setup() { + createCanvas(710, 400); + background(0); + noStroke(); +} + +function draw() { + // 创建一个透明度 (alpha) 混合背景 + fill(0, 10); + rect(0, 0, width, height); + + //let n = random(0,width); // 尝试用这一行代替 noise() + + // 基于 xoff 和 scale 得到一个噪声值 + // 并根据窗口宽度进行缩放 + let n = noise(xoff) * width; + + // 每一轮增加 xoff + xoff += xincrement; + + // 绘制由柏林噪声产生的数值的椭圆 + fill(200); + ellipse(n, height / 2, 64, 64); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/14_noisewave.js b/dist/assets/examples/zh-Hans/08_Math/14_noisewave.js new file mode 100644 index 0000000000..ba3fbaea91 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/14_noisewave.js @@ -0,0 +1,42 @@ +/* + * @name 噪声波 + * @description 调用柏林噪声来产生波状图案。 + * 作者:Daniel Shiffman + */ +let yoff = 0.0; // 柏林噪声的第二维度 + +function setup() { + createCanvas(710, 400); +} + +function draw() { + background(51); + + fill(255); + // 我们将从波点中绘制一个多边形 + beginShape(); + + let xoff = 0; // 选项 1: 2D 噪声 + // let xoff = yoff; // 选项 2: 1D 噪声 + + // 迭代所有水平像素 + for (let x = 0; x <= width; x += 10) { + // 根据noise() 和 map() 函数计算一个 y 值 + + // 选项 1: 2D 噪声 + let y = map(noise(xoff, yoff), 0, 1, 200, 300); + + // 选项 2: 1D 噪声 + // let y = map(noise(xoff), 0, 1, 200,300); + + // 设置顶点 + vertex(x, y); + // 增加噪声的 x 维度 + xoff += 0.05; + } + // 增加噪声的 y 维度 + yoff += 0.01; + vertex(width, height); + vertex(0, height); + endShape(CLOSE); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/15_Noise2D.js b/dist/assets/examples/zh-Hans/08_Math/15_Noise2D.js new file mode 100644 index 0000000000..769cc54909 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/15_Noise2D.js @@ -0,0 +1,42 @@ +/* + * @name 二维噪声 (Noise2D) + * @frame 710,400 (optional) + * @description 使用不同参数创建一个二维噪声。 + * + */ + +let noiseVal; +let noiseScale = 0.02; + +function setup() { + createCanvas(640, 360); +} + +function draw() { + background(0); + // 绘制左半边图像 + for (let y = 0; y < height - 30; y++) { + for (let x = 0; x < width / 2; x++) { + // 像素所使用的八度数和衰退因数的 noiceDetail + noiseDetail(2, 0.2); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // 绘制右半边图像 + for (let y = 0; y < height - 30; y++) { + for (let x = width / 2; x < width; x++) { + // 像素所使用的八度数和衰退因数的 noiceDetail + noiseDetail(5, 0.5); + noiseVal = noise((mouseX + x) * noiseScale, (mouseY + y) * noiseScale); + stroke(noiseVal * 255); + point(x, y); + } + } + // 显示左右两分区的详细信息 + textSize(18); + fill(255, 255, 255); + text('Noice2D with 2 octaves and 0.2 falloff', 10, 350); + text('Noice2D with 1 octaves and 0.7 falloff', 330, 350); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/16_Noise3D.js b/dist/assets/examples/zh-Hans/08_Math/16_Noise3D.js new file mode 100644 index 0000000000..7923d6699a --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/16_Noise3D.js @@ -0,0 +1,48 @@ +/* + * @name 三维噪声 (Noise3D) + * @frame 710,400 (optional) + * @description 使用三维噪声创建简单的动画纹理。 + */ + +let noiseVal; +// x 增加 0.01 +let x_increment = 0.01; +// 每一个 draw() 的周期,z 增加 0.02 +let z_increment = 0.02; + +// 偏移值 +let z_off, y_off, x_off; + +function setup() { + // 创建画布 + createCanvas(640, 360); + // 定义每一秒应该显示的影格数 + frameRate(20); + // 初始 z_off + z_off = 0; +} + +function draw() { + x_off = 0; + y_off = 0; + // 设置黑色背景 + background(0); + // 调整噪声细节 + noiseDetail(8, 0.65); + + // 对于每一个 x,y 计算噪声值 + for (let y = 0; y < height; y++) { + x_off += x_increment; + y_off = 0; + + for (let x = 0; x < width; x++) { + // 计算和绘制每一个像素 + 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/dist/assets/examples/zh-Hans/08_Math/17_Randomchords.js b/dist/assets/examples/zh-Hans/08_Math/17_Randomchords.js new file mode 100644 index 0000000000..84f5c693de --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/17_Randomchords.js @@ -0,0 +1,33 @@ +/* + * @name 随机弦 + * @description 累积一个圆的随机弦。每个弦都是半透明的,所以它们累积起来会造成阴影球面的错觉。 + * 贡献于 Aatish Bhatia,灵感来源于 Anders Hoff + */ +function setup() { + createCanvas(400, 400); + background(255, 255, 255); + + // 使用透明度值的半透明外形线 + stroke(0, 0, 0, 15); +} + +function draw() { + // 每一帧绘制两个随机弦 + randomChord(); + randomChord(); +} + +function randomChord() { + // 在圆上随机找一个点 + let angle1 = random(0, 2 * PI); + let xpos1 = 200 + 200 * cos(angle1); + let ypos1 = 200 + 200 * sin(angle1); + + // 在圆上随机找另一个点 + let angle2 = random(0, 2 * PI); + let xpos2 = 200 + 200 * cos(angle2); + let ypos2 = 200 + 200 * sin(angle2); + + // 在两点之间绘制一条直线 + line(xpos1, ypos1, xpos2, ypos2); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/18_Map.js b/dist/assets/examples/zh-Hans/08_Math/18_Map.js new file mode 100644 index 0000000000..ec6d6802f5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/18_Map.js @@ -0,0 +1,20 @@ +/* + * @name 映射 (Map) + * @description 调用 map() 函数将任意数值缩放至一个对于现在程序更有用的新数值。 + * 例如,使用鼠标的位置来控制形状的大小或颜色。 + * 此范例中,鼠标的 x 坐标( 0-360 之间的数字)将被缩放为新数值,用于设定圆的颜色和大小。 + */ +function setup() { + createCanvas(720, 400); + noStroke(); +} + +function draw() { + background(0); + // 将 mouseX 的数值从 0-720 缩放至 0-175 的范围内 + let c = map(mouseX, 0, width, 0, 175); + // 将 mouseX 的数值从 0-720 to 缩放至 40-300 的范围内 + let d = map(mouseX, 0, width, 40, 300); + fill(255, c, 0); + ellipse(width/2, height/2, d, d); +} diff --git a/dist/assets/examples/zh-Hans/08_Math/19_parametricEquation.js b/dist/assets/examples/zh-Hans/08_Math/19_parametricEquation.js new file mode 100644 index 0000000000..423400d4ae --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/19_parametricEquation.js @@ -0,0 +1,43 @@ +/* + * @name 参数方程 + * @description 参数方程是 x 和 y 坐标都用另外的字母表示。 + * 这被称为参数并且通常以字母 t 或 θ 给出。 + * 灵感来源于 Alexander Miller 油管频道。 + */ + +function setup(){ + createCanvas(720,400); +} + +// x 和 y 所依靠的参数通常被视为 t 或者 theta 的符号 +let t = 0; +function draw(){ + background('#fff'); + translate(width/2,height/2); + stroke('#0f0f0f'); + strokeWeight(1.5); + // 迭代来增加 100 条直线 + 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; +} +// 改变直线的初始 x 坐标 +function x1(t){ + return sin(t/10)*125+sin(t/20)*125+sin(t/30)*125; +} + +// 改变直线的初始 y 坐标 +function y1(t){ + return cos(t/10)*125+cos(t/20)*125+cos(t/30)*125; +} + +// 改变直线的最终 x 坐标 +function x2(t){ + return sin(t/15)*125+sin(t/25)*125+sin(t/35)*125; +} + +// 改变直线的最终 y 坐标 +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/dist/assets/examples/zh-Hans/08_Math/20_Graphing2DEquations.js b/dist/assets/examples/zh-Hans/08_Math/20_Graphing2DEquations.js new file mode 100644 index 0000000000..450f33c8ce --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/20_Graphing2DEquations.js @@ -0,0 +1,52 @@ +/** + * @name Graphing 2D Equations + * @frame 710, 400 + * @description Graphics the following equation: sin(n*cos(r) + 5*theta) where n is a function of horizontal mouse location. Original by Daniel Shiffman + */ +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/dist/assets/examples/zh-Hans/08_Math/21_parametricEquation.js b/dist/assets/examples/zh-Hans/08_Math/21_parametricEquation.js new file mode 100644 index 0000000000..83c1a3c336 --- /dev/null +++ b/dist/assets/examples/zh-Hans/08_Math/21_parametricEquation.js @@ -0,0 +1,44 @@ +/* + * @name Parametric Equations + * @description 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. + */ + +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/dist/assets/examples/zh-Hans/09_Simulate/00_Forces.js b/dist/assets/examples/zh-Hans/09_Simulate/00_Forces.js new file mode 100644 index 0000000000..6492ce8ff8 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/00_Forces.js @@ -0,0 +1,148 @@ +/* + * @name Forces + * @description Demonstration of multiple force acting on bodies + * (natureofcode.com) + */ +// Demonstration of multiple force acting on +// bodies (Mover class) +// Bodies experience gravity continuously +// Bodies experience fluid resistance when in "water" + +// Five 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/dist/assets/examples/zh-Hans/09_Simulate/01_ParticleSystem.js b/dist/assets/examples/zh-Hans/09_Simulate/01_ParticleSystem.js new file mode 100644 index 0000000000..a026e4623c --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/01_ParticleSystem.js @@ -0,0 +1,69 @@ +/* + * @name Particle System + * @description This is a basic Particle System + * (natureofcode.com) + */ +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/dist/assets/examples/zh-Hans/09_Simulate/02_Flocking.js b/dist/assets/examples/zh-Hans/09_Simulate/02_Flocking.js new file mode 100644 index 0000000000..4f08384666 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/02_Flocking.js @@ -0,0 +1,229 @@ +/* + * @name Flocking + * @description 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. + */ + + +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/dist/assets/examples/zh-Hans/09_Simulate/03_WolframCA.js b/dist/assets/examples/zh-Hans/09_Simulate/03_WolframCA.js new file mode 100644 index 0000000000..8e5dad9f9c --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/03_WolframCA.js @@ -0,0 +1,73 @@ +/* + * @name Wolfram CA + * @description Simple demonstration of a Wolfram 1-dimensional cellular automata + * (natureofcode.com) + */ + +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/dist/assets/examples/zh-Hans/09_Simulate/04_GameOfLife.js b/dist/assets/examples/zh-Hans/09_Simulate/04_GameOfLife.js new file mode 100644 index 0000000000..8a2dbdfe62 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/04_GameOfLife.js @@ -0,0 +1,94 @@ +/* + * @name Game of Life + * @description A basic implementation of John Conway's Game of Life CA + * (natureofcode.com) + */ + +let w; +let columns; +let rows; +let board; +let next; + +function setup() { + 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/dist/assets/examples/zh-Hans/09_Simulate/05_MultipleParticleSystems.js b/dist/assets/examples/zh-Hans/09_Simulate/05_MultipleParticleSystems.js new file mode 100644 index 0000000000..99ff1439a4 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/05_MultipleParticleSystems.js @@ -0,0 +1,138 @@ +/* + * @name Multiple Particle Systems + * @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. + */ +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(); +} diff --git a/dist/assets/examples/zh-Hans/09_Simulate/06_Spirograph.js b/dist/assets/examples/zh-Hans/09_Simulate/06_Spirograph.js new file mode 100644 index 0000000000..02cb918b09 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/06_Spirograph.js @@ -0,0 +1,73 @@ + +/* + * @name Spirograph + * @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 + */ +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 < sines.length; i++) { + sines[i] = PI; // start EVERYBODY facing NORTH + } +} + +function draw() { + if (!trace) { + background(204); // clear screen if showing geometry + stroke(0, 255); // black pen + noFill(); // don't fill + } + + // MAIN ACTION + push(); // start a transformation matrix + translate(width / 2, height / 2); // move to middle of screen + + for (let i = 0; i < sines.length; i++) { + let erad = 0; // radius for small "point" within circle... this is the 'pen' when tracing + // setup for tracing + if (trace) { + stroke(0, 0, 255 * (float(i) / sines.length), alpha); // blue + fill(0, 0, 255, alpha / 2); // also, um, blue + erad = 5.0 * (1.0 - float(i) / sines.length); // pen width will be related to which sine + } + let radius = rad / (i+1); // radius for circle itself + rotate(sines[i]); // rotate circle + if (!trace) ellipse(0, 0, radius * 2, radius * 2); // if we're simulating, draw the sine + push(); // go up one level + translate(0, radius); // move to sine edge + if (!trace) ellipse(0, 0, 5, 5); // draw a little circle + if (trace) ellipse(0, 0, erad, erad); // draw with erad if tracing + pop(); // go down one level + translate(0, radius); // move into position for next sine + sines[i] = (sines[i] + (fund + (fund * i * ratio))) % TWO_PI; // update angle based on fundamental + } + + pop(); // pop down final transformation + +} + +function keyReleased() { + if (key==' ') { + trace = !trace; + background(255); + } +} diff --git a/dist/assets/examples/zh-Hans/09_Simulate/07_LSystems.js b/dist/assets/examples/zh-Hans/09_Simulate/07_LSystems.js new file mode 100644 index 0000000000..c5a7902950 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/07_LSystems.js @@ -0,0 +1,106 @@ +/* + * @name L-Systems + * @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 + */ +// 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); +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/09_Simulate/08_Spring.js b/dist/assets/examples/zh-Hans/09_Simulate/08_Spring.js new file mode 100644 index 0000000000..2d0fc96a0a --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/08_Spring.js @@ -0,0 +1,92 @@ +/* + * @name Spring + * @frame 710, 400 + * @description Click, drag, and release the horizontal bar to start the spring. + */ +// 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/dist/assets/examples/zh-Hans/09_Simulate/09_Springs.js b/dist/assets/examples/zh-Hans/09_Simulate/09_Springs.js new file mode 100644 index 0000000000..ed0a185a65 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/09_Springs.js @@ -0,0 +1,147 @@ +/* + * @name Springs + * @frame 710,400 + * @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. + * (ported from https://processing.org/examples/springs.html) + */ +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; + } +}; \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/09_Simulate/10_SoftBody.js b/dist/assets/examples/zh-Hans/09_Simulate/10_SoftBody.js new file mode 100644 index 0000000000..b227393300 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/10_SoftBody.js @@ -0,0 +1,110 @@ +/* + * @name Soft Body + * @description Original example by Ira Greenberg. + *

Softbody dynamics simulation using curveVertex() and curveTightness(). + */ +// 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]; + } +} diff --git a/dist/assets/examples/zh-Hans/09_Simulate/11_SmokeParticleSystem.js b/dist/assets/examples/zh-Hans/09_Simulate/11_SmokeParticleSystem.js new file mode 100644 index 0000000000..c82e6b141c --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/11_SmokeParticleSystem.js @@ -0,0 +1,180 @@ +/* + * @name SmokeParticles + * @description a port of Dan Shiffman's SmokeParticleSystem example originally + * for Processing. Creates smokey particles :p + */ + +// 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/dist/assets/examples/zh-Hans/09_Simulate/12_BrownianMotion.js b/dist/assets/examples/zh-Hans/09_Simulate/12_BrownianMotion.js new file mode 100644 index 0000000000..449e5ad27e --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/12_BrownianMotion.js @@ -0,0 +1,46 @@ +/* + * @name Brownian Motion + * @description Recording random movement as a continuous line. + * Port of original example from the Processing examples page. + */ + +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/dist/assets/examples/zh-Hans/09_Simulate/13_Chain.js b/dist/assets/examples/zh-Hans/09_Simulate/13_Chain.js new file mode 100644 index 0000000000..ba52c54587 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/13_Chain.js @@ -0,0 +1,55 @@ +/* + * @name Chain + * @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. + * Ported from the Processing Examples page. + */ +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); + } +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/09_Simulate/14_SnowflakeParticleSystem.js b/dist/assets/examples/zh-Hans/09_Simulate/14_SnowflakeParticleSystem.js new file mode 100644 index 0000000000..0956a80792 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/14_SnowflakeParticleSystem.js @@ -0,0 +1,63 @@ +/* + * @name Snowflakes + * @description Particle system simulating the motion of falling snowflakes. + * Uses an array of objects to hold the snowflake particles. + * Contributed by Aatish Bhatia. + */ + +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/dist/assets/examples/zh-Hans/09_Simulate/15_penrose_tiles.js b/dist/assets/examples/zh-Hans/09_Simulate/15_penrose_tiles.js new file mode 100644 index 0000000000..41987d4ebd --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/15_penrose_tiles.js @@ -0,0 +1,125 @@ +/* + * @name Penrose Tiles + * @frame 710,400 + * @description This is a port by David Blitz of the "Penrose Tile" example from processing.org/examples + */ + +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 < this.steps; ++i) { + let step = this.production.charAt(i); + + //'W', 'X', 'Y', 'Z' symbols don't actually correspond to a turtle action + if( step == 'F') { + stroke(255, 60); + for(let j=0; j < this.repeats; j++) { + line(0, 0, 0, -this.drawLength); + noFill(); + translate(0, -this.drawLength); + } + this.repeats = 1; + } + else if (step == '+') { + rotate(this.theta); + } + else if (step == '-') { + rotate(-this.theta); + } + else if (step == '[') { + push(); + } + else if (step == ']') { + pop(); + } + } +} + + diff --git a/dist/assets/examples/zh-Hans/09_Simulate/16_Recursive_Tree.js b/dist/assets/examples/zh-Hans/09_Simulate/16_Recursive_Tree.js new file mode 100644 index 0000000000..c86a08e6a1 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/16_Recursive_Tree.js @@ -0,0 +1,55 @@ +/* + * @name Recursive Tree + * @description 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. + */ +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/dist/assets/examples/zh-Hans/09_Simulate/17_Mandelbrot.js b/dist/assets/examples/zh-Hans/09_Simulate/17_Mandelbrot.js new file mode 100644 index 0000000000..76b0bdc4b2 --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/17_Mandelbrot.js @@ -0,0 +1,86 @@ +/* + * @name The Mandelbrot Set + * @description Simple rendering of the Mandelbrot set. + * Based on Daniel Shiffman's Mandelbrot Example for Processing. + */ + +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/dist/assets/examples/zh-Hans/09_Simulate/18_Koch.js b/dist/assets/examples/zh-Hans/09_Simulate/18_Koch.js new file mode 100644 index 0000000000..e3323141ca --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/18_Koch.js @@ -0,0 +1,140 @@ +/* + * @name Koch Curve + * @description Renders a simple fractal, the Koch snowflake. Each recursive level is drawn in sequence. + * By Daniel Shiffman + */ + +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/dist/assets/examples/zh-Hans/09_Simulate/19_Bubblesort.js b/dist/assets/examples/zh-Hans/09_Simulate/19_Bubblesort.js new file mode 100644 index 0000000000..85d3402dfb --- /dev/null +++ b/dist/assets/examples/zh-Hans/09_Simulate/19_Bubblesort.js @@ -0,0 +1,67 @@ +/* + * @name Bubble Sort + * @description 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. + */ + +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= 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); + +// +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 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(paraticles) { + 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
+ * 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
+ */ + +// 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)); +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/10_Interaction/10_Tickle.js b/dist/assets/examples/zh-Hans/10_Interaction/10_Tickle.js new file mode 100644 index 0000000000..82b76bdbda --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/10_Tickle.js @@ -0,0 +1,48 @@ +/* + * @name Tickle + * @description "tickle" 这个单词会在光标移至它时抖动。 + * 有时还会抖出屏幕。 + */ +let message = 'tickle', + font, + bounds, // 存储文本框的 x, y, w, h 值 + fontsize = 60, + x, + y; // 文本的 x 和 y 坐标 + +function preload() { + font = loadFont('assets/SourceSansPro-Regular.otf'); +} + +function setup() { + createCanvas(710, 400); + + // 设置字体 + textFont(font); + textSize(fontsize); + + // 获取文本的宽度和高度,以便我们可以首先将其居中 + bounds = font.textBounds(message, 0, 0, fontsize); + x = width / 2 - bounds.w / 2; + y = height / 2 - bounds.h / 2; +} + +function draw() { + background(204, 120); + + // 写出黑色的文本并获取其文本框 + fill(0); + text(message, x, y); + bounds = font.textBounds(message, x, y, fontsize); + + // 检查鼠标是否在文本框里;如果在文本框内,抖动文本 + 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/dist/assets/examples/zh-Hans/10_Interaction/11_WeightLine.js b/dist/assets/examples/zh-Hans/10_Interaction/11_WeightLine.js new file mode 100644 index 0000000000..a455dcb781 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/11_WeightLine.js @@ -0,0 +1,55 @@ +/* + * @name Weight Line + * @frame 710,400 + * @description contributed by + Prof WM Harris, using the random function with events to color/weight a line
+ How to use the random function with events to color/ weight a line + dependent on mouse location, left mouse button clicks, character key types, and + random key releases.
+ Functions are created for both the canvas set up as well as the creation of + the line. Depending on the action taken by the user the line can + vary in width and color. Left mouse button clicks result in a color + change to blue, while the typing of any character key will change + the color to turquoise, each resulting in a variable stroke weight; + the width of the former will be between 0 – 1 while the width of + the latter will be 0 – 5. The release of any key will result in a + random hue, saturation, and brightness change to the line. + */ + + +function setup() { + createCanvas(400, 400); + background("beige"); + colorMode(HSB); + } + + function draw() { + //Line from prev pt to current pt + //of mouse position + line(mouseX, mouseY, pmouseX, pmouseY); + } + + //listen when we click the mouse + function mouseClicked() { + //weights 0 to 1 + stroke("slateBlue"); + strokeWeight(random()); + + //what if want weights 0 to .4? + //strokeWeight( random(.4) ); + } + + //listen when we release *any* key + function keyReleased() { + //color hue values between 20 and 145 + //saturation 0 to 100 + //brightness 80 to 100 + stroke(random(20, 145), random(100), random(80, 100)); + } + + //listen for only character keys + function keyTyped() { + //weights 0 to 5 + stroke("turquoise"); + strokeWeight(random(5)); + } \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/10_Interaction/20_Follow1.js b/dist/assets/examples/zh-Hans/10_Interaction/20_Follow1.js new file mode 100644 index 0000000000..290cec5a16 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/20_Follow1.js @@ -0,0 +1,37 @@ +/* + * @name 跟随 1 + * @frame 710,400 + * @description 被光标拉扯的一条线段。 + * 基于 Keith Peters 的代码。 + */ +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/dist/assets/examples/zh-Hans/10_Interaction/21_Follow2.js b/dist/assets/examples/zh-Hans/10_Interaction/21_Follow2.js new file mode 100644 index 0000000000..4d5c7e2aa5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/21_Follow2.js @@ -0,0 +1,39 @@ +/* + * @name 跟随 2 + * @frame 710,400 + * @description 跟随光标移动的两段式手臂。 + * 两个手臂之间的相对角度是用 atan2() 计算的,位置是用 sin() 和 cos() 计算的。 + * 基于 Keith Peters 的代码。 + */ +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/dist/assets/examples/zh-Hans/10_Interaction/22_Follow3.js b/dist/assets/examples/zh-Hans/10_Interaction/22_Follow3.js new file mode 100644 index 0000000000..155bf2783f --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/22_Follow3.js @@ -0,0 +1,47 @@ +/* + * @name 跟随 3 + * @frame 710,400 + * @description 随鼠标移动的一条分段式线条。 + * 每段之间的相对角度是用 atan2() 计算的,位置是用 sin() 和 cos() 计算的。 + * 基于 Keith Peters 的代码。 + */ +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/dist/assets/examples/zh-Hans/10_Interaction/23_snake.js b/dist/assets/examples/zh-Hans/10_Interaction/23_snake.js new file mode 100644 index 0000000000..e72105780a --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/23_snake.js @@ -0,0 +1,164 @@ +/* + * @name 贪吃蛇 + * @description 著名的贪吃蛇游戏!点击 run 后,在黑色区域里任意点击, + * 使用 i j k 和 l 控制蛇。注意不要让蛇碰到自己或者墙。
+ * 由 Prashant Gupta 创作的范例 + */ + +// 蛇被分为几小段,在每次调用 draw() 时进行绘制和编辑 +let numSegments = 10; +let direction = 'right'; + +const xStart = 0; // 蛇的初始 x 坐标 +const yStart = 250; //蛇的初始 y 坐标 +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(); +} + +/* + 根据蛇的方向更新每个小段。 + 从 0 至 n-1 的所有片段都被复制到 1 至 n,也就是说,段 0 获取 段 1 的值, + 段 1 获取 段 2 的值,以此类推。因此,蛇就会动起来了。 + + 最后一小段根据蛇运动的方向添加。如果蛇在左后移动,最后一小段的 x 坐标值将比倒数第二小段 + 增加预定义值 "diff";如果上下移动,则更改其 y 坐标值。 +*/ +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; + } +} + +/* + 检查蛇头的位置 xCor[xCor.length - 1] 和 yCor[yCor.length - 1] 来看它是否 + 碰到边界或者自己。 +*/ +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); + } +} + +/* + 如果蛇碰到自己,说明蛇头的 (x,y) 坐标和它自身的小段之一的 (x,y) 坐标相同。 +*/ +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; + } + } +} + +/* + 蛇每吃一个水果,小段的数量就会增加,然后将尾段插入数组的开头 + (将最后一个小段再次添加到尾部,从而延长了尾部) +*/ +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() { + /* + 这里的数学逻辑是因为我希望这个点位于 100 和 width-100 之间,并四舍五入到 + 10 的倍数 ,因为蛇以 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/dist/assets/examples/zh-Hans/10_Interaction/24_Wavemaker.js b/dist/assets/examples/zh-Hans/10_Interaction/24_Wavemaker.js new file mode 100644 index 0000000000..18c8639868 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/24_Wavemaker.js @@ -0,0 +1,37 @@ +/* + * @name 造波器 + * @description 此范例说明了波(如水波)是如何在粒子摆动中产生的。 + * 移动鼠标以引导波浪。 + * 由 Aatish Bhatia 贡献,灵感来自 Dave Whyte 的 Orbiters。 + */ + +let t = 0; // time variable + +function setup() { + createCanvas(600, 600); + noStroke(); + fill(40, 200, 40); +} + +function draw() { + background(10, 10); // 半透明背景(创建足迹) + + // 创建 x 和 y 网格上的椭圆 + for (let x = 0; x <= width; x = x + 30) { + for (let y = 0; y <= height; y = y + 30) { + // 每个圆的初始位置取决于鼠标位置 + const xAngle = map(mouseX, 0, width, -4 * PI, 4 * PI, true); + const yAngle = map(mouseY, 0, height, -4 * PI, 4 * PI, true); + // 也根据粒子的位置变化 + const angle = xAngle * (x / width) + yAngle * (y / height); + + // 每个粒子绕圈运动 + const myX = x + 20 * cos(2 * PI * t + angle); + const myY = y + 20 * sin(2 * PI * t + angle); + + ellipse(myX, myY, 10); // 绘制粒子 + } + } + + t = t + 0.01; // 更新时间 +} diff --git a/dist/assets/examples/zh-Hans/10_Interaction/25_reach1.js b/dist/assets/examples/zh-Hans/10_Interaction/25_reach1.js new file mode 100644 index 0000000000..d85f4f9025 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/25_reach1.js @@ -0,0 +1,57 @@ +/* + * @name 延伸 1 + * @frame 710,400 + * @description 手臂随鼠标的位置移动,使用 atan2() 计算角度。 + * 基于 Keith Peters 的代码。 + */ +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/dist/assets/examples/zh-Hans/10_Interaction/26_reach2.js b/dist/assets/examples/zh-Hans/10_Interaction/26_reach2.js new file mode 100644 index 0000000000..a086231b62 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/26_reach2.js @@ -0,0 +1,65 @@ +/* + * @name 延伸 2 + * @frame 710,400 + * @description 手臂随鼠标的位置移动,使用 atan2() 计算角度。 + * 基于 Keith Peters 的代码。 + */ +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; // // 设置基础 x 坐标 + y[x.length - 1] = height; // 设置基础 y 坐标 +} + +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/dist/assets/examples/zh-Hans/10_Interaction/27_reach3.js b/dist/assets/examples/zh-Hans/10_Interaction/27_reach3.js new file mode 100644 index 0000000000..2d971864a0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/27_reach3.js @@ -0,0 +1,81 @@ +/* + * @name 延伸 3 + * @frame 710,400 + * @description 手臂随球的位置移动,使用 atan2() 计算角度。 + * 基于 Keith Peters 的代码。 + */ +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; // 设置基础 x 坐标 + y[x.length - 1] = height; // 设置基础 y 坐标 +} + +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/dist/assets/examples/zh-Hans/10_Interaction/28_ArduinoSensor.js b/dist/assets/examples/zh-Hans/10_Interaction/28_ArduinoSensor.js new file mode 100644 index 0000000000..1b23ed2ed4 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/28_ArduinoSensor.js @@ -0,0 +1,34 @@ +/* + * @name 通过 WebJack 读取 Arduino 传感器数据 + * @description WebJack 是使用音频从 Arduino(和其他来源) + * 读取数据的方式 -- 它基本上将 Arduino 变成了音频调制解调器。 + * + * https://github.com/publiclab/webjack + * + * 注: WebJack 和 p5-webjack 库必须以以下方式添加到 index.html: + *
<script src="https://webjack.io/dist/webjack.js"></script>
+ *
<script src="https://jywarren.github.io/p5-webjack/lib.js"></script>
+ * + * 实例: https://editor.p5js.org/jywarren/sketches/rkztwSt8M + * + * 测试音频: https://www.youtube.com/watch?v=GtJW1Dlt3cg + * 将此草图加载到 Arduino: + * https://create.arduino.cc/editor/jywarren/023158d8-be51-4c78-99ff-36c63126b554/preview + * 从引脚 3 + 地引脚(GND)输出音频。请使用使用麦克风或音频线。 + */ + +function setup() { + createCanvas(400, 400); + noStroke(); + fill('#ff00aa22'); + receiveSensorData(handleData); +} + +function handleData(data) { + console.log(data); // 打出数据 + // data[0] 是第一个值, data[1] 是第二个, 以此类推. + + // 绘制! 参考 http://p5js.org/reference/ + background('#ddd'); + ellipse(100, 200, data[0] + 10, data[0] + 10); +} diff --git a/dist/assets/examples/zh-Hans/10_Interaction/29_kaleidoscope.js b/dist/assets/examples/zh-Hans/10_Interaction/29_kaleidoscope.js new file mode 100644 index 0000000000..b4f445fc60 --- /dev/null +++ b/dist/assets/examples/zh-Hans/10_Interaction/29_kaleidoscope.js @@ -0,0 +1,77 @@ +/* + * @name 万花筒 + * @description 万花筒是一个光学仪器,具有两个或多个互相倾斜的反射面。 + * 此范例尝试模仿万花筒的效果。 + * 通过 symmetry 变量设定反射的数量,并开始在屏幕上绘制。 + * 通过 slider 调整画笔的大小。 + * clearScreen(),顾名思义,清空屏幕。 + * save 按钮将你绘制的艺术品以 .jpg 的文件格式下载下来。 + */ +// Symmetry 指反射的次数。更改此数值以改变反射的次数。 +let symmetry = 6; + +let angle = 360 / symmetry; +let saveButton, clearButton, mouseButton, keyboardButton; +let slider; + +function setup() { + createCanvas(710, 710); + angleMode(DEGREES); + background(127); + + // 制作保存文件的按钮 + saveButton = createButton('save'); + saveButton.mousePressed(saveFile); + + // 制作清空屏幕的按钮 + clearButton = createButton('clear'); + clearButton.mousePressed(clearScreen); + + // 制作全屏按钮 + fullscreenButton = createButton('Full Screen'); + fullscreenButton.mousePressed(screenFull); + + // 设置 slider 以改变笔刷的粗细 + brushSizeSlider = createButton('Brush Size Slider'); + sizeSlider = createSlider(1, 32, 4, 0.1); +} + +// 保存文件函数 +function saveFile() { + save('design.jpg'); +} + +// 清空屏幕函数 +function clearScreen() { + background(127); +} + +// 全屏函数 +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/dist/assets/examples/zh-Hans/11_Objects/01_Objects.js b/dist/assets/examples/zh-Hans/11_Objects/01_Objects.js new file mode 100644 index 0000000000..009c6b4dd5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/01_Objects.js @@ -0,0 +1,38 @@ +/* + * @name 物件 (Objects) + * @description 创建一个 Jitter 类, 实例化一个物件,并且在屏幕上移动。 + * 改编自 Processing 入门,作者:Casey Reas 和 Ben Fry + */ + +let bug; // 声明物件 + +function setup() { + createCanvas(710, 400); + // 创造物件 + bug = new Jitter(); +} + +function draw() { + background(50, 89, 100); + bug.move(); + bug.display(); +} + +// Jitter 类 +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/dist/assets/examples/zh-Hans/11_Objects/02_Multiple_Objects.js b/dist/assets/examples/zh-Hans/11_Objects/02_Multiple_Objects.js new file mode 100644 index 0000000000..2268530df0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/02_Multiple_Objects.js @@ -0,0 +1,49 @@ +/* + * @name 多个物件 + * @description 创建一个 Jitter 类,实例化多个物件,并且在屏幕上移动。 + */ + +let bug1; // 声明物件 +let bug2; +let bug3; +let bug4; + +function setup() { + createCanvas(710, 400); + // 创造物件 + 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 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/dist/assets/examples/zh-Hans/11_Objects/03_Objects_Array.js b/dist/assets/examples/zh-Hans/11_Objects/03_Objects_Array.js new file mode 100644 index 0000000000..3e6c383566 --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/03_Objects_Array.js @@ -0,0 +1,41 @@ +/* + * @name 物件数组 + * @description 创建一个 Jitter 类,实例化多个物件,并且在屏幕上移动。 + */ + +let bugs = []; // Jitter 物件的数组 + +function setup() { + createCanvas(710, 400); + // 创造物件 + 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 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/dist/assets/examples/zh-Hans/11_Objects/03_Objects_Optional_Arguments.js b/dist/assets/examples/zh-Hans/11_Objects/03_Objects_Optional_Arguments.js new file mode 100644 index 0000000000..cc6ddc879f --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/03_Objects_Optional_Arguments.js @@ -0,0 +1,64 @@ +/* + * @name 物件 2 + * @description 转自 hbarragan 的范例。在图像上移动光标以更改几何图形的速度和位置。 + * MRect 类定义了一组线。 + */ + +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; // 单线条宽度 + this.xpos = ixp; // rect x 值 + this.h = ih; // rect 高度 + this.ypos = iyp; // rect y 值 + this.d = id; // 单线条间距 + this.t = it; // 单线条数量 + } + + 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/dist/assets/examples/zh-Hans/11_Objects/04_Inheritance.js b/dist/assets/examples/zh-Hans/11_Objects/04_Inheritance.js new file mode 100644 index 0000000000..2218f3c83f --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/04_Inheritance.js @@ -0,0 +1,69 @@ +/* @name 继承 (Inheritance) + * @description 可以用一个类作为基础来定义另一个类。在面向对象的编程术语中, + * 一个类可以继承另一个类的字段 (fields) 和方法 (methods)。 + * 从另一个物件继承了的物件称为子类 (subclass),其继承的物件称为基类 (superclass)。 + * 子类扩展基类。 + */ +let spots, arm; + +function setup() { + createCanvas(640, 360); + arm = new SpinArm(width/2, height/2, 0.01); + spots = new SpinSpots(width/2, height/2, -0.02, 90.0); +} + +function draw() { + background(204); + arm.update(); + arm.display(); + spots.update(); + spots.display(); +} + +class Spin { + constructor(x, y, s) { + this.x = x; + this.y = y; + this.speed = s; + this.angle = 0.0; + } + + update() { + this.angle += this.speed; + } +} + +class SpinArm extends Spin { + constructor(x, y, s) { + super(x, y, s) + } + + display() { + strokeWeight(1); + stroke(0); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + line(0, 0, 165, 0); + pop(); + } +} + +class SpinSpots extends Spin { + constructor(x, y, s, d) { + super(x, y, s) + this.dim = d; + } + + display() { + noStroke(); + push(); + translate(this.x, this.y); + this.angle += this.speed; + rotate(this.angle); + ellipse(-this.dim/2, 0, this.dim, this.dim); + ellipse(this.dim/2, 0, this.dim, this.dim); + pop(); + } +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/11_Objects/05_Composite_Objects.js b/dist/assets/examples/zh-Hans/11_Objects/05_Composite_Objects.js new file mode 100644 index 0000000000..f680925995 --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/05_Composite_Objects.js @@ -0,0 +1,98 @@ +/* @name 复合物件 + * @description 一个物件可以包含多个其他物件。 + * 创造复合物件是使用模块性和程序中构建更高级别的抽象的好方法。 + */ +let er1, er2; + +function setup() { + createCanvas(640, 360); + er1 = new EggRing(width*0.45, height*0.5, 0.1, 120); + er2 = new EggRing(width*0.65, height*0.8, 0.05, 180); +} + +function draw() { + background(0); + er1.transmit(); + er2.transmit(); +} + +class Egg { + constructor(xpos, ypos, t, s) { + this.x = xpos; + this.y = ypos; + this.tilt = t; + this.scalar = s / 100.0; + this.angle = 0.0; + } + + wobble() { + this.tilt = cos(this.angle) / 8; + this.angle += 0.1; + } + + display() { + noStroke(); + fill(255); + push(); + translate(this.x, this.y); + rotate(this.tilt); + scale(this.scalar); + beginShape(); + vertex(0, -100); + bezierVertex(25, -100, 40, -65, 40, -40); + bezierVertex(40, -15, 25, 0, 0, 0); + bezierVertex(-25, 0, -40, -15, -40, -40); + bezierVertex(-40, -65, -25, -100, 0, -100); + endShape(); + pop(); + } +} + +class Ring { + start(xpos, ypos) { + this.x = xpos; + this.y = ypos; + this.on = true; + this.diameter = 1; + } + + grow() { + if (this.on == true) { + this.diameter += 0.5; + if (this.diameter > width*2) { + this.diameter = 0.0; + } + } + } + + display() { + if (this.on == true) { + noFill(); + strokeWeight(4); + stroke(155, 153); + ellipse(this.x, this.y, this.diameter, this.diameter); + } + } +} + +class EggRing { + constructor(x, y, t, sp) { + this.x = x; + this.y = y; + this.t = t; + this.sp = sp; + this.circle = new Ring(); + this.ovoid = new Egg(this.x, this.y, this.t, this.sp); + this.circle.start(this.x, this.y - this.sp/2); + } + + transmit() { + this.ovoid.wobble(); + this.ovoid.display(); + this.circle.grow(); + this.circle.display(); + if (this.circle.on == false) { + this.circle.on = true; + } + } +} diff --git a/dist/assets/examples/zh-Hans/11_Objects/06_Car_Instances.js b/dist/assets/examples/zh-Hans/11_Objects/06_Car_Instances.js new file mode 100644 index 0000000000..1966f9c8e3 --- /dev/null +++ b/dist/assets/examples/zh-Hans/11_Objects/06_Car_Instances.js @@ -0,0 +1,82 @@ +/* + * @name Car Instances + * @frame 400,400 + * @description contributed by + Prof WM Harris, How to create three instances of Car Class and +invoke class methods.
+ A function is created for the canvas setup, and +3 car instances are initialized with different colors and canvas +positions. The speed of each car is set by passing value to the +instance’s start method. A second function calls class methods to +display and move the cars. +*/ +class Car { + /* Constructor expects parameters for + fill color, x and y coordinates that + will be used to initialize class properties. + */ + constructor(cColor, x, y) { + this.color = cColor; + this.doors = 4; + this.isConvertible = false; + this.x = x; + this.y = y; + this.speed = 0; + } + + start(speed) { // method expects parameter! + this.speed = speed; + } + + display() { // method! + fill(this.color); + rect(this.x, this.y, 20, 10); + } + + move() { // method! + this.x += this.speed; + // Wrap x around boundaries + if (this.x < -20) { + this.x = width; + } else if (this.x > width) { + this.x = -20; + } + } +} //end class Car + +let rav4; +let charger; +let nova; + +function setup() { + createCanvas(200, 400); + /* Construct the 3 Cars */ + //constructor expects cColor, x, y + rav4 = new Car("silver", 100, 300); + charger = new Car("gold", 0, 200); + nova = new Car("blue", 200, 100); + nova.doors = 2; //update nova's doors property + + console.log("rav4", rav4); + console.log("charger", charger); + console.log("nova", nova); + + //call start methods of Car instances + //the start method expects a number for speed + rav4.start(2.3); + charger.start(-4); + nova.start(random(-1, 1)); +} + +function draw() { + background("beige"); + + //display and move all 3 Cars + rav4.display(); + charger.display(); + nova.display(); + + rav4.move(); + charger.move(); + nova.move(); +} diff --git a/dist/assets/examples/zh-Hans/12_Lights/02_Directional.js b/dist/assets/examples/zh-Hans/12_Lights/02_Directional.js new file mode 100644 index 0000000000..71d46ea455 --- /dev/null +++ b/dist/assets/examples/zh-Hans/12_Lights/02_Directional.js @@ -0,0 +1,26 @@ +/* + * @name 定向光 + * @frame 710,400 + * @description 移动鼠标改变光线方向。 + * 定向光从一个方向打来,垂直打在一个表面上时会更强,而以平缓的角度打则会更弱。 + * 击打在表面上后,定向光会在所有方向上散射。 + */ +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/dist/assets/examples/zh-Hans/12_Lights/05_Mixture.js b/dist/assets/examples/zh-Hans/12_Lights/05_Mixture.js new file mode 100644 index 0000000000..51abe75dd3 --- /dev/null +++ b/dist/assets/examples/zh-Hans/12_Lights/05_Mixture.js @@ -0,0 +1,43 @@ +/* + * @name 混合光 + * @frame 710,400 (optional) + * @description 展示一个有三种不同光的盒子。 + */ +function setup() { + createCanvas(710, 400, WEBGL); + noStroke(); +} + +function draw() { + background(0); + + // 环境光 + ambientLight(0, 255/4, 0); + + // 设置光的位置,可将坐标想成如下: + // -宽度/2,-高度/2 -------- 宽度/2,-高度/2 + // | | + // | 0,0 | + // | | + // -宽度/2,高度/2--------宽度/2,高度/2 + + // 左侧:蓝色定向光 + directionalLight(0, 0, 255, -1, 0, 0); + + // 计算由中心点至 mouseX 的距离 + let lightX = mouseX - width / 2; + let lightY = mouseY - height / 2; + + // 红色聚光 + // 光的轴位置:lightX, lightY, 500 + // 光的轴方向:0, 0, -1 + spotLight(255, 0, 0, lightX, lightY, 500, 0, 0, -1); + + // 绕 X 轴旋转 + rotateX(-PI/4); + // 绕 Y 轴旋转 + rotateY(PI/4); + + // 将方块放置在 (0, 0, 0),并设大小为 100 + box(100); +} diff --git a/dist/assets/examples/zh-Hans/13_Motion/01_non_orthogonal_reflection.js b/dist/assets/examples/zh-Hans/13_Motion/01_non_orthogonal_reflection.js new file mode 100644 index 0000000000..1d5ed269c5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/01_non_orthogonal_reflection.js @@ -0,0 +1,110 @@ +/* + * @name Non Orthogonal Reflection + * @frame 710,400 (optional) + * @description This is a port by David Blitz of the "Reflection 1" example from processing.org/examples + */ + +//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/dist/assets/examples/zh-Hans/13_Motion/02_Linear_Motion.js b/dist/assets/examples/zh-Hans/13_Motion/02_Linear_Motion.js new file mode 100644 index 0000000000..421f99c104 --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/02_Linear_Motion.js @@ -0,0 +1,24 @@ +/* + * @name Linear + * @frame 720,400 + * @description 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. + */ + +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/dist/assets/examples/zh-Hans/13_Motion/03_Bounce.js b/dist/assets/examples/zh-Hans/13_Motion/03_Bounce.js new file mode 100644 index 0000000000..a3354e015f --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/03_Bounce.js @@ -0,0 +1,44 @@ +/* + * @name Bounce + * @frame 720,400 + * @description When the shape hits the edge of the window, it reverses its direction. + */ + +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/dist/assets/examples/zh-Hans/13_Motion/04_Bouncy_Bubbles.js b/dist/assets/examples/zh-Hans/13_Motion/04_Bouncy_Bubbles.js new file mode 100644 index 0000000000..7347157665 --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/04_Bouncy_Bubbles.js @@ -0,0 +1,95 @@ +/* + * @name Bouncy Bubbles + * @frame 720,400 + * @description based on code from Keith Peters. Multiple-object collision.. + */ + +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/dist/assets/examples/zh-Hans/13_Motion/05_Morph.js b/dist/assets/examples/zh-Hans/13_Motion/05_Morph.js new file mode 100644 index 0000000000..c6479c27d6 --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/05_Morph.js @@ -0,0 +1,93 @@ +/* + * @name Morph + * @frame 720,400 + * @description Changing one shape into another by interpolating vertices from one to another. + */ + +// 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/dist/assets/examples/zh-Hans/13_Motion/06_Moving_On_Curves.js b/dist/assets/examples/zh-Hans/13_Motion/06_Moving_On_Curves.js new file mode 100644 index 0000000000..4c347c7e00 --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/06_Moving_On_Curves.js @@ -0,0 +1,47 @@ +/* + * @name Moving On Curves + * @frame 720,400 + * @description In this example, the circles moves along the curve y = x^4. + * Click the mouse to have it move to a new position. + */ + +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/dist/assets/examples/zh-Hans/13_Motion/07_Circle_Collision.js b/dist/assets/examples/zh-Hans/13_Motion/07_Circle_Collision.js new file mode 100644 index 0000000000..876bc23d6e --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/07_Circle_Collision.js @@ -0,0 +1,145 @@ +/* + * @name Circle Collision + * @frame 710,400 (optional) + * @description This is a port of the "Circle Collision" example from processing.org/examples
This example uses vectors for better visualization of physical Quantity + */ +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]); + } +} diff --git a/dist/assets/examples/zh-Hans/13_Motion/08_Moving_On_Curves.js b/dist/assets/examples/zh-Hans/13_Motion/08_Moving_On_Curves.js new file mode 100644 index 0000000000..4c347c7e00 --- /dev/null +++ b/dist/assets/examples/zh-Hans/13_Motion/08_Moving_On_Curves.js @@ -0,0 +1,47 @@ +/* + * @name Moving On Curves + * @frame 720,400 + * @description In this example, the circles moves along the curve y = x^4. + * Click the mouse to have it move to a new position. + */ + +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/dist/assets/examples/zh-Hans/15_Instance_Mode/01_Instantiating.js b/dist/assets/examples/zh-Hans/15_Instance_Mode/01_Instantiating.js new file mode 100644 index 0000000000..592f0a3dcf --- /dev/null +++ b/dist/assets/examples/zh-Hans/15_Instance_Mode/01_Instantiating.js @@ -0,0 +1,34 @@ +/* + * @name 创建实例 + * @description 创建一个 p5 实例,以便让所有变量在全局作用域之外。 + */ +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); + +// “全局模式” 作为对照 +// 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/dist/assets/examples/zh-Hans/15_Instance_Mode/02_Instance_Container.js b/dist/assets/examples/zh-Hans/15_Instance_Mode/02_Instance_Container.js new file mode 100644 index 0000000000..3b901c7348 --- /dev/null +++ b/dist/assets/examples/zh-Hans/15_Instance_Mode/02_Instance_Container.js @@ -0,0 +1,90 @@ +/* + * @norender + * @name 实例容器 + * @description 第二个参数可以是你指定作为画布的默认容器,也可以是任何 + 你想要添加此 p5 实例容器至的元素。可以是带 ID 的 html 元素, 也可以是 html 节点本身。 + * + * 以下列举了三种选择 DOM 元素作为容器的方法。 + * 所有由 p5 创建的 DOM 元素(画布,按钮,div 等)都会被添加到指定的 DOM 元素上, + * 这个指定元素就是调用 p5() 时传递的第二个参数。 + */ + + + + + + +
+ + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/16_Dom/03_Input_Button.js b/dist/assets/examples/zh-Hans/16_Dom/03_Input_Button.js new file mode 100644 index 0000000000..d3aaf9cc42 --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/03_Input_Button.js @@ -0,0 +1,38 @@ +/* + * @name Input and Button + * @description Input text and click the button to see it affect the the canvas. + */ +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/dist/assets/examples/zh-Hans/16_Dom/04_Slider.js b/dist/assets/examples/zh-Hans/16_Dom/04_Slider.js new file mode 100644 index 0000000000..6cb48ced1c --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/04_Slider.js @@ -0,0 +1,30 @@ +/* + * @name Slider + * @description Move the sliders to control the R, G, B values of the background. + */ +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/dist/assets/examples/zh-Hans/16_Dom/07_Modify_DOM.js b/dist/assets/examples/zh-Hans/16_Dom/07_Modify_DOM.js new file mode 100644 index 0000000000..9ac89b7595 --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/07_Modify_DOM.js @@ -0,0 +1,54 @@ +/* + * @name Modifying the DOM + * @frame 710,300 + * @description Create DOM elements and modify their properties every time + * draw() is called. + */ +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/dist/assets/examples/zh-Hans/16_Dom/08_Video.js b/dist/assets/examples/zh-Hans/16_Dom/08_Video.js new file mode 100644 index 0000000000..0078d2d793 --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/08_Video.js @@ -0,0 +1,29 @@ +/* + * @name Video + * @frame 710,250 + * @description Load a video with multiple formats and toggle between playing + * and paused with a button press. + */ +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/dist/assets/examples/zh-Hans/16_Dom/09_Video_Canvas.js b/dist/assets/examples/zh-Hans/16_Dom/09_Video_Canvas.js new file mode 100644 index 0000000000..2a59151e06 --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/09_Video_Canvas.js @@ -0,0 +1,27 @@ +/* + * @name Video Canvas + * @description Load a video with multiple formats and draw it to the canvas. + * To run this example locally, you will need a running + * local server. + */ +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/dist/assets/examples/zh-Hans/16_Dom/10_Video_Pixels.js b/dist/assets/examples/zh-Hans/16_Dom/10_Video_Pixels.js new file mode 100644 index 0000000000..9169e37a3d --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/10_Video_Pixels.js @@ -0,0 +1,32 @@ +/* + * @name Video Pixels + * @frame 320,240 + * @description Load a video, manipulate its pixels and draw to canvas. + * To run this example locally, you will need a running + * local server. + */ +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/dist/assets/examples/zh-Hans/16_Dom/11_Capture.js b/dist/assets/examples/zh-Hans/16_Dom/11_Capture.js new file mode 100644 index 0000000000..4e22e6afef --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/11_Capture.js @@ -0,0 +1,24 @@ +/* + * @name Video Capture + * @frame 710,240 + * @description 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. + * To run this example locally, you will need a running + * local server. + */ +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/dist/assets/examples/zh-Hans/16_Dom/12_Drop.js b/dist/assets/examples/zh-Hans/16_Dom/12_Drop.js new file mode 100644 index 0000000000..a36665e460 --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/12_Drop.js @@ -0,0 +1,33 @@ +/* + * @name Drop + * @description Drag an image file onto the canvas to see it displayed. + */ + +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 { + println('Not an image file!'); + } +} diff --git a/dist/assets/examples/zh-Hans/16_Dom/13_DOM_Form_Elements.js b/dist/assets/examples/zh-Hans/16_Dom/13_DOM_Form_Elements.js new file mode 100644 index 0000000000..d83dfdc13e --- /dev/null +++ b/dist/assets/examples/zh-Hans/16_Dom/13_DOM_Form_Elements.js @@ -0,0 +1,152 @@ +/* + * @name DOM Form Elements + * @frame 600,400 + * @description contributed by + Prof WM Harris, How to use p5 DOM form elements to create a slider, +button, checkbox, radio group, select menu, and entry field.
+Functions are created that include: the canvas +setup, checkbox creation with text, text box with text that projects +typed text onto canvas, slider with button, three selections which +project a rectangle in different areas on the canvas depending on +selection, and a drop down menu with font change. +*/ + +/* global variables */ +//p5 DOM form elements +let slider1; +let button1; +let checkbox1; +let radio1; +let select1; +let entry1; + +function setup() { + createCanvas(200, 200); + background("beige"); + + checkbox1 = createCheckbox("Check me"); + + createP(); //spacer with

tag + + createSpan("What's your name? "); //label for entry1 + // createInput([value], [type]) + // type: "text" (default), "number", + // "date", "password", "email", etc. + entry1 = createInput(); + //If text in the entry field changes, call + //the entryCallback function. + entry1.changed(entryCallback); + + createP(); //spacer with

tag + + //createSlider(min, max, [value], [step]) + slider1 = createSlider(10, 200); + + button1 = createButton("Press me"); //, "pressed"); + //Assign callback fcn for button1 + //when user clicks mouse on it + button1.mouseClicked(button1Clicked); + + createP(); //spacer with

tag + + radio1 = createRadio(); + + //.option([value], [contentLabel]) + //If 1 param, it's both content AND + //value. Values treated as strings. + radio1.option(1, "cranberries"); + radio1.option(2, "almonds"); + radio1.option(3, "gouda"); + + radio1.value("1"); //set init value + + createP(); //spacer with

tag + + select1 = createSelect(); + //.option([contentValue],[value]) + //If 1 param, it's both content AND + //value. Values treated as strings. + select1.option("Sans-serif"); + select1.option("Serif"); + select1.option("Fantasy"); + //If changed, call select1Changed + select1.changed(select1Changed); +} + +function draw() { + //get value from slider 1 + let gray = slider1.value(); + fill(gray); + + //If mouse in corner, turn on checkbox1 + if ((mouseX < width / 3) && + (mouseY < height / 3)) { + checkbox1.checked(true); + } + //Is checkbox1 checked? Say so. + if (checkbox1.checked()) { + text("CHECKED", 20, 40); + } + + switch (radio1.value()) { + //radio value is always a string + case "1": + rect(0, 0, width, 50); + break; + case "2": + rect(0, 70, width, 50); + break; + case "3": + rect(0, 140, width, 50); + break; + } +} + +//callback fcn for button1 +function button1Clicked() { + //reset slider value to 200 + slider1.value(200); +} + + +//callback fcn for select1 +function select1Changed() { + switch (select1.value()) { + case "Sans-serif": + textFont("sans-serif"); + break; + case "Serif": + textFont("serif"); + break; + case "Fantasy": + textFont("fantasy"); + break; + } +} + +//callback function for entry1 +function entryCallback() { + for (let i = 0; i < 25; i++) { + text(entry1.value(), random(width), + random(height)); + } + +} + +function mouseClicked() { + console.log("button1?", button1.value()); + console.log("checkbox1?", checkbox1.value()); + //Update .value of either? No visible change + //to a button or checkbox + checkbox1.value("Check again"); + button1.value("clicked?"); +} + +function keyTyped() { + switch (key) { + case "r": + //move slider1 value to 100 + slider1.value(100); + break; + } +} diff --git a/dist/assets/examples/zh-Hans/17_Drawing/00_Continuous_Lines.js b/dist/assets/examples/zh-Hans/17_Drawing/00_Continuous_Lines.js new file mode 100644 index 0000000000..f0a598656f --- /dev/null +++ b/dist/assets/examples/zh-Hans/17_Drawing/00_Continuous_Lines.js @@ -0,0 +1,15 @@ +/* + * @name Líneas continuas + * @description Haga clic y arrastre el mouse para dibujar una línea. + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + stroke(255); + if (mouseIsPressed === true) { + line(mouseX, mouseY, pmouseX, pmouseY); + } +} diff --git a/dist/assets/examples/zh-Hans/17_Drawing/01_Pattern.js b/dist/assets/examples/zh-Hans/17_Drawing/01_Pattern.js new file mode 100644 index 0000000000..5f3401737d --- /dev/null +++ b/dist/assets/examples/zh-Hans/17_Drawing/01_Pattern.js @@ -0,0 +1,26 @@ +/* + * @name Patrones + * @description Mueva el cursor sobre la imagen para dibujar con una herramienta + * de software que responda a la velocidad del mouse. + */ +function setup() { + createCanvas(710, 400); + background(102); +} + +function draw() { + // Llame al método variableEllipse () y envíele los parámetros + // para la posición actual del mouse y la posición anterior del mouse + variableEllipse(mouseX, mouseY, pmouseX, pmouseY); +} + +// El método simple variableEllipse () fue creado específicamente +// para este programa. Calcula la velocidad del mouse +// y dibuja una pequeña elipse si el mouse se mueve lentamente +// y dibuja una elipse grande si el mouse se mueve rápidamente + +function variableEllipse(x, y, px, py) { + let speed = abs(x - px) + abs(y - py); + stroke(speed); + ellipse(x, y, speed, speed); +} diff --git a/dist/assets/examples/zh-Hans/17_Drawing/02_Pulses.js b/dist/assets/examples/zh-Hans/17_Drawing/02_Pulses.js new file mode 100644 index 0000000000..b808a4ece0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/17_Drawing/02_Pulses.js @@ -0,0 +1,31 @@ +/* + * @name Pulsos + * @description Los instrumentos de dibujo de software pueden seguir un ritmo o + * cumplir las reglas independientemente de los gestos dibujados. Esta es una + * forma de dibujo colaborativo en el que el dibujante controla algunos aspectos + * de la imagen y el software controla a los demás. + */ +let angle = 0; + +function setup() { + createCanvas(710, 400); + background(102); + noStroke(); + fill(0, 102); +} + +function draw() { + // Dibujar solo cuando se presiona el mouse + 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/dist/assets/examples/zh-Hans/18_Transform/00_Translate.js b/dist/assets/examples/zh-Hans/18_Transform/00_Translate.js new file mode 100644 index 0000000000..1599f1cf4f --- /dev/null +++ b/dist/assets/examples/zh-Hans/18_Transform/00_Translate.js @@ -0,0 +1,40 @@ +/* + * @name Translate + * @description 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. + */ + +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/dist/assets/examples/zh-Hans/18_Transform/01_Scale.js b/dist/assets/examples/zh-Hans/18_Transform/01_Scale.js new file mode 100644 index 0000000000..d176f25680 --- /dev/null +++ b/dist/assets/examples/zh-Hans/18_Transform/01_Scale.js @@ -0,0 +1,46 @@ +/* + * @name Scale + * @description 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. + */ + +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/dist/assets/examples/zh-Hans/18_Transform/02_Rotate.js b/dist/assets/examples/zh-Hans/18_Transform/02_Rotate.js new file mode 100644 index 0000000000..6b91dc2186 --- /dev/null +++ b/dist/assets/examples/zh-Hans/18_Transform/02_Rotate.js @@ -0,0 +1,43 @@ +/* + * @name Rotate + * @description 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: scale(radians(90)) is identical to the statement + * scale(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. + */ + +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/dist/assets/examples/zh-Hans/18_Transform/03_Arm.js b/dist/assets/examples/zh-Hans/18_Transform/03_Arm.js new file mode 100644 index 0000000000..733fe30909 --- /dev/null +++ b/dist/assets/examples/zh-Hans/18_Transform/03_Arm.js @@ -0,0 +1,49 @@ +/* + * @name Arm + * @description 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. + */ + +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/dist/assets/examples/zh-Hans/19_Typography/00_Letters.js b/dist/assets/examples/zh-Hans/19_Typography/00_Letters.js new file mode 100644 index 0000000000..44d4f2a7ee --- /dev/null +++ b/dist/assets/examples/zh-Hans/19_Typography/00_Letters.js @@ -0,0 +1,64 @@ +/* + * @name Letters + * @description 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. + */ +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 (y = 0; y < height - gap; y += gap) { + for (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/dist/assets/examples/zh-Hans/19_Typography/01_Words.js b/dist/assets/examples/zh-Hans/19_Typography/01_Words.js new file mode 100644 index 0000000000..d76271f2b8 --- /dev/null +++ b/dist/assets/examples/zh-Hans/19_Typography/01_Words.js @@ -0,0 +1,59 @@ +/* + * @name Words + * @description 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(). + */ +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/dist/assets/examples/zh-Hans/19_Typography/02_Text_Rotation.js b/dist/assets/examples/zh-Hans/19_Typography/02_Text_Rotation.js new file mode 100644 index 0000000000..fdfd7d31a5 --- /dev/null +++ b/dist/assets/examples/zh-Hans/19_Typography/02_Text_Rotation.js @@ -0,0 +1,62 @@ +/* + * @name Text Rotation + * @description Draws letters to the screen and rotates them at different angles. + * (ported from https://processing.org/examples/textrotation.html) + */ + +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); +} diff --git a/dist/assets/examples/zh-Hans/20_3D/00_geometries.js b/dist/assets/examples/zh-Hans/20_3D/00_geometries.js new file mode 100644 index 0000000000..a58cce64e8 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/00_geometries.js @@ -0,0 +1,60 @@ +/* + * @name Geometries + * @description There are six 3D primitives in p5 now. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + + translate(-240, -100, 0); + normalMaterial(); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + plane(70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + box(70, 70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cylinder(70, 70); + pop(); + + translate(-240 * 2, 200, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + cone(70, 70); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + torus(70, 20); + pop(); + + translate(240, 0, 0); + push(); + rotateZ(frameCount * 0.01); + rotateX(frameCount * 0.01); + rotateY(frameCount * 0.01); + sphere(70); + pop(); +} diff --git a/dist/assets/examples/zh-Hans/20_3D/01_sine_cosine_in_3D.js b/dist/assets/examples/zh-Hans/20_3D/01_sine_cosine_in_3D.js new file mode 100644 index 0000000000..d9adf11963 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/01_sine_cosine_in_3D.js @@ -0,0 +1,28 @@ +/* + * @name Sine Cosine in 3D + * @description Sine, cosine and push / pop could be applied in 3D as well. + */ +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/dist/assets/examples/zh-Hans/20_3D/02_multiple_lights.js b/dist/assets/examples/zh-Hans/20_3D/02_multiple_lights.js new file mode 100644 index 0000000000..7bed590f63 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/02_multiple_lights.js @@ -0,0 +1,30 @@ +/* + * @name Multiple Lights + * @description All types of lights could be used in one sketch. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(0); + + let locX = mouseX - height / 2; + let locY = mouseY - width / 2; + + ambientLight(50); + directionalLight(255, 0, 0, 0.25, 0.25, 0); + 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, 64); +} diff --git a/dist/assets/examples/zh-Hans/20_3D/03_materials.js b/dist/assets/examples/zh-Hans/20_3D/03_materials.js new file mode 100644 index 0000000000..4dd7e97e37 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/03_materials.js @@ -0,0 +1,65 @@ +/* + * @name Materials + * @description There are five types of materials supported. + * They respond to light differently. + * Move your mouse to change the light position. + */ +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/dist/assets/examples/zh-Hans/20_3D/04_textures.js b/dist/assets/examples/zh-Hans/20_3D/04_textures.js new file mode 100644 index 0000000000..0a4df84872 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/04_textures.js @@ -0,0 +1,40 @@ +/* + * @name Textures + * @description Images and videos are supported for texture. + */ +// 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/dist/assets/examples/zh-Hans/20_3D/05_ray_casting.js b/dist/assets/examples/zh-Hans/20_3D/05_ray_casting.js new file mode 100644 index 0000000000..98906dcb28 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/05_ray_casting.js @@ -0,0 +1,100 @@ +/* + * @name Ray Casting + * @description Original example by Jonathan Watson. + *

Detecting the position of the mouse in 3D space with ray casting. + */ +const objects = []; +let eyeZ; + +function setup() { + createCanvas(710, 400, WEBGL); + + eyeZ = height / 2 / tan((30 * PI) / 180); // 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); + } +} diff --git a/dist/assets/examples/zh-Hans/20_3D/07_orbit_control.js b/dist/assets/examples/zh-Hans/20_3D/07_orbit_control.js new file mode 100644 index 0000000000..7d30f82cbd --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/07_orbit_control.js @@ -0,0 +1,36 @@ +/* + * @name Orbit Control + * @description Orbit control allows you to drag and move around the world. + */ +function setup() { + createCanvas(710, 400, WEBGL); +} + +function draw() { + background(250); + let radius = width * 1.5; + + //drag to move the world. + orbitControl(); + + normalMaterial(); + translate(0, 0, -600); + 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/dist/assets/examples/zh-Hans/20_3D/08_basic_shader.js b/dist/assets/examples/zh-Hans/20_3D/08_basic_shader.js new file mode 100644 index 0000000000..32610c79e4 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/08_basic_shader.js @@ -0,0 +1,27 @@ +/* + * @name Basic Shader + * @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 + */ + +// 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); +} diff --git a/dist/assets/examples/zh-Hans/20_3D/09_shader_as_a_texture.js b/dist/assets/examples/zh-Hans/20_3D/09_shader_as_a_texture.js new file mode 100644 index 0000000000..7bffbab11b --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/09_shader_as_a_texture.js @@ -0,0 +1,68 @@ +/* + * @name Shader as a Texture + * @description Shaders can be applied to 2D/3D shapes as textures. + *
To learn more about using shaders in p5.js: p5.js Shaders + */ + + // 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); + } diff --git a/dist/assets/examples/zh-Hans/20_3D/10_passing_shader_uniforms.js b/dist/assets/examples/zh-Hans/20_3D/10_passing_shader_uniforms.js new file mode 100644 index 0000000000..3d6dc2ec1b --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/10_passing_shader_uniforms.js @@ -0,0 +1,33 @@ +/* + * @name Passing Shader Uniforms + * @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 + */ + + // 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(); + } + + function draw() { + // shader() sets the active shader with our shader + shader(theShader); + + // lets send the resolution, mouse, and time to our shader + // before sending mouse + time we modify the data so it's more easily usable by the shader + theShader.setUniform('resolution', [width, height]); + 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); + } diff --git a/dist/assets/examples/zh-Hans/20_3D/11_shader_using_webcam.js b/dist/assets/examples/zh-Hans/20_3D/11_shader_using_webcam.js new file mode 100644 index 0000000000..9e14ebe086 --- /dev/null +++ b/dist/assets/examples/zh-Hans/20_3D/11_shader_using_webcam.js @@ -0,0 +1,38 @@ +/* + * @name Shader Using Webcam + * @description The webcam can be passed to shaders as a texture. + *
To learn more about using shaders in p5.js: p5.js Shaders + */ + +// 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 sizeVideo() { + cam.size(710, 400); + cam.hide(); +} +function setup() { + // shaders require WEBGL mode to work + createCanvas(710, 400, WEBGL); + noStroke(); + + cam = createCapture(VIDEO, sizeVideo); +} + +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); +} diff --git a/dist/assets/examples/zh-Hans/21_Input/00_Clock.js b/dist/assets/examples/zh-Hans/21_Input/00_Clock.js new file mode 100644 index 0000000000..5603db0f3e --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/00_Clock.js @@ -0,0 +1,62 @@ +/* + * @name Clock + * @description 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. + */ +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/dist/assets/examples/zh-Hans/21_Input/01_Constrain.js b/dist/assets/examples/zh-Hans/21_Input/01_Constrain.js new file mode 100644 index 0000000000..36a08abd31 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/01_Constrain.js @@ -0,0 +1,36 @@ +/* + * @name Constrain + * @description Move the mouse across the screen to move + * the circle. The program constrains the circle to its box. + */ +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/dist/assets/examples/zh-Hans/21_Input/02_Easing.js b/dist/assets/examples/zh-Hans/21_Input/02_Easing.js new file mode 100644 index 0000000000..6fe01dc1b0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/02_Easing.js @@ -0,0 +1,30 @@ +/* + * @name Easing + * @description 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. + */ +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/dist/assets/examples/zh-Hans/21_Input/03_Keyboard.js b/dist/assets/examples/zh-Hans/21_Input/03_Keyboard.js new file mode 100644 index 0000000000..c7b50f99a3 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/03_Keyboard.js @@ -0,0 +1,38 @@ +/* + * @name Keyboard + * @description 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. + */ +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/dist/assets/examples/zh-Hans/21_Input/04_Mouse1D.js b/dist/assets/examples/zh-Hans/21_Input/04_Mouse1D.js new file mode 100644 index 0000000000..eb613fbab9 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/04_Mouse1D.js @@ -0,0 +1,24 @@ +/* + * @name Mouse 1D + * @description 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. + */ +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/dist/assets/examples/zh-Hans/21_Input/05_Mouse2D.js b/dist/assets/examples/zh-Hans/21_Input/05_Mouse2D.js new file mode 100644 index 0000000000..efc623adae --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/05_Mouse2D.js @@ -0,0 +1,20 @@ +/* + * @name Mouse 2D + * @description Moving the mouse changes the position and + * size of each box. + */ +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/dist/assets/examples/zh-Hans/21_Input/06_MouseIsPressed.js b/dist/assets/examples/zh-Hans/21_Input/06_MouseIsPressed.js new file mode 100644 index 0000000000..27279e99b0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/06_MouseIsPressed.js @@ -0,0 +1,20 @@ +/* + * @name Mouse Press + * @description Move the mouse to position the shape. + * Press the mouse button to invert the color. + */ +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/dist/assets/examples/zh-Hans/21_Input/07_Mouse_Functions.js b/dist/assets/examples/zh-Hans/21_Input/07_Mouse_Functions.js new file mode 100644 index 0000000000..ad1acdc7b2 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/07_Mouse_Functions.js @@ -0,0 +1,66 @@ +/* + * @name Mouse Functions + * @description Click on the box and drag it across the screen. + */ +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/dist/assets/examples/zh-Hans/21_Input/08_Mouse_Signals.js b/dist/assets/examples/zh-Hans/21_Input/08_Mouse_Signals.js new file mode 100644 index 0000000000..8847fe8f1c --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/08_Mouse_Signals.js @@ -0,0 +1,52 @@ +/* + * @name Mouse Signals + * @description 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". + */ +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/dist/assets/examples/zh-Hans/21_Input/09_Storing_Input.js b/dist/assets/examples/zh-Hans/21_Input/09_Storing_Input.js new file mode 100644 index 0000000000..563ff80759 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/09_Storing_Input.js @@ -0,0 +1,38 @@ +/* + * @name Storing Input + * @description 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. + */ +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/dist/assets/examples/zh-Hans/21_Input/10_Rollover.js b/dist/assets/examples/zh-Hans/21_Input/10_Rollover.js new file mode 100644 index 0000000000..09ebd6648c --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/10_Rollover.js @@ -0,0 +1,79 @@ +/* + * @name Rollover + * @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 + */ +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; + } +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/21_Input/11_Storing_Input.js b/dist/assets/examples/zh-Hans/21_Input/11_Storing_Input.js new file mode 100644 index 0000000000..563ff80759 --- /dev/null +++ b/dist/assets/examples/zh-Hans/21_Input/11_Storing_Input.js @@ -0,0 +1,38 @@ +/* + * @name Storing Input + * @description 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. + */ +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/dist/assets/examples/zh-Hans/22_Advanced_Data/00_Load_Saved_JSON.js b/dist/assets/examples/zh-Hans/22_Advanced_Data/00_Load_Saved_JSON.js new file mode 100644 index 0000000000..7d3e8f4b66 --- /dev/null +++ b/dist/assets/examples/zh-Hans/22_Advanced_Data/00_Load_Saved_JSON.js @@ -0,0 +1,104 @@ +/* + * @name Load Saved JSON + * @description Create a Bubble class, instantiate multiple bubbles using data from + * a JSON file, and display results on the screen. + * Because the 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. + */ + +// 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); +} diff --git a/dist/assets/examples/zh-Hans/22_Advanced_Data/01_Load_Saved_Table.js b/dist/assets/examples/zh-Hans/22_Advanced_Data/01_Load_Saved_Table.js new file mode 100644 index 0000000000..8536abcccc --- /dev/null +++ b/dist/assets/examples/zh-Hans/22_Advanced_Data/01_Load_Saved_Table.js @@ -0,0 +1,110 @@ +/* + * @name Load Saved Table + * @description Create a Bubble class, instantiate multiple bubbles using data from + * a csv file, and display results on the screen. + * Because the web browsers differ in where they save files, we do not make use of + * + * Based on Daniel Shiffman's LoadSaveTable Example for Processing. + */ + +// 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); +} diff --git a/dist/assets/examples/zh-Hans/33_Sound/00_Load_and_Play_Sound.js b/dist/assets/examples/zh-Hans/33_Sound/00_Load_and_Play_Sound.js new file mode 100644 index 0000000000..feffaffdc7 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/00_Load_and_Play_Sound.js @@ -0,0 +1,25 @@ +/* + * @name Load and Play Sound + * @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. + */ +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); + } +} diff --git a/dist/assets/examples/zh-Hans/33_Sound/01_Preload_Sound.js b/dist/assets/examples/zh-Hans/33_Sound/01_Preload_Sound.js new file mode 100644 index 0000000000..08c419179e --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/01_Preload_Sound.js @@ -0,0 +1,34 @@ +/* + * @name Preload SoundFile + * @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. + */ + +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); + } +} diff --git a/dist/assets/examples/zh-Hans/33_Sound/02_soundFormats.js b/dist/assets/examples/zh-Hans/33_Sound/02_soundFormats.js new file mode 100644 index 0000000000..ae7571fb01 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/02_soundFormats.js @@ -0,0 +1,54 @@ +/** + * @name soundFormats + * @description

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/03_Play_Mode.js b/dist/assets/examples/zh-Hans/33_Sound/03_Play_Mode.js new file mode 100644 index 0000000000..3b89691dee --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/03_Play_Mode.js @@ -0,0 +1,42 @@ +/* + * @name Play Mode + * @description + *

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/04_Pan_SoundFile.js b/dist/assets/examples/zh-Hans/33_Sound/04_Pan_SoundFile.js new file mode 100644 index 0000000000..b1d881db36 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/04_Pan_SoundFile.js @@ -0,0 +1,34 @@ +/* + * @name Pan Sound + * @description

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.

+ * + */ +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/dist/assets/examples/zh-Hans/33_Sound/05_Sound_Effect.js b/dist/assets/examples/zh-Hans/33_Sound/05_Sound_Effect.js new file mode 100644 index 0000000000..0839b9d7fb --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/05_Sound_Effect.js @@ -0,0 +1,69 @@ +/* + * @name Sound Effect + * @description

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.

+ */ +// 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/dist/assets/examples/zh-Hans/33_Sound/06_Manipulate_Sound.js b/dist/assets/examples/zh-Hans/33_Sound/06_Manipulate_Sound.js new file mode 100644 index 0000000000..60ad548038 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/06_Manipulate_Sound.js @@ -0,0 +1,49 @@ +/* + * @name Playback Rate + * @description

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.

+ */ +// 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/dist/assets/examples/zh-Hans/33_Sound/07_Amplitude_Analysis.js b/dist/assets/examples/zh-Hans/33_Sound/07_Amplitude_Analysis.js new file mode 100644 index 0000000000..7bf3446e4f --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/07_Amplitude_Analysis.js @@ -0,0 +1,50 @@ +/** + * @name Measuring Amplitude + * @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.

+ */ +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); +} diff --git a/dist/assets/examples/zh-Hans/33_Sound/08_Noise_Envelope.js b/dist/assets/examples/zh-Hans/33_Sound/08_Noise_Envelope.js new file mode 100644 index 0000000000..b38e423c75 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/08_Noise_Envelope.js @@ -0,0 +1,54 @@ +/** + * @name Noise Drum Envelope + * @description

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/09_Note_Envelope.js b/dist/assets/examples/zh-Hans/33_Sound/09_Note_Envelope.js new file mode 100644 index 0000000000..4b9122d244 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/09_Note_Envelope.js @@ -0,0 +1,61 @@ +/** + * @name Note Envelope + * @description

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/10_Oscillator_Waveform.js b/dist/assets/examples/zh-Hans/33_Sound/10_Oscillator_Waveform.js new file mode 100644 index 0000000000..4737680b81 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/10_Oscillator_Waveform.js @@ -0,0 +1,40 @@ +/* + * @name Oscillator Frequency + * @description

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/11_Live_Input.js b/dist/assets/examples/zh-Hans/33_Sound/11_Live_Input.js new file mode 100644 index 0000000000..30136d62a0 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/11_Live_Input.js @@ -0,0 +1,36 @@ +/** + * @name Mic Input + * @description

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/12_FFT_Spectrum.js b/dist/assets/examples/zh-Hans/33_Sound/12_FFT_Spectrum.js new file mode 100644 index 0000000000..9bc8dedfd7 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/12_FFT_Spectrum.js @@ -0,0 +1,30 @@ +/** + * @name Frequency Spectrum + * @description

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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/13_Mic_Threshold.js b/dist/assets/examples/zh-Hans/33_Sound/13_Mic_Threshold.js new file mode 100644 index 0000000000..4c765b059d --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/13_Mic_Threshold.js @@ -0,0 +1,49 @@ +/** + * @name Mic Threshold + * @description

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.

+ */ +// 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/dist/assets/examples/zh-Hans/33_Sound/14_Filter_LowPass.js b/dist/assets/examples/zh-Hans/33_Sound/14_Filter_LowPass.js new file mode 100644 index 0000000000..d1337ed63e --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/14_Filter_LowPass.js @@ -0,0 +1,62 @@ +/** + * @name Filter LowPass + * @description 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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/15_Filter_BandPass.js b/dist/assets/examples/zh-Hans/33_Sound/15_Filter_BandPass.js new file mode 100644 index 0000000000..5e128fcec1 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/15_Filter_BandPass.js @@ -0,0 +1,51 @@ +/** + * @name Filter BandPass + * @description 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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/16_Delay.js b/dist/assets/examples/zh-Hans/33_Sound/16_Delay.js new file mode 100644 index 0000000000..0027b42f73 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/16_Delay.js @@ -0,0 +1,56 @@ +/** + * @name Delay + * @description + * 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.

+ */ + +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/dist/assets/examples/zh-Hans/33_Sound/17_Reverb.js b/dist/assets/examples/zh-Hans/33_Sound/17_Reverb.js new file mode 100644 index 0000000000..db99aa3ed1 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/17_Reverb.js @@ -0,0 +1,36 @@ +/** + * @name Reverb + * @description 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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/18_Convolution_Reverb.js b/dist/assets/examples/zh-Hans/33_Sound/18_Convolution_Reverb.js new file mode 100644 index 0000000000..bfcfecb57e --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/18_Convolution_Reverb.js @@ -0,0 +1,87 @@ +/** + * @name Convolution Reverb + * @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

+ */ +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(); +} diff --git a/dist/assets/examples/zh-Hans/33_Sound/19_Record_Save.js b/dist/assets/examples/zh-Hans/33_Sound/19_Record_Save.js new file mode 100644 index 0000000000..b44b7379a8 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/19_Record_Save.js @@ -0,0 +1,58 @@ +/** + * @name Record Save Audio + * @description 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.

+ */ +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/dist/assets/examples/zh-Hans/33_Sound/21_FreqModulation.js b/dist/assets/examples/zh-Hans/33_Sound/21_FreqModulation.js new file mode 100644 index 0000000000..ab51e8bc61 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/21_FreqModulation.js @@ -0,0 +1,148 @@ +/** + * @name Frequency Modulation + * @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.

+ */ + +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); + }); +} diff --git a/dist/assets/examples/zh-Hans/33_Sound/22_AmplitudeModulation.js b/dist/assets/examples/zh-Hans/33_Sound/22_AmplitudeModulation.js new file mode 100644 index 0000000000..bc77cbd091 --- /dev/null +++ b/dist/assets/examples/zh-Hans/33_Sound/22_AmplitudeModulation.js @@ -0,0 +1,95 @@ +/** + * @name Amplitude Modulation + * @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.

+ */ +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); +} diff --git a/dist/assets/examples/zh-Hans/35_Mobile/00_Acceleration_Ball_Bounce.js b/dist/assets/examples/zh-Hans/35_Mobile/00_Acceleration_Ball_Bounce.js new file mode 100644 index 0000000000..0942148573 --- /dev/null +++ b/dist/assets/examples/zh-Hans/35_Mobile/00_Acceleration_Ball_Bounce.js @@ -0,0 +1,58 @@ +/* + * @name Acceleration Ball Bounce + * @description Move an ellipse around based on accelerationX and accelerationY values, and bounces when touch the edge of the canvas. + */ + +// 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/dist/assets/examples/zh-Hans/35_Mobile/01_Simple_Draw.js b/dist/assets/examples/zh-Hans/35_Mobile/01_Simple_Draw.js new file mode 100644 index 0000000000..80cddb8562 --- /dev/null +++ b/dist/assets/examples/zh-Hans/35_Mobile/01_Simple_Draw.js @@ -0,0 +1,15 @@ +/* + * @name Simple Draw + * @description Touch to draw on the screen using mouseX, mouseY, pmouseX, and pmouseY values. + */ + +function setup() { + createCanvas(displayWidth, displayHeight); + strokeWeight(10); + stroke(0); +} + +function touchMoved() { + line(mouseX, mouseY, pmouseX, pmouseY); + return false; +} diff --git a/dist/assets/examples/zh-Hans/35_Mobile/02_Acceleration_Color.js b/dist/assets/examples/zh-Hans/35_Mobile/02_Acceleration_Color.js new file mode 100644 index 0000000000..a7183d1def --- /dev/null +++ b/dist/assets/examples/zh-Hans/35_Mobile/02_Acceleration_Color.js @@ -0,0 +1,24 @@ +/* + * @name Acceleration Color + * @description Use deviceMoved() to detect when the device is rotated. The background RGB color values are mapped to accelerationX, accelerationY, and accelerationZ values. + */ + +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/dist/assets/examples/zh-Hans/35_Mobile/03_Shake_Ball_Bounce.js b/dist/assets/examples/zh-Hans/35_Mobile/03_Shake_Ball_Bounce.js new file mode 100644 index 0000000000..5d2880dbe7 --- /dev/null +++ b/dist/assets/examples/zh-Hans/35_Mobile/03_Shake_Ball_Bounce.js @@ -0,0 +1,114 @@ +/* + * @name Shake Ball Bounce + * @description 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. + */ + +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/dist/assets/examples/zh-Hans/35_Mobile/04_Tilted_3D_Box.js b/dist/assets/examples/zh-Hans/35_Mobile/04_Tilted_3D_Box.js new file mode 100644 index 0000000000..ea39b5414f --- /dev/null +++ b/dist/assets/examples/zh-Hans/35_Mobile/04_Tilted_3D_Box.js @@ -0,0 +1,15 @@ +/* + * @name Tilted 3D Box + * @description Use mobile to tilt a box + */ +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/dist/assets/examples/zh-Hans/90_Hello_P5/01_shapes.js b/dist/assets/examples/zh-Hans/90_Hello_P5/01_shapes.js new file mode 100644 index 0000000000..5196abef4a --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/01_shapes.js @@ -0,0 +1,28 @@ +/* + * @name Simple Shapes + * @description This examples includes a circle, square, triangle, and a flower. + */ +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/dist/assets/examples/zh-Hans/90_Hello_P5/02_interactivity.js b/dist/assets/examples/zh-Hans/90_Hello_P5/02_interactivity.js new file mode 100644 index 0000000000..5bc6687440 --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/02_interactivity.js @@ -0,0 +1,37 @@ +/* + * @name Interactivity 1 + * @frame 720,425 + * @description The circle changes color when you click on it. + */ + +// 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/dist/assets/examples/zh-Hans/90_Hello_P5/03_interactivity.js b/dist/assets/examples/zh-Hans/90_Hello_P5/03_interactivity.js new file mode 100644 index 0000000000..6ab965cbe9 --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/03_interactivity.js @@ -0,0 +1,26 @@ +/* + * @name Interactivity 2 + * @frame 720,425 + * @description The circle changes color when you move the slider. + */ + +// 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/dist/assets/examples/zh-Hans/90_Hello_P5/04_animate.js b/dist/assets/examples/zh-Hans/90_Hello_P5/04_animate.js new file mode 100644 index 0000000000..7c87da3a24 --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/04_animate.js @@ -0,0 +1,33 @@ +/* + * @name Animation + * @description The circle moves. + */ +// 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/dist/assets/examples/zh-Hans/90_Hello_P5/04_flocking.js b/dist/assets/examples/zh-Hans/90_Hello_P5/04_flocking.js new file mode 100644 index 0000000000..e4d5806a97 --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/04_flocking.js @@ -0,0 +1,188 @@ +/* + * @name Flocking + * @description Demonstration of Craig Reynolds' "Flocking" behavior.
+ * (Rules: Cohesion, Separation, Alignment.)
+ * From natureofcode.com. + */ +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); + } + } +} + + + + diff --git a/dist/assets/examples/zh-Hans/90_Hello_P5/05_weather.js b/dist/assets/examples/zh-Hans/90_Hello_P5/05_weather.js new file mode 100644 index 0000000000..db3a61141c --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/05_weather.js @@ -0,0 +1,70 @@ +/* + * @name Weather + * @frame 720,280 + * @description This example grabs JSON weather data from www.metaweather.com. +*/ + +// 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/dist/assets/examples/zh-Hans/90_Hello_P5/06_drawing.js b/dist/assets/examples/zh-Hans/90_Hello_P5/06_drawing.js new file mode 100644 index 0000000000..b9b884c4ad --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/06_drawing.js @@ -0,0 +1,132 @@ +/* +* @name Drawing +* @description Generative painting program. +*/ + +// 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); + } + } +} \ No newline at end of file diff --git a/dist/assets/examples/zh-Hans/90_Hello_P5/07_song.js b/dist/assets/examples/zh-Hans/90_Hello_P5/07_song.js new file mode 100644 index 0000000000..5e4337b7c9 --- /dev/null +++ b/dist/assets/examples/zh-Hans/90_Hello_P5/07_song.js @@ -0,0 +1,119 @@ +/* + * @name Song + * @frame 720, 430 + * @description Play a song. + * You will need to include the + * p5.sound + * library for this example to work in your own project. + */ +// 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/dist/assets/img/asterisk-01-01.png b/dist/assets/img/asterisk-01-01.png new file mode 100644 index 0000000000..446e558cc2 Binary files /dev/null and b/dist/assets/img/asterisk-01-01.png differ diff --git a/dist/assets/img/asterisk-01.png b/dist/assets/img/asterisk-01.png new file mode 100644 index 0000000000..22434179c5 Binary files /dev/null and b/dist/assets/img/asterisk-01.png differ diff --git a/dist/assets/img/asterisk.png b/dist/assets/img/asterisk.png new file mode 100644 index 0000000000..6821962dc7 Binary files /dev/null and b/dist/assets/img/asterisk.png differ diff --git a/dist/assets/img/books/aesthetic-programming.jpg b/dist/assets/img/books/aesthetic-programming.jpg new file mode 100644 index 0000000000..e1bfe03cad Binary files /dev/null and b/dist/assets/img/books/aesthetic-programming.jpg differ diff --git a/dist/assets/img/books/generative_design.jpg b/dist/assets/img/books/generative_design.jpg new file mode 100644 index 0000000000..2a27234a04 Binary files /dev/null and b/dist/assets/img/books/generative_design.jpg differ diff --git a/dist/assets/img/books/generative_gestaltung.jpg b/dist/assets/img/books/generative_gestaltung.jpg new file mode 100644 index 0000000000..158190cf48 Binary files /dev/null and b/dist/assets/img/books/generative_gestaltung.jpg differ diff --git a/dist/assets/img/books/gettingstarted-es.jpg b/dist/assets/img/books/gettingstarted-es.jpg new file mode 100644 index 0000000000..e27dd4f9f3 Binary files /dev/null and b/dist/assets/img/books/gettingstarted-es.jpg differ diff --git a/dist/assets/img/books/gettingstarted.jpg b/dist/assets/img/books/gettingstarted.jpg new file mode 100644 index 0000000000..05db48f71f Binary files /dev/null and b/dist/assets/img/books/gettingstarted.jpg differ diff --git a/dist/assets/img/books/learn_javascript.jpg b/dist/assets/img/books/learn_javascript.jpg new file mode 100644 index 0000000000..30e3b6830b Binary files /dev/null and b/dist/assets/img/books/learn_javascript.jpg differ diff --git a/dist/assets/img/cc_88x31.png b/dist/assets/img/cc_88x31.png new file mode 100644 index 0000000000..5f7863d5be Binary files /dev/null and b/dist/assets/img/cc_88x31.png differ diff --git a/dist/assets/img/community/2015_1.jpg b/dist/assets/img/community/2015_1.jpg new file mode 100644 index 0000000000..25ac4ca622 Binary files /dev/null and b/dist/assets/img/community/2015_1.jpg differ diff --git a/dist/assets/img/community/2015_10.jpg b/dist/assets/img/community/2015_10.jpg new file mode 100644 index 0000000000..6bce1d7805 Binary files /dev/null and b/dist/assets/img/community/2015_10.jpg differ diff --git a/dist/assets/img/community/2015_11.jpg b/dist/assets/img/community/2015_11.jpg new file mode 100644 index 0000000000..0eca240a21 Binary files /dev/null and b/dist/assets/img/community/2015_11.jpg differ diff --git a/dist/assets/img/community/2015_12.jpg b/dist/assets/img/community/2015_12.jpg new file mode 100644 index 0000000000..b6b9456230 Binary files /dev/null and b/dist/assets/img/community/2015_12.jpg differ diff --git a/dist/assets/img/community/2015_13.jpg b/dist/assets/img/community/2015_13.jpg new file mode 100644 index 0000000000..5cd8692887 Binary files /dev/null and b/dist/assets/img/community/2015_13.jpg differ diff --git a/dist/assets/img/community/2015_14.jpg b/dist/assets/img/community/2015_14.jpg new file mode 100644 index 0000000000..376626b091 Binary files /dev/null and b/dist/assets/img/community/2015_14.jpg differ diff --git a/dist/assets/img/community/2015_15.jpg b/dist/assets/img/community/2015_15.jpg new file mode 100644 index 0000000000..4ee765616e Binary files /dev/null and b/dist/assets/img/community/2015_15.jpg differ diff --git a/dist/assets/img/community/2015_2.jpg b/dist/assets/img/community/2015_2.jpg new file mode 100644 index 0000000000..187bac78d6 Binary files /dev/null and b/dist/assets/img/community/2015_2.jpg differ diff --git a/dist/assets/img/community/2015_3.jpg b/dist/assets/img/community/2015_3.jpg new file mode 100644 index 0000000000..cbb1e7e379 Binary files /dev/null and b/dist/assets/img/community/2015_3.jpg differ diff --git a/dist/assets/img/community/2015_4.jpg b/dist/assets/img/community/2015_4.jpg new file mode 100644 index 0000000000..0d9760dad9 Binary files /dev/null and b/dist/assets/img/community/2015_4.jpg differ diff --git a/dist/assets/img/community/2015_5.jpg b/dist/assets/img/community/2015_5.jpg new file mode 100644 index 0000000000..39f9b2365a Binary files /dev/null and b/dist/assets/img/community/2015_5.jpg differ diff --git a/dist/assets/img/community/2015_6.jpg b/dist/assets/img/community/2015_6.jpg new file mode 100644 index 0000000000..2f6c0f4f27 Binary files /dev/null and b/dist/assets/img/community/2015_6.jpg differ diff --git a/dist/assets/img/community/2015_7.jpg b/dist/assets/img/community/2015_7.jpg new file mode 100644 index 0000000000..235ab3cb15 Binary files /dev/null and b/dist/assets/img/community/2015_7.jpg differ diff --git a/dist/assets/img/community/2015_8.jpg b/dist/assets/img/community/2015_8.jpg new file mode 100644 index 0000000000..dbf0dd6cb7 Binary files /dev/null and b/dist/assets/img/community/2015_8.jpg differ diff --git a/dist/assets/img/community/2015_9.jpg b/dist/assets/img/community/2015_9.jpg new file mode 100644 index 0000000000..f1188e77b9 Binary files /dev/null and b/dist/assets/img/community/2015_9.jpg differ diff --git a/dist/assets/img/community/2019_1.jpg b/dist/assets/img/community/2019_1.jpg new file mode 100644 index 0000000000..820867650a Binary files /dev/null and b/dist/assets/img/community/2019_1.jpg differ diff --git a/dist/assets/img/community/2019_10.jpg b/dist/assets/img/community/2019_10.jpg new file mode 100644 index 0000000000..9b9237ab9c Binary files /dev/null and b/dist/assets/img/community/2019_10.jpg differ diff --git a/dist/assets/img/community/2019_11.jpg b/dist/assets/img/community/2019_11.jpg new file mode 100644 index 0000000000..60f92fc9aa Binary files /dev/null and b/dist/assets/img/community/2019_11.jpg differ diff --git a/dist/assets/img/community/2019_12.jpg b/dist/assets/img/community/2019_12.jpg new file mode 100644 index 0000000000..6fa1fad90c Binary files /dev/null and b/dist/assets/img/community/2019_12.jpg differ diff --git a/dist/assets/img/community/2019_13.jpg b/dist/assets/img/community/2019_13.jpg new file mode 100644 index 0000000000..9453c14cd1 Binary files /dev/null and b/dist/assets/img/community/2019_13.jpg differ diff --git a/dist/assets/img/community/2019_14.jpg b/dist/assets/img/community/2019_14.jpg new file mode 100644 index 0000000000..44809c8b9a Binary files /dev/null and b/dist/assets/img/community/2019_14.jpg differ diff --git a/dist/assets/img/community/2019_15.jpg b/dist/assets/img/community/2019_15.jpg new file mode 100644 index 0000000000..697b209dc1 Binary files /dev/null and b/dist/assets/img/community/2019_15.jpg differ diff --git a/dist/assets/img/community/2019_16.jpg b/dist/assets/img/community/2019_16.jpg new file mode 100644 index 0000000000..e57901907d Binary files /dev/null and b/dist/assets/img/community/2019_16.jpg differ diff --git a/dist/assets/img/community/2019_17.jpg b/dist/assets/img/community/2019_17.jpg new file mode 100644 index 0000000000..72d930c696 Binary files /dev/null and b/dist/assets/img/community/2019_17.jpg differ diff --git a/dist/assets/img/community/2019_18.jpg b/dist/assets/img/community/2019_18.jpg new file mode 100644 index 0000000000..40c5551679 Binary files /dev/null and b/dist/assets/img/community/2019_18.jpg differ diff --git a/dist/assets/img/community/2019_19.jpg b/dist/assets/img/community/2019_19.jpg new file mode 100644 index 0000000000..149a2997a4 Binary files /dev/null and b/dist/assets/img/community/2019_19.jpg differ diff --git a/dist/assets/img/community/2019_2.jpg b/dist/assets/img/community/2019_2.jpg new file mode 100644 index 0000000000..61a71505ed Binary files /dev/null and b/dist/assets/img/community/2019_2.jpg differ diff --git a/dist/assets/img/community/2019_20.jpg b/dist/assets/img/community/2019_20.jpg new file mode 100644 index 0000000000..0a0a4f5cbc Binary files /dev/null and b/dist/assets/img/community/2019_20.jpg differ diff --git a/dist/assets/img/community/2019_21.jpg b/dist/assets/img/community/2019_21.jpg new file mode 100644 index 0000000000..da9d037c7d Binary files /dev/null and b/dist/assets/img/community/2019_21.jpg differ diff --git a/dist/assets/img/community/2019_22.jpg b/dist/assets/img/community/2019_22.jpg new file mode 100644 index 0000000000..e52ee524bd Binary files /dev/null and b/dist/assets/img/community/2019_22.jpg differ diff --git a/dist/assets/img/community/2019_23.jpg b/dist/assets/img/community/2019_23.jpg new file mode 100644 index 0000000000..3a2cef2ef5 Binary files /dev/null and b/dist/assets/img/community/2019_23.jpg differ diff --git a/dist/assets/img/community/2019_24.jpg b/dist/assets/img/community/2019_24.jpg new file mode 100644 index 0000000000..83643badc2 Binary files /dev/null and b/dist/assets/img/community/2019_24.jpg differ diff --git a/dist/assets/img/community/2019_3.jpg b/dist/assets/img/community/2019_3.jpg new file mode 100644 index 0000000000..09151ecc7d Binary files /dev/null and b/dist/assets/img/community/2019_3.jpg differ diff --git a/dist/assets/img/community/2019_4.jpg b/dist/assets/img/community/2019_4.jpg new file mode 100644 index 0000000000..c39fe9a533 Binary files /dev/null and b/dist/assets/img/community/2019_4.jpg differ diff --git a/dist/assets/img/community/2019_5.jpg b/dist/assets/img/community/2019_5.jpg new file mode 100644 index 0000000000..4be4fc4872 Binary files /dev/null and b/dist/assets/img/community/2019_5.jpg differ diff --git a/dist/assets/img/community/2019_6.jpg b/dist/assets/img/community/2019_6.jpg new file mode 100644 index 0000000000..51d5663506 Binary files /dev/null and b/dist/assets/img/community/2019_6.jpg differ diff --git a/dist/assets/img/community/2019_7.jpg b/dist/assets/img/community/2019_7.jpg new file mode 100644 index 0000000000..935292af9e Binary files /dev/null and b/dist/assets/img/community/2019_7.jpg differ diff --git a/dist/assets/img/community/2019_8.jpg b/dist/assets/img/community/2019_8.jpg new file mode 100644 index 0000000000..85e76f8eec Binary files /dev/null and b/dist/assets/img/community/2019_8.jpg differ diff --git a/dist/assets/img/community/2019_9.jpg b/dist/assets/img/community/2019_9.jpg new file mode 100644 index 0000000000..4737541a31 Binary files /dev/null and b/dist/assets/img/community/2019_9.jpg differ diff --git a/dist/assets/img/community/COSA.png b/dist/assets/img/community/COSA.png new file mode 100644 index 0000000000..c9d94af605 Binary files /dev/null and b/dist/assets/img/community/COSA.png differ diff --git a/dist/assets/img/community/HGK.jpg b/dist/assets/img/community/HGK.jpg new file mode 100644 index 0000000000..73ed731721 Binary files /dev/null and b/dist/assets/img/community/HGK.jpg differ diff --git a/dist/assets/img/community/IDM.jpg b/dist/assets/img/community/IDM.jpg new file mode 100644 index 0000000000..194677e076 Binary files /dev/null and b/dist/assets/img/community/IDM.jpg differ diff --git a/dist/assets/img/community/NEA.png b/dist/assets/img/community/NEA.png new file mode 100644 index 0000000000..3df9374dd4 Binary files /dev/null and b/dist/assets/img/community/NEA.png differ diff --git a/dist/assets/img/community/Parsons.jpg b/dist/assets/img/community/Parsons.jpg new file mode 100644 index 0000000000..094518a0f9 Binary files /dev/null and b/dist/assets/img/community/Parsons.jpg differ diff --git a/dist/assets/img/community/bocoup.png b/dist/assets/img/community/bocoup.png new file mode 100644 index 0000000000..5f17d9f5ec Binary files /dev/null and b/dist/assets/img/community/bocoup.png differ diff --git a/dist/assets/img/community/campfire.jpg b/dist/assets/img/community/campfire.jpg new file mode 100644 index 0000000000..249347821e Binary files /dev/null and b/dist/assets/img/community/campfire.jpg differ diff --git a/dist/assets/img/community/depaul.png b/dist/assets/img/community/depaul.png new file mode 100644 index 0000000000..01c79a2917 Binary files /dev/null and b/dist/assets/img/community/depaul.png differ diff --git a/dist/assets/img/community/edp.png b/dist/assets/img/community/edp.png new file mode 100644 index 0000000000..46fb30505b Binary files /dev/null and b/dist/assets/img/community/edp.png differ diff --git a/dist/assets/img/community/itp.png b/dist/assets/img/community/itp.png new file mode 100644 index 0000000000..56dbf8d913 Binary files /dev/null and b/dist/assets/img/community/itp.png differ diff --git a/dist/assets/img/community/nea.jpg b/dist/assets/img/community/nea.jpg new file mode 100644 index 0000000000..b214d71c04 Binary files /dev/null and b/dist/assets/img/community/nea.jpg differ diff --git a/dist/assets/img/community/processing-foundation.png b/dist/assets/img/community/processing-foundation.png new file mode 100644 index 0000000000..6a18f001ba Binary files /dev/null and b/dist/assets/img/community/processing-foundation.png differ diff --git a/dist/assets/img/community/studio.png b/dist/assets/img/community/studio.png new file mode 100644 index 0000000000..3bed89e50b Binary files /dev/null and b/dist/assets/img/community/studio.png differ diff --git a/dist/assets/img/community/theartificial.png b/dist/assets/img/community/theartificial.png new file mode 100644 index 0000000000..45145985b6 Binary files /dev/null and b/dist/assets/img/community/theartificial.png differ diff --git a/dist/assets/img/community/theartificial.svg b/dist/assets/img/community/theartificial.svg new file mode 100644 index 0000000000..ef3393e862 --- /dev/null +++ b/dist/assets/img/community/theartificial.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + +theartificial.nl + diff --git a/dist/assets/img/download/Cassie_CodeMiami0.png b/dist/assets/img/download/Cassie_CodeMiami0.png new file mode 100644 index 0000000000..1dd3c6d734 Binary files /dev/null and b/dist/assets/img/download/Cassie_CodeMiami0.png differ diff --git a/dist/assets/img/download/Cassie_CodeMiami5.png b/dist/assets/img/download/Cassie_CodeMiami5.png new file mode 100644 index 0000000000..6e95b60579 Binary files /dev/null and b/dist/assets/img/download/Cassie_CodeMiami5.png differ diff --git a/dist/assets/img/download/LearningToTeach45-small.jpg b/dist/assets/img/download/LearningToTeach45-small.jpg new file mode 100644 index 0000000000..a90a11c774 Binary files /dev/null and b/dist/assets/img/download/LearningToTeach45-small.jpg differ diff --git a/dist/assets/img/download/aaron.jpg b/dist/assets/img/download/aaron.jpg new file mode 100644 index 0000000000..7680c1951d Binary files /dev/null and b/dist/assets/img/download/aaron.jpg differ diff --git a/dist/assets/img/download/conf2.jpg b/dist/assets/img/download/conf2.jpg new file mode 100644 index 0000000000..e8beedc81d Binary files /dev/null and b/dist/assets/img/download/conf2.jpg differ diff --git a/dist/assets/img/download/digitalcitizens-panel3.png b/dist/assets/img/download/digitalcitizens-panel3.png new file mode 100644 index 0000000000..4412e0fc21 Binary files /dev/null and b/dist/assets/img/download/digitalcitizens-panel3.png differ diff --git a/dist/assets/img/download/digitalcitizens7.jpg b/dist/assets/img/download/digitalcitizens7.jpg new file mode 100644 index 0000000000..c71715d806 Binary files /dev/null and b/dist/assets/img/download/digitalcitizens7.jpg differ diff --git a/dist/assets/img/download/diygirls1.jpg b/dist/assets/img/download/diygirls1.jpg new file mode 100644 index 0000000000..2f927f90b7 Binary files /dev/null and b/dist/assets/img/download/diygirls1.jpg differ diff --git a/dist/assets/img/download/gsoc_kickoff.jpg b/dist/assets/img/download/gsoc_kickoff.jpg new file mode 100644 index 0000000000..330aa265f4 Binary files /dev/null and b/dist/assets/img/download/gsoc_kickoff.jpg differ diff --git a/dist/assets/img/download/p5-coast2coast.jpg b/dist/assets/img/download/p5-coast2coast.jpg new file mode 100644 index 0000000000..3ff718aa6c Binary files /dev/null and b/dist/assets/img/download/p5-coast2coast.jpg differ diff --git a/dist/assets/img/download/p5js-5939.jpg b/dist/assets/img/download/p5js-5939.jpg new file mode 100644 index 0000000000..26d8529513 Binary files /dev/null and b/dist/assets/img/download/p5js-5939.jpg differ diff --git a/dist/assets/img/download/saskia-project.jpg b/dist/assets/img/download/saskia-project.jpg new file mode 100644 index 0000000000..14bb4393c9 Binary files /dev/null and b/dist/assets/img/download/saskia-project.jpg differ diff --git a/dist/assets/img/download/signingcoders0.jpg b/dist/assets/img/download/signingcoders0.jpg new file mode 100644 index 0000000000..49fb9ac16d Binary files /dev/null and b/dist/assets/img/download/signingcoders0.jpg differ diff --git a/dist/assets/img/download/signingcoders2.jpg b/dist/assets/img/download/signingcoders2.jpg new file mode 100644 index 0000000000..ac20d8efd7 Binary files /dev/null and b/dist/assets/img/download/signingcoders2.jpg differ diff --git a/dist/assets/img/download/signingcoders3.jpg b/dist/assets/img/download/signingcoders3.jpg new file mode 100644 index 0000000000..303041c678 Binary files /dev/null and b/dist/assets/img/download/signingcoders3.jpg differ diff --git a/dist/assets/img/favicon.ico b/dist/assets/img/favicon.ico new file mode 100644 index 0000000000..32d2ac48a0 Binary files /dev/null and b/dist/assets/img/favicon.ico differ diff --git a/dist/assets/img/gallery-images/PrismPusher.jpg b/dist/assets/img/gallery-images/PrismPusher.jpg new file mode 100644 index 0000000000..3845c5680b Binary files /dev/null and b/dist/assets/img/gallery-images/PrismPusher.jpg differ diff --git a/dist/assets/img/gallery-images/cell-flight.png b/dist/assets/img/gallery-images/cell-flight.png new file mode 100644 index 0000000000..dd089694bf Binary files /dev/null and b/dist/assets/img/gallery-images/cell-flight.png differ diff --git a/dist/assets/img/gallery-images/emoji-booth.png b/dist/assets/img/gallery-images/emoji-booth.png new file mode 100644 index 0000000000..510d005b2d Binary files /dev/null and b/dist/assets/img/gallery-images/emoji-booth.png differ diff --git a/dist/assets/img/gallery-images/hardmarubox2D.png b/dist/assets/img/gallery-images/hardmarubox2D.png new file mode 100644 index 0000000000..595fac3a55 Binary files /dev/null and b/dist/assets/img/gallery-images/hardmarubox2D.png differ diff --git a/dist/assets/img/gallery-images/hardmaruplanks.png b/dist/assets/img/gallery-images/hardmaruplanks.png new file mode 100644 index 0000000000..6bb84be2ea Binary files /dev/null and b/dist/assets/img/gallery-images/hardmaruplanks.png differ diff --git a/dist/assets/img/gallery-images/keyboard.png b/dist/assets/img/gallery-images/keyboard.png new file mode 100644 index 0000000000..98b352e68f Binary files /dev/null and b/dist/assets/img/gallery-images/keyboard.png differ diff --git a/dist/assets/img/gallery-images/magic-is-real-emoji.png b/dist/assets/img/gallery-images/magic-is-real-emoji.png new file mode 100644 index 0000000000..de228db68f Binary files /dev/null and b/dist/assets/img/gallery-images/magic-is-real-emoji.png differ diff --git a/dist/assets/img/gallery-images/music-viz.png b/dist/assets/img/gallery-images/music-viz.png new file mode 100644 index 0000000000..7c529cbf97 Binary files /dev/null and b/dist/assets/img/gallery-images/music-viz.png differ diff --git a/dist/assets/img/gallery-images/neobrush.png b/dist/assets/img/gallery-images/neobrush.png new file mode 100644 index 0000000000..265977d15e Binary files /dev/null and b/dist/assets/img/gallery-images/neobrush.png differ diff --git a/dist/assets/img/gallery-images/nithi-prasanpanich.png b/dist/assets/img/gallery-images/nithi-prasanpanich.png new file mode 100644 index 0000000000..5f9aaa0513 Binary files /dev/null and b/dist/assets/img/gallery-images/nithi-prasanpanich.png differ diff --git a/dist/assets/img/gallery-images/ol-scroll.png b/dist/assets/img/gallery-images/ol-scroll.png new file mode 100644 index 0000000000..3f5ff13ec5 Binary files /dev/null and b/dist/assets/img/gallery-images/ol-scroll.png differ diff --git a/dist/assets/img/gallery-images/organic-motion-sonification.png b/dist/assets/img/gallery-images/organic-motion-sonification.png new file mode 100644 index 0000000000..bf808881c2 Binary files /dev/null and b/dist/assets/img/gallery-images/organic-motion-sonification.png differ diff --git a/dist/assets/img/gallery-images/social-tension.png b/dist/assets/img/gallery-images/social-tension.png new file mode 100644 index 0000000000..bc6fa66188 Binary files /dev/null and b/dist/assets/img/gallery-images/social-tension.png differ diff --git a/dist/assets/img/gallery-images/springs.png b/dist/assets/img/gallery-images/springs.png new file mode 100644 index 0000000000..e33398c2bb Binary files /dev/null and b/dist/assets/img/gallery-images/springs.png differ diff --git a/dist/assets/img/gallery-images/star-trails.png b/dist/assets/img/gallery-images/star-trails.png new file mode 100644 index 0000000000..c9654b61bd Binary files /dev/null and b/dist/assets/img/gallery-images/star-trails.png differ diff --git a/dist/assets/img/get-started/first-sketch.png b/dist/assets/img/get-started/first-sketch.png new file mode 100644 index 0000000000..8505f3edb1 Binary files /dev/null and b/dist/assets/img/get-started/first-sketch.png differ diff --git a/dist/assets/img/get-started/first-sketch2.png b/dist/assets/img/get-started/first-sketch2.png new file mode 100644 index 0000000000..8f6eeed629 Binary files /dev/null and b/dist/assets/img/get-started/first-sketch2.png differ diff --git a/dist/assets/img/get-started/sublime.png b/dist/assets/img/get-started/sublime.png new file mode 100644 index 0000000000..92f504a5e8 Binary files /dev/null and b/dist/assets/img/get-started/sublime.png differ diff --git a/dist/assets/img/get-started/sublime2.png b/dist/assets/img/get-started/sublime2.png new file mode 100644 index 0000000000..2c8a5888a8 Binary files /dev/null and b/dist/assets/img/get-started/sublime2.png differ diff --git a/dist/assets/img/learn/3d.jpg b/dist/assets/img/learn/3d.jpg new file mode 100644 index 0000000000..af422f5db2 Binary files /dev/null and b/dist/assets/img/learn/3d.jpg differ diff --git a/dist/assets/img/learn/dom.jpg b/dist/assets/img/learn/dom.jpg new file mode 100644 index 0000000000..eb4a48ce65 Binary files /dev/null and b/dist/assets/img/learn/dom.jpg differ diff --git a/dist/assets/img/learn/lib_placeholder.jpg b/dist/assets/img/learn/lib_placeholder.jpg new file mode 100644 index 0000000000..422b3c87a5 Binary files /dev/null and b/dist/assets/img/learn/lib_placeholder.jpg differ diff --git a/dist/assets/img/libraries/Rotating_knobs.jpg b/dist/assets/img/libraries/Rotating_knobs.jpg new file mode 100644 index 0000000000..5a56e5510b Binary files /dev/null and b/dist/assets/img/libraries/Rotating_knobs.jpg differ diff --git a/dist/assets/img/libraries/Shape5.jpg b/dist/assets/img/libraries/Shape5.jpg new file mode 100644 index 0000000000..1fad657ca0 Binary files /dev/null and b/dist/assets/img/libraries/Shape5.jpg differ diff --git a/dist/assets/img/libraries/asciiart.jpg b/dist/assets/img/libraries/asciiart.jpg new file mode 100644 index 0000000000..04dca7b2c3 Binary files /dev/null and b/dist/assets/img/libraries/asciiart.jpg differ diff --git a/dist/assets/img/libraries/dom.jpg b/dist/assets/img/libraries/dom.jpg new file mode 100644 index 0000000000..e5cf131452 Binary files /dev/null and b/dist/assets/img/libraries/dom.jpg differ diff --git a/dist/assets/img/libraries/grafica.js.jpg b/dist/assets/img/libraries/grafica.js.jpg new file mode 100644 index 0000000000..4f873efd49 Binary files /dev/null and b/dist/assets/img/libraries/grafica.js.jpg differ diff --git a/dist/assets/img/libraries/lib_placeholder.jpg b/dist/assets/img/libraries/lib_placeholder.jpg new file mode 100644 index 0000000000..422b3c87a5 Binary files /dev/null and b/dist/assets/img/libraries/lib_placeholder.jpg differ diff --git a/dist/assets/img/libraries/mappa.jpg b/dist/assets/img/libraries/mappa.jpg new file mode 100644 index 0000000000..fe07153e8a Binary files /dev/null and b/dist/assets/img/libraries/mappa.jpg differ diff --git a/dist/assets/img/libraries/marching.jpg b/dist/assets/img/libraries/marching.jpg new file mode 100644 index 0000000000..fc0afef464 Binary files /dev/null and b/dist/assets/img/libraries/marching.jpg differ diff --git a/dist/assets/img/libraries/ml5.js.jpg b/dist/assets/img/libraries/ml5.js.jpg new file mode 100644 index 0000000000..1b05c58b01 Binary files /dev/null and b/dist/assets/img/libraries/ml5.js.jpg differ diff --git a/dist/assets/img/libraries/p5.3D.jpg b/dist/assets/img/libraries/p5.3D.jpg new file mode 100644 index 0000000000..ef3c5f3067 Binary files /dev/null and b/dist/assets/img/libraries/p5.3D.jpg differ diff --git a/dist/assets/img/libraries/p5.EasyCam.jpg b/dist/assets/img/libraries/p5.EasyCam.jpg new file mode 100644 index 0000000000..de2f98fd55 Binary files /dev/null and b/dist/assets/img/libraries/p5.EasyCam.jpg differ diff --git a/dist/assets/img/libraries/p5.Riso.jpg b/dist/assets/img/libraries/p5.Riso.jpg new file mode 100644 index 0000000000..862f1fdaf0 Binary files /dev/null and b/dist/assets/img/libraries/p5.Riso.jpg differ diff --git a/dist/assets/img/libraries/p5.acc.jpg b/dist/assets/img/libraries/p5.acc.jpg new file mode 100644 index 0000000000..e397d71489 Binary files /dev/null and b/dist/assets/img/libraries/p5.acc.jpg differ diff --git a/dist/assets/img/libraries/p5.accessibility.jpg b/dist/assets/img/libraries/p5.accessibility.jpg new file mode 100644 index 0000000000..9f3ad6d2d8 Binary files /dev/null and b/dist/assets/img/libraries/p5.accessibility.jpg differ diff --git a/dist/assets/img/libraries/p5.ble.jpg b/dist/assets/img/libraries/p5.ble.jpg new file mode 100644 index 0000000000..35bebb8abe Binary files /dev/null and b/dist/assets/img/libraries/p5.ble.jpg differ diff --git a/dist/assets/img/libraries/p5.bots.jpg b/dist/assets/img/libraries/p5.bots.jpg new file mode 100644 index 0000000000..62d426d57b Binary files /dev/null and b/dist/assets/img/libraries/p5.bots.jpg differ diff --git a/dist/assets/img/libraries/p5.clickable.jpg b/dist/assets/img/libraries/p5.clickable.jpg new file mode 100644 index 0000000000..26757f367b Binary files /dev/null and b/dist/assets/img/libraries/p5.clickable.jpg differ diff --git a/dist/assets/img/libraries/p5.cmyk.js.jpg b/dist/assets/img/libraries/p5.cmyk.js.jpg new file mode 100644 index 0000000000..cdb1a4ba5f Binary files /dev/null and b/dist/assets/img/libraries/p5.cmyk.js.jpg differ diff --git a/dist/assets/img/libraries/p5.collide2D.jpg b/dist/assets/img/libraries/p5.collide2D.jpg new file mode 100644 index 0000000000..1ba7ae9869 Binary files /dev/null and b/dist/assets/img/libraries/p5.collide2D.jpg differ diff --git a/dist/assets/img/libraries/p5.createloop.jpg b/dist/assets/img/libraries/p5.createloop.jpg new file mode 100644 index 0000000000..426d0d16d7 Binary files /dev/null and b/dist/assets/img/libraries/p5.createloop.jpg differ diff --git a/dist/assets/img/libraries/p5.dimensions.jpg b/dist/assets/img/libraries/p5.dimensions.jpg new file mode 100644 index 0000000000..a9b1afbffd Binary files /dev/null and b/dist/assets/img/libraries/p5.dimensions.jpg differ diff --git a/dist/assets/img/libraries/p5.experience.jpg b/dist/assets/img/libraries/p5.experience.jpg new file mode 100644 index 0000000000..90e9b66dcd Binary files /dev/null and b/dist/assets/img/libraries/p5.experience.jpg differ diff --git a/dist/assets/img/libraries/p5.func.jpg b/dist/assets/img/libraries/p5.func.jpg new file mode 100644 index 0000000000..ff5bb258ec Binary files /dev/null and b/dist/assets/img/libraries/p5.func.jpg differ diff --git a/dist/assets/img/libraries/p5.geolocation.jpg b/dist/assets/img/libraries/p5.geolocation.jpg new file mode 100644 index 0000000000..0fe7b16f74 Binary files /dev/null and b/dist/assets/img/libraries/p5.geolocation.jpg differ diff --git a/dist/assets/img/libraries/p5.gibber.jpg b/dist/assets/img/libraries/p5.gibber.jpg new file mode 100644 index 0000000000..db9892a801 Binary files /dev/null and b/dist/assets/img/libraries/p5.gibber.jpg differ diff --git a/dist/assets/img/libraries/p5.gif.jpg b/dist/assets/img/libraries/p5.gif.jpg new file mode 100644 index 0000000000..978263369c Binary files /dev/null and b/dist/assets/img/libraries/p5.gif.jpg differ diff --git a/dist/assets/img/libraries/p5.gui.jpg b/dist/assets/img/libraries/p5.gui.jpg new file mode 100644 index 0000000000..01d56c0c14 Binary files /dev/null and b/dist/assets/img/libraries/p5.gui.jpg differ diff --git a/dist/assets/img/libraries/p5.localmessage.jpg b/dist/assets/img/libraries/p5.localmessage.jpg new file mode 100644 index 0000000000..3368efd023 Binary files /dev/null and b/dist/assets/img/libraries/p5.localmessage.jpg differ diff --git a/dist/assets/img/libraries/p5.particle.jpg b/dist/assets/img/libraries/p5.particle.jpg new file mode 100644 index 0000000000..32297160b9 Binary files /dev/null and b/dist/assets/img/libraries/p5.particle.jpg differ diff --git a/dist/assets/img/libraries/p5.play.jpg b/dist/assets/img/libraries/p5.play.jpg new file mode 100644 index 0000000000..5359c2b8b3 Binary files /dev/null and b/dist/assets/img/libraries/p5.play.jpg differ diff --git a/dist/assets/img/libraries/p5.scenemanager.jpg b/dist/assets/img/libraries/p5.scenemanager.jpg new file mode 100644 index 0000000000..0884d8cdb6 Binary files /dev/null and b/dist/assets/img/libraries/p5.scenemanager.jpg differ diff --git a/dist/assets/img/libraries/p5.screenPosition.jpg b/dist/assets/img/libraries/p5.screenPosition.jpg new file mode 100644 index 0000000000..028c260c92 Binary files /dev/null and b/dist/assets/img/libraries/p5.screenPosition.jpg differ diff --git a/dist/assets/img/libraries/p5.scribble.jpg b/dist/assets/img/libraries/p5.scribble.jpg new file mode 100644 index 0000000000..9c8b613785 Binary files /dev/null and b/dist/assets/img/libraries/p5.scribble.jpg differ diff --git a/dist/assets/img/libraries/p5.serial.jpg b/dist/assets/img/libraries/p5.serial.jpg new file mode 100644 index 0000000000..a5d443e647 Binary files /dev/null and b/dist/assets/img/libraries/p5.serial.jpg differ diff --git a/dist/assets/img/libraries/p5.shape.js.jpg b/dist/assets/img/libraries/p5.shape.js.jpg new file mode 100644 index 0000000000..a13c941dbe Binary files /dev/null and b/dist/assets/img/libraries/p5.shape.js.jpg differ diff --git a/dist/assets/img/libraries/p5.sound.jpg b/dist/assets/img/libraries/p5.sound.jpg new file mode 100644 index 0000000000..ec13fe9f39 Binary files /dev/null and b/dist/assets/img/libraries/p5.sound.jpg differ diff --git a/dist/assets/img/libraries/p5.speech.jpg b/dist/assets/img/libraries/p5.speech.jpg new file mode 100644 index 0000000000..06556c7fc2 Binary files /dev/null and b/dist/assets/img/libraries/p5.speech.jpg differ diff --git a/dist/assets/img/libraries/p5.start.js.jpg b/dist/assets/img/libraries/p5.start.js.jpg new file mode 100644 index 0000000000..bdec92b8a3 Binary files /dev/null and b/dist/assets/img/libraries/p5.start.js.jpg differ diff --git a/dist/assets/img/libraries/p5.start2d.js.jpg b/dist/assets/img/libraries/p5.start2d.js.jpg new file mode 100644 index 0000000000..591381cf35 Binary files /dev/null and b/dist/assets/img/libraries/p5.start2d.js.jpg differ diff --git a/dist/assets/img/libraries/p5.tiledmap.jpg b/dist/assets/img/libraries/p5.tiledmap.jpg new file mode 100644 index 0000000000..a3c6fcda1e Binary files /dev/null and b/dist/assets/img/libraries/p5.tiledmap.jpg differ diff --git a/dist/assets/img/libraries/p5.touchgui.jpg b/dist/assets/img/libraries/p5.touchgui.jpg new file mode 100644 index 0000000000..677f7298b5 Binary files /dev/null and b/dist/assets/img/libraries/p5.touchgui.jpg differ diff --git a/dist/assets/img/libraries/p5.voronoi.jpg b/dist/assets/img/libraries/p5.voronoi.jpg new file mode 100644 index 0000000000..2cf921b5df Binary files /dev/null and b/dist/assets/img/libraries/p5.voronoi.jpg differ diff --git a/dist/assets/img/libraries/p5.xr.jpg b/dist/assets/img/libraries/p5.xr.jpg new file mode 100644 index 0000000000..bfea38b5ae Binary files /dev/null and b/dist/assets/img/libraries/p5.xr.jpg differ diff --git a/dist/assets/img/libraries/rita.js.jpg b/dist/assets/img/libraries/rita.js.jpg new file mode 100644 index 0000000000..5ac9c6c388 Binary files /dev/null and b/dist/assets/img/libraries/rita.js.jpg differ diff --git a/dist/assets/img/libraries/tramontana.jpg b/dist/assets/img/libraries/tramontana.jpg new file mode 100644 index 0000000000..615e7609b7 Binary files /dev/null and b/dist/assets/img/libraries/tramontana.jpg differ diff --git a/dist/assets/img/libraries/vida.jpg b/dist/assets/img/libraries/vida.jpg new file mode 100644 index 0000000000..98dbf474ba Binary files /dev/null and b/dist/assets/img/libraries/vida.jpg differ diff --git a/dist/assets/img/medium.svg b/dist/assets/img/medium.svg new file mode 100644 index 0000000000..e86110339e --- /dev/null +++ b/dist/assets/img/medium.svg @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/dist/assets/img/p5js-beta.svg b/dist/assets/img/p5js-beta.svg new file mode 100644 index 0000000000..0f4c46a0ad --- /dev/null +++ b/dist/assets/img/p5js-beta.svg @@ -0,0 +1,54 @@ + + + + + + diff --git a/dist/assets/img/p5js.svg b/dist/assets/img/p5js.svg new file mode 100644 index 0000000000..1492f8bf37 --- /dev/null +++ b/dist/assets/img/p5js.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + diff --git a/dist/assets/img/search.png b/dist/assets/img/search.png new file mode 100644 index 0000000000..472493680a Binary files /dev/null and b/dist/assets/img/search.png differ diff --git a/dist/assets/img/showcase/casey-louise/casey-louise_p5js-shaders.png b/dist/assets/img/showcase/casey-louise/casey-louise_p5js-shaders.png new file mode 100644 index 0000000000..e894579508 Binary files /dev/null and b/dist/assets/img/showcase/casey-louise/casey-louise_p5js-shaders.png differ diff --git a/dist/assets/img/showcase/daein-chung/daein-chung_chillin.png b/dist/assets/img/showcase/daein-chung/daein-chung_chillin.png new file mode 100644 index 0000000000..963a47d499 Binary files /dev/null and b/dist/assets/img/showcase/daein-chung/daein-chung_chillin.png differ diff --git a/dist/assets/img/showcase/moon-xin/moon-xin_poster-carlee.png b/dist/assets/img/showcase/moon-xin/moon-xin_poster-carlee.png new file mode 100644 index 0000000000..7044ea6101 Binary files /dev/null and b/dist/assets/img/showcase/moon-xin/moon-xin_poster-carlee.png differ diff --git a/dist/assets/img/showcase/phuong-ngo/phuong-ngo_airi-flies.png b/dist/assets/img/showcase/phuong-ngo/phuong-ngo_airi-flies.png new file mode 100644 index 0000000000..61a0752588 Binary files /dev/null and b/dist/assets/img/showcase/phuong-ngo/phuong-ngo_airi-flies.png differ diff --git a/dist/assets/img/showcase/qianqian-ye/qianqian-ye_qtv.png b/dist/assets/img/showcase/qianqian-ye/qianqian-ye_qtv.png new file mode 100644 index 0000000000..062cda619f Binary files /dev/null and b/dist/assets/img/showcase/qianqian-ye/qianqian-ye_qtv.png differ diff --git a/dist/assets/img/showcase/roni-cantor/roni-cantor_plotter-turquoise.jpg b/dist/assets/img/showcase/roni-cantor/roni-cantor_plotter-turquoise.jpg new file mode 100644 index 0000000000..ca237e56de Binary files /dev/null and b/dist/assets/img/showcase/roni-cantor/roni-cantor_plotter-turquoise.jpg differ diff --git a/dist/assets/img/showcase/roni-cantor/roni-cantor_plotter-white.jpg b/dist/assets/img/showcase/roni-cantor/roni-cantor_plotter-white.jpg new file mode 100644 index 0000000000..d75dbdcc95 Binary files /dev/null and b/dist/assets/img/showcase/roni-cantor/roni-cantor_plotter-white.jpg differ diff --git a/dist/assets/img/test-image-0.jpg b/dist/assets/img/test-image-0.jpg new file mode 100644 index 0000000000..f15abb1137 Binary files /dev/null and b/dist/assets/img/test-image-0.jpg differ diff --git a/dist/assets/img/test-image-1.jpg b/dist/assets/img/test-image-1.jpg new file mode 100644 index 0000000000..7962b03ac5 Binary files /dev/null and b/dist/assets/img/test-image-1.jpg differ diff --git a/dist/assets/img/thick-asterisk-alone-gray.svg b/dist/assets/img/thick-asterisk-alone-gray.svg new file mode 100644 index 0000000000..0313c0e024 --- /dev/null +++ b/dist/assets/img/thick-asterisk-alone-gray.svg @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/dist/assets/img/thick-asterisk-alone.svg b/dist/assets/img/thick-asterisk-alone.svg new file mode 100644 index 0000000000..3da8f9959d --- /dev/null +++ b/dist/assets/img/thick-asterisk-alone.svg @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/dist/assets/js/examples.js b/dist/assets/js/examples.js new file mode 100644 index 0000000000..a6837add4b --- /dev/null +++ b/dist/assets/js/examples.js @@ -0,0 +1,200 @@ +var examples = { + init: function(file) { + + // Editor + + examples.editor = ace.edit('exampleEditor'); + //examples.editor.setTheme('ace/theme/monokai'); + examples.editor.getSession().setMode('ace/mode/javascript'); + examples.editor.getSession().setTabSize(2); + + examples.dims = []; + + // Button + + $('#runButton').click( function() { + examples.runExample(); + }); + $('#resetButton').click( function() { + examples.resetExample(); + }); + $('#copyButton').click( function() { + // don't know why we need this twice, or the setTimeout + // guessing it's some interaction with the editor.. + document.querySelector('textarea').select(); + $('textarea')[0].select(); + document.execCommand('copy'); + setTimeout(function() { document.execCommand('copy'); }, 200); + }); + + + // Example Frame + if($('#isMobile-displayButton').length !== 0) { + //it mobile + + $('#isMobile-displayButton').click( function() { + + $('#exampleFrame').show(); + $('#exampleFrame').ready(function() { + // alert('exampleFrame load') + examples.loadExample(true); + }); + }); + } else { + $('#exampleFrame').load(function() { + examples.loadExample(false); + }); + } + + + + // Capture clicks + + $.ajax({ + url: file, + dataType: 'text' + }) + .done(function (data) { + $('#exampleSelector').hide(); + + // parse and set frame size + var frameReg = /@frame (.*),(.*)/g; + var arr = data.split(frameReg); + if (arr.length > 2) { + examples.dims[0] = arr[1]; + examples.dims[1] = arr[2]; + } + + // render? + var norender = data.indexOf('@norender') !== -1; + + // parse and set name, aria label, and description + var metaReg = new RegExp('\\* ', 'g'); + var spaceReg = new RegExp(' ', 'g'); + + var startName = data.indexOf("@name")+6; + var endName = data.indexOf("\n", startName); + + var name = startName !== 5 ? data.substring(startName, endName) : ''; + + var startAriaLabel = data.indexOf("@arialabel")+11; + var endAriaLabel = data.indexOf("\n", startAriaLabel); + + var ariaLabel = startAriaLabel !== 10 ? data.substring(startAriaLabel, endAriaLabel) : ''; + + var startDesc = data.indexOf("@description")+13; + var endDesc = data.indexOf("*/", startDesc); + + var desc = startDesc !== 12 ? data.substring(startDesc, endDesc) : ''; + desc = desc.replace(metaReg, ''); + + $('#example-name').html(name); + $('#example-desc').html(desc); + $('#exampleFrame').attr("aria-label", ariaLabel); + + // strip description and set code + var ind = data.indexOf('*/'); + data = data.substring(ind+3); + examples.resetData = data; + + examples.showExample(norender); + }) + }, + showExample: function(norender) { + examples.editor.getSession().setValue(examples.resetData); + + //resize height of editor + var rows = examples.editor.getSession().$rowLengthCache.length; + var lineH = examples.editor.renderer.lineHeight; + $('#exampleEditor').height(rows*lineH+'px'); + + if (examples.resetData.indexOf('') !== -1) { + examples.editor.getSession().setMode('ace/mode/html'); + } + + if (norender) { + $('iframe').hide(); + $('#resetButton').hide(); + $('#runButton').hide(); + $('#copyButton').hide(); + } else { + examples.runExample(); + $('#exampleDisplay').show(); + } + }, + // display iframe + runExample: function() { + $('#exampleFrame').attr('src', $('#exampleFrame').attr('src')); + }, + resetExample: function() { + examples.showExample(); + }, + // load script into iframe + loadExample: function(isMobile) { + + var exampleCode = examples.editor.getSession().getValue(); + + try { + + if (exampleCode.indexOf('new p5()') === -1) { + exampleCode += '\nnew p5();'; + } + + if(isMobile) { + + $('#exampleFrame').css('position', 'fixed'); + $('#exampleFrame').css('top', '0px'); + $('#exampleFrame').css('left', '0px'); + $('#exampleFrame').css('right', '0px'); + $('#exampleFrame').css('bottom', '0px'); + $('#exampleFrame').css('z-index', '999'); + // var re = /createCanvas\((.*),(.*)\)/g; + // var arr = exampleCode.split(re); + // var height = $(screen).height(); + // var width = $(screen).width() + // $('#exampleFrame').css('height', height+'px'); + // $('#exampleFrame').css('width', width+'px'); + // console.log(height + ' ,' + width); + //exampleCode = exampleCode.replace(/windowWidth/, winWidth).replace(/windowHeight/, winHeight); + + // var userCSS = $('#exampleFrame')[0].contentWindow.document.createElement('style'); + // userCSS.type = 'text/css'; + // userCSS.innerHTML = 'html, body, canvas { width: 100% !important; height: 100% !important;}'; + //$('#exampleFrame')[0].contentWindow.document.head.appendChild(userCSS); + + } else { + if (examples.dims.length < 2) { + var re = /createCanvas\((.*),(.*)\)/g; + var arr = exampleCode.split(re); + $('#exampleFrame').height(arr[2]+'px'); + } else { + $('#exampleFrame').height(examples.dims[1]+'px'); + } + + } + + var userScript = $('#exampleFrame')[0].contentWindow.document.createElement('script'); + userScript.type = 'text/javascript'; + userScript.text = exampleCode; + userScript.async = false; + $('#exampleFrame')[0].contentWindow.document.body.appendChild(userScript); + + } catch (e) { + console.log(e.message); + } + } + +} +if (typeof(window._p5jsExample) !== 'undefined') { + examples.init(window._p5jsExample); +} + +// if (typeof(window._p5jsLanguage) !== 'undefined') { +// $('.example-link').each(function() { +// var name = $(this).data(window._p5jsLanguage); +// console.log(window._p5jsLanguage, name) +// $(this).text(name); +// }); +// } else { +// console.log('no language') +// } diff --git a/dist/assets/js/get-started.js b/dist/assets/js/get-started.js new file mode 100644 index 0000000000..4686d623e8 --- /dev/null +++ b/dist/assets/js/get-started.js @@ -0,0 +1,31 @@ +const copyToClipboard = (element)=> { + const value = document.getElementById(element).innerText; + const el = document.createElement('textarea'); + el.value = value; + el.setAttribute('readonly', ''); + el.style.position = 'absolute'; + el.style.left = '-9999px'; + el.setAttribute('aria-hidden','true'); + document.body.appendChild(el); + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); +} +$("#copy_sketch1").click(()=>{ + copyToClipboard("first-sketch1"); +}) +$("#copy_sketch2").click(()=>{ + copyToClipboard("first-sketch2"); +}); +$("#copy_sketch3").click(()=>{ + copyToClipboard("first-sketch3"); +}); +$("#copy_p5_script").click(()=>{ + copyToClipboard("markup1"); +}); +$("#copy_p5_link").click(()=>{ + copyToClipboard("cdn-link"); +}); +$("#copy_p5_html").click(()=>{ + copyToClipboard("sample-html"); +}); diff --git a/dist/assets/js/init.js b/dist/assets/js/init.js new file mode 100644 index 0000000000..f015d97d09 --- /dev/null +++ b/dist/assets/js/init.js @@ -0,0 +1,220 @@ +// ================================================= +// Family bar: +window.onload = function() { + + var test_js = function() { + // http://stackoverflow.com/a/12410668/1293700 + document.documentElement.className = document.documentElement.className.replace(/\bno-js\b/,'') + ' js'; + }(); + var test_pointerevents = function() { + // https://github.com/ausi/Feature-detection-technique-for-pointer-events/blob/master/modernizr-pointerevents.js + var el = document.createElement('x'); + el.style.cssText = 'pointer-events:auto'; + return el.style.pointerEvents === 'auto'; + }; + if (test_pointerevents()) { + document.documentElement.className += ' pointerevents'; + } + + var search_form = document.getElementById('search_form'), + search_field = document.getElementById('search_field'); + if (search_form) { + var open_field = function() { + search_form.className = 'form__open'; + search_field.focus(); + }; + var close_field = function(e) { + if (e.type === 'focusout') { + search_form.className = ''; + } else { + if (search_field.value === '') { + search_form.className = ''; + } + } + }; + if (search_form.addEventListener) { + search_form.addEventListener('mouseover', open_field, false); + search_form.addEventListener('mouseout', close_field, false); + search_form.addEventListener('focusout', close_field, false); + } else { // IE + search_form.attachEvent('onmouseover', open_field); + search_form.attachEvent('onmouseout', close_field); + search_form.attachEvent('onfocusout', close_field); + } + } + + // ================================================= + // set language and tagline + var path = window.location.pathname; + var parts = path.split('/'); + for (var i=0; i>16&255,a[s++]=t>>8&255,a[s++]=255&t;2===i&&(t=u[e.charCodeAt(r)]<<2|u[e.charCodeAt(r+1)]>>4,a[s++]=255&t);1===i&&(t=u[e.charCodeAt(r)]<<10|u[e.charCodeAt(r+1)]<<4|u[e.charCodeAt(r+2)]>>2,a[s++]=t>>8&255,a[s++]=255&t);return a},r.fromByteArray=function(e){for(var t,r=e.length,n=r%3,o=[],i=0,a=r-n;i>2]+s[t<<4&63]+"==")):2==n&&(t=(e[r-2]<<8)+e[r-1],o.push(s[t>>10]+s[t>>4&63]+s[t<<2&63]+"="));return o.join("")};for(var s=[],u=[],c="undefined"!=typeof Uint8Array?Uint8Array:Array,n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=0,i=n.length;o>18&63]+s[o>>12&63]+s[o>>6&63]+s[63&o]);return i.join("")}u["-".charCodeAt(0)]=62,u["_".charCodeAt(0)]=63},{}],2:[function(e,t,r){},{}],3:[function(e,t,r){arguments[4][2][0].apply(r,arguments)},{dup:2}],4:[function(U,e,N){(function(d){"use strict";var n=U("base64-js"),i=U("ieee754"),e="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;N.Buffer=d,N.SlowBuffer=function(e){+e!=e&&(e=0);return d.alloc(+e)},N.INSPECT_MAX_BYTES=50;var r=2147483647;function a(e){if(r>>1;case"base64":return A(e).length;default:if(o)return n?-1:P(e).length;t=(""+t).toLowerCase(),o=!0}}function h(e,t,r){var n=e[t];e[t]=e[r],e[r]=n}function p(e,t,r,n,o){if(0===e.length)return-1;if("string"==typeof r?(n=r,r=0):2147483647=e.length){if(o)return-1;r=e.length-1}else if(r<0){if(!o)return-1;r=0}if("string"==typeof t&&(t=d.from(t,n)),d.isBuffer(t))return 0===t.length?-1:y(e,t,r,n,o);if("number"==typeof t)return t&=255,"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,r):Uint8Array.prototype.lastIndexOf.call(e,t,r):y(e,[t],r,n,o);throw new TypeError("val must be string, number or Buffer")}function y(e,t,r,n,o){var i,a=1,s=e.length,l=t.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(e.length<2||t.length<2)return-1;s/=a=2,l/=2,r/=2}function u(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}if(o){var c=-1;for(i=r;i>8,o=r%256,i.push(o),i.push(n);return i}(t,e.length-r),e,r,n)}function b(e,t,r){return 0===t&&r===e.length?n.fromByteArray(e):n.fromByteArray(e.slice(t,r))}function _(e,t,r){r=Math.min(e.length,r);for(var n=[],o=t;o>>10&1023|55296),c=56320|1023&c),n.push(c),o+=d}return function(e){var t=e.length;if(t<=x)return String.fromCharCode.apply(String,e);var r="",n=0;for(;nthis.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(t>>>=0))return"";for(e=e||"utf8";;)switch(e){case"hex":return S(this,t,r);case"utf8":case"utf-8":return _(this,t,r);case"ascii":return w(this,t,r);case"latin1":case"binary":return j(this,t,r);case"base64":return b(this,t,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return M(this,t,r);default:if(n)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),n=!0}}.apply(this,arguments)},d.prototype.equals=function(e){if(!d.isBuffer(e))throw new TypeError("Argument must be a Buffer");return this===e||0===d.compare(this,e)},d.prototype.inspect=function(){var e="",t=N.INSPECT_MAX_BYTES;return e=this.toString("hex",0,t).replace(/(.{2})/g,"$1 ").trim(),this.length>t&&(e+=" ... "),""},e&&(d.prototype[e]=d.prototype.inspect),d.prototype.compare=function(e,t,r,n,o){if(R(e,Uint8Array)&&(e=d.from(e,e.offset,e.byteLength)),!d.isBuffer(e))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof e);if(void 0===t&&(t=0),void 0===r&&(r=e?e.length:0),void 0===n&&(n=0),void 0===o&&(o=this.length),t<0||r>e.length||n<0||o>this.length)throw new RangeError("out of range index");if(o<=n&&r<=t)return 0;if(o<=n)return-1;if(r<=t)return 1;if(this===e)return 0;for(var i=(o>>>=0)-(n>>>=0),a=(r>>>=0)-(t>>>=0),s=Math.min(i,a),l=this.slice(n,o),u=e.slice(t,r),c=0;c>>=0,isFinite(r)?(r>>>=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}var o=this.length-t;if((void 0===r||othis.length)throw new RangeError("Attempt to write outside buffer bounds");n=n||"utf8";for(var i,a,s,l,u,c,d=!1;;)switch(n){case"hex":return m(this,e,t,r);case"utf8":case"utf-8":return u=t,c=r,k(P(e,(l=this).length-u),l,u,c);case"ascii":return g(this,e,t,r);case"latin1":case"binary":return g(this,e,t,r);case"base64":return i=this,a=t,s=r,k(A(e),i,a,s);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return v(this,e,t,r);default:if(d)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),d=!0}},d.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var x=4096;function w(e,t,r){var n="";r=Math.min(e.length,r);for(var o=t;oe.length)throw new RangeError("Index out of range")}function O(e,t,r,n){if(r+n>e.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function C(e,t,r,n,o){return t=+t,r>>>=0,o||O(e,0,r,4),i.write(e,t,r,n,23,4),r+4}function L(e,t,r,n,o){return t=+t,r>>>=0,o||O(e,0,r,8),i.write(e,t,r,n,52,8),r+8}d.prototype.slice=function(e,t){var r=this.length;(e=~~e)<0?(e+=r)<0&&(e=0):r>>=0,t>>>=0,r||E(e,t,this.length);for(var n=this[e],o=1,i=0;++i>>=0,t>>>=0,r||E(e,t,this.length);for(var n=this[e+--t],o=1;0>>=0,t||E(e,1,this.length),this[e]},d.prototype.readUInt16LE=function(e,t){return e>>>=0,t||E(e,2,this.length),this[e]|this[e+1]<<8},d.prototype.readUInt16BE=function(e,t){return e>>>=0,t||E(e,2,this.length),this[e]<<8|this[e+1]},d.prototype.readUInt32LE=function(e,t){return e>>>=0,t||E(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},d.prototype.readUInt32BE=function(e,t){return e>>>=0,t||E(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},d.prototype.readIntLE=function(e,t,r){e>>>=0,t>>>=0,r||E(e,t,this.length);for(var n=this[e],o=1,i=0;++i>>=0,t>>>=0,r||E(e,t,this.length);for(var n=t,o=1,i=this[e+--n];0>>=0,t||E(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},d.prototype.readInt16LE=function(e,t){e>>>=0,t||E(e,2,this.length);var r=this[e]|this[e+1]<<8;return 32768&r?4294901760|r:r},d.prototype.readInt16BE=function(e,t){e>>>=0,t||E(e,2,this.length);var r=this[e+1]|this[e]<<8;return 32768&r?4294901760|r:r},d.prototype.readInt32LE=function(e,t){return e>>>=0,t||E(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},d.prototype.readInt32BE=function(e,t){return e>>>=0,t||E(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},d.prototype.readFloatLE=function(e,t){return e>>>=0,t||E(e,4,this.length),i.read(this,e,!0,23,4)},d.prototype.readFloatBE=function(e,t){return e>>>=0,t||E(e,4,this.length),i.read(this,e,!1,23,4)},d.prototype.readDoubleLE=function(e,t){return e>>>=0,t||E(e,8,this.length),i.read(this,e,!0,52,8)},d.prototype.readDoubleBE=function(e,t){return e>>>=0,t||E(e,8,this.length),i.read(this,e,!1,52,8)},d.prototype.writeUIntLE=function(e,t,r,n){e=+e,t>>>=0,r>>>=0,n||T(this,e,t,r,Math.pow(2,8*r)-1,0);var o=1,i=0;for(this[t]=255&e;++i>>=0,r>>>=0,n||T(this,e,t,r,Math.pow(2,8*r)-1,0);var o=r-1,i=1;for(this[t+o]=255&e;0<=--o&&(i*=256);)this[t+o]=e/i&255;return t+r},d.prototype.writeUInt8=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,1,255,0),this[t]=255&e,t+1},d.prototype.writeUInt16LE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,2,65535,0),this[t]=255&e,this[t+1]=e>>>8,t+2},d.prototype.writeUInt16BE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,2,65535,0),this[t]=e>>>8,this[t+1]=255&e,t+2},d.prototype.writeUInt32LE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,4,4294967295,0),this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e,t+4},d.prototype.writeUInt32BE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,4,4294967295,0),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},d.prototype.writeIntLE=function(e,t,r,n){if(e=+e,t>>>=0,!n){var o=Math.pow(2,8*r-1);T(this,e,t,r,o-1,-o)}var i=0,a=1,s=0;for(this[t]=255&e;++i>0)-s&255;return t+r},d.prototype.writeIntBE=function(e,t,r,n){if(e=+e,t>>>=0,!n){var o=Math.pow(2,8*r-1);T(this,e,t,r,o-1,-o)}var i=r-1,a=1,s=0;for(this[t+i]=255&e;0<=--i&&(a*=256);)e<0&&0===s&&0!==this[t+i+1]&&(s=1),this[t+i]=(e/a>>0)-s&255;return t+r},d.prototype.writeInt8=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,1,127,-128),e<0&&(e=255+e+1),this[t]=255&e,t+1},d.prototype.writeInt16LE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,2,32767,-32768),this[t]=255&e,this[t+1]=e>>>8,t+2},d.prototype.writeInt16BE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,2,32767,-32768),this[t]=e>>>8,this[t+1]=255&e,t+2},d.prototype.writeInt32LE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,4,2147483647,-2147483648),this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24,t+4},d.prototype.writeInt32BE=function(e,t,r){return e=+e,t>>>=0,r||T(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e,t+4},d.prototype.writeFloatLE=function(e,t,r){return C(this,e,t,!0,r)},d.prototype.writeFloatBE=function(e,t,r){return C(this,e,t,!1,r)},d.prototype.writeDoubleLE=function(e,t,r){return L(this,e,t,!0,r)},d.prototype.writeDoubleBE=function(e,t,r){return L(this,e,t,!1,r)},d.prototype.copy=function(e,t,r,n){if(!d.isBuffer(e))throw new TypeError("argument should be a Buffer");if(r=r||0,n||0===n||(n=this.length),t>=e.length&&(t=e.length),t=t||0,0=this.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),e.length-t>>=0,r=void 0===r?this.length:r>>>0,"number"==typeof(e=e||0))for(i=t;i>6|192,63&r|128)}else if(r<65536){if((t-=3)<0)break;i.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;i.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return i}function A(e){return n.toByteArray(function(e){if((e=(e=e.split("=")[0]).trim().replace(t,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function k(e,t,r,n){for(var o=0;o=t.length||o>=e.length);++o)t[o+r]=e[o];return o}function R(e,t){return e instanceof t||null!=e&&null!=e.constructor&&null!=e.constructor.name&&e.constructor.name===t.name}function D(e){return e!=e}var I=function(){for(var e="0123456789abcdef",t=new Array(256),r=0;r<16;++r)for(var n=16*r,o=0;o<16;++o)t[n+o]=e[r]+e[o];return t}()}).call(this,U("buffer").Buffer)},{"base64-js":1,buffer:4,ieee754:236}],5:[function(e,t,r){t.exports=function(e){if("function"!=typeof e)throw TypeError(String(e)+" is not a function");return e}},{}],6:[function(e,t,r){var n=e("../internals/is-object");t.exports=function(e){if(!n(e)&&null!==e)throw TypeError("Can't set "+String(e)+" as a prototype");return e}},{"../internals/is-object":74}],7:[function(e,t,r){var n=e("../internals/well-known-symbol"),o=e("../internals/object-create"),i=e("../internals/object-define-property"),a=n("unscopables"),s=Array.prototype;null==s[a]&&i.f(s,a,{configurable:!0,value:o(null)}),t.exports=function(e){s[a][e]=!0}},{"../internals/object-create":90,"../internals/object-define-property":92,"../internals/well-known-symbol":146}],8:[function(e,t,r){"use strict";var n=e("../internals/string-multibyte").charAt;t.exports=function(e,t,r){return t+(r?n(e,t).length:1)}},{"../internals/string-multibyte":123}],9:[function(e,t,r){t.exports=function(e,t,r){if(!(e instanceof t))throw TypeError("Incorrect "+(r?r+" ":"")+"invocation");return e}},{}],10:[function(e,t,r){var n=e("../internals/is-object");t.exports=function(e){if(!n(e))throw TypeError(String(e)+" is not an object");return e}},{"../internals/is-object":74}],11:[function(e,t,r){t.exports="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof DataView},{}],12:[function(e,t,r){"use strict";function n(e){return l(e)&&u(L,c(e))}var o,i=e("../internals/array-buffer-native"),a=e("../internals/descriptors"),s=e("../internals/global"),l=e("../internals/is-object"),u=e("../internals/has"),c=e("../internals/classof"),d=e("../internals/create-non-enumerable-property"),f=e("../internals/redefine"),h=e("../internals/object-define-property").f,p=e("../internals/object-get-prototype-of"),y=e("../internals/object-set-prototype-of"),m=e("../internals/well-known-symbol"),g=e("../internals/uid"),v=s.Int8Array,b=v&&v.prototype,_=s.Uint8ClampedArray,x=_&&_.prototype,w=v&&p(v),j=b&&p(b),S=Object.prototype,M=S.isPrototypeOf,E=m("toStringTag"),T=g("TYPED_ARRAY_TAG"),O=i&&!!y&&"Opera"!==c(s.opera),C=!1,L={Int8Array:1,Uint8Array:1,Uint8ClampedArray:1,Int16Array:2,Uint16Array:2,Int32Array:4,Uint32Array:4,Float32Array:4,Float64Array:8};for(o in L)s[o]||(O=!1);if((!O||"function"!=typeof w||w===Function.prototype)&&(w=function(){throw TypeError("Incorrect invocation")},O))for(o in L)s[o]&&y(s[o],w);if((!O||!j||j===S)&&(j=w.prototype,O))for(o in L)s[o]&&y(s[o].prototype,j);if(O&&p(x)!==j&&y(x,j),a&&!u(j,E))for(o in C=!0,h(j,E,{get:function(){return l(this)?this[T]:void 0}}),L)s[o]&&d(s[o],T,o);t.exports={NATIVE_ARRAY_BUFFER_VIEWS:O,TYPED_ARRAY_TAG:C&&T,aTypedArray:function(e){if(n(e))return e;throw TypeError("Target is not a typed array")},aTypedArrayConstructor:function(e){if(y){if(M.call(w,e))return e}else for(var t in L)if(u(L,o)){var r=s[t];if(r&&(e===r||M.call(r,e)))return e}throw TypeError("Target is not a typed array constructor")},exportTypedArrayMethod:function(e,t,r){if(a){if(r)for(var n in L){var o=s[n];o&&u(o.prototype,e)&&delete o.prototype[e]}j[e]&&!r||f(j,e,r?t:O&&b[e]||t)}},exportTypedArrayStaticMethod:function(e,t,r){var n,o;if(a){if(y){if(r)for(n in L)(o=s[n])&&u(o,e)&&delete o[e];if(w[e]&&!r)return;try{return f(w,e,r?t:O&&v[e]||t)}catch(e){}}for(n in L)!(o=s[n])||o[e]&&!r||f(o,e,t)}},isView:function(e){var t=c(e);return"DataView"===t||u(L,t)},isTypedArray:n,TypedArray:w,TypedArrayPrototype:j}},{"../internals/array-buffer-native":11,"../internals/classof":29,"../internals/create-non-enumerable-property":37,"../internals/descriptors":42,"../internals/global":59,"../internals/has":60,"../internals/is-object":74,"../internals/object-define-property":92,"../internals/object-get-prototype-of":97,"../internals/object-set-prototype-of":101,"../internals/redefine":108,"../internals/uid":143,"../internals/well-known-symbol":146}],13:[function(e,t,r){"use strict";function n(e){return[255&e]}function o(e){return[255&e,e>>8&255]}function i(e){return[255&e,e>>8&255,e>>16&255,e>>24&255]}function a(e){return e[3]<<24|e[2]<<16|e[1]<<8|e[0]}function s(e){return V(e,23,4)}function l(e){return V(e,52,8)}function u(e,t){E(e[R],t,{get:function(){return L(this)[t]}})}function c(e,t,r,n){var o=x(r),i=L(e);if(o+t>i.byteLength)throw G(D);var a=L(i.buffer).bytes,s=o+i.byteOffset,l=a.slice(s,s+t);return n?l:l.reverse()}function d(e,t,r,n,o,i){var a=x(r),s=L(e);if(a+t>s.byteLength)throw G(D);for(var l=L(s.buffer).bytes,u=a+s.byteOffset,c=n(+o),d=0;dX;)(H=q[X++])in U||y(U,H,I[H]);W.constructor=U}S&&j(F)!==B&&S(F,B);var Y=new N(new U(2)),Z=F.setInt8;Y.setInt8(0,2147483648),Y.setInt8(1,2147483649),!Y.getInt8(0)&&Y.getInt8(1)||m(F,{setInt8:function(e,t){Z.call(this,e,t<<24>>24)},setUint8:function(e,t){Z.call(this,e,t<<24>>24)}},{unsafe:!0})}else U=function(e){v(this,U,A);var t=x(e);P(this,{bytes:T.call(new Array(t),0),byteLength:t}),h||(this.byteLength=t)},N=function(e,t,r){v(this,N,k),v(e,U,k);var n=L(e).byteLength,o=b(t);if(o<0||n>24},getUint8:function(e){return c(this,1,e)[0]},getInt16:function(e,t){var r=c(this,2,e,1>16},getUint16:function(e,t){var r=c(this,2,e,1>>0},getFloat32:function(e,t){return z(c(this,4,e,1"+o+""}},{"../internals/require-object-coercible":113}],36:[function(e,t,r){"use strict";function o(){return this}var i=e("../internals/iterators-core").IteratorPrototype,a=e("../internals/object-create"),s=e("../internals/create-property-descriptor"),l=e("../internals/set-to-string-tag"),u=e("../internals/iterators");t.exports=function(e,t,r){var n=t+" Iterator";return e.prototype=a(i,{next:s(1,r)}),l(e,n,!1,!0),u[n]=o,e}},{"../internals/create-property-descriptor":38,"../internals/iterators":79,"../internals/iterators-core":78,"../internals/object-create":90,"../internals/set-to-string-tag":117}],37:[function(e,t,r){var n=e("../internals/descriptors"),o=e("../internals/object-define-property"),i=e("../internals/create-property-descriptor");t.exports=n?function(e,t,r){return o.f(e,t,i(1,r))}:function(e,t,r){return e[t]=r,e}},{"../internals/create-property-descriptor":38,"../internals/descriptors":42,"../internals/object-define-property":92}],38:[function(e,t,r){t.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},{}],39:[function(e,t,r){"use strict";var o=e("../internals/to-primitive"),i=e("../internals/object-define-property"),a=e("../internals/create-property-descriptor");t.exports=function(e,t,r){var n=o(t);n in e?i.f(e,n,a(0,r)):e[n]=r}},{"../internals/create-property-descriptor":38,"../internals/object-define-property":92,"../internals/to-primitive":138}],40:[function(e,t,r){"use strict";function g(){return this}var v=e("../internals/export"),b=e("../internals/create-iterator-constructor"),_=e("../internals/object-get-prototype-of"),x=e("../internals/object-set-prototype-of"),w=e("../internals/set-to-string-tag"),j=e("../internals/create-non-enumerable-property"),S=e("../internals/redefine"),n=e("../internals/well-known-symbol"),M=e("../internals/is-pure"),E=e("../internals/iterators"),o=e("../internals/iterators-core"),T=o.IteratorPrototype,O=o.BUGGY_SAFARI_ITERATORS,C=n("iterator"),L="values",P="entries";t.exports=function(e,t,r,n,o,i,a){b(r,t,n);function s(e){if(e===o&&y)return y;if(!O&&e in h)return h[e];switch(e){case"keys":case L:case P:return function(){return new r(this,e)}}return function(){return new r(this)}}var l,u,c,d=t+" Iterator",f=!1,h=e.prototype,p=h[C]||h["@@iterator"]||o&&h[o],y=!O&&p||s(o),m="Array"==t&&h.entries||p;if(m&&(l=_(m.call(new e)),T!==Object.prototype&&l.next&&(M||_(l)===T||(x?x(l,T):"function"!=typeof l[C]&&j(l,C,g)),w(l,d,!0,!0),M&&(E[d]=g))),o==L&&p&&p.name!==L&&(f=!0,y=function(){return p.call(this)}),M&&!a||h[C]===y||j(h,C,y),E[t]=y,o)if(u={values:s(L),keys:i?y:s("keys"),entries:s(P)},a)for(c in u)!O&&!f&&c in h||S(h,c,u[c]);else v({target:t,proto:!0,forced:O||f},u);return u}},{"../internals/create-iterator-constructor":36,"../internals/create-non-enumerable-property":37,"../internals/export":49,"../internals/is-pure":75,"../internals/iterators":79,"../internals/iterators-core":78,"../internals/object-get-prototype-of":97,"../internals/object-set-prototype-of":101,"../internals/redefine":108,"../internals/set-to-string-tag":117,"../internals/well-known-symbol":146}],41:[function(e,t,r){var n=e("../internals/path"),o=e("../internals/has"),i=e("../internals/well-known-symbol-wrapped"),a=e("../internals/object-define-property").f;t.exports=function(e){var t=n.Symbol||(n.Symbol={});o(t,e)||a(t,e,{value:i.f(e)})}},{"../internals/has":60,"../internals/object-define-property":92,"../internals/path":104,"../internals/well-known-symbol-wrapped":145}],42:[function(e,t,r){var n=e("../internals/fails");t.exports=!n(function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})},{"../internals/fails":50}],43:[function(e,t,r){var n=e("../internals/global"),o=e("../internals/is-object"),i=n.document,a=o(i)&&o(i.createElement);t.exports=function(e){return a?i.createElement(e):{}}},{"../internals/global":59,"../internals/is-object":74}],44:[function(e,t,r){t.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},{}],45:[function(e,t,r){var n=e("../internals/engine-user-agent");t.exports=/(iphone|ipod|ipad).*applewebkit/i.test(n)},{"../internals/engine-user-agent":46}],46:[function(e,t,r){var n=e("../internals/get-built-in");t.exports=n("navigator","userAgent")||""},{"../internals/get-built-in":56}],47:[function(e,t,r){var n,o,i=e("../internals/global"),a=e("../internals/engine-user-agent"),s=i.process,l=s&&s.versions,u=l&&l.v8;u?o=(n=u.split("."))[0]+n[1]:a&&(!(n=a.match(/Edge\/(\d+)/))||74<=n[1])&&(n=a.match(/Chrome\/(\d+)/))&&(o=n[1]),t.exports=o&&+o},{"../internals/engine-user-agent":46,"../internals/global":59}],48:[function(e,t,r){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},{}],49:[function(e,t,r){var c=e("../internals/global"),d=e("../internals/object-get-own-property-descriptor").f,f=e("../internals/create-non-enumerable-property"),h=e("../internals/redefine"),p=e("../internals/set-global"),y=e("../internals/copy-constructor-properties"),m=e("../internals/is-forced");t.exports=function(e,t){var r,n,o,i,a,s=e.target,l=e.global,u=e.stat;if(r=l?c:u?c[s]||p(s,{}):(c[s]||{}).prototype)for(n in t){if(i=t[n],o=e.noTargetGet?(a=d(r,n))&&a.value:r[n],!m(l?n:s+(u?".":"#")+n,e.forced)&&void 0!==o){if(typeof i==typeof o)continue;y(i,o)}(e.sham||o&&o.sham)&&f(i,"sham",!0),h(r,n,i,e)}}},{"../internals/copy-constructor-properties":32,"../internals/create-non-enumerable-property":37,"../internals/global":59,"../internals/is-forced":73,"../internals/object-get-own-property-descriptor":93,"../internals/redefine":108,"../internals/set-global":115}],50:[function(e,t,r){t.exports=function(e){try{return!!e()}catch(e){return!0}}},{}],51:[function(e,t,r){"use strict";e("../modules/es.regexp.exec");var d=e("../internals/redefine"),f=e("../internals/fails"),h=e("../internals/well-known-symbol"),p=e("../internals/regexp-exec"),y=e("../internals/create-non-enumerable-property"),m=h("species"),g=!f(function(){var e=/./;return e.exec=function(){var e=[];return e.groups={a:"7"},e},"7"!=="".replace(e,"$")}),v="$0"==="a".replace(/./,"$0"),n=h("replace"),b=!!/./[n]&&""===/./[n]("a","$0"),_=!f(function(){var e=/(?:)/,t=e.exec;e.exec=function(){return t.apply(this,arguments)};var r="ab".split(e);return 2!==r.length||"a"!==r[0]||"b"!==r[1]});t.exports=function(r,e,t,n){var o=h(r),i=!f(function(){var e={};return e[o]=function(){return 7},7!=""[r](e)}),a=i&&!f(function(){var e=!1,t=/a/;return"split"===r&&((t={constructor:{}}).constructor[m]=function(){return t},t.flags="",t[o]=/./[o]),t.exec=function(){return e=!0,null},t[o](""),!e});if(!i||!a||"replace"===r&&(!g||!v||b)||"split"===r&&!_){var s=/./[o],l=t(o,""[r],function(e,t,r,n,o){return t.exec===p?i&&!o?{done:!0,value:s.call(t,r,n)}:{done:!0,value:e.call(r,t,n)}:{done:!1}},{REPLACE_KEEPS_$0:v,REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE:b}),u=l[0],c=l[1];d(String.prototype,r,u),d(RegExp.prototype,o,2==e?function(e,t){return c.call(e,this,t)}:function(e){return c.call(e,this)})}n&&y(RegExp.prototype[o],"sham",!0)}},{"../internals/create-non-enumerable-property":37,"../internals/fails":50,"../internals/redefine":108,"../internals/regexp-exec":110,"../internals/well-known-symbol":146,"../modules/es.regexp.exec":181}],52:[function(e,t,r){"use strict";var f=e("../internals/is-array"),h=e("../internals/to-length"),p=e("../internals/function-bind-context"),y=function(e,t,r,n,o,i,a,s){for(var l,u=o,c=0,d=!!a&&p(a,s,3);c>1,c=23===t?p(2,-24)-p(2,-77):0,d=e<0||0===e&&1/e<0?1:0,f=0;for((e=h(e))!=e||e===1/0?(o=e!=e?1:0,n=l):(n=y(m(e)/g),e*(i=p(2,-n))<1&&(n--,i*=2),2<=(e+=1<=n+u?c/i:c*p(2,1-u))*i&&(n++,i/=2),l<=n+u?(o=0,n=l):1<=n+u?(o=(e*i-1)*p(2,t),n+=u):(o=e*p(2,u-1)*p(2,t),n=0));8<=t;a[f++]=255&o,o/=256,t-=8);for(n=n<>1,s=o-7,l=n-1,u=e[l--],c=127&u;for(u>>=7;0>=-s,s+=t;0"+e+""}var i,a=e("../internals/an-object"),s=e("../internals/object-define-properties"),l=e("../internals/enum-bug-keys"),u=e("../internals/hidden-keys"),c=e("../internals/html"),d=e("../internals/document-create-element"),f=e("../internals/shared-key"),h="prototype",p="script",y=f("IE_PROTO"),m=function(){try{i=document.domain&&new ActiveXObject("htmlfile")}catch(e){}var e,t;m=i?function(e){e.write(o("")),e.close();var t=e.parentWindow.Object;return e=null,t}(i):((t=d("iframe")).style.display="none",c.appendChild(t),t.src=String("javascript:"),(e=t.contentWindow.document).open(),e.write(o("document.F=Object")),e.close(),e.F);for(var r=l.length;r--;)delete m[h][l[r]];return m()};u[y]=!0,t.exports=Object.create||function(e,t){var r;return null!==e?(n[h]=a(e),r=new n,n[h]=null,r[y]=e):r=m(),void 0===t?r:s(r,t)}},{"../internals/an-object":10,"../internals/document-create-element":43,"../internals/enum-bug-keys":48,"../internals/hidden-keys":61,"../internals/html":63,"../internals/object-define-properties":91,"../internals/shared-key":118}],91:[function(e,t,r){var n=e("../internals/descriptors"),a=e("../internals/object-define-property"),s=e("../internals/an-object"),l=e("../internals/object-keys");t.exports=n?Object.defineProperties:function(e,t){s(e);for(var r,n=l(t),o=n.length,i=0;io;)a(n,r=t[o++])&&(~l(i,r)||i.push(r));return i}},{"../internals/array-includes":18,"../internals/has":60,"../internals/hidden-keys":61,"../internals/to-indexed-object":132}],99:[function(e,t,r){var n=e("../internals/object-keys-internal"),o=e("../internals/enum-bug-keys");t.exports=Object.keys||function(e){return n(e,o)}},{"../internals/enum-bug-keys":48,"../internals/object-keys-internal":98}],100:[function(e,t,r){"use strict";var n={}.propertyIsEnumerable,o=Object.getOwnPropertyDescriptor,i=o&&!n.call({1:2},1);r.f=i?function(e){var t=o(this,e);return!!t&&t.enumerable}:n},{}],101:[function(e,t,r){var o=e("../internals/an-object"),i=e("../internals/a-possible-prototype");t.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var r,n=!1,e={};try{(r=Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set).call(e,[]),n=e instanceof Array}catch(e){}return function(e,t){return o(e),i(t),n?r.call(e,t):e.__proto__=t,e}}():void 0)},{"../internals/a-possible-prototype":6,"../internals/an-object":10}],102:[function(e,t,r){"use strict";var n=e("../internals/to-string-tag-support"),o=e("../internals/classof");t.exports=n?{}.toString:function(){return"[object "+o(this)+"]"}},{"../internals/classof":29,"../internals/to-string-tag-support":139}],103:[function(e,t,r){var n=e("../internals/get-built-in"),o=e("../internals/object-get-own-property-names"),i=e("../internals/object-get-own-property-symbols"),a=e("../internals/an-object");t.exports=n("Reflect","ownKeys")||function(e){var t=o.f(a(e)),r=i.f;return r?t.concat(r(e)):t}},{"../internals/an-object":10,"../internals/get-built-in":56,"../internals/object-get-own-property-names":95,"../internals/object-get-own-property-symbols":96}],104:[function(e,t,r){var n=e("../internals/global");t.exports=n},{"../internals/global":59}],105:[function(e,t,r){t.exports=function(e){try{return{error:!1,value:e()}}catch(e){return{error:!0,value:e}}}},{}],106:[function(e,t,r){var n=e("../internals/an-object"),o=e("../internals/is-object"),i=e("../internals/new-promise-capability");t.exports=function(e,t){if(n(e),o(t)&&t.constructor===e)return t;var r=i.f(e);return(0,r.resolve)(t),r.promise}},{"../internals/an-object":10,"../internals/is-object":74,"../internals/new-promise-capability":86}],107:[function(e,t,r){var o=e("../internals/redefine");t.exports=function(e,t,r){for(var n in t)o(e,n,t[n],r);return e}},{"../internals/redefine":108}],108:[function(e,t,r){var s=e("../internals/global"),l=e("../internals/create-non-enumerable-property"),u=e("../internals/has"),c=e("../internals/set-global"),n=e("../internals/inspect-source"),o=e("../internals/internal-state"),i=o.get,d=o.enforce,f=String(String).split("String");(t.exports=function(e,t,r,n){var o=!!n&&!!n.unsafe,i=!!n&&!!n.enumerable,a=!!n&&!!n.noTargetGet;"function"==typeof r&&("string"!=typeof t||u(r,"name")||l(r,"name",t),d(r).source=f.join("string"==typeof t?t:"")),e!==s?(o?!a&&e[t]&&(i=!0):delete e[t],i?e[t]=r:l(e,t,r)):i?e[t]=r:c(t,r)})(Function.prototype,"toString",function(){return"function"==typeof this&&i(this).source||n(this)})},{"../internals/create-non-enumerable-property":37,"../internals/global":59,"../internals/has":60,"../internals/inspect-source":68,"../internals/internal-state":70,"../internals/set-global":115}],109:[function(e,t,r){var o=e("./classof-raw"),i=e("./regexp-exec");t.exports=function(e,t){var r=e.exec;if("function"==typeof r){var n=r.call(e,t);if("object"!=typeof n)throw TypeError("RegExp exec method returned something other than an Object or null");return n}if("RegExp"!==o(e))throw TypeError("RegExp#exec called on incompatible receiver");return i.call(e,t)}},{"./classof-raw":28,"./regexp-exec":110}],110:[function(e,t,r){"use strict";var n,o,d=e("./regexp-flags"),i=e("./regexp-sticky-helpers"),f=RegExp.prototype.exec,h=String.prototype.replace,a=f,p=(n=/a/,o=/b*/g,f.call(n,"a"),f.call(o,"a"),0!==n.lastIndex||0!==o.lastIndex),y=i.UNSUPPORTED_Y||i.BROKEN_CARET,m=void 0!==/()??/.exec("")[1];(p||m||y)&&(a=function(e){var t,r,n,o,i=this,a=y&&i.sticky,s=d.call(i),l=i.source,u=0,c=e;return a&&(-1===(s=s.replace("y","")).indexOf("g")&&(s+="g"),c=String(e).slice(i.lastIndex),0>1,e+=x(e/t);455x((b-a)/d))throw RangeError(_);for(a+=(c-i)*d,i=c,t=0;tb)throw RangeError(_);if(r==i){for(var f=a,h=36;;h+=36){var p=h<=s?1:s+26<=h?26:h-s;if(f>>=1)&&(t+=t))1&n&&(r+=t);return r}},{"../internals/require-object-coercible":113,"../internals/to-integer":133}],126:[function(e,t,r){var n=e("../internals/fails"),o=e("../internals/whitespaces");t.exports=function(e){return n(function(){return!!o[e]()||"​…᠎"!="​…᠎"[e]()||o[e].name!==e})}},{"../internals/fails":50,"../internals/whitespaces":147}],127:[function(e,t,r){function n(r){return function(e){var t=String(o(e));return 1&r&&(t=t.replace(a,"")),2&r&&(t=t.replace(s,"")),t}}var o=e("../internals/require-object-coercible"),i="["+e("../internals/whitespaces")+"]",a=RegExp("^"+i+i+"*"),s=RegExp(i+i+"*$");t.exports={start:n(1),end:n(2),trim:n(3)}},{"../internals/require-object-coercible":113,"../internals/whitespaces":147}],128:[function(e,t,r){function n(e){if(S.hasOwnProperty(e)){var t=S[e];delete S[e],t()}}function o(e){return function(){n(e)}}function i(e){n(e.data)}function a(e){c.postMessage(e+"",g.protocol+"//"+g.host)}var s,l,u,c=e("../internals/global"),d=e("../internals/fails"),f=e("../internals/classof-raw"),h=e("../internals/function-bind-context"),p=e("../internals/html"),y=e("../internals/document-create-element"),m=e("../internals/engine-is-ios"),g=c.location,v=c.setImmediate,b=c.clearImmediate,_=c.process,x=c.MessageChannel,w=c.Dispatch,j=0,S={},M="onreadystatechange";v&&b||(v=function(e){for(var t=[],r=1;r=t.length?{value:e.target=void 0,done:!0}:"keys"==r?{value:n,done:!1}:"values"==r?{value:t[n],done:!1}:{value:[n,t[n]],done:!1}},"values"),i.Arguments=i.Array,o("keys"),o("values"),o("entries")},{"../internals/add-to-unscopables":7,"../internals/define-iterator":40,"../internals/internal-state":70,"../internals/iterators":79,"../internals/to-indexed-object":132}],159:[function(e,t,r){"use strict";var n=e("../internals/export"),o=e("../internals/indexed-object"),i=e("../internals/to-indexed-object"),a=e("../internals/array-method-is-strict"),s=[].join,l=o!=Object,u=a("join",",");n({target:"Array",proto:!0,forced:l||!u},{join:function(e){return s.call(i(this),void 0===e?",":e)}})},{"../internals/array-method-is-strict":22,"../internals/export":49,"../internals/indexed-object":66,"../internals/to-indexed-object":132}],160:[function(e,t,r){var n=e("../internals/export"),o=e("../internals/array-last-index-of");n({target:"Array",proto:!0,forced:o!==[].lastIndexOf},{lastIndexOf:o})},{"../internals/array-last-index-of":20,"../internals/export":49}],161:[function(e,t,r){"use strict";var n=e("../internals/export"),o=e("../internals/array-iteration").map,i=e("../internals/array-method-has-species-support"),a=e("../internals/array-method-uses-to-length"),s=i("map"),l=a("map");n({target:"Array",proto:!0,forced:!s||!l},{map:function(e,t){return o(this,e,1M;M++)l(b,w=S[M])&&!l(j,w)&&m(j,w,y(b,w));(j.prototype=_).constructor=j,s(i,v,j)}},{"../internals/classof-raw":28,"../internals/descriptors":42,"../internals/fails":50,"../internals/global":59,"../internals/has":60,"../internals/inherit-if-required":67,"../internals/is-forced":73,"../internals/object-create":90,"../internals/object-define-property":92,"../internals/object-get-own-property-descriptor":93,"../internals/object-get-own-property-names":95,"../internals/redefine":108,"../internals/string-trim":127,"../internals/to-primitive":138}],171:[function(e,t,r){e("../internals/export")({target:"Number",stat:!0},{isFinite:e("../internals/number-is-finite")})},{"../internals/export":49,"../internals/number-is-finite":88}],172:[function(e,t,r){"use strict";var n=e("../internals/export"),h=e("../internals/to-integer"),p=e("../internals/this-number-value"),y=e("../internals/string-repeat"),o=e("../internals/fails"),i=1..toFixed,m=Math.floor,g=function(e,t,r){return 0===t?r:t%2==1?g(e,t-1,r*e):g(e*e,t/2,r)};n({target:"Number",proto:!0,forced:i&&("0.000"!==8e-5.toFixed(3)||"1"!==.9.toFixed(0)||"1.25"!==1.255.toFixed(2)||"1000000000000000128"!==(0xde0b6b3a7640080).toFixed(0))||!o(function(){i.call({})})},{toFixed:function(e){function t(e,t){for(var r=-1,n=t;++r<6;)n+=e*c[r],c[r]=n%1e7,n=m(n/1e7)}function r(e){for(var t=6,r=0;0<=--t;)r+=c[t],c[t]=m(r/e),r=r%e*1e7}function n(){for(var e=6,t="";0<=--e;)if(""!==t||0===e||0!==c[e]){var r=String(c[e]);t=""===t?r:t+y.call("0",7-r.length)+r}return t}var o,i,a,s,l=p(this),u=h(e),c=[0,0,0,0,0,0],d="",f="0";if(u<0||20r;){var n,o,i,a=p[r++],s=t?a.ok:a.fail,l=a.resolve,u=a.reject,c=a.domain;try{s?(t||(2===f.rejection&&oe(d,f),f.rejection=1),!0===s?n=e:(c&&c.enter(),n=s(e),c&&(c.exit(),i=!0)),n===a.promise?u(W("Promise-chain cycle")):(o=y(n))?o.call(n,l,u):l(n)):u(e)}catch(e){c&&!i&&c.exit(),u(e)}}f.reactions=[],f.notified=!1,h&&!f.rejection&&re(d,f)})}}function o(e,t,r){var n,o;J?((n=q.createEvent("Event")).promise=t,n.reason=r,n.initEvent(e,!1,!0),h.dispatchEvent(n)):n={promise:t,reason:r},(o=h["on"+e])?o(n):e===$&&A("Unhandled promise rejection",r)}function a(t,r,n,o){return function(e){t(r,n,e,o)}}function s(e,t,r,n){t.done||(t.done=!0,n&&(t=n),t.value=r,t.state=2,i(e,t,!0))}var n,l,u,c,d=e("../internals/export"),f=e("../internals/is-pure"),h=e("../internals/global"),p=e("../internals/get-built-in"),m=e("../internals/native-promise-constructor"),g=e("../internals/redefine"),v=e("../internals/redefine-all"),b=e("../internals/set-to-string-tag"),_=e("../internals/set-species"),x=e("../internals/is-object"),w=e("../internals/a-function"),j=e("../internals/an-instance"),S=e("../internals/classof-raw"),M=e("../internals/inspect-source"),E=e("../internals/iterate"),T=e("../internals/check-correctness-of-iteration"),O=e("../internals/species-constructor"),C=e("../internals/task").set,L=e("../internals/microtask"),P=e("../internals/promise-resolve"),A=e("../internals/host-report-errors"),k=e("../internals/new-promise-capability"),R=e("../internals/perform"),D=e("../internals/internal-state"),I=e("../internals/is-forced"),U=e("../internals/well-known-symbol"),N=e("../internals/engine-v8-version"),F=U("species"),B="Promise",G=D.get,V=D.set,z=D.getterFor(B),H=m,W=h.TypeError,q=h.document,X=h.process,Y=p("fetch"),Z=k.f,Q=Z,K="process"==S(X),J=!!(q&&q.createEvent&&h.dispatchEvent),$="unhandledrejection",ee=I(B,function(){if(!(M(H)!==String(H))){if(66===N)return!0;if(!K&&"function"!=typeof PromiseRejectionEvent)return!0}if(f&&!H.prototype.finally)return!0;if(51<=N&&/native code/.test(H))return!1;function e(e){e(function(){},function(){})}var t=H.resolve(1);return(t.constructor={})[F]=e,!(t.then(function(){})instanceof e)}),te=ee||!T(function(e){H.all(e).catch(function(){})}),re=function(r,n){C.call(h,function(){var e,t=n.value;if(ne(n)&&(e=R(function(){K?X.emit("unhandledRejection",t,r):o($,r,t)}),n.rejection=K||ne(n)?2:1,e.error))throw e.value})},ne=function(e){return 1!==e.rejection&&!e.parent},oe=function(e,t){C.call(h,function(){K?X.emit("rejectionHandled",e):o("rejectionhandled",e,t.value)})},ie=function(r,n,e,t){if(!n.done){n.done=!0,t&&(n=t);try{if(r===e)throw W("Promise can't be resolved itself");var o=y(e);o?L(function(){var t={done:!1};try{o.call(e,a(ie,r,t,n),a(s,r,t,n))}catch(e){s(r,t,e,n)}}):(n.value=e,n.state=1,i(r,n,!1))}catch(e){s(r,{done:!1},e,n)}}};ee&&(H=function(e){j(this,H,B),w(e),n.call(this);var t=G(this);try{e(a(ie,this,t),a(s,this,t))}catch(e){s(this,t,e)}},(n=function(){V(this,{type:B,done:!1,notified:!1,parent:!1,reactions:[],rejection:!1,state:0,value:void 0})}).prototype=v(H.prototype,{then:function(e,t){var r=z(this),n=Z(O(this,H));return n.ok="function"!=typeof e||e,n.fail="function"==typeof t&&t,n.domain=K?X.domain:void 0,r.parent=!0,r.reactions.push(n),0!=r.state&&i(this,r,!1),n.promise},catch:function(e){return this.then(void 0,e)}}),l=function(){var e=new n,t=G(e);this.promise=e,this.resolve=a(ie,e,t),this.reject=a(s,e,t)},k.f=Z=function(e){return e===H||e===u?new l(e):Q(e)},f||"function"!=typeof m||(c=m.prototype.then,g(m.prototype,"then",function(e,t){var r=this;return new H(function(e,t){c.call(r,e,t)}).then(e,t)},{unsafe:!0}),"function"==typeof Y&&d({global:!0,enumerable:!0,forced:!0},{fetch:function(e){return P(H,Y.apply(h,arguments))}}))),d({global:!0,wrap:!0,forced:ee},{Promise:H}),b(H,B,!1,!0),_(B),u=p(B),d({target:B,stat:!0,forced:ee},{reject:function(e){var t=Z(this);return t.reject.call(void 0,e),t.promise}}),d({target:B,stat:!0,forced:f||ee},{resolve:function(e){return P(f&&this===u?H:this,e)}}),d({target:B,stat:!0,forced:te},{all:function(e){var s=this,t=Z(s),l=t.resolve,u=t.reject,r=R(function(){var n=w(s.resolve),o=[],i=0,a=1;E(e,function(e){var t=i++,r=!1;o.push(void 0),a++,n.call(s,e).then(function(e){r||(r=!0,o[t]=e,--a||l(o))},u)}),--a||l(o)});return r.error&&u(r.value),t.promise},race:function(e){var r=this,n=Z(r),o=n.reject,t=R(function(){var t=w(r.resolve);E(e,function(e){t.call(r,e).then(n.resolve,o)})});return t.error&&o(t.value),n.promise}})},{"../internals/a-function":5,"../internals/an-instance":9,"../internals/check-correctness-of-iteration":27,"../internals/classof-raw":28,"../internals/engine-v8-version":47,"../internals/export":49,"../internals/get-built-in":56,"../internals/global":59,"../internals/host-report-errors":62,"../internals/inspect-source":68,"../internals/internal-state":70,"../internals/is-forced":73,"../internals/is-object":74,"../internals/is-pure":75,"../internals/iterate":77,"../internals/microtask":81,"../internals/native-promise-constructor":82,"../internals/new-promise-capability":86,"../internals/perform":105,"../internals/promise-resolve":106,"../internals/redefine":108,"../internals/redefine-all":107,"../internals/set-species":116,"../internals/set-to-string-tag":117,"../internals/species-constructor":121,"../internals/task":128,"../internals/well-known-symbol":146}],179:[function(e,t,r){var n=e("../internals/export"),o=e("../internals/get-built-in"),l=e("../internals/a-function"),u=e("../internals/an-object"),c=e("../internals/is-object"),d=e("../internals/object-create"),f=e("../internals/function-bind"),i=e("../internals/fails"),h=o("Reflect","construct"),p=i(function(){function e(){}return!(h(function(){},[],e)instanceof e)}),y=!i(function(){h(function(){})}),a=p||y;n({target:"Reflect",stat:!0,forced:a,sham:a},{construct:function(e,t,r){l(e),u(t);var n=arguments.length<3?e:l(r);if(y&&!p)return h(e,t,n);if(e==n){switch(t.length){case 0:return new e;case 1:return new e(t[0]);case 2:return new e(t[0],t[1]);case 3:return new e(t[0],t[1],t[2]);case 4:return new e(t[0],t[1],t[2],t[3])}var o=[null];return o.push.apply(o,t),new(f.apply(e,o))}var i=n.prototype,a=d(c(i)?i:Object.prototype),s=Function.apply.call(e,a,t);return c(s)?s:a}})},{"../internals/a-function":5,"../internals/an-object":10,"../internals/export":49,"../internals/fails":50,"../internals/function-bind":55,"../internals/get-built-in":56,"../internals/is-object":74,"../internals/object-create":90}],180:[function(e,t,r){var n=e("../internals/descriptors"),o=e("../internals/global"),i=e("../internals/is-forced"),s=e("../internals/inherit-if-required"),a=e("../internals/object-define-property").f,l=e("../internals/object-get-own-property-names").f,u=e("../internals/is-regexp"),c=e("../internals/regexp-flags"),d=e("../internals/regexp-sticky-helpers"),f=e("../internals/redefine"),h=e("../internals/fails"),p=e("../internals/internal-state").set,y=e("../internals/set-species"),m=e("../internals/well-known-symbol")("match"),g=o.RegExp,v=g.prototype,b=/a/g,_=/a/g,x=new g(b)!==b,w=d.UNSUPPORTED_Y;if(n&&i("RegExp",!x||w||h(function(){return _[m]=!1,g(b)!=b||g(_)==_||"/a/i"!=g(b,"i")}))){function j(t){t in S||a(S,t,{configurable:!0,get:function(){return g[t]},set:function(e){g[t]=e}})}for(var S=function(e,t){var r,n=this instanceof S,o=u(e),i=void 0===t;if(!n&&o&&e.constructor===S&&i)return e;x?o&&!i&&(e=e.source):e instanceof S&&(i&&(t=c.call(e)),e=e.source),w&&(r=!!t&&-1E;)j(M[E++]);(v.constructor=S).prototype=v,f(o,"RegExp",S)}y("RegExp")},{"../internals/descriptors":42,"../internals/fails":50,"../internals/global":59,"../internals/inherit-if-required":67,"../internals/internal-state":70,"../internals/is-forced":73,"../internals/is-regexp":76,"../internals/object-define-property":92,"../internals/object-get-own-property-names":95,"../internals/redefine":108,"../internals/regexp-flags":111,"../internals/regexp-sticky-helpers":112,"../internals/set-species":116,"../internals/well-known-symbol":146}],181:[function(e,t,r){"use strict";var n=e("../internals/export"),o=e("../internals/regexp-exec");n({target:"RegExp",proto:!0,forced:/./.exec!==o},{exec:o})},{"../internals/export":49,"../internals/regexp-exec":110}],182:[function(e,t,r){"use strict";var n=e("../internals/redefine"),o=e("../internals/an-object"),i=e("../internals/fails"),a=e("../internals/regexp-flags"),s="toString",l=RegExp.prototype,u=l[s],c=i(function(){return"/a/b"!=u.call({source:"a",flags:"b"})}),d=u.name!=s;(c||d)&&n(RegExp.prototype,s,function(){var e=o(this),t=String(e.source),r=e.flags;return"/"+t+"/"+String(void 0===r&&e instanceof RegExp&&!("flags"in l)?a.call(e):r)},{unsafe:!0})},{"../internals/an-object":10,"../internals/fails":50,"../internals/redefine":108,"../internals/regexp-flags":111}],183:[function(e,t,r){"use strict";var n=e("../internals/collection"),o=e("../internals/collection-strong");t.exports=n("Set",function(t){return function(e){return t(this,arguments.length?e:void 0)}},o)},{"../internals/collection":31,"../internals/collection-strong":30}],184:[function(e,t,r){"use strict";var n,o=e("../internals/export"),i=e("../internals/object-get-own-property-descriptor").f,s=e("../internals/to-length"),l=e("../internals/not-a-regexp"),u=e("../internals/require-object-coercible"),a=e("../internals/correct-is-regexp-logic"),c=e("../internals/is-pure"),d="".endsWith,f=Math.min,h=a("endsWith");o({target:"String",proto:!0,forced:!!(c||h||(!(n=i(String.prototype,"endsWith"))||n.writable))&&!h},{endsWith:function(e,t){var r=String(u(this));l(e);var n=1=r.length?{value:void 0,done:!0}:(e=o(r,n),t.index+=e.length,{value:e,done:!1})})},{"../internals/define-iterator":40,"../internals/internal-state":70,"../internals/string-multibyte":123}],187:[function(e,t,r){"use strict";var n=e("../internals/fix-regexp-well-known-symbol-logic"),d=e("../internals/an-object"),f=e("../internals/to-length"),o=e("../internals/require-object-coercible"),h=e("../internals/advance-string-index"),p=e("../internals/regexp-exec-abstract");n("match",1,function(n,u,c){return[function(e){var t=o(this),r=null==e?void 0:e[n];return void 0!==r?r.call(e,t):new RegExp(e)[n](String(t))},function(e){var t=c(u,e,this);if(t.done)return t.value;var r=d(e),n=String(this);if(!r.global)return p(r,n);for(var o,i=r.unicode,a=[],s=r.lastIndex=0;null!==(o=p(r,n));){var l=String(o[0]);""===(a[s]=l)&&(r.lastIndex=h(n,f(r.lastIndex),i)),s++}return 0===s?null:a}]})},{"../internals/advance-string-index":8,"../internals/an-object":10,"../internals/fix-regexp-well-known-symbol-logic":51,"../internals/regexp-exec-abstract":109,"../internals/require-object-coercible":113,"../internals/to-length":134}],188:[function(e,t,r){e("../internals/export")({target:"String",proto:!0},{repeat:e("../internals/string-repeat")})},{"../internals/export":49,"../internals/string-repeat":125}],189:[function(e,t,r){"use strict";var n=e("../internals/fix-regexp-well-known-symbol-logic"),T=e("../internals/an-object"),f=e("../internals/to-object"),O=e("../internals/to-length"),C=e("../internals/to-integer"),i=e("../internals/require-object-coercible"),L=e("../internals/advance-string-index"),P=e("../internals/regexp-exec-abstract"),A=Math.max,k=Math.min,h=Math.floor,p=/\$([$&'`]|\d\d?|<[^>]*>)/g,y=/\$([$&'`]|\d\d?)/g;n("replace",2,function(o,x,w,e){var j=e.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,S=e.REPLACE_KEEPS_$0,M=j?"$":"$0";return[function(e,t){var r=i(this),n=null==e?void 0:e[o];return void 0!==n?n.call(e,r,t):x.call(String(r),e,t)},function(e,t){if(!j&&S||"string"==typeof t&&-1===t.indexOf(M)){var r=w(x,e,this,t);if(r.done)return r.value}var n=T(e),o=String(this),i="function"==typeof t;i||(t=String(t));var a=n.global;if(a){var s=n.unicode;n.lastIndex=0}for(var l=[];;){var u=P(n,o);if(null===u)break;if(l.push(u),!a)break;""===String(u[0])&&(n.lastIndex=L(o,O(n.lastIndex),s))}for(var c,d="",f=0,h=0;h>>0;if(0==n)return[];if(void 0===e)return[r];if(!d(e))return m.call(r,e,n);for(var o,i,a,s=[],l=(e.ignoreCase?"i":"")+(e.multiline?"m":"")+(e.unicode?"u":"")+(e.sticky?"y":""),u=0,c=new RegExp(e.source,l+"g");(o=h.call(c,r))&&!(u<(i=c.lastIndex)&&(s.push(r.slice(u,o.index)),1=n));)c.lastIndex===o.index&&c.lastIndex++;return u===r.length?!a&&c.test("")||s.push(""):s.push(r.slice(u)),s.length>n?s.slice(0,n):s}:"0".split(void 0,0).length?function(e,t){return void 0===e&&0===t?[]:m.call(this,e,t)}:m,[function(e,t){var r=f(this),n=null==e?void 0:e[o];return void 0!==n?n.call(e,r,t):v.call(String(r),e,t)},function(e,t){var r=g(v,e,this,t,v!==m);if(r.done)return r.value;var n=b(e),o=String(this),i=_(n,RegExp),a=n.unicode,s=(n.ignoreCase?"i":"")+(n.multiline?"m":"")+(n.unicode?"u":"")+(E?"y":"g"),l=new i(E?n:"^(?:"+n.source+")",s),u=void 0===t?M:t>>>0;if(0==u)return[];if(0===o.length)return null===j(l,o)?[o]:[];for(var c=0,d=0,f=[];de.key){o.splice(t,0,e);break}t===r&&o.push(e)}n.updateURL()},forEach:function(e,t){for(var r,n=D(this).entries,o=_(e,1=R(256,5-t))return null}else if(255":1,"`":1}),$=p({},J,{"#":1,"?":1,"{":1,"}":1}),ee=p({},$,{"/":1,":":1,";":1,"=":1,"@":1,"[":1,"\\":1,"]":1,"^":1,"|":1}),te=function(e,t){var r=y(e,0);return 32>1,c=-7,d=r?o-1:0,f=r?-1:1,h=e[t+d];for(d+=f,i=h&(1<<-c)-1,h>>=-c,c+=s;0>=-c,c+=n;0>1,f=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,h=n?0:i-1,p=n?1:-1,y=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=c):(a=Math.floor(Math.log(t)/Math.LN2),t*(l=Math.pow(2,-a))<1&&(a--,l*=2),2<=(t+=1<=a+d?f/l:f*Math.pow(2,1-d))*l&&(a++,l/=2),c<=a+d?(s=0,a=c):1<=a+d?(s=(t*l-1)*Math.pow(2,o),a+=d):(s=t*Math.pow(2,d-1)*Math.pow(2,o),a=0));8<=o;e[r+h]=255&s,h+=p,s/=256,o-=8);for(a=a<Math.abs(e[0])&&(t=1),Math.abs(e[2])>Math.abs(e[t])&&(t=2),t}function T(e,t){e.f+=t.f,e.b.f+=t.b.f}function u(e,t,r){return e=e.a,t=t.a,r=r.a,t.b.a===e?r.b.a===e?g(t.a,r.a)?b(r.b.a,t.a,r.a)<=0:0<=b(t.b.a,r.a,t.a):b(r.b.a,e,r.a)<=0:r.b.a===e?0<=b(t.b.a,e,t.a):(t=v(t.b.a,e,t.a),(e=v(r.b.a,e,r.a))<=t)}function O(e){e.a.i=null;var t=e.e;t.a.c=t.c,t.c.a=t.a,e.e=null}function c(e,t){d(e.a),e.c=!1,(e.a=t).i=e}function C(e){for(var t=e.a.a;(e=de(e)).a.a===t;);return e.c&&(c(e,t=f(ce(e).a.b,e.a.e)),e=de(e)),e}function L(e,t,r){var n=new ue;return n.a=r,n.e=H(e.f,t.e,n),r.i=n}function P(e,t){switch(e.s){case 100130:return 0!=(1&t);case 100131:return 0!==t;case 100132:return 0>1]],s[a[u]])?se(r,u):le(r,u)),s[i]=null,l[i]=r.b,r.b=i}else for(r.c[-(i+1)]=null;0Math.max(a.a,l.a))return!1;if(g(i,a)){if(0n.f&&(n.f*=2,n.c=oe(n.c,n.f+1)),0===n.b?r=o:(r=n.b,n.b=n.c[n.b]),n.e[r]=t,n.c[r]=o,n.d[o]=r,n.h&&le(n,o),r}return n=e.a++,e.c[n]=t,-(n+1)}function re(e){if(0===e.a)return ae(e.b);var t=e.c[e.d[e.a-1]];if(0!==e.b.a&&g(ie(e.b),t))return ae(e.b);for(;--e.a,0e.a||g(n[a],n[l])){o[r[i]=a]=i;break}o[r[i]=l]=i,i=s}}function le(e,t){for(var r=e.d,n=e.e,o=e.c,i=t,a=r[i];;){var s=i>>1,l=r[s];if(0==s||g(n[l],n[a])){o[r[i]=a]=i;break}o[r[i]=l]=i,i=s}}function ue(){this.e=this.a=null,this.f=0,this.c=this.b=this.h=this.d=!1}function ce(e){return e.e.c.b}function de(e){return e.e.a.b}(n=q.prototype).x=function(){X(this,0)},n.B=function(e,t){switch(e){case 100142:return;case 100140:switch(t){case 100130:case 100131:case 100132:case 100133:case 100134:return void(this.s=t)}break;case 100141:return void(this.m=!!t);default:return void Y(this,100900)}Y(this,100901)},n.y=function(e){switch(e){case 100142:return 0;case 100140:return this.s;case 100141:return this.m;default:Y(this,100900)}return!1},n.A=function(e,t,r){this.j[0]=e,this.j[1]=t,this.j[2]=r},n.z=function(e,t){var r=t||null;switch(e){case 100100:case 100106:this.h=r;break;case 100104:case 100110:this.l=r;break;case 100101:case 100107:this.k=r;break;case 100102:case 100108:this.i=r;break;case 100103:case 100109:this.p=r;break;case 100105:case 100111:this.o=r;break;case 100112:this.r=r;break;default:Y(this,100900)}},n.C=function(e,t){var r=!1,n=[0,0,0];X(this,2);for(var o=0;o<3;++o){var i=e[o];i<-1e150&&(i=-1e150,r=!0),1e150o[u]&&(o[u]=c,a[u]=l)}if(l=0,o[1]-i[1]>o[0]-i[0]&&(l=1),o[2]-i[2]>o[l]-i[l]&&(l=2),i[l]>=o[l])n[0]=0,n[1]=0,n[2]=1;else{for(o=0,i=s[l],a=a[l],s=[0,0,0],i=[i.g[0]-a.g[0],i.g[1]-a.g[1],i.g[2]-a.g[2]],u=[0,0,0],l=r.e;l!==r;l=l.e)u[0]=l.g[0]-a.g[0],u[1]=l.g[1]-a.g[1],u[2]=l.g[2]-a.g[2],s[0]=i[1]*u[2]-i[2]*u[1],s[1]=i[2]*u[0]-i[0]*u[2],s[2]=i[0]*u[1]-i[1]*u[0],o<(c=s[0]*s[0]+s[1]*s[1]+s[2]*s[2])&&(o=c,n[0]=s[0],n[1]=s[1],n[2]=s[2]);o<=0&&(n[0]=n[1]=n[2]=0,n[E(i)]=1)}r=!0}for(s=E(n),l=this.b.c,o=(s+1)%3,a=(s+2)%3,s=0>=l,c-=l,m!=i){if(m==a)break;for(var g=m>8,++v;var _=b;if(n>=8;null!==y&&s<4096&&(p[s++]=y<<8|_,u+1<=s&&l<12&&(++l,u=u<<1|1)),y=m}else s=1+a,u=(1<<(l=o+1))-1,y=null}return f!==n&&console.log("Warning, gif stream shorter than expected."),r}try{r.GifWriter=function(g,e,t,r){var v=0,n=void 0===(r=void 0===r?{}:r).loop?null:r.loop,b=void 0===r.palette?null:r.palette;if(e<=0||t<=0||65535>=1;)++o;if(a=1<>8&255,g[v++]=255&t,g[v++]=t>>8&255,g[v++]=(null!==b?128:0)|o,g[v++]=i,g[v++]=0,null!==b)for(var s=0,l=b.length;s>16&255,g[v++]=u>>8&255,g[v++]=255&u}if(null!==n){if(n<0||65535>8&255,g[v++]=0}var x=!1;this.addFrame=function(e,t,r,n,o,i){if(!0===x&&(--v,x=!1),i=void 0===i?{}:i,e<0||t<0||65535>=1;)++u;l=1<>8&255,g[v++]=h,g[v++]=0),g[v++]=44,g[v++]=255&e,g[v++]=e>>8&255,g[v++]=255&t,g[v++]=t>>8&255,g[v++]=255&r,g[v++]=r>>8&255,g[v++]=255&n,g[v++]=n>>8&255,g[v++]=!0===a?128|u-1:0,!0===a)for(var p=0,y=s.length;p>16&255,g[v++]=m>>8&255,g[v++]=255&m}return v=function(t,r,e,n){t[r++]=e;var o=r++,i=1<>=8,c-=8,r===o+256&&(t[o]=255,o=r++)}function h(e){d|=e<>=8,c-=8,r===o+256&&(t[o]=255,o=r++);4096===l?(h(i),l=1+s,u=e+1,y={}):(1<>7,o=1<<1+(7&r);x[e++],x[e++];var i=null,a=null;n&&(i=e,e+=3*(a=o));var s=!0,l=[],u=0,c=null,d=0,f=null;for(this.width=w,this.height=t;s&&e>2&7,e++;break;case 254:for(;;){if(!(0<=(T=x[e++])))throw Error("Invalid block size");if(0===T)break;e+=T}break;default:throw new Error("Unknown graphic control label: 0x"+x[e-1].toString(16))}break;case 44:var p=x[e++]|x[e++]<<8,y=x[e++]|x[e++]<<8,m=x[e++]|x[e++]<<8,g=x[e++]|x[e++]<<8,v=x[e++],b=v>>6&1,_=1<<1+(7&v),j=i,S=a,M=!1;if(v>>7){M=!0;j=e,e+=3*(S=_)}var E=e;for(e++;;){var T;if(!(0<=(T=x[e++])))throw Error("Invalid block size");if(0===T)break;e+=T}l.push({x:p,y:y,width:m,height:g,has_local_palette:M,palette_offset:j,palette_size:S,data_offset:E,data_length:e-E,transparent_index:c,interlaced:!!b,delay:u,disposal:d});break;case 59:s=!1;break;default:throw new Error("Unknown gif block: 0x"+x[e-1].toString(16))}this.numFrames=function(){return l.length},this.loopCount=function(){return f},this.frameInfo=function(e){if(e<0||e>=l.length)throw new Error("Frame index out of range.");return l[e]},this.decodeAndBlitFrameBGRA=function(e,t){var r=this.frameInfo(e),n=r.width*r.height,o=new Uint8Array(n);O(x,r.data_offset,o,n);var i=r.palette_offset,a=r.transparent_index;null===a&&(a=256);var s=r.width,l=w-s,u=s,c=4*(r.y*w+r.x),d=4*((r.y+r.height)*w+r.x),f=c,h=4*l;!0===r.interlaced&&(h+=4*w*7);for(var p=8,y=0,m=o.length;y>=1)),g===a)f+=4;else{var v=x[i+3*g],b=x[i+3*g+1],_=x[i+3*g+2];t[f++]=_,t[f++]=b,t[f++]=v,t[f++]=255}--u}},this.decodeAndBlitFrameRGBA=function(e,t){var r=this.frameInfo(e),n=r.width*r.height,o=new Uint8Array(n);O(x,r.data_offset,o,n);var i=r.palette_offset,a=r.transparent_index;null===a&&(a=256);var s=r.width,l=w-s,u=s,c=4*(r.y*w+r.x),d=4*((r.y+r.height)*w+r.x),f=c,h=4*l;!0===r.interlaced&&(h+=4*w*7);for(var p=8,y=0,m=o.length;y>=1)),g===a)f+=4;else{var v=x[i+3*g],b=x[i+3*g+1],_=x[i+3*g+2];t[f++]=v,t[f++]=b,t[f++]=_,t[f++]=255}--u}}}}catch(e){}},{}],239:[function(Br,r,n){(function(Fr){var e,t;e=this,t=function(M){"use strict";function e(e){if(null==this)throw TypeError();var t=String(this),r=t.length,n=e?Number(e):0;if(n!=n&&(n=0),!(n<0||r<=n)){var o,i=t.charCodeAt(n);return 55296<=i&&i<=56319&&n+1>>=1,t}function _(e,t,r){if(!t)return r;for(;e.bitcount<24;)e.tag|=e.source[e.sourceIndex++]<>>16-t;return e.tag>>>=t,e.bitcount-=t,n+r}function x(e,t){for(;e.bitcount<24;)e.tag|=e.source[e.sourceIndex++]<>>=1,++o,r+=t.table[o],0<=(n-=t.table[o]););return e.tag=i,e.bitcount-=o,t.trans[r+n]}function w(e,t,r){var n,o,i,a,s,l;for(n=_(e,5,257),o=_(e,5,1),i=_(e,4,4),a=0;a<19;++a)m[a]=0;for(a=0;athis.x2&&(this.x2=e)),"number"==typeof t&&((isNaN(this.y1)||isNaN(this.y2))&&(this.y1=t,this.y2=t),tthis.y2&&(this.y2=t))},T.prototype.addX=function(e){this.addPoint(e,null)},T.prototype.addY=function(e){this.addPoint(null,e)},T.prototype.addBezier=function(e,t,r,n,o,i,a,s){var l=[e,t],u=[r,n],c=[o,i],d=[a,s];this.addPoint(e,t),this.addPoint(a,s);for(var f=0;f<=1;f++){var h=6*l[f]-12*u[f]+6*c[f],p=-3*l[f]+9*u[f]-9*c[f]+3*d[f],y=3*u[f]-3*l[f];if(0!=p){var m=Math.pow(h,2)-4*y*p;if(!(m<0)){var g=(-h+Math.sqrt(m))/(2*p);0>8&255,255&e]},k.USHORT=R(2),A.SHORT=function(e){return 32768<=e&&(e=-(65536-e)),[e>>8&255,255&e]},k.SHORT=R(2),A.UINT24=function(e){return[e>>16&255,e>>8&255,255&e]},k.UINT24=R(3),A.ULONG=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]},k.ULONG=R(4),A.LONG=function(e){return 2147483648<=e&&(e=-(4294967296-e)),[e>>24&255,e>>16&255,e>>8&255,255&e]},k.LONG=R(4),A.FIXED=A.ULONG,k.FIXED=k.ULONG,A.FWORD=A.SHORT,k.FWORD=k.SHORT,A.UFWORD=A.USHORT,k.UFWORD=k.USHORT,A.LONGDATETIME=function(e){return[0,0,0,0,e>>24&255,e>>16&255,e>>8&255,255&e]},k.LONGDATETIME=R(8),A.TAG=function(e){return L.argument(4===e.length,"Tag should be exactly 4 ASCII characters."),[e.charCodeAt(0),e.charCodeAt(1),e.charCodeAt(2),e.charCodeAt(3)]},k.TAG=R(4),A.Card8=A.BYTE,k.Card8=k.BYTE,A.Card16=A.USHORT,k.Card16=k.USHORT,A.OffSize=A.BYTE,k.OffSize=k.BYTE,A.SID=A.USHORT,k.SID=k.USHORT,A.NUMBER=function(e){return-107<=e&&e<=107?[e+139]:108<=e&&e<=1131?[247+((e-=108)>>8),255&e]:-1131<=e&&e<=-108?[251+((e=-e-108)>>8),255&e]:-32768<=e&&e<=32767?A.NUMBER16(e):A.NUMBER32(e)},k.NUMBER=function(e){return A.NUMBER(e).length},A.NUMBER16=function(e){return[28,e>>8&255,255&e]},k.NUMBER16=R(3),A.NUMBER32=function(e){return[29,e>>24&255,e>>16&255,e>>8&255,255&e]},k.NUMBER32=R(5),A.REAL=function(e){var t=e.toString(),r=/\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(t);if(r){var n=parseFloat("1e"+((r[2]?+r[2]:0)+r[1].length));t=(Math.round(e*n)/n).toString()}for(var o="",i=0,a=t.length;i>8&255,t[t.length]=255&n}return t},k.UTF16=function(e){return 2*e.length};var I={"x-mac-croatian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®Š™´¨≠ŽØ∞±≤≥∆µ∂∑∏š∫ªºΩžø¿¡¬√ƒ≈ƫȅ ÀÃÕŒœĐ—“”‘’÷◊©⁄€‹›Æ»–·‚„‰ÂćÁčÈÍÎÏÌÓÔđÒÚÛÙıˆ˜¯πË˚¸Êæˇ","x-mac-cyrillic":"АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю","x-mac-gaelic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØḂ±≤≥ḃĊċḊḋḞḟĠġṀæøṁṖṗɼƒſṠ«»… ÀÃÕŒœ–—“”‘’ṡẛÿŸṪ€‹›Ŷŷṫ·Ỳỳ⁊ÂÊÁËÈÍÎÏÌÓÔ♣ÒÚÛÙıÝýŴŵẄẅẀẁẂẃ","x-mac-greek":"Ĺ²É³ÖÜ΅àâä΄¨çéèê룙î‰ôö¦€ùûü†ΓΔΘΛΞΠß®©ΣΪ§≠°·Α±≤≥¥ΒΕΖΗΙΚΜΦΫΨΩάΝ¬ΟΡ≈Τ«»… ΥΧΆΈœ–―“”‘’÷ΉΊΌΎέήίόΏύαβψδεφγηιξκλμνοπώρστθωςχυζϊϋΐΰ­","x-mac-icelandic":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüݰ¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-inuit":"ᐃᐄᐅᐆᐊᐋᐱᐲᐳᐴᐸᐹᑉᑎᑏᑐᑑᑕᑖᑦᑭᑮᑯᑰᑲᑳᒃᒋᒌᒍᒎᒐᒑ°ᒡᒥᒦ•¶ᒧ®©™ᒨᒪᒫᒻᓂᓃᓄᓅᓇᓈᓐᓯᓰᓱᓲᓴᓵᔅᓕᓖᓗᓘᓚᓛᓪᔨᔩᔪᔫᔭ… ᔮᔾᕕᕖᕗ–—“”‘’ᕘᕙᕚᕝᕆᕇᕈᕉᕋᕌᕐᕿᖀᖁᖂᖃᖄᖅᖏᖐᖑᖒᖓᖔᖕᙱᙲᙳᙴᙵᙶᖖᖠᖡᖢᖣᖤᖥᖦᕼŁł","x-mac-ce":"ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ",macintosh:"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-romanian":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ĂȘ∞±≤≥¥µ∂∑∏π∫ªºΩăș¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›Țț‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ","x-mac-turkish":"ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙˆ˜¯˘˙˚¸˝˛ˇ"};P.MACSTRING=function(e,t,r,n){var o=I[n];if(void 0!==o){for(var i="",a=0;a>8&255,l+256&255)}return i}A.MACSTRING=function(e,t){var r=function(e){if(!U)for(var t in U={},I)U[t]=new String(t);var r=U[e];if(void 0!==r){if(N){var n=N.get(r);if(void 0!==n)return n}var o=I[e];if(void 0!==o){for(var i={},a=0;a>8,t[d+1]=255&f,t=t.concat(n[c])}return t},k.TABLE=function(e){for(var t=0,r=e.fields.length,n=0;n>1,t.skip("uShort",3),e.glyphIndexMap={};for(var a=new ae.Parser(r,n+o+14),s=new ae.Parser(r,n+o+16+2*i),l=new ae.Parser(r,n+o+16+4*i),u=new ae.Parser(r,n+o+16+6*i),c=n+o+16+8*i,d=0;d>4,i=15&n;if(15==o)break;if(t+=r[o],15==i)break;t+=r[i]}return parseFloat(t)}(e);if(32<=t&&t<=246)return t-139;if(247<=t&&t<=250)return 256*(t-247)+e.parseByte()+108;if(251<=t&&t<=254)return 256*-(t-251)-e.parseByte()-108;throw new Error("Invalid b0 "+t)}function Me(e,t,r){t=void 0!==t?t:0;var n=new ae.Parser(e,t),o=[],i=[];for(r=void 0!==r?r:e.length;n.relativeOffset>1,E.length=0,O=!0}return function e(t){for(var r,n,o,i,a,s,l,u,c,d,f,h,p=0;pMath.abs(h-P)?L=f+E.shift():P=h+E.shift(),M.curveTo(v,b,_,x,l,u),M.curveTo(c,d,f,h,L,P);break;default:console.log("Glyph "+g.index+": unknown operator 1200"+y),E.length=0}break;case 14:0>3;break;case 21:2>16),p+=2;break;case 29:a=E.pop()+m.gsubrsBias,(s=m.gsubrs[a])&&e(s);break;case 30:for(;0=r.begin&&e=de.length){var a=n.parseChar();r.names.push(n.parseString(a))}break;case 2.5:r.numberOfGlyphs=n.parseUShort(),r.offset=new Array(r.numberOfGlyphs);for(var s=0;st.value.tag?1:-1}),t.fields=t.fields.concat(n),t.fields=t.fields.concat(o),t}function yt(e,t,r){for(var n=0;n 123 are reserved for internal usage");h|=1<>>1,i=e[o].tag;if(i===t)return o;i>>1,i=e[o];if(i===t)return o;i>>1,a=(r=e[i]).start;if(a===t)return r;a(r=e[n-1]).end?0:r}function _t(e,t){this.font=e,this.tableName=t}function xt(e){_t.call(this,e,"gpos")}function wt(e){_t.call(this,e,"gsub")}function jt(e,t){var r=e.length;if(r!==t.length)return!1;for(var n=0;nt.points.length-1||n.matchedPoints[1]>o.points.length-1)throw Error("Matched points out of range in "+t.name);var a=t.points[n.matchedPoints[0]],s=o.points[n.matchedPoints[1]],l={xScale:n.xScale,scale01:n.scale01,scale10:n.scale10,yScale:n.yScale,dx:0,dy:0};s=Ct([s],l)[0],l.dx=a.x-s.x,l.dy=a.y-s.y,i=Ct(o.points,l)}t.points=t.points.concat(i)}}return Lt(t.points)}(xt.prototype=_t.prototype={searchTag:gt,binSearch:vt,getTable:function(e){var t=this.font.tables[this.tableName];return!t&&e&&(t=this.font.tables[this.tableName]=this.createDefaultTable()),t},getScriptNames:function(){var e=this.getTable();return e?e.scripts.map(function(e){return e.tag}):[]},getDefaultScriptName:function(){var e=this.getTable();if(e){for(var t=!1,r=0;r=s[u-1].tag,"Features must be added in alphabetical order."),i={tag:r,feature:{params:0,lookupListIndexes:[]}},s.push(i),a.push(u),i.feature}}},getLookupTables:function(e,t,r,n,o){var i=this.getFeatureTable(e,t,r,o),a=[];if(i){for(var s,l=i.lookupListIndexes,u=this.font.tables[this.tableName].lookups,c=0;c",s),t.stack.push(Math.round(64*s))}function mr(e,t){var r=t.stack,n=r.pop(),o=t.fv,i=t.pv,a=t.ppem,s=t.deltaBase+16*(e-1),l=t.deltaShift,u=t.z0;M.DEBUG&&console.log(t.step,"DELTAP["+e+"]",n,r);for(var c=0;c>4)===a){var h=(15&f)-8;0<=h&&h++,M.DEBUG&&console.log(t.step,"DELTAPFIX",d,"by",h*l);var p=u[d];o.setRelative(p,p,h*l,i)}}}function gr(e,t){var r=t.stack,n=r.pop();M.DEBUG&&console.log(t.step,"ROUND[]"),r.push(64*t.round(n/64))}function vr(e,t){var r=t.stack,n=r.pop(),o=t.ppem,i=t.deltaBase+16*(e-1),a=t.deltaShift;M.DEBUG&&console.log(t.step,"DELTAC["+e+"]",n,r);for(var s=0;s>4)===o){var c=(15&u)-8;0<=c&&c++;var d=c*a;M.DEBUG&&console.log(t.step,"DELTACFIX",l,"by",d),t.cvt[l]+=d}}}function br(e,t){var r,n,o=t.stack,i=o.pop(),a=o.pop(),s=t.z2[i],l=t.z1[a];M.DEBUG&&console.log(t.step,"SDPVTL["+e+"]",i,a),n=e?(r=s.y-l.y,l.x-s.x):(r=l.x-s.x,l.y-s.y),t.dpv=Yt(r,n)}function _r(e,t){var r=t.stack,n=t.prog,o=t.ip;M.DEBUG&&console.log(t.step,"PUSHB["+e+"]");for(var i=0;i":"_")+(n?"R":"_")+(0===o?"Gr":1===o?"Bl":2===o?"Wh":"")+"]",e?d+"("+i.cvt[d]+","+u+")":"",f,"(d =",a,"->",l*s,")"),i.rp1=i.rp0,i.rp2=f,t&&(i.rp0=f)}Ut.prototype.exec=function(e,t){if("number"!=typeof t)throw new Error("Point size is not a number!");if(!(2",n),s.interpolate(d,i,a,l),s.touch(d)}e.loop=1},fr.bind(void 0,0),fr.bind(void 0,1),function(e){for(var t=e.stack,r=e.rp0,n=e.z0[r],o=e.loop,i=e.fv,a=e.pv,s=e.z1;o--;){var l=t.pop(),u=s[l];M.DEBUG&&console.log(e.step,(1").concat(t,"");this.dummyDOM||(this.dummyDOM=document.getElementById(n).parentNode),this.descriptions?this.descriptions.fallbackElements||(this.descriptions.fallbackElements={}):this.descriptions={fallbackElements:{}},this.descriptions.fallbackElements[e]?this.descriptions.fallbackElements[e].innerHTML!==i&&(this.descriptions.fallbackElements[e].innerHTML=i):this._describeElementHTML("fallback",e,i),r===this.LABEL&&(this.descriptions.labelElements||(this.descriptions.labelElements={}),this.descriptions.labelElements[e]?this.descriptions.labelElements[e].innerHTML!==i&&(this.descriptions.labelElements[e].innerHTML=i):this._describeElementHTML("label",e,i))}},a.default.prototype._describeHTML=function(e,t){var r=this.canvas.id;if("fallback"===e){if(this.dummyDOM.querySelector("#".concat(r+l)))this.dummyDOM.querySelector("#"+r+c).insertAdjacentHTML("beforebegin",'

'));else{var n='

');this.dummyDOM.querySelector("#".concat(r,"accessibleOutput"))?this.dummyDOM.querySelector("#".concat(r,"accessibleOutput")).insertAdjacentHTML("beforebegin",n):this.dummyDOM.querySelector("#".concat(r)).innerHTML=n}return this.descriptions.fallback=this.dummyDOM.querySelector("#".concat(r).concat(u)),void(this.descriptions.fallback.innerHTML=t)}if("label"===e){if(this.dummyDOM.querySelector("#".concat(r+d)))this.dummyDOM.querySelector("#".concat(r+h))&&this.dummyDOM.querySelector("#".concat(r+h)).insertAdjacentHTML("beforebegin",'

'));else{var o='

');this.dummyDOM.querySelector("#".concat(r,"accessibleOutputLabel"))?this.dummyDOM.querySelector("#".concat(r,"accessibleOutputLabel")).insertAdjacentHTML("beforebegin",o):this.dummyDOM.querySelector("#"+r).insertAdjacentHTML("afterend",o)}return this.descriptions.label=this.dummyDOM.querySelector("#"+r+f),void(this.descriptions.label.innerHTML=t)}},a.default.prototype._describeElementHTML=function(e,t,r){var n=this.canvas.id;if("fallback"===e){if(this.dummyDOM.querySelector("#".concat(n+l)))this.dummyDOM.querySelector("#"+n+c)||this.dummyDOM.querySelector("#"+n+u).insertAdjacentHTML("afterend",'
Canvas elements and their descriptions
'));else{var o='
Canvas elements and their descriptions
');this.dummyDOM.querySelector("#".concat(n,"accessibleOutput"))?this.dummyDOM.querySelector("#".concat(n,"accessibleOutput")).insertAdjacentHTML("beforebegin",o):this.dummyDOM.querySelector("#"+n).innerHTML=o}var i=document.createElement("tr");return i.id=n+"_fte_"+t,this.dummyDOM.querySelector("#"+n+c).appendChild(i),this.descriptions.fallbackElements[t]=this.dummyDOM.querySelector("#".concat(n).concat("_fte_").concat(t)),void(this.descriptions.fallbackElements[t].innerHTML=r)}if("label"===e){if(this.dummyDOM.querySelector("#".concat(n+d)))this.dummyDOM.querySelector("#".concat(n+h))||this.dummyDOM.querySelector("#"+n+f).insertAdjacentHTML("afterend",'
'));else{var a='
');this.dummyDOM.querySelector("#".concat(n,"accessibleOutputLabel"))?this.dummyDOM.querySelector("#".concat(n,"accessibleOutputLabel")).insertAdjacentHTML("beforebegin",a):this.dummyDOM.querySelector("#"+n).insertAdjacentHTML("afterend",a)}var s=document.createElement("tr");s.id=n+"_lte_"+t,this.dummyDOM.querySelector("#"+n+h).appendChild(s),this.descriptions.labelElements[t]=this.dummyDOM.querySelector("#".concat(n).concat("_lte_").concat(t)),this.descriptions.labelElements[t].innerHTML=r}};var o=a.default;r.default=o},{"../core/main":264,"core-js/modules/es.array.concat":149,"core-js/modules/es.regexp.exec":181,"core-js/modules/es.string.ends-with":184,"core-js/modules/es.string.replace":189}],245:[function(e,t,r){"use strict";e("core-js/modules/es.array.concat"),e("core-js/modules/es.array.map"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,o=(n=e("../core/main"))&&n.__esModule?n:{default:n};o.default.prototype._updateGridOutput=function(e){if(this.dummyDOM.querySelector("#".concat(e,"_summary"))){var t=this._accessibleOutputs[e],r=function(e,t){var r="",n="",o=0;for(var i in t){var a=0;for(var s in t[i]){var l='
  • ').concat(t[i][s].color," ").concat(i,",");"line"===i?l+=" location = ".concat(t[i][s].pos,", length = ").concat(t[i][s].length," pixels"):(l+=" location = ".concat(t[i][s].pos),"point"!==i&&(l+=", area = ".concat(t[i][s].area," %")),l+="
  • "),r+=l,a++,o++}n=1').concat(t[a][s].color," ").concat(a,"
    "):'').concat(t[a][s].color," ").concat(a," midpoint"),o[t[a][s].loc.locY][t[a][s].loc.locX]?o[t[a][s].loc.locY][t[a][s].loc.locX]=o[t[a][s].loc.locY][t[a][s].loc.locX]+" "+l:o[t[a][s].loc.locY][t[a][s].loc.locX]=l,r++}for(var u in o){var c="";for(var d in o[u])c+="",void 0!==o[u][d]&&(c+=o[u][d]),c+="";n=n+c+""}return n}(e,this.ingredients.shapes);n!==t.summary.innerHTML&&(t.summary.innerHTML=n),o!==t.map.innerHTML&&(t.map.innerHTML=o),r.details!==t.shapeDetails.innerHTML&&(t.shapeDetails.innerHTML=r.details),this._accessibleOutputs[e]=t}};var i=o.default;r.default=i},{"../core/main":264,"core-js/modules/es.array.concat":149,"core-js/modules/es.array.map":161}],246:[function(e,t,r){"use strict";e("core-js/modules/es.array.concat"),e("core-js/modules/es.array.fill"),e("core-js/modules/es.array.map"),e("core-js/modules/es.number.to-fixed"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,o=(n=e("../core/main"))&&n.__esModule?n:{default:n};function l(e,t,r){return e[0]<.4*t?e[1]<.4*r?"top left":e[1]>.6*r?"bottom left":"mid left":e[0]>.6*t?e[1]<.4*r?"top right":e[1]>.6*r?"bottom right":"mid right":e[1]<.4*r?"top middle":e[1]>.6*r?"bottom middle":"middle"}function u(e,t,r){var n=Math.floor(e[0]/t*10),o=Math.floor(e[1]/r*10);return 10===n&&--n,10===o&&--o,{locX:n,locY:o}}o.default.prototype.textOutput=function(e){o.default._validateParameters("textOutput",arguments),this._accessibleOutputs.text||(this._accessibleOutputs.text=!0,this._createOutput("textOutput","Fallback"),e===this.LABEL&&(this._accessibleOutputs.textLabel=!0,this._createOutput("textOutput","Label")))},o.default.prototype.gridOutput=function(e){o.default._validateParameters("gridOutput",arguments),this._accessibleOutputs.grid||(this._accessibleOutputs.grid=!0,this._createOutput("gridOutput","Fallback"),e===this.LABEL&&(this._accessibleOutputs.gridLabel=!0,this._createOutput("gridOutput","Label")))},o.default.prototype._addAccsOutput=function(){return this._accessibleOutputs||(this._accessibleOutputs={text:!1,grid:!1,textLabel:!1,gridLabel:!1}),this._accessibleOutputs.grid||this._accessibleOutputs.text},o.default.prototype._createOutput=function(e,t){var r,n,o,i=this.canvas.id;this.ingredients||(this.ingredients={shapes:{},colors:{background:"white",fill:"white",stroke:"black"},pShapes:""}),this.dummyDOM||(this.dummyDOM=document.getElementById(i).parentNode);var a="";"Fallback"===t?(r=i+e,n=i+"accessibleOutput",this.dummyDOM.querySelector("#".concat(n))||(this.dummyDOM.querySelector("#".concat(i,"_Description"))?this.dummyDOM.querySelector("#".concat(i,"_Description")).insertAdjacentHTML("afterend",'
    ')):this.dummyDOM.querySelector("#".concat(i)).innerHTML='
    '))):"Label"===t&&(r=i+e+(a=t),n=i+"accessibleOutput"+t,this.dummyDOM.querySelector("#".concat(n))||(this.dummyDOM.querySelector("#".concat(i,"_Label"))?this.dummyDOM.querySelector("#".concat(i,"_Label")).insertAdjacentHTML("afterend",'
    ')):this.dummyDOM.querySelector("#".concat(i)).insertAdjacentHTML("afterend",'
    ')))),this._accessibleOutputs[r]={},"textOutput"===e?(a="#".concat(i,"gridOutput").concat(a),o='
    Text Output

      '),this.dummyDOM.querySelector(a)?this.dummyDOM.querySelector(a).insertAdjacentHTML("beforebegin",o):this.dummyDOM.querySelector("#".concat(n)).innerHTML=o,this._accessibleOutputs[r].list=this.dummyDOM.querySelector("#".concat(r,"_list"))):"gridOutput"===e&&(a="#".concat(i,"textOutput").concat(a),o='
      Grid Output

        '),this.dummyDOM.querySelector(a)?this.dummyDOM.querySelector(a).insertAdjacentHTML("afterend",o):this.dummyDOM.querySelector("#".concat(n)).innerHTML=o,this._accessibleOutputs[r].map=this.dummyDOM.querySelector("#".concat(r,"_map"))),this._accessibleOutputs[r].shapeDetails=this.dummyDOM.querySelector("#".concat(r,"_shapeDetails")),this._accessibleOutputs[r].summary=this.dummyDOM.querySelector("#".concat(r,"_summary"))},o.default.prototype._updateAccsOutput=function(){var e=this.canvas.id;JSON.stringify(this.ingredients.shapes)!==this.ingredients.pShapes&&(this.ingredients.pShapes=JSON.stringify(this.ingredients.shapes),this._accessibleOutputs.text&&this._updateTextOutput(e+"textOutput"),this._accessibleOutputs.grid&&this._updateGridOutput(e+"gridOutput"),this._accessibleOutputs.textLabel&&this._updateTextOutput(e+"textOutputLabel"),this._accessibleOutputs.gridLabel&&this._updateGridOutput(e+"gridOutputLabel"))},o.default.prototype._accsBackground=function(e){this.ingredients.pShapes=JSON.stringify(this.ingredients.shapes),this.ingredients.shapes={},this.ingredients.colors.backgroundRGBA!==e&&(this.ingredients.colors.backgroundRGBA=e,this.ingredients.colors.background=this._rgbColorName(e))},o.default.prototype._accsCanvasColors=function(e,t){"fill"===e?this.ingredients.colors.fillRGBA!==t&&(this.ingredients.colors.fillRGBA=t,this.ingredients.colors.fill=this._rgbColorName(t)):"stroke"===e&&this.ingredients.colors.strokeRGBA!==t&&(this.ingredients.colors.strokeRGBA=t,this.ingredients.colors.stroke=this._rgbColorName(t))},o.default.prototype._accsOutput=function(e,t){"ellipse"===e&&t[2]===t[3]?e="circle":"rectangle"===e&&t[2]===t[3]&&(e="square");var r={},n=!0,o=function(e,t){var r,n;n="rectangle"===e||"ellipse"===e||"arc"===e||"circle"===e||"square"===e?(r=Math.round(t[0]+t[2]/2),Math.round(t[1]+t[3]/2)):"triangle"===e?(r=(t[0]+t[2]+t[4])/3,(t[1]+t[3]+t[5])/3):"quadrilateral"===e?(r=(t[0]+t[2]+t[4]+t[6])/4,(t[1]+t[3]+t[5]+t[7])/4):"line"===e?(r=(t[0]+t[2])/2,(t[1]+t[3])/2):(r=t[0],t[1]);return[r,n]}(e,t);if("line"===e){r.color=this.ingredients.colors.stroke,r.length=Math.round(this.dist(t[0],t[1],t[2],t[3]));var i=l([t[0],[1]],this.width,this.height),a=l([t[2],[3]],this.width,this.height);r.loc=u(o,this.width,this.height),r.pos=i===a?"at ".concat(i):"from ".concat(i," to ").concat(a)}else"point"===e?r.color=this.ingredients.colors.stroke:(r.color=this.ingredients.colors.fill,r.area=function(e,t,r,n){var o=0;if("arc"===e){var i=((t[5]-t[4])%(2*Math.PI)+2*Math.PI)%(2*Math.PI);if(o=i*t[2]*t[3]/8,"open"===t[6]||"chord"===t[6]){var a=t[0],s=t[1],l=t[0]+t[2]/2*Math.cos(t[4]).toFixed(2),u=t[1]+t[3]/2*Math.sin(t[4]).toFixed(2),c=t[0]+t[2]/2*Math.cos(t[5]).toFixed(2),d=t[1]+t[3]/2*Math.sin(t[5]).toFixed(2),f=Math.abs(a*(u-d)+l*(d-s)+c*(s-u))/2;i>Math.PI?o+=f:o-=f}}else"ellipse"===e||"circle"===e?o=3.14*t[2]/2*t[3]/2:"line"===e?o=0:"point"===e?o=0:"quadrilateral"===e?o=Math.abs((t[6]+t[0])*(t[7]-t[1])+(t[0]+t[2])*(t[1]-t[3])+(t[2]+t[4])*(t[3]-t[5])+(t[4]+t[6])*(t[5]-t[7]))/2:"rectangle"===e||"square"===e?o=t[2]*t[3]:"triangle"===e&&(o=Math.abs(t[0]*(t[3]-t[5])+t[2]*(t[5]-t[1])+t[4]*(t[1]-t[3]))/2);return Math.round(100*o/(r*n))}(e,t,this.width,this.height)),r.pos=l(o,this.width,this.height),r.loc=u(o,this.width,this.height);if(this.ingredients.shapes[e]){if(this.ingredients.shapes[e]!==[r]){for(var s in this.ingredients.shapes[e])JSON.stringify(this.ingredients.shapes[e][s])===JSON.stringify(r)&&(n=!1);!0===n&&this.ingredients.shapes[e].push(r)}}else this.ingredients.shapes[e]=[r]};var i=o.default;r.default=i},{"../core/main":264,"core-js/modules/es.array.concat":149,"core-js/modules/es.array.fill":151,"core-js/modules/es.array.map":161,"core-js/modules/es.number.to-fixed":172}],247:[function(e,t,r){"use strict";e("core-js/modules/es.array.concat"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,o=(n=e("../core/main"))&&n.__esModule?n:{default:n};o.default.prototype._updateTextOutput=function(e){if(this.dummyDOM.querySelector("#".concat(e,"_summary"))){var t=this._accessibleOutputs[e],r=function(e,t){var r="",n=0;for(var o in t)for(var i in t[o]){var a='
      • ').concat(t[o][i].color," ").concat(o,"");"line"===o?a+=", ".concat(t[o][i].pos,", ").concat(t[o][i].length," pixels long.
      • "):(a+=", at ".concat(t[o][i].pos),"point"!==o&&(a+=", covering ".concat(t[o][i].area,"% of the canvas")),a+="."),r+=a,n++}return{numShapes:n,listShapes:r}}(e,this.ingredients.shapes),n=function(e,t,r,n){var o="Your output is a, ".concat(r," by ").concat(n," pixels, ").concat(t," canvas containing the following");o=1===e?"".concat(o," shape:"):"".concat(o," ").concat(e," shapes:");return o}(r.numShapes,this.ingredients.colors.background,this.width,this.height),o=function(e,t){var r="",n=0;for(var o in t)for(var i in t[o]){var a='').concat(t[o][i].color," ").concat(o,"");"line"===o?a+="location = ".concat(t[o][i].pos,"length = ").concat(t[o][i].length," pixels"):(a+="location = ".concat(t[o][i].pos,""),"point"!==o&&(a+=" area = ".concat(t[o][i].area,"%")),a+=""),r+=a,n++}return r}(e,this.ingredients.shapes);n!==t.summary.innerHTML&&(t.summary.innerHTML=n),r.listShapes!==t.list.innerHTML&&(t.list.innerHTML=r.listShapes),o!==t.shapeDetails.innerHTML&&(t.shapeDetails.innerHTML=o),this._accessibleOutputs[e]=t}};var i=o.default;r.default=i},{"../core/main":264,"core-js/modules/es.array.concat":149}],248:[function(e,t,r){"use strict";var n,o=(n=e("./core/main"))&&n.__esModule?n:{default:n};e("./core/constants"),e("./core/environment"),e("./core/friendly_errors/stacktrace"),e("./core/friendly_errors/validate_params"),e("./core/friendly_errors/file_errors"),e("./core/friendly_errors/fes_core"),e("./core/friendly_errors/sketch_reader"),e("./core/helpers"),e("./core/legacy"),e("./core/preload"),e("./core/p5.Element"),e("./core/p5.Graphics"),e("./core/p5.Renderer"),e("./core/p5.Renderer2D"),e("./core/rendering"),e("./core/shim"),e("./core/structure"),e("./core/transform"),e("./core/shape/2d_primitives"),e("./core/shape/attributes"),e("./core/shape/curves"),e("./core/shape/vertex"),e("./accessibility/outputs"),e("./accessibility/textOutput"),e("./accessibility/gridOutput"),e("./accessibility/color_namer"),e("./color/color_conversion"),e("./color/creating_reading"),e("./color/p5.Color"),e("./color/setting"),e("./data/p5.TypedDict"),e("./data/local_storage.js"),e("./dom/dom"),e("./accessibility/describe"),e("./events/acceleration"),e("./events/keyboard"),e("./events/mouse"),e("./events/touch"),e("./image/filters"),e("./image/image"),e("./image/loading_displaying"),e("./image/p5.Image"),e("./image/pixels"),e("./io/files"),e("./io/p5.Table"),e("./io/p5.TableRow"),e("./io/p5.XML"),e("./math/calculation"),e("./math/math"),e("./math/noise"),e("./math/p5.Vector"),e("./math/random"),e("./math/trigonometry"),e("./typography/attributes"),e("./typography/loading_displaying"),e("./typography/p5.Font"),e("./utilities/array_functions"),e("./utilities/conversion"),e("./utilities/string_functions"),e("./utilities/time_date"),e("./webgl/3d_primitives"),e("./webgl/interaction"),e("./webgl/light"),e("./webgl/loading"),e("./webgl/material"),e("./webgl/p5.Camera"),e("./webgl/p5.Geometry"),e("./webgl/p5.Matrix"),e("./webgl/p5.RendererGL.Immediate"),e("./webgl/p5.RendererGL"),e("./webgl/p5.RendererGL.Retained"),e("./webgl/p5.Shader"),e("./webgl/p5.RenderBuffer"),e("./webgl/p5.Texture"),e("./webgl/text"),e("./core/init"),t.exports=o.default},{"./accessibility/color_namer":243,"./accessibility/describe":244,"./accessibility/gridOutput":245,"./accessibility/outputs":246,"./accessibility/textOutput":247,"./color/color_conversion":249,"./color/creating_reading":250,"./color/p5.Color":251,"./color/setting":252,"./core/constants":253,"./core/environment":254,"./core/friendly_errors/fes_core":255,"./core/friendly_errors/file_errors":256,"./core/friendly_errors/sketch_reader":257,"./core/friendly_errors/stacktrace":258,"./core/friendly_errors/validate_params":259,"./core/helpers":260,"./core/init":261,"./core/legacy":263,"./core/main":264,"./core/p5.Element":265,"./core/p5.Graphics":266,"./core/p5.Renderer":267,"./core/p5.Renderer2D":268,"./core/preload":269,"./core/rendering":270,"./core/shape/2d_primitives":271,"./core/shape/attributes":272,"./core/shape/curves":273,"./core/shape/vertex":274,"./core/shim":275,"./core/structure":276,"./core/transform":277,"./data/local_storage.js":278,"./data/p5.TypedDict":279,"./dom/dom":280,"./events/acceleration":281,"./events/keyboard":282,"./events/mouse":283,"./events/touch":284,"./image/filters":285,"./image/image":286,"./image/loading_displaying":287,"./image/p5.Image":288,"./image/pixels":289,"./io/files":290,"./io/p5.Table":291,"./io/p5.TableRow":292,"./io/p5.XML":293,"./math/calculation":294,"./math/math":295,"./math/noise":296,"./math/p5.Vector":297,"./math/random":298,"./math/trigonometry":299,"./typography/attributes":300,"./typography/loading_displaying":301,"./typography/p5.Font":302,"./utilities/array_functions":303,"./utilities/conversion":304,"./utilities/string_functions":305,"./utilities/time_date":306,"./webgl/3d_primitives":307,"./webgl/interaction":308,"./webgl/light":309,"./webgl/loading":310,"./webgl/material":311,"./webgl/p5.Camera":312,"./webgl/p5.Geometry":313,"./webgl/p5.Matrix":314,"./webgl/p5.RenderBuffer":315,"./webgl/p5.RendererGL":318,"./webgl/p5.RendererGL.Immediate":316,"./webgl/p5.RendererGL.Retained":317,"./webgl/p5.Shader":319,"./webgl/p5.Texture":320,"./webgl/text":321}],249:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,o=(n=e("../core/main"))&&n.__esModule?n:{default:n};o.default.ColorConversion={},o.default.ColorConversion._hsbaToHSLA=function(e){var t=e[0],r=e[1],n=e[2],o=(2-r)*n/2;return 0!=o&&(1==o?r=0:o<.5?r/=2-r:r=r*n/(2-2*o)),[t,r,o,e[3]]},o.default.ColorConversion._hsbaToRGBA=function(e){var t=6*e[0],r=e[1],n=e[2],o=[];if(0===r)o=[n,n,n,e[3]];else{var i,a,s,l=Math.floor(t),u=n*(1-r),c=n*(1-r*(t-l)),d=n*(1-r*(1+l-t));s=1===l?(i=c,a=n,u):2===l?(i=u,a=n,d):3===l?(i=u,a=c,n):4===l?(i=d,a=u,n):5===l?(i=n,a=u,c):(i=n,a=d,u),o=[i,a,s,e[3]]}return o},o.default.ColorConversion._hslaToHSBA=function(e){var t,r=e[0],n=e[1],o=e[2];return[r,n=2*((t=o<.5?(1+n)*o:o+n-o*n)-o)/t,t,e[3]]},o.default.ColorConversion._hslaToRGBA=function(e){var t=6*e[0],r=e[1],n=e[2],o=[];if(0===r)o=[n,n,n,e[3]];else{var i,a=2*n-(i=n<.5?(1+r)*n:n+r-n*r),s=function(e,t,r){return e<0?e+=6:6<=e&&(e-=6),e<1?t+(r-t)*e:e<3?r:e<4?t+(r-t)*(4-e):t};o=[s(2+t,a,i),s(t,a,i),s(t-2,a,i),e[3]]}return o},o.default.ColorConversion._rgbaToHSBA=function(e){var t,r,n=e[0],o=e[1],i=e[2],a=Math.max(n,o,i),s=a-Math.min(n,o,i);return 0==s?r=t=0:(r=s/a,n===a?t=(o-i)/s:o===a?t=2+(i-n)/s:i===a&&(t=4+(n-o)/s),t<0?t+=6:6<=t&&(t-=6)),[t/6,r,a,e[3]]},o.default.ColorConversion._rgbaToHSLA=function(e){var t,r,n=e[0],o=e[1],i=e[2],a=Math.max(n,o,i),s=Math.min(n,o,i),l=a+s,u=a-s;return 0==u?r=t=0:(r=l<1?u/l:u/(2-l),n===a?t=(o-i)/u:o===a?t=2+(i-n)/u:i===a&&(t=4+(n-o)/u),t<0?t+=6:6<=t&&(t-=6)),[t/6,r,l/2,e[3]]};var i=o.default.ColorConversion;r.default=i},{"../core/main":264}],250:[function(e,t,r){"use strict";function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}e("core-js/modules/es.array.map"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,d=(n=e("../core/main"))&&n.__esModule?n:{default:n},f=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var t=s();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(e("../core/constants"));function s(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return s=function(){return e},e}e("./p5.Color"),e("../core/friendly_errors/validate_params"),e("../core/friendly_errors/file_errors"),e("../core/friendly_errors/fes_core"),d.default.prototype.alpha=function(e){return d.default._validateParameters("alpha",arguments),this.color(e)._getAlpha()},d.default.prototype.blue=function(e){return d.default._validateParameters("blue",arguments),this.color(e)._getBlue()},d.default.prototype.brightness=function(e){return d.default._validateParameters("brightness",arguments),this.color(e)._getBrightness()},d.default.prototype.color=function(){if(d.default._validateParameters("color",arguments),arguments[0]instanceof d.default.Color)return arguments[0];var e=arguments[0]instanceof Array?arguments[0]:arguments;return new d.default.Color(this,e)},d.default.prototype.green=function(e){return d.default._validateParameters("green",arguments),this.color(e)._getGreen()},d.default.prototype.hue=function(e){return d.default._validateParameters("hue",arguments),this.color(e)._getHue()},d.default.prototype.lerpColor=function(e,t,r){d.default._validateParameters("lerpColor",arguments);var n,o,i,a,s,l,u=this._colorMode,c=this._colorMaxes;if(u===f.RGB)s=e.levels.map(function(e){return e/255}),l=t.levels.map(function(e){return e/255});else if(u===f.HSB)e._getBrightness(),t._getBrightness(),s=e.hsba,l=t.hsba;else{if(u!==f.HSL)throw new Error("".concat(u,"cannot be used for interpolation."));e._getLightness(),t._getLightness(),s=e.hsla,l=t.hsla}return r=Math.max(Math.min(r,1),0),void 0===this.lerp&&(this.lerp=function(e,t,r){return r*(t-e)+e}),n=this.lerp(s[0],l[0],r),o=this.lerp(s[1],l[1],r),i=this.lerp(s[2],l[2],r),a=this.lerp(s[3],l[3],r),n*=c[u][0],o*=c[u][1],i*=c[u][2],a*=c[u][3],this.color(n,o,i,a)},d.default.prototype.lightness=function(e){return d.default._validateParameters("lightness",arguments),this.color(e)._getLightness()},d.default.prototype.red=function(e){return d.default._validateParameters("red",arguments),this.color(e)._getRed()},d.default.prototype.saturation=function(e){return d.default._validateParameters("saturation",arguments),this.color(e)._getSaturation()};var o=d.default;r.default=o},{"../core/constants":253,"../core/friendly_errors/fes_core":255,"../core/friendly_errors/file_errors":256,"../core/friendly_errors/validate_params":259,"../core/main":264,"./p5.Color":251,"core-js/modules/es.array.map":161}],251:[function(e,t,r){"use strict";function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}e("core-js/modules/es.array.join"),e("core-js/modules/es.array.map"),e("core-js/modules/es.array.slice"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.regexp.constructor"),e("core-js/modules/es.regexp.exec"),e("core-js/modules/es.regexp.to-string"),e("core-js/modules/es.string.trim"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var d=n(e("../core/main")),f=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var t=s();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(e("../core/constants")),h=n(e("./color_conversion"));function s(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return s=function(){return e},e}function n(e){return e&&e.__esModule?e:{default:e}}d.default.Color=function(e,t){if(this._storeModeAndMaxes(e._colorMode,e._colorMaxes),this.mode!==f.RGB&&this.mode!==f.HSL&&this.mode!==f.HSB)throw new Error("".concat(this.mode," is an invalid colorMode."));return this._array=d.default.Color._parseInputs.apply(this,t),this._calculateLevels(),this},d.default.Color.prototype.toString=function(e){var t=this.levels,r=this._array,n=r[3];switch(e){case"#rrggbb":return"#".concat(t[0]<16?"0".concat(t[0].toString(16)):t[0].toString(16),t[1]<16?"0".concat(t[1].toString(16)):t[1].toString(16),t[2]<16?"0".concat(t[2].toString(16)):t[2].toString(16));case"#rrggbbaa":return"#".concat(t[0]<16?"0".concat(t[0].toString(16)):t[0].toString(16),t[1]<16?"0".concat(t[1].toString(16)):t[1].toString(16),t[2]<16?"0".concat(t[2].toString(16)):t[2].toString(16),t[3]<16?"0".concat(t[3].toString(16)):t[3].toString(16));case"#rgb":return"#".concat(Math.round(15*r[0]).toString(16),Math.round(15*r[1]).toString(16),Math.round(15*r[2]).toString(16));case"#rgba":return"#".concat(Math.round(15*r[0]).toString(16),Math.round(15*r[1]).toString(16),Math.round(15*r[2]).toString(16),Math.round(15*r[3]).toString(16));case"rgb":return"rgb(".concat(t[0],", ",t[1],", ",t[2],")");case"rgb%":return"rgb(".concat((100*r[0]).toPrecision(3),"%, ",(100*r[1]).toPrecision(3),"%, ",(100*r[2]).toPrecision(3),"%)");case"rgba%":return"rgba(".concat((100*r[0]).toPrecision(3),"%, ",(100*r[1]).toPrecision(3),"%, ",(100*r[2]).toPrecision(3),"%, ",(100*r[3]).toPrecision(3),"%)");case"hsb":case"hsv":return this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),"hsb(".concat(this.hsba[0]*this.maxes[f.HSB][0],", ",this.hsba[1]*this.maxes[f.HSB][1],", ",this.hsba[2]*this.maxes[f.HSB][2],")");case"hsb%":case"hsv%":return this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),"hsb(".concat((100*this.hsba[0]).toPrecision(3),"%, ",(100*this.hsba[1]).toPrecision(3),"%, ",(100*this.hsba[2]).toPrecision(3),"%)");case"hsba":case"hsva":return this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),"hsba(".concat(this.hsba[0]*this.maxes[f.HSB][0],", ",this.hsba[1]*this.maxes[f.HSB][1],", ",this.hsba[2]*this.maxes[f.HSB][2],", ",n,")");case"hsba%":case"hsva%":return this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),"hsba(".concat((100*this.hsba[0]).toPrecision(3),"%, ",(100*this.hsba[1]).toPrecision(3),"%, ",(100*this.hsba[2]).toPrecision(3),"%, ",(100*n).toPrecision(3),"%)");case"hsl":return this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),"hsl(".concat(this.hsla[0]*this.maxes[f.HSL][0],", ",this.hsla[1]*this.maxes[f.HSL][1],", ",this.hsla[2]*this.maxes[f.HSL][2],")");case"hsl%":return this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),"hsl(".concat((100*this.hsla[0]).toPrecision(3),"%, ",(100*this.hsla[1]).toPrecision(3),"%, ",(100*this.hsla[2]).toPrecision(3),"%)");case"hsla":return this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),"hsla(".concat(this.hsla[0]*this.maxes[f.HSL][0],", ",this.hsla[1]*this.maxes[f.HSL][1],", ",this.hsla[2]*this.maxes[f.HSL][2],", ",n,")");case"hsla%":return this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),"hsl(".concat((100*this.hsla[0]).toPrecision(3),"%, ",(100*this.hsla[1]).toPrecision(3),"%, ",(100*this.hsla[2]).toPrecision(3),"%, ",(100*n).toPrecision(3),"%)");case"rgba":default:return"rgba(".concat(t[0],",",t[1],",",t[2],",",n,")")}},d.default.Color.prototype.setRed=function(e){this._array[0]=e/this.maxes[f.RGB][0],this._calculateLevels()},d.default.Color.prototype.setGreen=function(e){this._array[1]=e/this.maxes[f.RGB][1],this._calculateLevels()},d.default.Color.prototype.setBlue=function(e){this._array[2]=e/this.maxes[f.RGB][2],this._calculateLevels()},d.default.Color.prototype.setAlpha=function(e){this._array[3]=e/this.maxes[this.mode][3],this._calculateLevels()},d.default.Color.prototype._calculateLevels=function(){for(var e=this._array,t=this.levels=new Array(e.length),r=e.length-1;0<=r;--r)t[r]=Math.round(255*e[r])},d.default.Color.prototype._getAlpha=function(){return this._array[3]*this.maxes[this.mode][3]},d.default.Color.prototype._storeModeAndMaxes=function(e,t){this.mode=e,this.maxes=t},d.default.Color.prototype._getMode=function(){return this.mode},d.default.Color.prototype._getMaxes=function(){return this.maxes},d.default.Color.prototype._getBlue=function(){return this._array[2]*this.maxes[f.RGB][2]},d.default.Color.prototype._getBrightness=function(){return this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),this.hsba[2]*this.maxes[f.HSB][2]},d.default.Color.prototype._getGreen=function(){return this._array[1]*this.maxes[f.RGB][1]},d.default.Color.prototype._getHue=function(){return this.mode===f.HSB?(this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),this.hsba[0]*this.maxes[f.HSB][0]):(this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),this.hsla[0]*this.maxes[f.HSL][0])},d.default.Color.prototype._getLightness=function(){return this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),this.hsla[2]*this.maxes[f.HSL][2]},d.default.Color.prototype._getRed=function(){return this._array[0]*this.maxes[f.RGB][0]},d.default.Color.prototype._getSaturation=function(){return this.mode===f.HSB?(this.hsba||(this.hsba=h.default._rgbaToHSBA(this._array)),this.hsba[1]*this.maxes[f.HSB][1]):(this.hsla||(this.hsla=h.default._rgbaToHSLA(this._array)),this.hsla[1]*this.maxes[f.HSL][1])};var p={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},o=/\s*/,i=/(\d{1,3})/,l=/((?:\d+(?:\.\d+)?)|(?:\.\d+))/,u=new RegExp("".concat(l.source,"%")),y={HEX3:/^#([a-f0-9])([a-f0-9])([a-f0-9])$/i,HEX4:/^#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])$/i,HEX6:/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i,HEX8:/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i,RGB:new RegExp(["^rgb\\(",i.source,",",i.source,",",i.source,"\\)$"].join(o.source),"i"),RGB_PERCENT:new RegExp(["^rgb\\(",u.source,",",u.source,",",u.source,"\\)$"].join(o.source),"i"),RGBA:new RegExp(["^rgba\\(",i.source,",",i.source,",",i.source,",",l.source,"\\)$"].join(o.source),"i"),RGBA_PERCENT:new RegExp(["^rgba\\(",u.source,",",u.source,",",u.source,",",l.source,"\\)$"].join(o.source),"i"),HSL:new RegExp(["^hsl\\(",i.source,",",u.source,",",u.source,"\\)$"].join(o.source),"i"),HSLA:new RegExp(["^hsla\\(",i.source,",",u.source,",",u.source,",",l.source,"\\)$"].join(o.source),"i"),HSB:new RegExp(["^hsb\\(",i.source,",",u.source,",",u.source,"\\)$"].join(o.source),"i"),HSBA:new RegExp(["^hsba\\(",i.source,",",u.source,",",u.source,",",l.source,"\\)$"].join(o.source),"i")};d.default.Color._parseInputs=function(e,t,r,n){var o,i=arguments.length,a=this.mode,s=this.maxes[a],l=[];if(3<=i){for(l[0]=e/s[0],l[1]=t/s[1],l[2]=r/s[2],l[3]="number"==typeof n?n/s[3]:1,o=l.length-1;0<=o;--o){var u=l[o];u<0?l[o]=0:1"].indexOf(o[0])?void 0:o[0],lineNumber:o[1],columnNumber:o[2],source:e}},this)},parseFFOrSafari:function(e){return e.stack.split("\n").filter(function(e){return!e.match(n)},this).map(function(e){if(-1 eval")&&(e=e.replace(/ line (\d+)(?: > eval line \d+)* > eval:\d+:\d+/g,":$1")),-1===e.indexOf("@")&&-1===e.indexOf(":"))return{functionName:e};var t=/((.*".+"[^@]*)?[^@]*)(?:@)/,r=e.match(t),n=r&&r[1]?r[1]:void 0,o=this.extractLocation(e.replace(t,""));return{functionName:n,fileName:o[0],lineNumber:o[1],columnNumber:o[2],source:e}},this)},parseOpera:function(e){return!e.stacktrace||-1e.stacktrace.split("\n").length?this.parseOpera9(e):e.stack?this.parseOpera11(e):this.parseOpera10(e)},parseOpera9:function(e){for(var t=/Line (\d+).*script (?:in )?(\S+)/i,r=e.message.split("\n"),n=[],o=2,i=r.length;o/,"$2").replace(/\([^)]*\)/g,"")||void 0;return o.match(/\(([^)]*)\)/)&&(t=o.replace(/^[^(]+\(([^)]*)\)$/,"$1")),{functionName:i,args:void 0===t||"[arguments not available]"===t?void 0:t.split(","),fileName:n[0],lineNumber:n[1],columnNumber:n[2],source:e}},this)}}}o.default._getErrorStackParser=function(){return new i};var a=o.default;r.default=a},{"../main":264,"core-js/modules/es.array.filter":152,"core-js/modules/es.array.index-of":157,"core-js/modules/es.array.join":159,"core-js/modules/es.array.map":161,"core-js/modules/es.array.slice":162,"core-js/modules/es.regexp.exec":181,"core-js/modules/es.string.match":187,"core-js/modules/es.string.replace":189,"core-js/modules/es.string.split":191}],259:[function(e,t,r){"use strict";e("core-js/modules/es.symbol"),e("core-js/modules/es.symbol.description"),e("core-js/modules/es.symbol.iterator"),e("core-js/modules/es.array.concat"),e("core-js/modules/es.array.for-each"),e("core-js/modules/es.array.includes"),e("core-js/modules/es.array.index-of"),e("core-js/modules/es.array.iterator"),e("core-js/modules/es.array.join"),e("core-js/modules/es.array.last-index-of"),e("core-js/modules/es.array.map"),e("core-js/modules/es.array.slice"),e("core-js/modules/es.function.name"),e("core-js/modules/es.map"),e("core-js/modules/es.number.constructor"),e("core-js/modules/es.object.get-prototype-of"),e("core-js/modules/es.object.keys"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.reflect.construct"),e("core-js/modules/es.regexp.exec"),e("core-js/modules/es.regexp.to-string"),e("core-js/modules/es.set"),e("core-js/modules/es.string.includes"),e("core-js/modules/es.string.iterator"),e("core-js/modules/es.string.split"),e("core-js/modules/web.dom-collections.for-each"),e("core-js/modules/web.dom-collections.iterator"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,o=(n=e("../main"))&&n.__esModule?n:{default:n};(function(e){if(e&&e.__esModule)return;if(null===e||"object"!==s(e)&&"function"!=typeof e)return;var t=a();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r)})(e("../constants")),e("../internationalization");function a(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return a=function(){return e},e}function s(e){return(s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}o.default._validateParameters=o.default._clearValidateParamsCache=function(){};var i=o.default;r.default=i},{"../../../docs/parameterData.json":void 0,"../constants":253,"../internationalization":262,"../main":264,"core-js/modules/es.array.concat":149,"core-js/modules/es.array.for-each":154,"core-js/modules/es.array.includes":156,"core-js/modules/es.array.index-of":157,"core-js/modules/es.array.iterator":158,"core-js/modules/es.array.join":159,"core-js/modules/es.array.last-index-of":160,"core-js/modules/es.array.map":161,"core-js/modules/es.array.slice":162,"core-js/modules/es.function.name":166,"core-js/modules/es.map":167,"core-js/modules/es.number.constructor":170,"core-js/modules/es.object.get-prototype-of":175,"core-js/modules/es.object.keys":176,"core-js/modules/es.object.to-string":177,"core-js/modules/es.reflect.construct":179,"core-js/modules/es.regexp.exec":181,"core-js/modules/es.regexp.to-string":182,"core-js/modules/es.set":183,"core-js/modules/es.string.includes":185,"core-js/modules/es.string.iterator":186,"core-js/modules/es.string.split":191,"core-js/modules/es.symbol":196,"core-js/modules/es.symbol.description":194,"core-js/modules/es.symbol.iterator":195,"core-js/modules/web.dom-collections.for-each":228,"core-js/modules/web.dom-collections.iterator":229}],260:[function(e,t,r){"use strict";function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var i=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var t=s();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(e("./constants"));function s(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return s=function(){return e},e}var n={modeAdjust:function(e,t,r,n,o){return o===i.CORNER?{x:e,y:t,w:r,h:n}:o===i.CORNERS?{x:e,y:t,w:r-e,h:n-t}:o===i.RADIUS?{x:e-r,y:t-n,w:2*r,h:2*n}:o===i.CENTER?{x:e-.5*r,y:t-.5*n,w:r,h:n}:void 0}};r.default=n},{"./constants":253}],261:[function(e,t,r){"use strict";e("core-js/modules/es.array.iterator"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.promise"),e("core-js/modules/es.string.iterator"),e("core-js/modules/web.dom-collections.iterator");var n,o=(n=e("../core/main"))&&n.__esModule?n:{default:n};e("./internationalization");var i=Promise.resolve();Promise.all([new Promise(function(e,t){"complete"===document.readyState?e():window.addEventListener("load",e,!1)}),i]).then(function(){void 0===window._setupDone?window.mocha||(window.setup&&"function"==typeof window.setup||window.draw&&"function"==typeof window.draw)&&!o.default.instance&&new o.default:console.warn("p5.js seems to have been imported multiple times. Please remove the duplicate import")})},{"../core/main":264,"./internationalization":262,"core-js/modules/es.array.iterator":158,"core-js/modules/es.object.to-string":177,"core-js/modules/es.promise":178,"core-js/modules/es.string.iterator":186,"core-js/modules/web.dom-collections.iterator":229}],262:[function(e,t,r){"use strict";e("core-js/modules/es.array.includes"),e("core-js/modules/es.array.iterator"),e("core-js/modules/es.array.join"),e("core-js/modules/es.array.slice"),e("core-js/modules/es.object.keys"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.promise"),e("core-js/modules/es.regexp.exec"),e("core-js/modules/es.string.includes"),e("core-js/modules/es.string.iterator"),e("core-js/modules/es.string.split"),e("core-js/modules/web.dom-collections.iterator"),Object.defineProperty(r,"__esModule",{value:!0}),r.setTranslatorLanguage=r.currentTranslatorLanguage=r.availableTranslatorLanguages=r.initialize=r.translator=void 0;var i,a,n=s(e("i18next")),o=s(e("i18next-browser-languagedetector"));function s(e){return e&&e.__esModule?e:{default:e}}function l(e,t){for(var r=0;r=a.width||t>=a.height?[0,0,0,0]:this._getPixel(e,t);var s=new l.default.Image(r,n);return s.canvas.getContext("2d").drawImage(a,e,t,r*i,n*i,0,0,r,n),s},l.default.Renderer.prototype.textLeading=function(e){return"number"==typeof e?(this._setProperty("_leadingSet",!0),this._setProperty("_textLeading",e),this._pInst):this._textLeading},l.default.Renderer.prototype.textSize=function(e){return"number"==typeof e?(this._setProperty("_textSize",e),this._leadingSet||this._setProperty("_textLeading",e*k._DEFAULT_LEADMULT),this._applyTextProperties()):this._textSize},l.default.Renderer.prototype.textStyle=function(e){return e?(e!==k.NORMAL&&e!==k.ITALIC&&e!==k.BOLD&&e!==k.BOLDITALIC||this._setProperty("_textStyle",e),this._applyTextProperties()):this._textStyle},l.default.Renderer.prototype.textAscent=function(){return null===this._textAscent&&this._updateTextMetrics(),this._textAscent},l.default.Renderer.prototype.textDescent=function(){return null===this._textDescent&&this._updateTextMetrics(),this._textDescent},l.default.Renderer.prototype.textAlign=function(e,t){return void 0!==e?(this._setProperty("_textAlign",e),void 0!==t&&this._setProperty("_textBaseline",t),this._applyTextProperties()):{horizontal:this._textAlign,vertical:this._textBaseline}},l.default.Renderer.prototype.textWrap=function(e){return this._setProperty("_textWrap",e),this._textWrap},l.default.Renderer.prototype.text=function(e,t,r,n,o){var i,a,s,l,u,c,d,f=this._pInst,h=this._textWrap,p=Number.MAX_VALUE;if((this._doFill||this._doStroke)&&void 0!==e){if("string"!=typeof e&&(e=e.toString()),i=(e=e.replace(/(\t)/g," ")).split("\n"),void 0!==n){switch(this._rectMode===k.CENTER&&(t-=n/2),this._textAlign){case k.CENTER:t+=n/2;break;case k.RIGHT:t+=n}var y=!1;if(void 0!==o){switch(this._rectMode===k.CENTER&&(r-=o/2),this._textBaseline){case k.BOTTOM:d=r+o,r=Math.max(d,r);break;case k.CENTER:d=r+o/2,r=Math.max(d,r);break;case k.BASELINE:y=!0,this._textBaseline=k.TOP}p=r+o-f.textAscent()}if(h===k.WORD){for(var m=[],g=0;gs.HALF_PI&&e<=3*s.HALF_PI?Math.atan(r/n*Math.tan(e))+s.PI:Math.atan(r/n*Math.tan(e))+s.TWO_PI,t=t<=s.HALF_PI?Math.atan(r/n*Math.tan(t)):t>s.HALF_PI&&t<=3*s.HALF_PI?Math.atan(r/n*Math.tan(t))+s.PI:Math.atan(r/n*Math.tan(t))+s.TWO_PI),ty||Math.abs(this.accelerationY-this.pAccelerationY)>y||Math.abs(this.accelerationZ-this.pAccelerationZ)>y)&&r.deviceMoved(),"function"==typeof r.deviceTurned){var n=this.rotationX+180,o=this.pRotationX+180,i=u+180;0>>24],n+=x[(16711680&T)>>16],o+=x[(65280&T)>>8],i+=x[255&T],r+=L[_],s++}w[l=E+v]=a/r,j[l]=n/r,S[l]=o/r,M[l]=i/r}E+=h}for(c=(u=-O)*h,b=E=0;b>>16,e[r+1]=(65280&t[n])>>>8,e[r+2]=255&t[n],e[r+3]=(4278190080&t[n])>>>24},A._toImageData=function(e){return e instanceof ImageData?e:e.getContext("2d").getImageData(0,0,e.width,e.height)},A._createImageData=function(e,t){return A._tmpCanvas=document.createElement("canvas"),A._tmpCtx=A._tmpCanvas.getContext("2d"),this._tmpCtx.createImageData(e,t)},A.apply=function(e,t,r){var n=e.getContext("2d"),o=n.getImageData(0,0,e.width,e.height),i=t(o,r);i instanceof ImageData?n.putImageData(i,0,0,0,0,e.width,e.height):n.putImageData(o,0,0,0,0,e.width,e.height)},A.threshold=function(e,t){var r=A._toPixels(e);void 0===t&&(t=.5);for(var n=Math.floor(255*t),o=0;o>8)/n,r[o+1]=255*(a*t>>8)/n,r[o+2]=255*(s*t>>8)/n}},A.dilate=function(e){for(var t,r,n,o,i,a,s,l,u,c,d,f,h,p,y,m,g,v=A._toPixels(e),b=0,_=v.length?v.length/4:0,x=new Int32Array(_);b<_;)for(r=(t=b)+e.width;b>16&255)+151*(n>>8&255)+28*(255&n))<(y=77*(d>>16&255)+151*(d>>8&255)+28*(255&d))&&(o=d,i=y),i<(p=77*((c=A._getARGB(v,a))>>16&255)+151*(c>>8&255)+28*(255&c))&&(o=c,i=p),i<(m=77*(f>>16&255)+151*(f>>8&255)+28*(255&f))&&(o=f,i=m),i<(g=77*(h>>16&255)+151*(h>>8&255)+28*(255&h))&&(o=h,i=g),x[b++]=o;A._setPixels(v,x)},A.erode=function(e){for(var t,r,n,o,i,a,s,l,u,c,d,f,h,p,y,m,g,v=A._toPixels(e),b=0,_=v.length?v.length/4:0,x=new Int32Array(_);b<_;)for(r=(t=b)+e.width;b>16&255)+151*(d>>8&255)+28*(255&d))<(i=77*(n>>16&255)+151*(n>>8&255)+28*(255&n))&&(o=d,i=y),(p=77*((c=A._getARGB(v,a))>>16&255)+151*(c>>8&255)+28*(255&c))>16&255)+151*(f>>8&255)+28*(255&f))>16&255)+151*(h>>8&255)+28*(255&h))=n){var o=Math.floor(t.timeDisplayed/n);if(t.timeDisplayed=0,t.lastChangeTime=r,t.displayIndex+=o,t.loopCount=Math.floor(t.displayIndex/t.numFrames),null!==t.loopLimit&&t.loopCount>=t.loopLimit)t.playing=!1;else{var i=t.displayIndex%t.numFrames;this.drawingContext.putImageData(t.frames[i].image,0,0),t.displayIndex=i,this.setModified(!0)}}}},o.default.Image.prototype._setProperty=function(e,t){this[e]=t,this.setModified(!0)},o.default.Image.prototype.loadPixels=function(){o.default.Renderer2D.prototype.loadPixels.call(this),this.setModified(!0)},o.default.Image.prototype.updatePixels=function(e,t,r,n){o.default.Renderer2D.prototype.updatePixels.call(this,e,t,r,n),this.setModified(!0)},o.default.Image.prototype.get=function(e,t,r,n){return o.default._validateParameters("p5.Image.get",arguments),o.default.Renderer2D.prototype.get.apply(this,arguments)},o.default.Image.prototype._getPixel=o.default.Renderer2D.prototype._getPixel,o.default.Image.prototype.set=function(e,t,r){o.default.Renderer2D.prototype.set.call(this,e,t,r),this.setModified(!0)},o.default.Image.prototype.resize=function(e,t){0===e&&0===t?(e=this.canvas.width,t=this.canvas.height):0===e?e=this.canvas.width*t/this.canvas.height:0===t&&(t=this.canvas.height*e/this.canvas.width),e=Math.floor(e),t=Math.floor(t);var r=document.createElement("canvas");if(r.width=e,r.height=t,this.gifProperties)for(var n=this.gifProperties,o=function(e,t){for(var r=0,n=0;n/g,">").replace(/"/g,""").replace(/'/g,"'")}function l(e,t){t&&!0!==t&&"true"!==t||(t="");var r="";return(e=e||"untitled")&&e.includes(".")&&(r=e.split(".").pop()),t&&r!==t&&(r=t,e="".concat(e,".").concat(r)),[e,r]}e("../core/friendly_errors/validate_params"),e("../core/friendly_errors/file_errors"),e("../core/friendly_errors/fes_core"),g.default.prototype.loadJSON=function(){for(var e=arguments.length,t=new Array(e),r=0;r"),o.print("");if(o.print(' '),o.print(""),o.print(""),o.print(" "),"0"!==i[0]){o.print(" ");for(var c=0;c".concat(d)),o.print(" ")}o.print(" ")}for(var f=0;f");for(var h=0;h".concat(p)),o.print(" ")}o.print(" ")}o.print("
        "),o.print(""),o.print("")}o.close(),o.clear()},g.default.prototype.writeFile=function(e,t,r){var n="application/octet-stream";g.default.prototype._isSafari()&&(n="text/plain");var o=new Blob(e,{type:n});g.default.prototype.downloadFile(o,t,r)},g.default.prototype.downloadFile=function(e,t,r){var n=l(t,r),o=n[0];if(e instanceof Blob)s.default.saveAs(e,o);else{var i=document.createElement("a");if(i.href=e,i.download=o,i.onclick=function(e){var t;t=e,document.body.removeChild(t.target),e.stopPropagation()},i.style.display="none",document.body.appendChild(i),g.default.prototype._isSafari()){var a="Hello, Safari user! To download this file...\n";a+="1. Go to File --\x3e Save As.\n",a+='2. Choose "Page Source" as the Format.\n',a+='3. Name it with this extension: ."'.concat(n[1],'"'),alert(a)}i.click()}},g.default.prototype._checkFileExtension=l,g.default.prototype._isSafari=function(){return 0>>0},getSeed:function(){return t},rand:function(){return(r=(1664525*r+1013904223)%n)/n}});o.setSeed(e),_=new Array(4096);for(var i=0;i<4096;i++)_[i]=o.rand()};var i=o.default;r.default=i},{"../core/main":264}],297:[function(e,t,r){"use strict";function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}e("core-js/modules/es.array.concat"),e("core-js/modules/es.array.every"),e("core-js/modules/es.array.slice"),e("core-js/modules/es.array.some"),e("core-js/modules/es.math.sign"),e("core-js/modules/es.number.constructor"),e("core-js/modules/es.number.is-finite"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.regexp.to-string"),e("core-js/modules/es.string.sub"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,l=(n=e("../core/main"))&&n.__esModule?n:{default:n},i=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var t=s();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(e("../core/constants"));function s(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return s=function(){return e},e}l.default.Vector=function(e,t,r,n,o){var i,a,s;s="[object Function]"==={}.toString.call(e)?(this.isPInst=!0,this._fromRadians=e,this._toRadians=t,i=r||0,a=n||0,o||0):(i=e||0,a=t||0,r||0),this.x=i,this.y=a,this.z=s},l.default.Vector.prototype.toString=function(){return"p5.Vector Object : [".concat(this.x,", ").concat(this.y,", ").concat(this.z,"]")},l.default.Vector.prototype.set=function(e,t,r){return e instanceof l.default.Vector?(this.x=e.x||0,this.y=e.y||0,this.z=e.z||0):e instanceof Array?(this.x=e[0]||0,this.y=e[1]||0,this.z=e[2]||0):(this.x=e||0,this.y=t||0,this.z=r||0),this},l.default.Vector.prototype.copy=function(){return this.isPInst?new l.default.Vector(this._fromRadians,this._toRadians,this.x,this.y,this.z):new l.default.Vector(this.x,this.y,this.z)},l.default.Vector.prototype.add=function(e,t,r){return e instanceof l.default.Vector?(this.x+=e.x||0,this.y+=e.y||0,this.z+=e.z||0):e instanceof Array?(this.x+=e[0]||0,this.y+=e[1]||0,this.z+=e[2]||0):(this.x+=e||0,this.y+=t||0,this.z+=r||0),this};function u(e,t){return 0!==e&&(this.x=this.x%e),0!==t&&(this.y=this.y%t),this}function c(e,t,r){return 0!==e&&(this.x=this.x%e),0!==t&&(this.y=this.y%t),0!==r&&(this.z=this.z%r),this}l.default.Vector.prototype.rem=function(e,t,r){if(e instanceof l.default.Vector){if(Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.z)){var n=parseFloat(e.x),o=parseFloat(e.y),i=parseFloat(e.z);return c.call(this,n,o,i)}}else if(e instanceof Array){if(e.every(function(e){return Number.isFinite(e)})){if(2===e.length)return u.call(this,e[0],e[1]);if(3===e.length)return c.call(this,e[0],e[1],e[2])}}else if(1===arguments.length){if(Number.isFinite(e)&&0!==e)return this.x=this.x%e,this.y=this.y%e,this.z=this.z%e,this}else if(2===arguments.length){var a=Array.prototype.slice.call(arguments);if(a.every(function(e){return Number.isFinite(e)})&&2===a.length)return u.call(this,a[0],a[1])}else if(3===arguments.length){var s=Array.prototype.slice.call(arguments);if(s.every(function(e){return Number.isFinite(e)})&&3===s.length)return c.call(this,s[0],s[1],s[2])}},l.default.Vector.prototype.sub=function(e,t,r){return e instanceof l.default.Vector?(this.x-=e.x||0,this.y-=e.y||0,this.z-=e.z||0):e instanceof Array?(this.x-=e[0]||0,this.y-=e[1]||0,this.z-=e[2]||0):(this.x-=e||0,this.y-=t||0,this.z-=r||0),this},l.default.Vector.prototype.mult=function(e,t,r){if(e instanceof l.default.Vector)return Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.z)&&"number"==typeof e.x&&"number"==typeof e.y&&"number"==typeof e.z?(this.x*=e.x,this.y*=e.y,this.z*=e.z):console.warn("p5.Vector.prototype.mult:","x contains components that are either undefined or not finite numbers"),this;if(e instanceof Array)return e.every(function(e){return Number.isFinite(e)})&&e.every(function(e){return"number"==typeof e})?1===e.length?(this.x*=e[0],this.y*=e[0],this.z*=e[0]):2===e.length?(this.x*=e[0],this.y*=e[1]):3===e.length&&(this.x*=e[0],this.y*=e[1],this.z*=e[2]):console.warn("p5.Vector.prototype.mult:","x contains elements that are either undefined or not finite numbers"),this;var n=Array.prototype.slice.call(arguments);return n.every(function(e){return Number.isFinite(e)})&&n.every(function(e){return"number"==typeof e})?(1===arguments.length&&(this.x*=e,this.y*=e,this.z*=e),2===arguments.length&&(this.x*=e,this.y*=t),3===arguments.length&&(this.x*=e,this.y*=t,this.z*=r)):console.warn("p5.Vector.prototype.mult:","x, y, or z arguments are either undefined or not a finite number"),this},l.default.Vector.prototype.div=function(e,t,r){if(e instanceof l.default.Vector){if(Number.isFinite(e.x)&&Number.isFinite(e.y)&&Number.isFinite(e.z)&&"number"==typeof e.x&&"number"==typeof e.y&&"number"==typeof e.z){if(0===e.x||0===e.y||0===e.z)return console.warn("p5.Vector.prototype.div:","divide by 0"),this;this.x/=e.x,this.y/=e.y,this.z/=e.z}else console.warn("p5.Vector.prototype.div:","x contains components that are either undefined or not finite numbers");return this}if(e instanceof Array){if(e.every(function(e){return Number.isFinite(e)})&&e.every(function(e){return"number"==typeof e})){if(e.some(function(e){return 0===e}))return console.warn("p5.Vector.prototype.div:","divide by 0"),this;1===e.length?(this.x/=e[0],this.y/=e[0],this.z/=e[0]):2===e.length?(this.x/=e[0],this.y/=e[1]):3===e.length&&(this.x/=e[0],this.y/=e[1],this.z/=e[2])}else console.warn("p5.Vector.prototype.div:","x contains components that are either undefined or not finite numbers");return this}var n=Array.prototype.slice.call(arguments);if(n.every(function(e){return Number.isFinite(e)})&&n.every(function(e){return"number"==typeof e})){if(n.some(function(e){return 0===e}))return console.warn("p5.Vector.prototype.div:","divide by 0"),this;1===arguments.length&&(this.x/=e,this.y/=e,this.z/=e),2===arguments.length&&(this.x/=e,this.y/=t),3===arguments.length&&(this.x/=e,this.y/=t,this.z/=r)}else console.warn("p5.Vector.prototype.div:","x, y, or z arguments are either undefined or not a finite number");return this},l.default.Vector.prototype.mag=function(){return Math.sqrt(this.magSq())},l.default.Vector.prototype.magSq=function(){var e=this.x,t=this.y,r=this.z;return e*e+t*t+r*r},l.default.Vector.prototype.dot=function(e,t,r){return e instanceof l.default.Vector?this.dot(e.x,e.y,e.z):this.x*(e||0)+this.y*(t||0)+this.z*(r||0)},l.default.Vector.prototype.cross=function(e){var t=this.y*e.z-this.z*e.y,r=this.z*e.x-this.x*e.z,n=this.x*e.y-this.y*e.x;return this.isPInst?new l.default.Vector(this._fromRadians,this._toRadians,t,r,n):new l.default.Vector(t,r,n)},l.default.Vector.prototype.dist=function(e){return e.copy().sub(this).mag()},l.default.Vector.prototype.normalize=function(){var e=this.mag();return 0!==e&&this.mult(1/e),this},l.default.Vector.prototype.limit=function(e){var t=this.magSq();return e*e>>0},o.default.prototype.randomSeed=function(e){this._lcgSetSeed(i,e),this._gaussian_previous=!1},o.default.prototype.random=function(e,t){var r;if(o.default._validateParameters("random",arguments),r=null!=this[i]?this._lcg(i):Math.random(),void 0===e)return r;if(void 0===t)return e instanceof Array?e[Math.floor(r*e.length)]:r*e;if(tf){var O=p,C=l,L=u;p=h+f*(s&&h=t&&(r=r.substring(r.length-t,r.length)),r}},o.default.prototype.unhex=function(e){return e instanceof Array?e.map(o.default.prototype.unhex):parseInt("0x".concat(e),16)};var i=o.default;r.default=i},{"../core/main":264,"core-js/modules/es.array.map":161,"core-js/modules/es.number.constructor":170,"core-js/modules/es.object.to-string":177,"core-js/modules/es.regexp.to-string":182,"core-js/modules/es.string.repeat":188}],305:[function(e,t,r){"use strict";e("core-js/modules/es.array.filter"),e("core-js/modules/es.array.index-of"),e("core-js/modules/es.array.join"),e("core-js/modules/es.array.map"),e("core-js/modules/es.array.slice"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.regexp.constructor"),e("core-js/modules/es.regexp.exec"),e("core-js/modules/es.regexp.to-string"),e("core-js/modules/es.string.match"),e("core-js/modules/es.string.replace"),e("core-js/modules/es.string.split"),e("core-js/modules/es.string.trim"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,a=(n=e("../core/main"))&&n.__esModule?n:{default:n};function o(e,t,r){var n=e<0,o=n?e.toString().substring(1):e.toString(),i=o.indexOf("."),a=-1!==i?o.substring(0,i):o,s=-1!==i?o.substring(i+1):"",l=n?"-":"";if(void 0!==r){var u="";(-1!==i||0r&&(s=s.substring(0,r));for(var c=0;cn.length)for(var i=t-(n+=-1===r?".":"").length+1,a=0;a=h.TWO_PI?"".concat(t="ellipse","|").concat(c,"|"):"".concat(t="arc","|").concat(s,"|").concat(l,"|").concat(u,"|").concat(c,"|"),!this.geometryInHash(r)){var d=new E.default.Geometry(c,1,function(){if(this.strokeIndices=[],s.toFixed(10)!==l.toFixed(10)){u!==h.PIE&&void 0!==u||(this.vertices.push(new E.default.Vector(.5,.5,0)),this.uvs.push([.5,.5]));for(var e=0;e<=c;e++){var t=(l-s)*(e/c)+s,r=.5+Math.cos(t)/2,n=.5+Math.sin(t)/2;this.vertices.push(new E.default.Vector(r,n,0)),this.uvs.push([r,n]),e>5&31)/31,(v>>10&31)/31):(r=a,n=s,l)}for(var b=new j.default.Vector(y,m,g),_=1;_<=3;_++){var x=p+12*_,w=new j.default.Vector(u.getFloat32(x,!0),u.getFloat32(4+x,!0),u.getFloat32(8+x,!0));e.vertices.push(w),e.vertexNormals.push(b),d&&i.push(r,n,o)}e.faces.push([3*h,3*h+1,3*h+2]),e.uvs.push([0,0],[0,0],[0,0])}}(e,t);else{var r=new DataView(t);if(!("TextDecoder"in window))return console.warn("Sorry, ASCII STL loading only works in browsers that support TextDecoder (https://caniuse.com/#feat=textencoder)");var n=new TextDecoder("utf-8").decode(r).split("\n");!function(e,t){for(var r,n,o="",i=[],a=0;aMath.PI?l=Math.PI:l<=0&&(l=.001);var u=Math.sin(l)*a*Math.sin(s),c=Math.cos(l)*a,d=Math.sin(l)*a*Math.cos(s);this.camera(u+this.centerX,c+this.centerY,d+this.centerZ,this.centerX,this.centerY,this.centerZ,0,1,0)},y.default.Camera.prototype._isActive=function(){return this===this._renderer._curCamera},y.default.prototype.setCamera=function(e){this._renderer._curCamera=e,this._renderer.uPMatrix.set(e.projMatrix.mat4[0],e.projMatrix.mat4[1],e.projMatrix.mat4[2],e.projMatrix.mat4[3],e.projMatrix.mat4[4],e.projMatrix.mat4[5],e.projMatrix.mat4[6],e.projMatrix.mat4[7],e.projMatrix.mat4[8],e.projMatrix.mat4[9],e.projMatrix.mat4[10],e.projMatrix.mat4[11],e.projMatrix.mat4[12],e.projMatrix.mat4[13],e.projMatrix.mat4[14],e.projMatrix.mat4[15])};var o=y.default.Camera;r.default=o},{"../core/main":264}],313:[function(e,t,r){"use strict";e("core-js/modules/es.string.sub"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var n,c=(n=e("../core/main"))&&n.__esModule?n:{default:n};c.default.Geometry=function(e,t,r){return this.vertices=[],this.lineVertices=[],this.lineNormals=[],this.vertexNormals=[],this.faces=[],this.uvs=[],this.edges=[],this.vertexColors=[],this.detailX=void 0!==e?e:1,this.detailY=void 0!==t?t:1,this.dirtyFlags={},r instanceof Function&&r.call(this),this},c.default.Geometry.prototype.reset=function(){this.lineVertices.length=0,this.lineNormals.length=0,this.vertices.length=0,this.edges.length=0,this.vertexColors.length=0,this.vertexNormals.length=0,this.uvs.length=0,this.dirtyFlags={}},c.default.Geometry.prototype.computeFaces=function(){this.faces.length=0;for(var e,t,r,n,o=this.detailX+1,i=0;ithis.vertices.length-1-this.detailX;n--)e.add(this.vertexNormals[n]);e=c.default.Vector.div(e,this.detailX);for(var o=this.vertices.length-1;o>this.vertices.length-1-this.detailX;o--)this.vertexNormals[o]=e;return this},c.default.Geometry.prototype._makeTriangleEdges=function(){if(this.edges.length=0,Array.isArray(this.strokeIndices))for(var e=0,t=this.strokeIndices.length;e 65535 triangles. Your web browser does not support the WebGL Extension OES_element_index_uint.");n.drawElements(n.TRIANGLES,r.vertexCount,r.indexBufferType,0)}else n.drawArrays(e||n.TRIANGLES,0,r.vertexCount)},l.default.RendererGL.prototype._drawPoints=function(e,t){var r=this.GL,n=this._getImmediatePointShader();this._setPointUniforms(n),this._bindBuffer(t,r.ARRAY_BUFFER,this._vToNArray(e),Float32Array,r.STATIC_DRAW),n.enableAttrib(n.attributes.aPosition,3),r.drawArrays(r.Points,0,e.length),n.unbindShader()};var i=l.default.RendererGL;r.default=i},{"../core/main":264,"./p5.RenderBuffer":315,"./p5.RendererGL":318,"core-js/modules/es.array.fill":151,"core-js/modules/es.array.iterator":158,"core-js/modules/es.array.some":163,"core-js/modules/es.object.keys":176,"core-js/modules/es.object.to-string":177,"core-js/modules/es.string.iterator":186,"core-js/modules/es.symbol":196,"core-js/modules/es.symbol.description":194,"core-js/modules/es.symbol.iterator":195,"core-js/modules/es.typed-array.copy-within":197,"core-js/modules/es.typed-array.every":198,"core-js/modules/es.typed-array.fill":199,"core-js/modules/es.typed-array.filter":200,"core-js/modules/es.typed-array.find":202,"core-js/modules/es.typed-array.find-index":201,"core-js/modules/es.typed-array.float32-array":203,"core-js/modules/es.typed-array.for-each":205,"core-js/modules/es.typed-array.includes":206,"core-js/modules/es.typed-array.index-of":207,"core-js/modules/es.typed-array.iterator":210,"core-js/modules/es.typed-array.join":211,"core-js/modules/es.typed-array.last-index-of":212,"core-js/modules/es.typed-array.map":213,"core-js/modules/es.typed-array.reduce":215,"core-js/modules/es.typed-array.reduce-right":214,"core-js/modules/es.typed-array.reverse":216,"core-js/modules/es.typed-array.set":217,"core-js/modules/es.typed-array.slice":218,"core-js/modules/es.typed-array.some":219,"core-js/modules/es.typed-array.sort":220,"core-js/modules/es.typed-array.subarray":221,"core-js/modules/es.typed-array.to-locale-string":222,"core-js/modules/es.typed-array.to-string":223,"core-js/modules/es.typed-array.uint16-array":224,"core-js/modules/es.typed-array.uint32-array":225,"core-js/modules/web.dom-collections.iterator":229}],318:[function(e,t,r){"use strict";function a(e){return(a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}e("core-js/modules/es.symbol"),e("core-js/modules/es.symbol.description"),e("core-js/modules/es.symbol.iterator"),e("core-js/modules/es.array.concat"),e("core-js/modules/es.array.fill"),e("core-js/modules/es.array.filter"),e("core-js/modules/es.array.from"),e("core-js/modules/es.array.includes"),e("core-js/modules/es.array.iterator"),e("core-js/modules/es.array.slice"),e("core-js/modules/es.object.assign"),e("core-js/modules/es.object.to-string"),e("core-js/modules/es.regexp.to-string"),e("core-js/modules/es.string.includes"),e("core-js/modules/es.string.iterator"),e("core-js/modules/es.typed-array.float32-array"),e("core-js/modules/es.typed-array.float64-array"),e("core-js/modules/es.typed-array.int16-array"),e("core-js/modules/es.typed-array.uint8-array"),e("core-js/modules/es.typed-array.uint16-array"),e("core-js/modules/es.typed-array.uint32-array"),e("core-js/modules/es.typed-array.copy-within"),e("core-js/modules/es.typed-array.every"),e("core-js/modules/es.typed-array.fill"),e("core-js/modules/es.typed-array.filter"),e("core-js/modules/es.typed-array.find"),e("core-js/modules/es.typed-array.find-index"),e("core-js/modules/es.typed-array.for-each"),e("core-js/modules/es.typed-array.includes"),e("core-js/modules/es.typed-array.index-of"),e("core-js/modules/es.typed-array.iterator"),e("core-js/modules/es.typed-array.join"),e("core-js/modules/es.typed-array.last-index-of"),e("core-js/modules/es.typed-array.map"),e("core-js/modules/es.typed-array.reduce"),e("core-js/modules/es.typed-array.reduce-right"),e("core-js/modules/es.typed-array.reverse"),e("core-js/modules/es.typed-array.set"),e("core-js/modules/es.typed-array.slice"),e("core-js/modules/es.typed-array.some"),e("core-js/modules/es.typed-array.sort"),e("core-js/modules/es.typed-array.subarray"),e("core-js/modules/es.typed-array.to-locale-string"),e("core-js/modules/es.typed-array.to-string"),e("core-js/modules/web.dom-collections.iterator"),Object.defineProperty(r,"__esModule",{value:!0}),r.default=void 0;var u=o(e("../core/main")),i=function(e){if(e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var t=s();if(t&&t.has(e))return t.get(e);var r={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var o in e)if(Object.prototype.hasOwnProperty.call(e,o)){var i=n?Object.getOwnPropertyDescriptor(e,o):null;i&&(i.get||i.set)?Object.defineProperty(r,o,i):r[o]=e[o]}r.default=e,t&&t.set(e,r);return r}(e("../core/constants")),n=o(e("libtess"));e("./p5.Shader"),e("./p5.Camera"),e("../core/p5.Renderer"),e("./p5.Matrix");e("path");function s(){if("function"!=typeof WeakMap)return null;var e=new WeakMap;return s=function(){return e},e}function o(e){return e&&e.__esModule?e:{default:e}}function l(e){return function(e){if(Array.isArray(e)){for(var t=0,r=new Array(e.length);t vTexCoord.y;\n bool y1 = p1.y > vTexCoord.y;\n bool y2 = p2.y > vTexCoord.y;\n\n // could web be under the curve (after t1)?\n if (y1 ? !y2 : y0) {\n // add the coverage for t1\n coverage.x += saturate(C1.x + 0.5);\n // calculate the anti-aliasing for t1\n weight.x = min(weight.x, abs(C1.x));\n }\n\n // are we outside the curve (after t2)?\n if (y1 ? !y0 : y2) {\n // subtract the coverage for t2\n coverage.x -= saturate(C2.x + 0.5);\n // calculate the anti-aliasing for t2\n weight.x = min(weight.x, abs(C2.x));\n }\n}\n\n// this is essentially the same as coverageX, but with the axes swapped\nvoid coverageY(vec2 p0, vec2 p1, vec2 p2) {\n\n vec2 C1, C2;\n calulateCrossings(p0, p1, p2, C1, C2);\n\n bool x0 = p0.x > vTexCoord.x;\n bool x1 = p1.x > vTexCoord.x;\n bool x2 = p2.x > vTexCoord.x;\n\n if (x1 ? !x2 : x0) {\n coverage.y -= saturate(C1.y + 0.5);\n weight.y = min(weight.y, abs(C1.y));\n }\n\n if (x1 ? !x0 : x2) {\n coverage.y += saturate(C2.y + 0.5);\n weight.y = min(weight.y, abs(C2.y));\n }\n}\n\nvoid main() {\n\n // calculate the pixel scale based on screen-coordinates\n pixelScale = hardness / fwidth(vTexCoord);\n\n // which grid cell is this pixel in?\n ivec2 gridCoord = ifloor(vTexCoord * vec2(uGridSize));\n\n // intersect curves in this row\n {\n // the index into the row info bitmap\n int rowIndex = gridCoord.y + uGridOffset.y;\n // fetch the info texel\n vec4 rowInfo = getTexel(uSamplerRows, rowIndex, uGridImageSize);\n // unpack the rowInfo\n int rowStrokeIndex = getInt16(rowInfo.xy);\n int rowStrokeCount = getInt16(rowInfo.zw);\n\n for (int iRowStroke = INT(0); iRowStroke < N; iRowStroke++) {\n if (iRowStroke >= rowStrokeCount)\n break;\n\n // each stroke is made up of 3 points: the start and control point\n // and the start of the next curve.\n // fetch the indices of this pair of strokes:\n vec4 strokeIndices = getTexel(uSamplerRowStrokes, rowStrokeIndex++, uCellsImageSize);\n\n // unpack the stroke index\n int strokePos = getInt16(strokeIndices.xy);\n\n // fetch the two strokes\n vec4 stroke0 = getTexel(uSamplerStrokes, strokePos + INT(0), uStrokeImageSize);\n vec4 stroke1 = getTexel(uSamplerStrokes, strokePos + INT(1), uStrokeImageSize);\n\n // calculate the coverage\n coverageX(stroke0.xy, stroke0.zw, stroke1.xy);\n }\n }\n\n // intersect curves in this column\n {\n int colIndex = gridCoord.x + uGridOffset.x;\n vec4 colInfo = getTexel(uSamplerCols, colIndex, uGridImageSize);\n int colStrokeIndex = getInt16(colInfo.xy);\n int colStrokeCount = getInt16(colInfo.zw);\n \n for (int iColStroke = INT(0); iColStroke < N; iColStroke++) {\n if (iColStroke >= colStrokeCount)\n break;\n\n vec4 strokeIndices = getTexel(uSamplerColStrokes, colStrokeIndex++, uCellsImageSize);\n\n int strokePos = getInt16(strokeIndices.xy);\n vec4 stroke0 = getTexel(uSamplerStrokes, strokePos + INT(0), uStrokeImageSize);\n vec4 stroke1 = getTexel(uSamplerStrokes, strokePos + INT(1), uStrokeImageSize);\n coverageY(stroke0.xy, stroke0.zw, stroke1.xy);\n }\n }\n\n weight = saturate(1.0 - weight * 2.0);\n float distance = max(weight.x + weight.y, minDistance); // manhattan approx.\n float antialias = abs(dot(coverage, weight) / distance);\n float cover = min(abs(coverage.x), abs(coverage.y));\n gl_FragColor = uMaterialColor;\n gl_FragColor.a *= saturate(max(antialias, cover));\n}",lineVert:"/*\n Part of the Processing project - http://processing.org\n Copyright (c) 2012-15 The Processing Foundation\n Copyright (c) 2004-12 Ben Fry and Casey Reas\n Copyright (c) 2001-04 Massachusetts Institute of Technology\n This library is free software; you can redistribute it and/or\n modify it under the terms of the GNU Lesser General Public\n License as published by the Free Software Foundation, version 2.1.\n This library is distributed in the hope that it will be useful,\n but WITHOUT ANY WARRANTY; without even the implied warranty of\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n Lesser General Public License for more details.\n You should have received a copy of the GNU Lesser General\n Public License along with this library; if not, write to the\n Free Software Foundation, Inc., 59 Temple Place, Suite 330,\n Boston, MA 02111-1307 USA\n*/\n\n#define PROCESSING_LINE_SHADER\n\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nuniform float uStrokeWeight;\n\nuniform vec4 uViewport;\nuniform int uPerspective;\n\nattribute vec4 aPosition;\nattribute vec4 aDirection;\n \nvoid main() {\n // using a scale <1 moves the lines towards the camera\n // in order to prevent popping effects due to half of\n // the line disappearing behind the geometry faces.\n vec3 scale = vec3(0.9995);\n\n vec4 posp = uModelViewMatrix * aPosition;\n vec4 posq = uModelViewMatrix * (aPosition + vec4(aDirection.xyz, 0));\n\n // Moving vertices slightly toward the camera\n // to avoid depth-fighting with the fill triangles.\n // Discussed here:\n // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=252848 \n posp.xyz = posp.xyz * scale;\n posq.xyz = posq.xyz * scale;\n\n vec4 p = uProjectionMatrix * posp;\n vec4 q = uProjectionMatrix * posq;\n\n // formula to convert from clip space (range -1..1) to screen space (range 0..[width or height])\n // screen_p = (p.xy/p.w + <1,1>) * 0.5 * uViewport.zw\n\n // prevent division by W by transforming the tangent formula (div by 0 causes\n // the line to disappear, see https://github.com/processing/processing/issues/5183)\n // t = screen_q - screen_p\n //\n // tangent is normalized and we don't care which aDirection it points to (+-)\n // t = +- normalize( screen_q - screen_p )\n // t = +- normalize( (q.xy/q.w+<1,1>)*0.5*uViewport.zw - (p.xy/p.w+<1,1>)*0.5*uViewport.zw )\n //\n // extract common factor, <1,1> - <1,1> cancels out\n // t = +- normalize( (q.xy/q.w - p.xy/p.w) * 0.5 * uViewport.zw )\n //\n // convert to common divisor\n // t = +- normalize( ((q.xy*p.w - p.xy*q.w) / (p.w*q.w)) * 0.5 * uViewport.zw )\n //\n // remove the common scalar divisor/factor, not needed due to normalize and +-\n // (keep uViewport - can't remove because it has different components for x and y\n // and corrects for aspect ratio, see https://github.com/processing/processing/issues/5181)\n // t = +- normalize( (q.xy*p.w - p.xy*q.w) * uViewport.zw )\n\n vec2 tangent = normalize((q.xy*p.w - p.xy*q.w) * uViewport.zw);\n\n // flip tangent to normal (it's already normalized)\n vec2 normal = vec2(-tangent.y, tangent.x);\n\n float thickness = aDirection.w * uStrokeWeight;\n vec2 offset = normal * thickness / 2.0;\n\n vec2 curPerspScale;\n\n if(uPerspective == 1) {\n // Perspective ---\n // convert from world to clip by multiplying with projection scaling factor\n // to get the right thickness (see https://github.com/processing/processing/issues/5182)\n // invert Y, projections in Processing invert Y\n curPerspScale = (uProjectionMatrix * vec4(1, -1, 0, 0)).xy;\n } else {\n // No Perspective ---\n // multiply by W (to cancel out division by W later in the pipeline) and\n // convert from screen to clip (derived from clip to screen above)\n curPerspScale = p.w / (0.5 * uViewport.zw);\n }\n\n gl_Position.xy = p.xy + offset.xy * curPerspScale;\n gl_Position.zw = p.zw;\n}\n",lineFrag:"precision mediump float;\nprecision mediump int;\n\nuniform vec4 uMaterialColor;\n\nvoid main() {\n gl_FragColor = uMaterialColor;\n}",pointVert:"attribute vec3 aPosition;\nuniform float uPointSize;\nvarying float vStrokeWeight;\nuniform mat4 uModelViewMatrix;\nuniform mat4 uProjectionMatrix;\nvoid main() {\n\tvec4 positionVec4 = vec4(aPosition, 1.0);\n\tgl_Position = uProjectionMatrix * uModelViewMatrix * positionVec4;\n\tgl_PointSize = uPointSize;\n\tvStrokeWeight = uPointSize;\n}",pointFrag:"precision mediump float;\nprecision mediump int;\nuniform vec4 uMaterialColor;\nvarying float vStrokeWeight;\n\nvoid main(){\n\tfloat mask = 0.0;\n\n\t// make a circular mask using the gl_PointCoord (goes from 0 - 1 on a point)\n // might be able to get a nicer edge on big strokeweights with smoothstep but slightly less performant\n\n\tmask = step(0.98, length(gl_PointCoord * 2.0 - 1.0));\n\n\t// if strokeWeight is 1 or less lets just draw a square\n\t// this prevents weird artifacting from carving circles when our points are really small\n\t// if strokeWeight is larger than 1, we just use it as is\n\n\tmask = mix(0.0, mask, clamp(floor(vStrokeWeight - 0.5),0.0,1.0));\n\n\t// throw away the borders of the mask\n // otherwise we get weird alpha blending issues\n\n\tif(mask > 0.98){\n discard;\n \t}\n\n \tgl_FragColor = vec4(uMaterialColor.rgb * (1.0 - mask), uMaterialColor.a) ;\n}"};u.default.RendererGL=function(e,t,r,n){return u.default.Renderer.call(this,e,t,r),this._setAttributeDefaults(t),this._initContext(),this.isP3D=!0,this.GL=this.drawingContext,this._pInst._setProperty("drawingContext",this.drawingContext),this._isErasing=!1,this._enableLighting=!1,this.ambientLightColors=[],this.specularColors=[1,1,1],this.directionalLightDirections=[],this.directionalLightDiffuseColors=[],this.directionalLightSpecularColors=[],this.pointLightPositions=[],this.pointLightDiffuseColors=[],this.pointLightSpecularColors=[],this.spotLightPositions=[],this.spotLightDirections=[],this.spotLightDiffuseColors=[],this.spotLightSpecularColors=[],this.spotLightAngle=[],this.spotLightConc=[],this.drawMode=i.FILL,this.curFillColor=this._cachedFillStyle=[1,1,1,1],this.curStrokeColor=this._cachedStrokeStyle=[0,0,0,1],this.curBlendMode=i.BLEND,this._cachedBlendMode=void 0,this.blendExt=this.GL.getExtension("EXT_blend_minmax"),this._isBlending=!1,this._useSpecularMaterial=!1,this._useEmissiveMaterial=!1,this._useNormalMaterial=!1,this._useShininess=1,this._tint=[255,255,255,255],this.constantAttenuation=1,this.linearAttenuation=0,this.quadraticAttenuation=0,this.uMVMatrix=new u.default.Matrix,this.uPMatrix=new u.default.Matrix,this.uNMatrix=new u.default.Matrix("mat3"),this._currentNormal=new u.default.Vector(0,0,1),this._curCamera=new u.default.Camera(this),this._curCamera._computeCameraDefaultSettings(),this._curCamera._setDefaultCamera(),this._defaultLightShader=void 0,this._defaultImmediateModeShader=void 0,this._defaultNormalShader=void 0,this._defaultColorShader=void 0,this._defaultPointShader=void 0,this.userFillShader=void 0,this.userStrokeShader=void 0,this.userPointShader=void 0,this.retainedMode={geometry:{},buffers:{stroke:[new u.default.RenderBuffer(3,"lineVertices","lineVertexBuffer","aPosition",this,this._flatten),new u.default.RenderBuffer(4,"lineNormals","lineNormalBuffer","aDirection",this,this._flatten)],fill:[new u.default.RenderBuffer(3,"vertices","vertexBuffer","aPosition",this,this._vToNArray),new u.default.RenderBuffer(3,"vertexNormals","normalBuffer","aNormal",this,this._vToNArray),new u.default.RenderBuffer(4,"vertexColors","colorBuffer","aVertexColor",this),new u.default.RenderBuffer(3,"vertexAmbients","ambientBuffer","aAmbientColor",this),new u.default.RenderBuffer(2,"uvs","uvBuffer","aTexCoord",this,this._flatten)],text:[new u.default.RenderBuffer(3,"vertices","vertexBuffer","aPosition",this,this._vToNArray),new u.default.RenderBuffer(2,"uvs","uvBuffer","aTexCoord",this,this._flatten)]}},this.immediateMode={geometry:new u.default.Geometry,shapeMode:i.TRIANGLE_FAN,_bezierVertex:[],_quadraticVertex:[],_curveVertex:[],buffers:{fill:[new u.default.RenderBuffer(3,"vertices","vertexBuffer","aPosition",this,this._vToNArray),new u.default.RenderBuffer(3,"vertexNormals","normalBuffer","aNormal",this,this._vToNArray),new u.default.RenderBuffer(4,"vertexColors","colorBuffer","aVertexColor",this),new u.default.RenderBuffer(3,"vertexAmbients","ambientBuffer","aAmbientColor",this),new u.default.RenderBuffer(2,"uvs","uvBuffer","aTexCoord",this,this._flatten)],stroke:[new u.default.RenderBuffer(3,"lineVertices","lineVertexBuffer","aPosition",this,this._flatten),new u.default.RenderBuffer(4,"lineNormals","lineNormalBuffer","aDirection",this,this._flatten)],point:this.GL.createBuffer()}},this.pointSize=5,this.curStrokeWeight=1,this.textures=[],this.textureMode=i.IMAGE,this.textureWrapX=i.CLAMP,this.textureWrapY=i.CLAMP,this._tex=null,this._curveTightness=6,this._lookUpTableBezier=[],this._lookUpTableQuadratic=[],this._lutBezierDetail=0,this._lutQuadraticDetail=0,this._tessy=this._initTessy(),this.fontInfos={},this._curShader=void 0,this},u.default.RendererGL.prototype=Object.create(u.default.Renderer.prototype),u.default.RendererGL.prototype._setAttributeDefaults=function(e){var t={alpha:!1,depth:!0,stencil:!0,antialias:navigator.userAgent.toLowerCase().includes("safari"),premultipliedAlpha:!1,preserveDrawingBuffer:!0,perPixelLighting:!0};null===e._glAttributes?e._glAttributes=t:e._glAttributes=Object.assign(t,e._glAttributes)},u.default.RendererGL.prototype._initContext=function(){try{if(this.drawingContext=this.canvas.getContext("webgl",this._pInst._glAttributes)||this.canvas.getContext("experimental-webgl",this._pInst._glAttributes),null===this.drawingContext)throw new Error("Error creating webgl context");var e=this.drawingContext;e.enable(e.DEPTH_TEST),e.depthFunc(e.LEQUAL),e.viewport(0,0,e.drawingBufferWidth,e.drawingBufferHeight),this._viewport=this.drawingContext.getParameter(this.drawingContext.VIEWPORT)}catch(e){throw e}},u.default.RendererGL.prototype._resetContext=function(e,t){var r=this.width,n=this.height,o=this.canvas.id,i=this._pInst instanceof u.default.Graphics;if(i){var a=this._pInst;a.canvas.parentNode.removeChild(a.canvas),a.canvas=document.createElement("canvas"),(a._pInst._userNode||document.body).appendChild(a.canvas),u.default.Element.call(a,a.canvas,a._pInst),a.width=r,a.height=n}else{var s=this.canvas;s&&s.parentNode.removeChild(s),(s=document.createElement("canvas")).id=o,this._pInst._userNode?this._pInst._userNode.appendChild(s):document.body.appendChild(s),this._pInst.canvas=s}var l=new u.default.RendererGL(this._pInst.canvas,this._pInst,!i);this._pInst._setProperty("_renderer",l),l.resize(r,n),l._applyDefaults(),i||this._pInst._elements.push(l),"function"==typeof t&&setTimeout(function(){t.apply(window._renderer,e)},0)},u.default.prototype.setAttributes=function(e,t){if(void 0!==this._glAttributes){var r=!0;if(void 0!==t?(null===this._glAttributes&&(this._glAttributes={}),this._glAttributes[e]!==t&&(this._glAttributes[e]=t,r=!1)):e instanceof Object&&this._glAttributes!==e&&(this._glAttributes=e,r=!1),this._renderer.isP3D&&!r){if(!this._setupDone)for(var n in this._renderer.retainedMode.geometry)if(this._renderer.retainedMode.geometry.hasOwnProperty(n))return void console.error("Sorry, Could not set the attributes, you need to call setAttributes() before calling the other drawing methods in setup()");this.push(),this._renderer._resetContext(),this.pop(),this._renderer._curCamera&&(this._renderer._curCamera._renderer=this._renderer)}}else console.log("You are trying to use setAttributes on a p5.Graphics object that does not use a WEBGL renderer.")},u.default.RendererGL.prototype._update=function(){this.uMVMatrix.set(this._curCamera.cameraMatrix.mat4[0],this._curCamera.cameraMatrix.mat4[1],this._curCamera.cameraMatrix.mat4[2],this._curCamera.cameraMatrix.mat4[3],this._curCamera.cameraMatrix.mat4[4],this._curCamera.cameraMatrix.mat4[5],this._curCamera.cameraMatrix.mat4[6],this._curCamera.cameraMatrix.mat4[7],this._curCamera.cameraMatrix.mat4[8],this._curCamera.cameraMatrix.mat4[9],this._curCamera.cameraMatrix.mat4[10],this._curCamera.cameraMatrix.mat4[11],this._curCamera.cameraMatrix.mat4[12],this._curCamera.cameraMatrix.mat4[13],this._curCamera.cameraMatrix.mat4[14],this._curCamera.cameraMatrix.mat4[15]),this.ambientLightColors.length=0,this.specularColors=[1,1,1],this.directionalLightDirections.length=0,this.directionalLightDiffuseColors.length=0,this.directionalLightSpecularColors.length=0,this.pointLightPositions.length=0,this.pointLightDiffuseColors.length=0,this.pointLightSpecularColors.length=0,this.spotLightPositions.length=0,this.spotLightDirections.length=0,this.spotLightDiffuseColors.length=0,this.spotLightSpecularColors.length=0,this.spotLightAngle.length=0,this.spotLightConc.length=0,this._enableLighting=!1,this._tint=[255,255,255,255],this.GL.clear(this.GL.DEPTH_BUFFER_BIT)},u.default.RendererGL.prototype.background=function(){var e,t=(e=this._pInst).color.apply(e,arguments),r=t.levels[0]/255,n=t.levels[1]/255,o=t.levels[2]/255,i=t.levels[3]/255;this.GL.clearColor(r,n,o,i),this.GL.clear(this.GL.COLOR_BUFFER_BIT)},u.default.RendererGL.prototype.fill=function(e,t,r,n){var o=u.default.prototype.color.apply(this._pInst,arguments);this.curFillColor=o._array,this.drawMode=i.FILL,this._useNormalMaterial=!1,this._tex=null},u.default.RendererGL.prototype.stroke=function(e,t,r,n){arguments[3]=255;var o=u.default.prototype.color.apply(this._pInst,arguments);this.curStrokeColor=o._array},u.default.RendererGL.prototype.strokeCap=function(e){console.error("Sorry, strokeCap() is not yet implemented in WEBGL mode")},u.default.RendererGL.prototype.strokeJoin=function(e){console.error("Sorry, strokeJoin() is not yet implemented in WEBGL mode")},u.default.RendererGL.prototype.filter=function(e){console.error("filter() does not work in WEBGL mode")},u.default.RendererGL.prototype.blendMode=function(e){e===i.DARKEST||e===i.LIGHTEST||e===i.ADD||e===i.BLEND||e===i.SUBTRACT||e===i.SCREEN||e===i.EXCLUSION||e===i.REPLACE||e===i.MULTIPLY||e===i.REMOVE?this.curBlendMode=e:e!==i.BURN&&e!==i.OVERLAY&&e!==i.HARD_LIGHT&&e!==i.SOFT_LIGHT&&e!==i.DODGE||console.warn("BURN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, and DODGE only work for blendMode in 2D mode.")},u.default.RendererGL.prototype.erase=function(e,t){this._isErasing||(this._applyBlendMode(i.REMOVE),this._isErasing=!0,this._cachedFillStyle=this.curFillColor.slice(),this.curFillColor=[1,1,1,e/255],this._cachedStrokeStyle=this.curStrokeColor.slice(),this.curStrokeColor=[1,1,1,t/255])},u.default.RendererGL.prototype.noErase=function(){this._isErasing&&(this._isErasing=!1,this.curFillColor=this._cachedFillStyle.slice(),this.curStrokeColor=this._cachedStrokeStyle.slice(),this.blendMode(this._cachedBlendMode))},u.default.RendererGL.prototype.strokeWeight=function(e){this.curStrokeWeight!==e&&(this.pointSize=e,this.curStrokeWeight=e)},u.default.RendererGL.prototype._getPixel=function(e,t){var r;return r=new Uint8Array(4),this.drawingContext.readPixels(e,t,1,1,this.drawingContext.RGBA,this.drawingContext.UNSIGNED_BYTE,r),[r[0],r[1],r[2],r[3]]},u.default.RendererGL.prototype.loadPixels=function(){var e=this._pixelsState;if(!0===this._pInst._glAttributes.preserveDrawingBuffer){var t=e.pixels,r=this.GL.drawingBufferWidth*this.GL.drawingBufferHeight*4;t instanceof Uint8Array&&t.length===r||(t=new Uint8Array(r),this._pixelsState._setProperty("pixels",t));var n=this._pInst._pixelDensity;this.GL.readPixels(0,0,this.width*n,this.height*n,this.GL.RGBA,this.GL.UNSIGNED_BYTE,t)}else console.log("loadPixels only works in WebGL when preserveDrawingBuffer is true.")},u.default.RendererGL.prototype.geometryInHash=function(e){return void 0!==this.retainedMode.geometry[e]},u.default.RendererGL.prototype.resize=function(e,t){u.default.Renderer.prototype.resize.call(this,e,t),this.GL.viewport(0,0,this.GL.drawingBufferWidth,this.GL.drawingBufferHeight),this._viewport=this.GL.getParameter(this.GL.VIEWPORT),this._curCamera._resize();var r=this._pixelsState;void 0!==r.pixels&&r._setProperty("pixels",new Uint8Array(this.GL.drawingBufferWidth*this.GL.drawingBufferHeight*4))},u.default.RendererGL.prototype.clear=function(){var e=(arguments.length<=0?void 0:arguments[0])||0,t=(arguments.length<=1?void 0:arguments[1])||0,r=(arguments.length<=2?void 0:arguments[2])||0,n=(arguments.length<=3?void 0:arguments[3])||0;this.GL.clearColor(e,t,r,n),this.GL.clearDepth(1),this.GL.clear(this.GL.COLOR_BUFFER_BIT|this.GL.DEPTH_BUFFER_BIT)},u.default.RendererGL.prototype.applyMatrix=function(e,t,r,n,o,i){16===arguments.length?u.default.Matrix.prototype.apply.apply(this.uMVMatrix,arguments):this.uMVMatrix.apply([e,t,0,0,r,n,0,0,0,0,1,0,o,i,0,1])},u.default.RendererGL.prototype.translate=function(e,t,r){return e instanceof u.default.Vector&&(r=e.z,t=e.y,e=e.x),this.uMVMatrix.translate([e,t,r]),this},u.default.RendererGL.prototype.scale=function(e,t,r){return this.uMVMatrix.scale(e,t,r),this},u.default.RendererGL.prototype.rotate=function(e,t){return void 0===t?this.rotateZ(e):(u.default.Matrix.prototype.rotate.apply(this.uMVMatrix,arguments),this)},u.default.RendererGL.prototype.rotateX=function(e){return this.rotate(e,1,0,0),this},u.default.RendererGL.prototype.rotateY=function(e){return this.rotate(e,0,1,0),this},u.default.RendererGL.prototype.rotateZ=function(e){return this.rotate(e,0,0,1),this},u.default.RendererGL.prototype.push=function(){var e=u.default.Renderer.prototype.push.apply(this),t=e.properties;return t.uMVMatrix=this.uMVMatrix.copy(),t.uPMatrix=this.uPMatrix.copy(),t._curCamera=this._curCamera,this._curCamera=this._curCamera.copy(),t.ambientLightColors=this.ambientLightColors.slice(),t.specularColors=this.specularColors.slice(),t.directionalLightDirections=this.directionalLightDirections.slice(),t.directionalLightDiffuseColors=this.directionalLightDiffuseColors.slice(),t.directionalLightSpecularColors=this.directionalLightSpecularColors.slice(),t.pointLightPositions=this.pointLightPositions.slice(),t.pointLightDiffuseColors=this.pointLightDiffuseColors.slice(),t.pointLightSpecularColors=this.pointLightSpecularColors.slice(),t.spotLightPositions=this.spotLightPositions.slice(),t.spotLightDirections=this.spotLightDirections.slice(),t.spotLightDiffuseColors=this.spotLightDiffuseColors.slice(),t.spotLightSpecularColors=this.spotLightSpecularColors.slice(),t.spotLightAngle=this.spotLightAngle.slice(),t.spotLightConc=this.spotLightConc.slice(),t.userFillShader=this.userFillShader,t.userStrokeShader=this.userStrokeShader,t.userPointShader=this.userPointShader,t.pointSize=this.pointSize,t.curStrokeWeight=this.curStrokeWeight,t.curStrokeColor=this.curStrokeColor,t.curFillColor=this.curFillColor,t._useSpecularMaterial=this._useSpecularMaterial,t._useEmissiveMaterial=this._useEmissiveMaterial,t._useShininess=this._useShininess,t.constantAttenuation=this.constantAttenuation,t.linearAttenuation=this.linearAttenuation,t.quadraticAttenuation=this.quadraticAttenuation,t._enableLighting=this._enableLighting,t._useNormalMaterial=this._useNormalMaterial,t._tex=this._tex,t.drawMode=this.drawMode,t._currentNormal=this._currentNormal,e},u.default.RendererGL.prototype.resetMatrix=function(){return this.uMVMatrix=u.default.Matrix.identity(this._pInst),this},u.default.RendererGL.prototype._getImmediateStrokeShader=function(){var e=this.userStrokeShader;return e&&e.isStrokeShader()?e:this._getLineShader()},u.default.RendererGL.prototype._getRetainedStrokeShader=u.default.RendererGL.prototype._getImmediateStrokeShader,u.default.RendererGL.prototype._getImmediateFillShader=function(){var e=this.userFillShader;if(this._useNormalMaterial&&(!e||!e.isNormalShader()))return this._getNormalShader();if(this._enableLighting){if(!e||!e.isLightShader())return this._getLightShader()}else if(this._tex){if(!e||!e.isTextureShader())return this._getLightShader()}else if(!e)return this._getImmediateModeShader();return e},u.default.RendererGL.prototype._getRetainedFillShader=function(){if(this._useNormalMaterial)return this._getNormalShader();var e=this.userFillShader;if(this._enableLighting){if(!e||!e.isLightShader())return this._getLightShader()}else if(this._tex){if(!e||!e.isTextureShader())return this._getLightShader()}else if(!e)return this._getColorShader();return e},u.default.RendererGL.prototype._getImmediatePointShader=function(){var e=this.userPointShader;return e&&e.isPointShader()?e:this._getPointShader()},u.default.RendererGL.prototype._getRetainedLineShader=u.default.RendererGL.prototype._getImmediateLineShader,u.default.RendererGL.prototype._getLightShader=function(){return this._defaultLightShader||(this._pInst._glAttributes.perPixelLighting?this._defaultLightShader=new u.default.Shader(this,d.phongVert,d.phongFrag):this._defaultLightShader=new u.default.Shader(this,d.lightVert,d.lightTextureFrag)),this._defaultLightShader},u.default.RendererGL.prototype._getImmediateModeShader=function(){return this._defaultImmediateModeShader||(this._defaultImmediateModeShader=new u.default.Shader(this,d.immediateVert,d.vertexColorFrag)),this._defaultImmediateModeShader},u.default.RendererGL.prototype._getNormalShader=function(){return this._defaultNormalShader||(this._defaultNormalShader=new u.default.Shader(this,d.normalVert,d.normalFrag)),this._defaultNormalShader},u.default.RendererGL.prototype._getColorShader=function(){return this._defaultColorShader||(this._defaultColorShader=new u.default.Shader(this,d.normalVert,d.basicFrag)),this._defaultColorShader},u.default.RendererGL.prototype._getPointShader=function(){return this._defaultPointShader||(this._defaultPointShader=new u.default.Shader(this,d.pointVert,d.pointFrag)),this._defaultPointShader},u.default.RendererGL.prototype._getLineShader=function(){return this._defaultLineShader||(this._defaultLineShader=new u.default.Shader(this,d.lineVert,d.lineFrag)),this._defaultLineShader},u.default.RendererGL.prototype._getFontShader=function(){return this._defaultFontShader||(this.GL.getExtension("OES_standard_derivatives"),this._defaultFontShader=new u.default.Shader(this,d.fontVert,d.fontFrag)),this._defaultFontShader},u.default.RendererGL.prototype._getEmptyTexture=function(){if(!this._emptyTexture){var e=new u.default.Image(1,1);e.set(0,0,255),this._emptyTexture=new u.default.Texture(this,e)}return this._emptyTexture},u.default.RendererGL.prototype.getTexture=function(e){var t=this.textures,r=!0,n=!1,o=void 0;try{for(var i,a=t[Symbol.iterator]();!(r=(i=a.next()).done);r=!0){var s=i.value;if(s.src===e)return s}}catch(e){n=!0,o=e}finally{try{r||null==a.return||a.return()}finally{if(n)throw o}}var l=new u.default.Texture(this,e);return t.push(l),l},u.default.RendererGL.prototype._setStrokeUniforms=function(e){e.bindShader(),e.setUniform("uMaterialColor",this.curStrokeColor),e.setUniform("uStrokeWeight",this.curStrokeWeight)},u.default.RendererGL.prototype._setFillUniforms=function(e){e.bindShader(),e.setUniform("uMaterialColor",this.curFillColor),e.setUniform("isTexture",!!this._tex),this._tex&&e.setUniform("uSampler",this._tex),e.setUniform("uTint",this._tint),e.setUniform("uSpecular",this._useSpecularMaterial),e.setUniform("uEmissive",this._useEmissiveMaterial),e.setUniform("uShininess",this._useShininess),e.setUniform("uUseLighting",this._enableLighting);var t=this.pointLightDiffuseColors.length/3;e.setUniform("uPointLightCount",t),e.setUniform("uPointLightLocation",this.pointLightPositions),e.setUniform("uPointLightDiffuseColors",this.pointLightDiffuseColors),e.setUniform("uPointLightSpecularColors",this.pointLightSpecularColors);var r=this.directionalLightDiffuseColors.length/3;e.setUniform("uDirectionalLightCount",r),e.setUniform("uLightingDirection",this.directionalLightDirections),e.setUniform("uDirectionalDiffuseColors",this.directionalLightDiffuseColors),e.setUniform("uDirectionalSpecularColors",this.directionalLightSpecularColors);var n=this.ambientLightColors.length/3;e.setUniform("uAmbientLightCount",n),e.setUniform("uAmbientColor",this.ambientLightColors);var o=this.spotLightDiffuseColors.length/3;e.setUniform("uSpotLightCount",o),e.setUniform("uSpotLightAngle",this.spotLightAngle),e.setUniform("uSpotLightConc",this.spotLightConc),e.setUniform("uSpotLightDiffuseColors",this.spotLightDiffuseColors),e.setUniform("uSpotLightSpecularColors",this.spotLightSpecularColors),e.setUniform("uSpotLightLocation",this.spotLightPositions),e.setUniform("uSpotLightDirection",this.spotLightDirections),e.setUniform("uConstantAttenuation",this.constantAttenuation),e.setUniform("uLinearAttenuation",this.linearAttenuation),e.setUniform("uQuadraticAttenuation",this.quadraticAttenuation),e.bindTextures()},u.default.RendererGL.prototype._setPointUniforms=function(e){e.bindShader(),e.setUniform("uMaterialColor",this.curStrokeColor),e.setUniform("uPointSize",this.pointSize*this._pInst._pixelDensity)},u.default.RendererGL.prototype._bindBuffer=function(e,t,r,n,o){if(t=t||this.GL.ARRAY_BUFFER,this.GL.bindBuffer(t,e),void 0!==r){var i=new(n||Float32Array)(r);this.GL.bufferData(t,i,o||this.GL.STATIC_DRAW)}},u.default.RendererGL.prototype._arraysEqual=function(e,t){var r=e.length;if(r!==t.length)return!1;for(var n=0;n>7,127&f,d>>7,127&d);for(var h=0;h>7,127&p,0,0)}}return{cellImageInfo:l,dimOffset:i,dimImageInfo:o}}return(t=this.glyphInfos[e.index]={glyph:e,uGlyphRect:[n.x1,-n.y1,n.x2,-n.y2],strokeImageInfo:I,strokes:h,colInfo:B(y,this.colDimImageInfos,this.colCellImageInfos),rowInfo:B(p,this.rowDimImageInfos,this.rowCellImageInfos)}).uGridOffset=[t.colInfo.dimOffset,t.rowInfo.dimOffset],t}}var z=Math.sqrt(3);G.default.RendererGL.prototype._renderText=function(e,t,r,n,o){if(this._textFont&&"string"!=typeof this._textFont){if(!(o<=n)&&this._doFill){if(!this._isOpenType())return console.log("WEBGL: only Opentype (.otf) and Truetype (.ttf) fonts are supported"),e;e.push();var i=this._doStroke,a=this.drawMode;this._doStroke=!1,this.drawMode=k.TEXTURE;var s=this._textFont.font,l=this._textFont._fontInfo;l=l||(this._textFont._fontInfo=new R(s));var u=this._textFont._handleAlignment(this,t,r,n),c=this._textSize/s.unitsPerEm;this.translate(u.x,u.y,0),this.scale(c,c,1);var d=this.GL,f=!this._defaultFontShader,h=this._getFontShader();h.init(),h.bindShader(),f&&(h.setUniform("uGridImageSize",[64,64]),h.setUniform("uCellsImageSize",[64,64]),h.setUniform("uStrokeImageSize",[64,64]),h.setUniform("uGridSize",[9,9])),this._applyColorBlend(this.curFillColor);var p=this.retainedMode.geometry.glyph;if(!p){var y=this._textGeom=new G.default.Geometry(1,1,function(){for(var e=0;e<=1;e++)for(var t=0;t<=1;t++)this.vertices.push(new G.default.Vector(t,e,0)),this.uvs.push(t,e)});y.computeFaces().computeNormals(),p=this.createBuffers("glyph",y)}var m=!0,g=!1,v=void 0;try{for(var b,_=this.retainedMode.buffers.text[Symbol.iterator]();!(m=(b=_.next()).done);m=!0){b.value._prepareBuffer(p,h)}}catch(e){g=!0,v=e}finally{try{m||null==_.return||_.return()}finally{if(g)throw v}}this._bindBuffer(p.indexBuffer,d.ELEMENT_ARRAY_BUFFER),h.setUniform("uMaterialColor",this.curFillColor);try{var x=0,w=null,j=s.stringToGlyphs(t),S=!0,M=!1,E=void 0;try{for(var T,O=j[Symbol.iterator]();!(S=(T=O.next()).done);S=!0){var C=T.value;w&&(x+=s.getKerningValue(w,C));var L=l.getGlyphInfo(C);if(L.uGlyphRect){var P=L.rowInfo,A=L.colInfo;h.setUniform("uSamplerStrokes",L.strokeImageInfo.imageData),h.setUniform("uSamplerRowStrokes",P.cellImageInfo.imageData),h.setUniform("uSamplerRows",P.dimImageInfo.imageData),h.setUniform("uSamplerColStrokes",A.cellImageInfo.imageData),h.setUniform("uSamplerCols",A.dimImageInfo.imageData),h.setUniform("uGridOffset",L.uGridOffset),h.setUniform("uGlyphRect",L.uGlyphRect),h.setUniform("uGlyphOffset",x),h.bindTextures(),d.drawElements(d.TRIANGLES,6,this.GL.UNSIGNED_SHORT,0)}x+=C.advanceWidth,w=C}}catch(e){M=!0,E=e}finally{try{S||null==O.return||O.return()}finally{if(M)throw E}}}finally{h.unbindShader(),this._doStroke=i,this.drawMode=a,e.pop()}return e}}else console.log("WEBGL: you must load and set a font before drawing text. See `loadFont` and `textFont` for more details.")}},{"../core/constants":253,"../core/main":264,"./p5.RendererGL.Retained":317,"./p5.Shader":319,"core-js/modules/es.array.iterator":158,"core-js/modules/es.object.to-string":177,"core-js/modules/es.regexp.exec":181,"core-js/modules/es.string.iterator":186,"core-js/modules/es.string.split":191,"core-js/modules/es.string.sub":192,"core-js/modules/es.symbol":196,"core-js/modules/es.symbol.description":194,"core-js/modules/es.symbol.iterator":195,"core-js/modules/web.dom-collections.iterator":229}]},{},[248])(248)}); \ No newline at end of file diff --git a/dist/assets/js/p5.sound.min.js b/dist/assets/js/p5.sound.min.js new file mode 100644 index 0000000000..44f2523182 --- /dev/null +++ b/dist/assets/js/p5.sound.min.js @@ -0,0 +1,3 @@ +/** [p5.sound] Version: 1.0.1 - 2021-05-25 */ + !function(n){var i={};function r(t){if(i[t])return i[t].exports;var e=i[t]={i:t,l:!1,exports:{}};return n[t].call(e.exports,e,e.exports,r),e.l=!0,e.exports}r.m=n,r.c=i,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)r.d(n,i,function(t){return e[t]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=40)}([function(t,e,n){var i;void 0===(i=function(){"use strict";function l(t,e){this.isUndef(t)||1===t?this.input=this.context.createGain():1t)this.cancelScheduledValues(t),this.linearRampToValueAtTime(e,t);else{var i=this._searchAfter(t);i&&(this.cancelScheduledValues(t),i.type===u.TimelineSignal.Type.Linear?this.linearRampToValueAtTime(e,t):i.type===u.TimelineSignal.Type.Exponential&&this.exponentialRampToValueAtTime(e,t)),this.setValueAtTime(e,t)}return this},u.TimelineSignal.prototype.linearRampToValueBetween=function(t,e,n){return this.setRampPoint(e),this.linearRampToValueAtTime(t,n),this},u.TimelineSignal.prototype.exponentialRampToValueBetween=function(t,e,n){return this.setRampPoint(e),this.exponentialRampToValueAtTime(t,n),this},u.TimelineSignal.prototype._searchBefore=function(t){return this._events.get(t)},u.TimelineSignal.prototype._searchAfter=function(t){return this._events.getAfter(t)},u.TimelineSignal.prototype.getValueAtTime=function(t){t=this.toSeconds(t);var e=this._searchAfter(t),n=this._searchBefore(t),i=this._initial;if(null===n)i=this._initial;else if(n.type===u.TimelineSignal.Type.Target){var r,o=this._events.getBefore(n.time);r=null===o?this._initial:o.value,i=this._exponentialApproach(n.time,r,n.value,n.constant,t)}else i=n.type===u.TimelineSignal.Type.Curve?this._curveInterpolate(n.time,n.value,n.duration,t):null===e?n.value:e.type===u.TimelineSignal.Type.Linear?this._linearInterpolate(n.time,n.value,e.time,e.value,t):e.type===u.TimelineSignal.Type.Exponential?this._exponentialInterpolate(n.time,n.value,e.time,e.value,t):n.value;return i},u.TimelineSignal.prototype.connect=u.SignalBase.prototype.connect,u.TimelineSignal.prototype._exponentialApproach=function(t,e,n,i,r){return n+(e-n)*Math.exp(-(r-t)/i)},u.TimelineSignal.prototype._linearInterpolate=function(t,e,n,i,r){return e+(r-t)/(n-t)*(i-e)},u.TimelineSignal.prototype._exponentialInterpolate=function(t,e,n,i,r){return(e=Math.max(this._minOutput,e))*Math.pow(i/e,(r-t)/(n-t))},u.TimelineSignal.prototype._curveInterpolate=function(t,e,n,i){var r=e.length;if(t+n<=i)return e[r-1];if(i<=t)return e[0];var o=(i-t)/n,s=Math.floor((r-1)*o),a=Math.ceil((r-1)*o),u=e[s],c=e[a];return a===s?u:this._linearInterpolate(s,u,a,c,o*(r-1))},u.TimelineSignal.prototype.dispose=function(){u.Signal.prototype.dispose.call(this),u.Param.prototype.dispose.call(this),this._events.dispose(),this._events=null},u.TimelineSignal}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r;i=[n(0),n(4),n(1),n(2)],void 0===(r=function(n){"use strict";return n.Scale=function(t,e){this._outputMin=this.defaultArg(t,0),this._outputMax=this.defaultArg(e,1),this._scale=this.input=new n.Multiply(1),this._add=this.output=new n.Add(0),this._scale.connect(this._add),this._setRange()},n.extend(n.Scale,n.SignalBase),Object.defineProperty(n.Scale.prototype,"min",{get:function(){return this._outputMin},set:function(t){this._outputMin=t,this._setRange()}}),Object.defineProperty(n.Scale.prototype,"max",{get:function(){return this._outputMax},set:function(t){this._outputMax=t,this._setRange()}}),n.Scale.prototype._setRange=function(){this._add.value=this._outputMin,this._scale.value=this._outputMax-this._outputMin},n.Scale.prototype.dispose=function(){return n.prototype.dispose.call(this),this._add.dispose(),this._add=null,this._scale.dispose(),this._scale=null,this},n.Scale}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r;i=[n(0),n(16),n(30),n(31),n(12)],void 0===(r=function(e){return e.Type={Default:"number",Time:"time",Frequency:"frequency",TransportTime:"transportTime",Ticks:"ticks",NormalRange:"normalRange",AudioRange:"audioRange",Decibels:"db",Interval:"interval",BPM:"bpm",Positive:"positive",Cents:"cents",Degrees:"degrees",MIDI:"midi",BarsBeatsSixteenths:"barsBeatsSixteenths",Samples:"samples",Hertz:"hertz",Note:"note",Milliseconds:"milliseconds",Seconds:"seconds",Notation:"notation"},e.prototype.toSeconds=function(t){return this.isNumber(t)?t:this.isUndef(t)?this.now():this.isString(t)?new e.Time(t).toSeconds():t instanceof e.TimeBase?t.toSeconds():void 0},e.prototype.toFrequency=function(t){return this.isNumber(t)?t:this.isString(t)||this.isUndef(t)?new e.Frequency(t).valueOf():t instanceof e.TimeBase?t.toFrequency():void 0},e.prototype.toTicks=function(t){return this.isNumber(t)||this.isString(t)?new e.TransportTime(t).toTicks():this.isUndef(t)?e.Transport.ticks:t instanceof e.TimeBase?t.toTicks():void 0},e}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r;i=[n(0),n(18),n(9)],void 0===(r=function(n){"use strict";return window.GainNode&&!AudioContext.prototype.createGain&&(AudioContext.prototype.createGain=AudioContext.prototype.createGainNode),n.Gain=function(){var t=this.optionsObject(arguments,["gain","units"],n.Gain.defaults);this.input=this.output=this._gainNode=this.context.createGain(),this.gain=new n.Param({param:this._gainNode.gain,units:t.units,value:t.gain,convert:t.convert}),this._readOnly("gain")},n.extend(n.Gain),n.Gain.defaults={gain:1,convert:!0},n.Gain.prototype.dispose=function(){n.Param.prototype.dispose.call(this),this._gainNode.disconnect(),this._gainNode=null,this._writable("gain"),this.gain.dispose(),this.gain=null},n.prototype.createInsOuts=function(t,e){1===t?this.input=new n.Gain:1this._nextTick&&this._state;){var e=this._state.getValueAtTime(this._nextTick);if(e!==this._lastState){this._lastState=e;var n=this._state.get(this._nextTick);e===r.State.Started?(this._nextTick=n.time,this.isUndef(n.offset)||(this.ticks=n.offset),this.emit("start",n.time,this.ticks)):e===r.State.Stopped?(this.ticks=0,this.emit("stop",n.time)):e===r.State.Paused&&this.emit("pause",n.time)}var i=this._nextTick;this.frequency&&(this._nextTick+=1/this.frequency.getValueAtTime(this._nextTick),e===r.State.Started&&(this.callback(i),this.ticks++))}},r.Clock.prototype.getStateAtTime=function(t){return t=this.toSeconds(t),this._state.getValueAtTime(t)},r.Clock.prototype.dispose=function(){r.Emitter.prototype.dispose.call(this),this.context.off("tick",this._boundLoop),this._writable("frequency"),this.frequency.dispose(),this.frequency=null,this._boundLoop=null,this._nextTick=1/0,this.callback=null,this._state.dispose(),this._state=null},r.Clock}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r;i=[n(0),n(14)],void 0===(r=function(i){function t(t,e,n){if(t.input)Array.isArray(t.input)?(i.prototype.isUndef(n)&&(n=0),this.connect(t.input[n])):this.connect(t.input,e,n);else try{t instanceof AudioNode?r.call(this,t,e,n):r.call(this,t,e)}catch(e){throw new Error("error connecting to node: "+t+"\n"+e)}}var r,o;return!window.hasOwnProperty("AudioContext")&&window.hasOwnProperty("webkitAudioContext")&&(window.AudioContext=window.webkitAudioContext),i.Context=function(t){for(var e in i.Emitter.call(this),t=t||new window.AudioContext,this._context=t,this._context)this._defineProperty(this._context,e);this._latencyHint="interactive",this._lookAhead=.1,this._updateInterval=this._lookAhead/3,this._computedUpdateInterval=0,this._worker=this._createWorker(),this._constants={}},i.extend(i.Context,i.Emitter),i.Emitter.mixin(i.Context),i.Context.prototype._defineProperty=function(e,n){this.isUndef(this[n])&&Object.defineProperty(this,n,{get:function(){return"function"==typeof e[n]?e[n].bind(e):e[n]},set:function(t){e[n]=t}})},i.Context.prototype.now=function(){return this._context.currentTime},i.Context.prototype._createWorker=function(){window.URL=window.URL||window.webkitURL;var t=new Blob(["var timeoutTime = "+(1e3*this._updateInterval).toFixed(1)+";self.onmessage = function(msg){\ttimeoutTime = parseInt(msg.data);};function tick(){\tsetTimeout(tick, timeoutTime);\tself.postMessage('tick');}tick();"]),e=URL.createObjectURL(t),n=new Worker(e);return n.addEventListener("message",function(){this.emit("tick")}.bind(this)),n.addEventListener("message",function(){var t=this.now();if(this.isNumber(this._lastUpdate)){var e=t-this._lastUpdate;this._computedUpdateInterval=Math.max(e,.97*this._computedUpdateInterval)}this._lastUpdate=t}.bind(this)),n},i.Context.prototype.getConstant=function(t){if(this._constants[t])return this._constants[t];for(var e=this._context.createBuffer(1,128,this._context.sampleRate),n=e.getChannelData(0),i=0;ithis.memory){var n=this.length-this.memory;this._timeline.splice(0,n)}return this},e.Timeline.prototype.remove=function(t){if(this._iterating)this._toRemove.push(t);else{var e=this._timeline.indexOf(t);-1!==e&&this._timeline.splice(e,1)}return this},e.Timeline.prototype.get=function(t){var e=this._search(t);return-1!==e?this._timeline[e]:null},e.Timeline.prototype.peek=function(){return this._timeline[0]},e.Timeline.prototype.shift=function(){return this._timeline.shift()},e.Timeline.prototype.getAfter=function(t){var e=this._search(t);return e+1=t&&(this._timeline=[]);return this},e.Timeline.prototype.cancelBefore=function(t){if(this._timeline.length){var e=this._search(t);0<=e&&(this._timeline=this._timeline.slice(e+1))}return this},e.Timeline.prototype._search=function(t){var e=0,n=this._timeline.length,i=n;if(0t)return r;o.time>t?i=r:o.time=t;)n--;return this._iterate(e,n+1),this},e.Timeline.prototype.forEachAtTime=function(e,n){var t=this._search(e);return-1!==t&&this._iterate(function(t){t.time===e&&n(t)},0,t),this},e.Timeline.prototype.dispose=function(){e.prototype.dispose.call(this),this._timeline=null,this._toRemove=null},e.Timeline}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r;i=[n(0),n(1),n(2)],void 0===(r=function(t){"use strict";return t.Negate=function(){this._multiply=this.input=this.output=new t.Multiply(-1)},t.extend(t.Negate,t.SignalBase),t.Negate.prototype.dispose=function(){return t.prototype.dispose.call(this),this._multiply.dispose(),this._multiply=null,this},t.Negate}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r;i=[n(0),n(2),n(1),n(6)],void 0===(r=function(t){"use strict";return t.GreaterThanZero=function(){this._thresh=this.output=new t.WaveShaper(function(t){return t<=0?0:1},127),this._scale=this.input=new t.Multiply(1e4),this._scale.connect(this._thresh)},t.extend(t.GreaterThanZero,t.SignalBase),t.GreaterThanZero.prototype.dispose=function(){return t.prototype.dispose.call(this),this._scale.dispose(),this._scale=null,this._thresh.dispose(),this._thresh=null,this},t.GreaterThanZero}.apply(e,i))||(t.exports=r)},function(t,e,n){var i,r,o;r=[],void 0===(o="function"==typeof(i=function(){var s=function(t,e){this._dragged=!1,this._element=t,this._bindedMove=this._moved.bind(this),this._bindedEnd=this._ended.bind(this,e),t.addEventListener("touchstart",this._bindedEnd),t.addEventListener("touchmove",this._bindedMove),t.addEventListener("touchend",this._bindedEnd),t.addEventListener("mouseup",this._bindedEnd)};function o(t){return"running"===t.state}return s.prototype._moved=function(t){this._dragged=!0},s.prototype._ended=function(t){this._dragged||function(t){var e=t.createBuffer(1,1,t.sampleRate),n=t.createBufferSource();n.buffer=e,n.connect(t.destination),n.start(0),t.resume&&t.resume()}(t),this._dragged=!1},s.prototype.dispose=function(){this._element.removeEventListener("touchstart",this._bindedEnd),this._element.removeEventListener("touchmove",this._bindedMove),this._element.removeEventListener("touchend",this._bindedEnd),this._element.removeEventListener("mouseup",this._bindedEnd),this._bindedMove=null,this._bindedEnd=null,this._element=null},function(e,t,n){var i=new Promise(function(t){!function(e,n){o(e)?n():function t(){o(e)?n():(requestAnimationFrame(t),e.resume&&e.resume())}()}(e,t)}),r=[];return function t(e,n,i){if(Array.isArray(e)||NodeList&&e instanceof NodeList)for(var r=0;r= this._length) {\n this._writeIndex = 0;\n } // For excessive frames, the buffer will be overwritten.\n\n\n this._framesAvailable += sourceLength;\n\n if (this._framesAvailable > this._length) {\n this._framesAvailable = this._length;\n }\n }\n /**\n * Pull data out of buffer and fill a given sequence of Float32Arrays.\n *\n * @param {array} arraySequence An array of Float32Arrays.\n */\n\n }, {\n key: "pull",\n value: function pull(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // If the FIFO is completely empty, do nothing.\n if (this._framesAvailable === 0) {\n return;\n }\n\n var destinationLength = arraySequence[0].length; // Transfer data from the internal buffer to the |arraySequence| storage.\n\n for (var i = 0; i < destinationLength; ++i) {\n var readIndex = (this._readIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n arraySequence[channel][i] = this._channelData[channel][readIndex];\n }\n }\n\n this._readIndex += destinationLength;\n\n if (this._readIndex >= this._length) {\n this._readIndex = 0;\n }\n\n this._framesAvailable -= destinationLength;\n\n if (this._framesAvailable < 0) {\n this._framesAvailable = 0;\n }\n }\n }, {\n key: "framesAvailable",\n get: function get() {\n return this._framesAvailable;\n }\n }]);\n\n return RingBuffer;\n }()\n}["default"];\n\nvar RecorderProcessor =\n/*#__PURE__*/\nfunction (_AudioWorkletProcesso) {\n _inherits(RecorderProcessor, _AudioWorkletProcesso);\n\n function RecorderProcessor(options) {\n var _this;\n\n _classCallCheck(this, RecorderProcessor);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(RecorderProcessor).call(this));\n var processorOptions = options.processorOptions || {};\n _this.numOutputChannels = options.outputChannelCount || 2;\n _this.numInputChannels = processorOptions.numInputChannels || 2;\n _this.bufferSize = processorOptions.bufferSize || 1024;\n _this.recording = false;\n\n _this.clear();\n\n _this.port.onmessage = function (event) {\n var data = event.data;\n\n if (data.name === \'start\') {\n _this.record(data.duration);\n } else if (data.name === \'stop\') {\n _this.stop();\n }\n };\n\n return _this;\n }\n\n _createClass(RecorderProcessor, [{\n key: "process",\n value: function process(inputs) {\n if (!this.recording) {\n return true;\n } else if (this.sampleLimit && this.recordedSamples >= this.sampleLimit) {\n this.stop();\n return true;\n }\n\n var input = inputs[0];\n this.inputRingBuffer.push(input);\n\n if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {\n this.inputRingBuffer.pull(this.inputRingBufferArraySequence);\n\n for (var channel = 0; channel < this.numOutputChannels; ++channel) {\n var inputChannelCopy = this.inputRingBufferArraySequence[channel].slice();\n\n if (channel === 0) {\n this.leftBuffers.push(inputChannelCopy);\n\n if (this.numInputChannels === 1) {\n this.rightBuffers.push(inputChannelCopy);\n }\n } else if (channel === 1 && this.numInputChannels > 1) {\n this.rightBuffers.push(inputChannelCopy);\n }\n }\n\n this.recordedSamples += this.bufferSize;\n }\n\n return true;\n }\n }, {\n key: "record",\n value: function record(duration) {\n if (duration) {\n this.sampleLimit = Math.round(duration * sampleRate);\n }\n\n this.recording = true;\n }\n }, {\n key: "stop",\n value: function stop() {\n this.recording = false;\n var buffers = this.getBuffers();\n var leftBuffer = buffers[0].buffer;\n var rightBuffer = buffers[1].buffer;\n this.port.postMessage({\n name: \'buffers\',\n leftBuffer: leftBuffer,\n rightBuffer: rightBuffer\n }, [leftBuffer, rightBuffer]);\n this.clear();\n }\n }, {\n key: "getBuffers",\n value: function getBuffers() {\n var buffers = [];\n buffers.push(this.mergeBuffers(this.leftBuffers));\n buffers.push(this.mergeBuffers(this.rightBuffers));\n return buffers;\n }\n }, {\n key: "mergeBuffers",\n value: function mergeBuffers(channelBuffer) {\n var result = new Float32Array(this.recordedSamples);\n var offset = 0;\n var lng = channelBuffer.length;\n\n for (var i = 0; i < lng; i++) {\n var buffer = channelBuffer[i];\n result.set(buffer, offset);\n offset += buffer.length;\n }\n\n return result;\n }\n }, {\n key: "clear",\n value: function clear() {\n var _this2 = this;\n\n this.leftBuffers = [];\n this.rightBuffers = [];\n this.inputRingBuffer = new RingBuffer(this.bufferSize, this.numInputChannels);\n this.inputRingBufferArraySequence = new Array(this.numInputChannels).fill(null).map(function () {\n return new Float32Array(_this2.bufferSize);\n });\n this.recordedSamples = 0;\n this.sampleLimit = null;\n }\n }]);\n\n return RecorderProcessor;\n}(_wrapNativeSuper(AudioWorkletProcessor));\n\nregisterProcessor(processorNames.recorderProcessor, RecorderProcessor);'},function(t,e,n){"use strict";n.r(e),e.default='function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn\'t been initialised - super() hasn\'t been called"); } return self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }\n\nfunction isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }\n\nfunction _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// import dependencies via preval.require so that they\'re available as values at compile time\nvar processorNames = {\n "recorderProcessor": "recorder-processor",\n "soundFileProcessor": "sound-file-processor",\n "amplitudeProcessor": "amplitude-processor"\n};\nvar RingBuffer = {\n "default":\n /*#__PURE__*/\n function () {\n /**\n * @constructor\n * @param {number} length Buffer length in frames.\n * @param {number} channelCount Buffer channel count.\n */\n function RingBuffer(length, channelCount) {\n _classCallCheck(this, RingBuffer);\n\n this._readIndex = 0;\n this._writeIndex = 0;\n this._framesAvailable = 0;\n this._channelCount = channelCount;\n this._length = length;\n this._channelData = [];\n\n for (var i = 0; i < this._channelCount; ++i) {\n this._channelData[i] = new Float32Array(length);\n }\n }\n /**\n * Getter for Available frames in buffer.\n *\n * @return {number} Available frames in buffer.\n */\n\n\n _createClass(RingBuffer, [{\n key: "push",\n\n /**\n * Push a sequence of Float32Arrays to buffer.\n *\n * @param {array} arraySequence A sequence of Float32Arrays.\n */\n value: function push(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // Transfer data from the |arraySequence| storage to the internal buffer.\n var sourceLength = arraySequence[0] ? arraySequence[0].length : 0;\n\n for (var i = 0; i < sourceLength; ++i) {\n var writeIndex = (this._writeIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n this._channelData[channel][writeIndex] = arraySequence[channel][i];\n }\n }\n\n this._writeIndex += sourceLength;\n\n if (this._writeIndex >= this._length) {\n this._writeIndex = 0;\n } // For excessive frames, the buffer will be overwritten.\n\n\n this._framesAvailable += sourceLength;\n\n if (this._framesAvailable > this._length) {\n this._framesAvailable = this._length;\n }\n }\n /**\n * Pull data out of buffer and fill a given sequence of Float32Arrays.\n *\n * @param {array} arraySequence An array of Float32Arrays.\n */\n\n }, {\n key: "pull",\n value: function pull(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // If the FIFO is completely empty, do nothing.\n if (this._framesAvailable === 0) {\n return;\n }\n\n var destinationLength = arraySequence[0].length; // Transfer data from the internal buffer to the |arraySequence| storage.\n\n for (var i = 0; i < destinationLength; ++i) {\n var readIndex = (this._readIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n arraySequence[channel][i] = this._channelData[channel][readIndex];\n }\n }\n\n this._readIndex += destinationLength;\n\n if (this._readIndex >= this._length) {\n this._readIndex = 0;\n }\n\n this._framesAvailable -= destinationLength;\n\n if (this._framesAvailable < 0) {\n this._framesAvailable = 0;\n }\n }\n }, {\n key: "framesAvailable",\n get: function get() {\n return this._framesAvailable;\n }\n }]);\n\n return RingBuffer;\n }()\n}["default"];\n\nvar SoundFileProcessor =\n/*#__PURE__*/\nfunction (_AudioWorkletProcesso) {\n _inherits(SoundFileProcessor, _AudioWorkletProcesso);\n\n function SoundFileProcessor(options) {\n var _this;\n\n _classCallCheck(this, SoundFileProcessor);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(SoundFileProcessor).call(this));\n var processorOptions = options.processorOptions || {};\n _this.bufferSize = processorOptions.bufferSize || 256;\n _this.inputRingBuffer = new RingBuffer(_this.bufferSize, 1);\n _this.inputRingBufferArraySequence = [new Float32Array(_this.bufferSize)];\n return _this;\n }\n\n _createClass(SoundFileProcessor, [{\n key: "process",\n value: function process(inputs) {\n var input = inputs[0]; // we only care about the first input channel, because that contains the position data\n\n this.inputRingBuffer.push([input[0]]);\n\n if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {\n this.inputRingBuffer.pull(this.inputRingBufferArraySequence);\n var inputChannel = this.inputRingBufferArraySequence[0];\n var position = inputChannel[inputChannel.length - 1] || 0;\n this.port.postMessage({\n name: \'position\',\n position: position\n });\n }\n\n return true;\n }\n }]);\n\n return SoundFileProcessor;\n}(_wrapNativeSuper(AudioWorkletProcessor));\n\nregisterProcessor(processorNames.soundFileProcessor, SoundFileProcessor);'},function(t,e,n){"use strict";n.r(e),e.default='function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn\'t been initialised - super() hasn\'t been called"); } return self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }\n\nfunction isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }\n\nfunction _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n// import dependencies via preval.require so that they\'re available as values at compile time\nvar processorNames = {\n "recorderProcessor": "recorder-processor",\n "soundFileProcessor": "sound-file-processor",\n "amplitudeProcessor": "amplitude-processor"\n};\nvar RingBuffer = {\n "default":\n /*#__PURE__*/\n function () {\n /**\n * @constructor\n * @param {number} length Buffer length in frames.\n * @param {number} channelCount Buffer channel count.\n */\n function RingBuffer(length, channelCount) {\n _classCallCheck(this, RingBuffer);\n\n this._readIndex = 0;\n this._writeIndex = 0;\n this._framesAvailable = 0;\n this._channelCount = channelCount;\n this._length = length;\n this._channelData = [];\n\n for (var i = 0; i < this._channelCount; ++i) {\n this._channelData[i] = new Float32Array(length);\n }\n }\n /**\n * Getter for Available frames in buffer.\n *\n * @return {number} Available frames in buffer.\n */\n\n\n _createClass(RingBuffer, [{\n key: "push",\n\n /**\n * Push a sequence of Float32Arrays to buffer.\n *\n * @param {array} arraySequence A sequence of Float32Arrays.\n */\n value: function push(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // Transfer data from the |arraySequence| storage to the internal buffer.\n var sourceLength = arraySequence[0] ? arraySequence[0].length : 0;\n\n for (var i = 0; i < sourceLength; ++i) {\n var writeIndex = (this._writeIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n this._channelData[channel][writeIndex] = arraySequence[channel][i];\n }\n }\n\n this._writeIndex += sourceLength;\n\n if (this._writeIndex >= this._length) {\n this._writeIndex = 0;\n } // For excessive frames, the buffer will be overwritten.\n\n\n this._framesAvailable += sourceLength;\n\n if (this._framesAvailable > this._length) {\n this._framesAvailable = this._length;\n }\n }\n /**\n * Pull data out of buffer and fill a given sequence of Float32Arrays.\n *\n * @param {array} arraySequence An array of Float32Arrays.\n */\n\n }, {\n key: "pull",\n value: function pull(arraySequence) {\n // The channel count of arraySequence and the length of each channel must\n // match with this buffer obejct.\n // If the FIFO is completely empty, do nothing.\n if (this._framesAvailable === 0) {\n return;\n }\n\n var destinationLength = arraySequence[0].length; // Transfer data from the internal buffer to the |arraySequence| storage.\n\n for (var i = 0; i < destinationLength; ++i) {\n var readIndex = (this._readIndex + i) % this._length;\n\n for (var channel = 0; channel < this._channelCount; ++channel) {\n arraySequence[channel][i] = this._channelData[channel][readIndex];\n }\n }\n\n this._readIndex += destinationLength;\n\n if (this._readIndex >= this._length) {\n this._readIndex = 0;\n }\n\n this._framesAvailable -= destinationLength;\n\n if (this._framesAvailable < 0) {\n this._framesAvailable = 0;\n }\n }\n }, {\n key: "framesAvailable",\n get: function get() {\n return this._framesAvailable;\n }\n }]);\n\n return RingBuffer;\n }()\n}["default"];\n\nvar AmplitudeProcessor =\n/*#__PURE__*/\nfunction (_AudioWorkletProcesso) {\n _inherits(AmplitudeProcessor, _AudioWorkletProcesso);\n\n function AmplitudeProcessor(options) {\n var _this;\n\n _classCallCheck(this, AmplitudeProcessor);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(AmplitudeProcessor).call(this));\n var processorOptions = options.processorOptions || {};\n _this.numOutputChannels = options.outputChannelCount || 1;\n _this.numInputChannels = processorOptions.numInputChannels || 2;\n _this.normalize = processorOptions.normalize || false;\n _this.smoothing = processorOptions.smoothing || 0;\n _this.bufferSize = processorOptions.bufferSize || 2048;\n _this.inputRingBuffer = new RingBuffer(_this.bufferSize, _this.numInputChannels);\n _this.outputRingBuffer = new RingBuffer(_this.bufferSize, _this.numOutputChannels);\n _this.inputRingBufferArraySequence = new Array(_this.numInputChannels).fill(null).map(function () {\n return new Float32Array(_this.bufferSize);\n });\n _this.stereoVol = [0, 0];\n _this.stereoVolNorm = [0, 0];\n _this.volMax = 0.001;\n\n _this.port.onmessage = function (event) {\n var data = event.data;\n\n if (data.name === \'toggleNormalize\') {\n _this.normalize = data.normalize;\n } else if (data.name === \'smoothing\') {\n _this.smoothing = Math.max(0, Math.min(1, data.smoothing));\n }\n };\n\n return _this;\n } // TO DO make this stereo / dependent on # of audio channels\n\n\n _createClass(AmplitudeProcessor, [{\n key: "process",\n value: function process(inputs, outputs) {\n var input = inputs[0];\n var output = outputs[0];\n var smoothing = this.smoothing;\n this.inputRingBuffer.push(input);\n\n if (this.inputRingBuffer.framesAvailable >= this.bufferSize) {\n this.inputRingBuffer.pull(this.inputRingBufferArraySequence);\n\n for (var channel = 0; channel < this.numInputChannels; ++channel) {\n var inputBuffer = this.inputRingBufferArraySequence[channel];\n var bufLength = inputBuffer.length;\n var sum = 0;\n\n for (var i = 0; i < bufLength; i++) {\n var x = inputBuffer[i];\n\n if (this.normalize) {\n sum += Math.max(Math.min(x / this.volMax, 1), -1) * Math.max(Math.min(x / this.volMax, 1), -1);\n } else {\n sum += x * x;\n }\n } // ... then take the square root of the sum.\n\n\n var rms = Math.sqrt(sum / bufLength);\n this.stereoVol[channel] = Math.max(rms, this.stereoVol[channel] * smoothing);\n this.volMax = Math.max(this.stereoVol[channel], this.volMax);\n } // calculate stero normalized volume and add volume from all channels together\n\n\n var volSum = 0;\n\n for (var index = 0; index < this.stereoVol.length; index++) {\n this.stereoVolNorm[index] = Math.max(Math.min(this.stereoVol[index] / this.volMax, 1), 0);\n volSum += this.stereoVol[index];\n } // volume is average of channels\n\n\n var volume = volSum / this.stereoVol.length; // normalized value\n\n var volNorm = Math.max(Math.min(volume / this.volMax, 1), 0);\n this.port.postMessage({\n name: \'amplitude\',\n volume: volume,\n volNorm: volNorm,\n stereoVol: this.stereoVol,\n stereoVolNorm: this.stereoVolNorm\n }); // pass input through to output\n\n this.outputRingBuffer.push(this.inputRingBufferArraySequence);\n } // pull 128 frames out of the ring buffer\n // if the ring buffer does not have enough frames, the output will be silent\n\n\n this.outputRingBuffer.pull(output);\n return true;\n }\n }]);\n\n return AmplitudeProcessor;\n}(_wrapNativeSuper(AudioWorkletProcessor));\n\nregisterProcessor(processorNames.amplitudeProcessor, AmplitudeProcessor);'},function(t,e,n){var i,r;i=[n(0),n(17)],void 0===(r=function(r){r.Frequency=function(t,e){if(!(this instanceof r.Frequency))return new r.Frequency(t,e);r.TimeBase.call(this,t,e)},r.extend(r.Frequency,r.TimeBase),r.Frequency.prototype._primaryExpressions=Object.create(r.TimeBase.prototype._primaryExpressions),r.Frequency.prototype._primaryExpressions.midi={regexp:/^(\d+(?:\.\d+)?midi)/,method:function(t){return this.midiToFrequency(t)}},r.Frequency.prototype._primaryExpressions.note={regexp:/^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,method:function(t,e){var n=i[t.toLowerCase()]+12*(parseInt(e)+1);return this.midiToFrequency(n)}},r.Frequency.prototype._primaryExpressions.tr={regexp:/^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,method:function(t,e,n){var i=1;return t&&"0"!==t&&(i*=this._beatsToUnits(this._timeSignature()*parseFloat(t))),e&&"0"!==e&&(i*=this._beatsToUnits(parseFloat(e))),n&&"0"!==n&&(i*=this._beatsToUnits(parseFloat(n)/4)),i}},r.Frequency.prototype.transpose=function(t){return this._expr=function(t,e){return t()*this.intervalToFrequencyRatio(e)}.bind(this,this._expr,t),this},r.Frequency.prototype.harmonize=function(t){return this._expr=function(t,e){for(var n=t(),i=[],r=0;rthis.buffer.duration)throw"jump time out of range";if(e>this.buffer.duration-t)throw"end time out of range";var n=t||0,i=e||void 0;this.isPlaying()&&(this.stop(0),this.play(0,this.playbackRate,this.output.gain.value,n,i))}},{key:"channels",value:function(){return this.buffer.numberOfChannels}},{key:"sampleRate",value:function(){return this.buffer.sampleRate}},{key:"frames",value:function(){return this.buffer.length}},{key:"getPeaks",value:function(t){if(!this.buffer)throw"Cannot load peaks yet, buffer is not loaded";if(t=t||5*window.width,this.buffer){for(var e=this.buffer,n=e.length/t,i=~~(n/10)||1,r=e.numberOfChannels,o=new Float32Array(Math.round(t)),s=0;so[u])&&(o[u]=h)}return o}}},{key:"reverseBuffer",value:function(){if(!this.buffer)throw"SoundFile is not done loading";var t=this._lastPos/R.sampleRate,e=this.getVolume();this.setVolume(0,.001);for(var n=this.buffer.numberOfChannels,i=0;it[o].hi&&o++,r[o]=void 0!==r[o]?(r[o]+n[s])/2:n[s]}return r}},{key:"getOctaveBands",value:function(t,e){var n=t||3,i=e||15.625,r=[],o={lo:i/Math.pow(2,1/(2*n)),ctr:i,hi:i*Math.pow(2,1/(2*n))};r.push(o);for(var s=p.audiocontext.sampleRate/2;o.hi=this._maxDelay)throw new Error("Delay Time exceeds maximum delay time of "+this._maxDelay+" second.");t.connect(this.input),this.leftDelay.delayTime.setValueAtTime(o,this.ac.currentTime),this.rightDelay.delayTime.setValueAtTime(o,this.ac.currentTime),this._leftGain.gain.value=r,this._rightGain.gain.value=r,i&&(this._leftFilter.freq(i),this._rightFilter.freq(i))}},{key:"delayTime",value:function(t){"number"!=typeof t?(t.connect(this.leftDelay.delayTime),t.connect(this.rightDelay.delayTime)):(this.leftDelay.delayTime.cancelScheduledValues(this.ac.currentTime),this.rightDelay.delayTime.cancelScheduledValues(this.ac.currentTime),this.leftDelay.delayTime.linearRampToValueAtTime(t,this.ac.currentTime),this.rightDelay.delayTime.linearRampToValueAtTime(t,this.ac.currentTime))}},{key:"feedback",value:function(t){if(t&&"number"!=typeof t)t.connect(this._leftGain.gain),t.connect(this._rightGain.gain);else{if(1<=t)throw new Error("Feedback value will force a positive feedback loop.");"number"==typeof t&&(this._leftGain.gain.value=t,this._rightGain.gain.value=t)}return this._leftGain.gain.value}},{key:"filter",value:function(t,e){this._leftFilter.set(t,e),this._rightFilter.set(t,e)}},{key:"setType",value:function(t){switch(1===t&&(t="pingPong"),this._split.disconnect(),this._leftFilter.disconnect(),this._rightFilter.disconnect(),this._split.connect(this.leftDelay,0),this._split.connect(this.rightDelay,1),t){case"pingPong":this._rightFilter.setType(this._leftFilter.biquad.type),this._leftFilter.output.connect(this._merge,0,0),this._rightFilter.output.connect(this._merge,0,1),this._leftFilter.output.connect(this.rightDelay),this._rightFilter.output.connect(this.leftDelay);break;default:this._leftFilter.output.connect(this._merge,0,0),this._rightFilter.output.connect(this._merge,0,1),this._leftFilter.output.connect(this.leftDelay),this._rightFilter.output.connect(this.rightDelay)}}},{key:"dispose",value:function(){de(ye(e.prototype),"dispose",this).call(this),this._split.disconnect(),this._leftFilter.dispose(),this._rightFilter.dispose(),this._merge.disconnect(),this._leftGain.disconnect(),this._rightGain.disconnect(),this.leftDelay.disconnect(),this.rightDelay.disconnect(),this._split=void 0,this._leftFilter=void 0,this._rightFilter=void 0,this._merge=void 0,this._leftGain=void 0,this._rightGain=void 0,this.leftDelay=void 0,this.rightDelay=void 0}}]),e}();function _e(t){return(_e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function ge(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function be(t,e){for(var n=0;nthis.length&&(this.length=i.sequence.length)}},{key:"removePhrase",value:function(t){for(var e in this.phrases)this.phrases[e].name===t&&this.phrases.splice(e,1)}},{key:"getPhrase",value:function(t){for(var e in this.phrases)if(this.phrases[e].name===t)return this.phrases[e]}},{key:"replaceSequence",value:function(t,e){for(var n in this.phrases)this.phrases[n].name===t&&(this.phrases[n].sequence=e)}},{key:"incrementStep",value:function(t){this.partStep=t.parts.length?(t.scoreStep=0,t.onended()):(t.scoreStep=0,t.parts[t.currentPart-1].stop(),t.parts[t.currentPart].start())}function Ue(t,e){for(var n=0;nthis.cutoff&&e>this.threshold&&0this.treshold){this.isDetected=!0,this.callback?this.callback(this.energy):e&&e(this.energy);var n=this;setTimeout(function(){n.isDetected=!1},this.sensitivity)}this.penergy=this.energy}}]),r}();function xn(t,e){for(var n=0;n/im, + bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, + hasLocation = typeof location !== 'undefined' && location.href, + defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), + defaultHostName = hasLocation && location.hostname, + defaultPort = hasLocation && (location.port || undefined), + buildMap = {}, + masterConfig = (module.config && module.config()) || {}; + + text = { + version: '2.0.10', + + strip: function (content) { + //Strips declarations so that external SVG and XML + //documents can be added to a document without worry. Also, if the string + //is an HTML document, only the part inside the body tag is returned. + if (content) { + content = content.replace(xmlRegExp, ""); + var matches = content.match(bodyRegExp); + if (matches) { + content = matches[1]; + } + } else { + content = ""; + } + return content; + }, + + jsEscape: function (content) { + return content.replace(/(['\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r") + .replace(/[\u2028]/g, "\\u2028") + .replace(/[\u2029]/g, "\\u2029"); + }, + + createXhr: masterConfig.createXhr || function () { + //Would love to dump the ActiveX crap in here. Need IE 6 to die first. + var xhr, i, progId; + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } else if (typeof ActiveXObject !== "undefined") { + for (i = 0; i < 3; i += 1) { + progId = progIds[i]; + try { + xhr = new ActiveXObject(progId); + } catch (e) {} + + if (xhr) { + progIds = [progId]; // so faster next time + break; + } + } + } + + return xhr; + }, + + /** + * Parses a resource name into its component parts. Resource names + * look like: module/name.ext!strip, where the !strip part is + * optional. + * @param {String} name the resource name + * @returns {Object} with properties "moduleName", "ext" and "strip" + * where strip is a boolean. + */ + parseName: function (name) { + var modName, ext, temp, + strip = false, + index = name.indexOf("."), + isRelative = name.indexOf('./') === 0 || + name.indexOf('../') === 0; + + if (index !== -1 && (!isRelative || index > 1)) { + modName = name.substring(0, index); + ext = name.substring(index + 1, name.length); + } else { + modName = name; + } + + temp = ext || modName; + index = temp.indexOf("!"); + if (index !== -1) { + //Pull off the strip arg. + strip = temp.substring(index + 1) === "strip"; + temp = temp.substring(0, index); + if (ext) { + ext = temp; + } else { + modName = temp; + } + } + + return { + moduleName: modName, + ext: ext, + strip: strip + }; + }, + + xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + + /** + * Is an URL on another domain. Only works for browser use, returns + * false in non-browser environments. Only used to know if an + * optimized .js version of a text resource should be loaded + * instead. + * @param {String} url + * @returns Boolean + */ + useXhr: function (url, protocol, hostname, port) { + var uProtocol, uHostName, uPort, + match = text.xdRegExp.exec(url); + if (!match) { + return true; + } + uProtocol = match[2]; + uHostName = match[3]; + + uHostName = uHostName.split(':'); + uPort = uHostName[1]; + uHostName = uHostName[0]; + + return (!uProtocol || uProtocol === protocol) && + (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && + ((!uPort && !uHostName) || uPort === port); + }, + + finishLoad: function (name, strip, content, onLoad) { + content = strip ? text.strip(content) : content; + if (masterConfig.isBuild) { + buildMap[name] = content; + } + onLoad(content); + }, + + load: function (name, req, onLoad, config) { + //Name has format: some.module.filext!strip + //The strip part is optional. + //if strip is present, then that means only get the string contents + //inside a body tag in an HTML string. For XML/SVG content it means + //removing the declarations so the content can be inserted + //into the current doc without problems. + + // Do not bother with the work if a build and text will + // not be inlined. + if (config.isBuild && !config.inlineText) { + onLoad(); + return; + } + + masterConfig.isBuild = config.isBuild; + + var parsed = text.parseName(name), + nonStripName = parsed.moduleName + + (parsed.ext ? '.' + parsed.ext : ''), + url = req.toUrl(nonStripName), + useXhr = (masterConfig.useXhr) || + text.useXhr; + + // Do not load if it is an empty: url + if (url.indexOf('empty:') === 0) { + onLoad(); + return; + } + + //Load the text. Use XHR if possible and in a browser. + if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { + text.get(url, function (content) { + text.finishLoad(name, parsed.strip, content, onLoad); + }, function (err) { + if (onLoad.error) { + onLoad.error(err); + } + }); + } else { + //Need to fetch the resource across domains. Assume + //the resource has been optimized into a JS module. Fetch + //by the module name + extension, but do not include the + //!strip part to avoid file system issues. + req([nonStripName], function (content) { + text.finishLoad(parsed.moduleName + '.' + parsed.ext, + parsed.strip, content, onLoad); + }); + } + }, + + write: function (pluginName, moduleName, write, config) { + if (buildMap.hasOwnProperty(moduleName)) { + var content = text.jsEscape(buildMap[moduleName]); + write.asModule(pluginName + "!" + moduleName, + "define(function () { return '" + + content + + "';});\n"); + } + }, + + writeFile: function (pluginName, moduleName, req, write, config) { + var parsed = text.parseName(moduleName), + extPart = parsed.ext ? '.' + parsed.ext : '', + nonStripName = parsed.moduleName + extPart, + //Use a '.js' file name so that it indicates it is a + //script that can be loaded across domains. + fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; + + //Leverage own load() method to load plugin value, but only + //write out values that do not have the strip argument, + //to avoid any potential issues with ! in file names. + text.load(nonStripName, req, function (value) { + //Use own write() method to construct full module value. + //But need to create shell that translates writeFile's + //write() to the right interface. + var textWrite = function (contents) { + return write(fileName, contents); + }; + textWrite.asModule = function (moduleName, contents) { + return write.asModule(moduleName, fileName, contents); + }; + + text.write(pluginName, nonStripName, textWrite, config); + }, config); + } + }; + + if (masterConfig.env === 'node' || (!masterConfig.env && + typeof process !== "undefined" && + process.versions && + !!process.versions.node && + !process.versions['node-webkit'])) { + //Using special require.nodeRequire, something added by r.js. + fs = require.nodeRequire('fs'); + + text.get = function (url, callback, errback) { + try { + var file = fs.readFileSync(url, 'utf8'); + //Remove BOM (Byte Mark Order) from utf8 files if it is there. + if (file.indexOf('\uFEFF') === 0) { + file = file.substring(1); + } + callback(file); + } catch (e) { + errback(e); + } + }; + } else if (masterConfig.env === 'xhr' || (!masterConfig.env && + text.createXhr())) { + text.get = function (url, callback, errback, headers) { + var xhr = text.createXhr(), header; + xhr.open('GET', url, true); + + //Allow plugins direct access to xhr headers + if (headers) { + for (header in headers) { + if (headers.hasOwnProperty(header)) { + xhr.setRequestHeader(header.toLowerCase(), headers[header]); + } + } + } + + //Allow overrides specified in config + if (masterConfig.onXhr) { + masterConfig.onXhr(xhr, url); + } + + xhr.onreadystatechange = function (evt) { + var status, err; + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + status = xhr.status; + if (status > 399 && status < 600) { + //An http 4xx or 5xx error. Signal an error. + err = new Error(url + ' HTTP status: ' + status); + err.xhr = xhr; + errback(err); + } else { + callback(xhr.responseText); + } + + if (masterConfig.onXhrComplete) { + masterConfig.onXhrComplete(xhr, url); + } + } + }; + xhr.send(null); + }; + } else if (masterConfig.env === 'rhino' || (!masterConfig.env && + typeof Packages !== 'undefined' && typeof java !== 'undefined')) { + //Why Java, why is this so awkward? + text.get = function (url, callback) { + var stringBuffer, line, + encoding = "utf-8", + file = new java.io.File(url), + lineSeparator = java.lang.System.getProperty("line.separator"), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), + content = ''; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + + if (line !== null) { + stringBuffer.append(line); + } + + while ((line = input.readLine()) !== null) { + stringBuffer.append(lineSeparator); + stringBuffer.append(line); + } + //Make sure we return a JavaScript string and not a Java string. + content = String(stringBuffer.toString()); //String + } finally { + input.close(); + } + callback(content); + }; + } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && + typeof Components !== 'undefined' && Components.classes && + Components.interfaces)) { + //Avert your gaze! + Cc = Components.classes, + Ci = Components.interfaces; + Components.utils['import']('resource://gre/modules/FileUtils.jsm'); + xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); + + text.get = function (url, callback) { + var inStream, convertStream, fileObj, + readData = {}; + + if (xpcIsWindows) { + url = url.replace(/\//g, '\\'); + } + + fileObj = new FileUtils.File(url); + + //XPCOM, you so crazy + try { + inStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + inStream.init(fileObj, 1, 0, false); + + convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] + .createInstance(Ci.nsIConverterInputStream); + convertStream.init(inStream, "utf-8", inStream.available(), + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + + convertStream.readString(inStream.available(), readData); + convertStream.close(); + inStream.close(); + callback(readData.value); + } catch (e) { + throw new Error((fileObj && fileObj.path || '') + ': ' + e); + } + }; + } + return text; +}); + + +define('text!tpl/search.html',[],function () { return '

        search

        \r\n
        \r\n \r\n \r\n
        \r\n\r\n';}); + + +define('text!tpl/search_suggestion.html',[],function () { return '

        \r\n\r\n <%=name%>\r\n\r\n \r\n <% if (final) { %>\r\n constant\r\n <% } else if (itemtype) { %>\r\n <%=itemtype%> \r\n <% } %>\r\n\r\n <% if (className) { %>\r\n in <%=className%>\r\n <% } %>\r\n\r\n <% if (typeof is_constructor !== \'undefined\' && is_constructor) { %>\r\n constructor\r\n <% } %>\r\n \r\n\r\n

        ';}); + +/*! + * typeahead.js 0.10.2 + * https://github.com/twitter/typeahead.js + * Copyright 2013-2014 Twitter, Inc. and other contributors; Licensed MIT + */ +define('typeahead',[], function() { + +//(function($) { + + + var _ = { + isMsie: function() { + return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false; + }, + isBlankString: function(str) { + return !str || /^\s*$/.test(str); + }, + escapeRegExChars: function(str) { + return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + }, + isString: function(obj) { + return typeof obj === "string"; + }, + isNumber: function(obj) { + return typeof obj === "number"; + }, + isArray: $.isArray, + isFunction: $.isFunction, + isObject: $.isPlainObject, + isUndefined: function(obj) { + return typeof obj === "undefined"; + }, + bind: $.proxy, + each: function(collection, cb) { + $.each(collection, reverseArgs); + function reverseArgs(index, value) { + return cb(value, index); + } + }, + map: $.map, + filter: $.grep, + every: function(obj, test) { + var result = true; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (!(result = test.call(null, val, key, obj))) { + return false; + } + }); + return !!result; + }, + some: function(obj, test) { + var result = false; + if (!obj) { + return result; + } + $.each(obj, function(key, val) { + if (result = test.call(null, val, key, obj)) { + return false; + } + }); + return !!result; + }, + mixin: $.extend, + getUniqueId: function() { + var counter = 0; + return function() { + return counter++; + }; + }(), + templatify: function templatify(obj) { + return $.isFunction(obj) ? obj : template; + function template() { + return String(obj); + } + }, + defer: function(fn) { + setTimeout(fn, 0); + }, + debounce: function(func, wait, immediate) { + var timeout, result; + return function() { + var context = this, args = arguments, later, callNow; + later = function() { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + } + }; + callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + } + return result; + }; + }, + throttle: function(func, wait) { + var context, args, timeout, result, previous, later; + previous = 0; + later = function() { + previous = new Date(); + timeout = null; + result = func.apply(context, args); + }; + return function() { + var now = new Date(), remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0) { + clearTimeout(timeout); + timeout = null; + previous = now; + result = func.apply(context, args); + } else if (!timeout) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }, + noop: function() {} + }; + var VERSION = "0.10.2"; + var tokenizers = function(root) { + return { + nonword: nonword, + whitespace: whitespace, + obj: { + nonword: getObjTokenizer(nonword), + whitespace: getObjTokenizer(whitespace) + } + }; + function whitespace(s) { + return s.split(/\s+/); + } + function nonword(s) { + return s.split(/\W+/); + } + function getObjTokenizer(tokenizer) { + return function setKey(key) { + return function tokenize(o) { + return tokenizer(o[key]); + }; + }; + } + }(); + var LruCache = function() { + function LruCache(maxSize) { + this.maxSize = maxSize || 100; + this.size = 0; + this.hash = {}; + this.list = new List(); + } + _.mixin(LruCache.prototype, { + set: function set(key, val) { + var tailItem = this.list.tail, node; + if (this.size >= this.maxSize) { + this.list.remove(tailItem); + delete this.hash[tailItem.key]; + } + if (node = this.hash[key]) { + node.val = val; + this.list.moveToFront(node); + } else { + node = new Node(key, val); + this.list.add(node); + this.hash[key] = node; + this.size++; + } + }, + get: function get(key) { + var node = this.hash[key]; + if (node) { + this.list.moveToFront(node); + return node.val; + } + } + }); + function List() { + this.head = this.tail = null; + } + _.mixin(List.prototype, { + add: function add(node) { + if (this.head) { + node.next = this.head; + this.head.prev = node; + } + this.head = node; + this.tail = this.tail || node; + }, + remove: function remove(node) { + node.prev ? node.prev.next = node.next : this.head = node.next; + node.next ? node.next.prev = node.prev : this.tail = node.prev; + }, + moveToFront: function(node) { + this.remove(node); + this.add(node); + } + }); + function Node(key, val) { + this.key = key; + this.val = val; + this.prev = this.next = null; + } + return LruCache; + }(); + var PersistentStorage = function() { + var ls, methods; + try { + ls = window.localStorage; + ls.setItem("~~~", "!"); + ls.removeItem("~~~"); + } catch (err) { + ls = null; + } + function PersistentStorage(namespace) { + this.prefix = [ "__", namespace, "__" ].join(""); + this.ttlKey = "__ttl__"; + this.keyMatcher = new RegExp("^" + this.prefix); + } + if (ls && window.JSON) { + methods = { + _prefix: function(key) { + return this.prefix + key; + }, + _ttlKey: function(key) { + return this._prefix(key) + this.ttlKey; + }, + get: function(key) { + if (this.isExpired(key)) { + this.remove(key); + } + return decode(ls.getItem(this._prefix(key))); + }, + set: function(key, val, ttl) { + if (_.isNumber(ttl)) { + ls.setItem(this._ttlKey(key), encode(now() + ttl)); + } else { + ls.removeItem(this._ttlKey(key)); + } + return ls.setItem(this._prefix(key), encode(val)); + }, + remove: function(key) { + ls.removeItem(this._ttlKey(key)); + ls.removeItem(this._prefix(key)); + return this; + }, + clear: function() { + var i, key, keys = [], len = ls.length; + for (i = 0; i < len; i++) { + if ((key = ls.key(i)).match(this.keyMatcher)) { + keys.push(key.replace(this.keyMatcher, "")); + } + } + for (i = keys.length; i--; ) { + this.remove(keys[i]); + } + return this; + }, + isExpired: function(key) { + var ttl = decode(ls.getItem(this._ttlKey(key))); + return _.isNumber(ttl) && now() > ttl ? true : false; + } + }; + } else { + methods = { + get: _.noop, + set: _.noop, + remove: _.noop, + clear: _.noop, + isExpired: _.noop + }; + } + _.mixin(PersistentStorage.prototype, methods); + return PersistentStorage; + function now() { + return new Date().getTime(); + } + function encode(val) { + return JSON.stringify(_.isUndefined(val) ? null : val); + } + function decode(val) { + return JSON.parse(val); + } + }(); + var Transport = function() { + var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, requestCache = new LruCache(10); + function Transport(o) { + o = o || {}; + this._send = o.transport ? callbackToDeferred(o.transport) : $.ajax; + this._get = o.rateLimiter ? o.rateLimiter(this._get) : this._get; + } + Transport.setMaxPendingRequests = function setMaxPendingRequests(num) { + maxPendingRequests = num; + }; + Transport.resetCache = function clearCache() { + requestCache = new LruCache(10); + }; + _.mixin(Transport.prototype, { + _get: function(url, o, cb) { + var that = this, jqXhr; + if (jqXhr = pendingRequests[url]) { + jqXhr.done(done).fail(fail); + } else if (pendingRequestsCount < maxPendingRequests) { + pendingRequestsCount++; + pendingRequests[url] = this._send(url, o).done(done).fail(fail).always(always); + } else { + this.onDeckRequestArgs = [].slice.call(arguments, 0); + } + function done(resp) { + cb && cb(null, resp); + requestCache.set(url, resp); + } + function fail() { + cb && cb(true); + } + function always() { + pendingRequestsCount--; + delete pendingRequests[url]; + if (that.onDeckRequestArgs) { + that._get.apply(that, that.onDeckRequestArgs); + that.onDeckRequestArgs = null; + } + } + }, + get: function(url, o, cb) { + var resp; + if (_.isFunction(o)) { + cb = o; + o = {}; + } + if (resp = requestCache.get(url)) { + _.defer(function() { + cb && cb(null, resp); + }); + } else { + this._get(url, o, cb); + } + return !!resp; + } + }); + return Transport; + function callbackToDeferred(fn) { + return function customSendWrapper(url, o) { + var deferred = $.Deferred(); + fn(url, o, onSuccess, onError); + return deferred; + function onSuccess(resp) { + _.defer(function() { + deferred.resolve(resp); + }); + } + function onError(err) { + _.defer(function() { + deferred.reject(err); + }); + } + }; + } + }(); + var SearchIndex = function() { + function SearchIndex(o) { + o = o || {}; + if (!o.datumTokenizer || !o.queryTokenizer) { + $.error("datumTokenizer and queryTokenizer are both required"); + } + this.datumTokenizer = o.datumTokenizer; + this.queryTokenizer = o.queryTokenizer; + this.reset(); + } + _.mixin(SearchIndex.prototype, { + bootstrap: function bootstrap(o) { + this.datums = o.datums; + this.trie = o.trie; + }, + add: function(data) { + var that = this; + data = _.isArray(data) ? data : [ data ]; + _.each(data, function(datum) { + var id, tokens; + id = that.datums.push(datum) - 1; + tokens = normalizeTokens(that.datumTokenizer(datum)); + _.each(tokens, function(token) { + var node, chars, ch; + node = that.trie; + chars = token.split(""); + while (ch = chars.shift()) { + node = node.children[ch] || (node.children[ch] = newNode()); + node.ids.push(id); + } + }); + }); + }, + get: function get(query) { + var that = this, tokens, matches; + tokens = normalizeTokens(this.queryTokenizer(query)); + _.each(tokens, function(token) { + var node, chars, ch, ids; + if (matches && matches.length === 0) { + return false; + } + node = that.trie; + chars = token.split(""); + while (node && (ch = chars.shift())) { + node = node.children[ch]; + } + if (node && chars.length === 0) { + ids = node.ids.slice(0); + matches = matches ? getIntersection(matches, ids) : ids; + } else { + matches = []; + return false; + } + }); + return matches ? _.map(unique(matches), function(id) { + return that.datums[id]; + }) : []; + }, + reset: function reset() { + this.datums = []; + this.trie = newNode(); + }, + serialize: function serialize() { + return { + datums: this.datums, + trie: this.trie + }; + } + }); + return SearchIndex; + function normalizeTokens(tokens) { + tokens = _.filter(tokens, function(token) { + return !!token; + }); + tokens = _.map(tokens, function(token) { + return token.toLowerCase(); + }); + return tokens; + } + function newNode() { + return { + ids: [], + children: {} + }; + } + function unique(array) { + var seen = {}, uniques = []; + for (var i = 0; i < array.length; i++) { + if (!seen[array[i]]) { + seen[array[i]] = true; + uniques.push(array[i]); + } + } + return uniques; + } + function getIntersection(arrayA, arrayB) { + var ai = 0, bi = 0, intersection = []; + arrayA = arrayA.sort(compare); + arrayB = arrayB.sort(compare); + while (ai < arrayA.length && bi < arrayB.length) { + if (arrayA[ai] < arrayB[bi]) { + ai++; + } else if (arrayA[ai] > arrayB[bi]) { + bi++; + } else { + intersection.push(arrayA[ai]); + ai++; + bi++; + } + } + return intersection; + function compare(a, b) { + return a - b; + } + } + }(); + var oParser = function() { + return { + local: getLocal, + prefetch: getPrefetch, + remote: getRemote + }; + function getLocal(o) { + return o.local || null; + } + function getPrefetch(o) { + var prefetch, defaults; + defaults = { + url: null, + thumbprint: "", + ttl: 24 * 60 * 60 * 1e3, + filter: null, + ajax: {} + }; + if (prefetch = o.prefetch || null) { + prefetch = _.isString(prefetch) ? { + url: prefetch + } : prefetch; + prefetch = _.mixin(defaults, prefetch); + prefetch.thumbprint = VERSION + prefetch.thumbprint; + prefetch.ajax.type = prefetch.ajax.type || "GET"; + prefetch.ajax.dataType = prefetch.ajax.dataType || "json"; + !prefetch.url && $.error("prefetch requires url to be set"); + } + return prefetch; + } + function getRemote(o) { + var remote, defaults; + defaults = { + url: null, + wildcard: "%QUERY", + replace: null, + rateLimitBy: "debounce", + rateLimitWait: 300, + send: null, + filter: null, + ajax: {} + }; + if (remote = o.remote || null) { + remote = _.isString(remote) ? { + url: remote + } : remote; + remote = _.mixin(defaults, remote); + remote.rateLimiter = /^throttle$/i.test(remote.rateLimitBy) ? byThrottle(remote.rateLimitWait) : byDebounce(remote.rateLimitWait); + remote.ajax.type = remote.ajax.type || "GET"; + remote.ajax.dataType = remote.ajax.dataType || "json"; + delete remote.rateLimitBy; + delete remote.rateLimitWait; + !remote.url && $.error("remote requires url to be set"); + } + return remote; + function byDebounce(wait) { + return function(fn) { + return _.debounce(fn, wait); + }; + } + function byThrottle(wait) { + return function(fn) { + return _.throttle(fn, wait); + }; + } + } + }(); + (function(root) { + var old, keys; + old = root.Bloodhound; + keys = { + data: "data", + protocol: "protocol", + thumbprint: "thumbprint" + }; + root.Bloodhound = Bloodhound; + function Bloodhound(o) { + if (!o || !o.local && !o.prefetch && !o.remote) { + $.error("one of local, prefetch, or remote is required"); + } + this.limit = o.limit || 5; + this.sorter = getSorter(o.sorter); + this.dupDetector = o.dupDetector || ignoreDuplicates; + this.local = oParser.local(o); + this.prefetch = oParser.prefetch(o); + this.remote = oParser.remote(o); + this.cacheKey = this.prefetch ? this.prefetch.cacheKey || this.prefetch.url : null; + this.index = new SearchIndex({ + datumTokenizer: o.datumTokenizer, + queryTokenizer: o.queryTokenizer + }); + this.storage = this.cacheKey ? new PersistentStorage(this.cacheKey) : null; + } + Bloodhound.noConflict = function noConflict() { + root.Bloodhound = old; + return Bloodhound; + }; + Bloodhound.tokenizers = tokenizers; + _.mixin(Bloodhound.prototype, { + _loadPrefetch: function loadPrefetch(o) { + var that = this, serialized, deferred; + if (serialized = this._readFromStorage(o.thumbprint)) { + this.index.bootstrap(serialized); + deferred = $.Deferred().resolve(); + } else { + deferred = $.ajax(o.url, o.ajax).done(handlePrefetchResponse); + } + return deferred; + function handlePrefetchResponse(resp) { + that.clear(); + that.add(o.filter ? o.filter(resp) : resp); + that._saveToStorage(that.index.serialize(), o.thumbprint, o.ttl); + } + }, + _getFromRemote: function getFromRemote(query, cb) { + var that = this, url, uriEncodedQuery; + query = query || ""; + uriEncodedQuery = encodeURIComponent(query); + url = this.remote.replace ? this.remote.replace(this.remote.url, query) : this.remote.url.replace(this.remote.wildcard, uriEncodedQuery); + return this.transport.get(url, this.remote.ajax, handleRemoteResponse); + function handleRemoteResponse(err, resp) { + err ? cb([]) : cb(that.remote.filter ? that.remote.filter(resp) : resp); + } + }, + _saveToStorage: function saveToStorage(data, thumbprint, ttl) { + if (this.storage) { + this.storage.set(keys.data, data, ttl); + this.storage.set(keys.protocol, location.protocol, ttl); + this.storage.set(keys.thumbprint, thumbprint, ttl); + } + }, + _readFromStorage: function readFromStorage(thumbprint) { + var stored = {}, isExpired; + if (this.storage) { + stored.data = this.storage.get(keys.data); + stored.protocol = this.storage.get(keys.protocol); + stored.thumbprint = this.storage.get(keys.thumbprint); + } + isExpired = stored.thumbprint !== thumbprint || stored.protocol !== location.protocol; + return stored.data && !isExpired ? stored.data : null; + }, + _initialize: function initialize() { + var that = this, local = this.local, deferred; + deferred = this.prefetch ? this._loadPrefetch(this.prefetch) : $.Deferred().resolve(); + local && deferred.done(addLocalToIndex); + this.transport = this.remote ? new Transport(this.remote) : null; + return this.initPromise = deferred.promise(); + function addLocalToIndex() { + that.add(_.isFunction(local) ? local() : local); + } + }, + initialize: function initialize(force) { + return !this.initPromise || force ? this._initialize() : this.initPromise; + }, + add: function add(data) { + this.index.add(data); + }, + get: function get(query, cb) { + var that = this, matches = [], cacheHit = false; + matches = this.index.get(query); + matches = this.sorter(matches).slice(0, this.limit); + if (matches.length < this.limit && this.transport) { + cacheHit = this._getFromRemote(query, returnRemoteMatches); + } + if (!cacheHit) { + (matches.length > 0 || !this.transport) && cb && cb(matches); + } + function returnRemoteMatches(remoteMatches) { + var matchesWithBackfill = matches.slice(0); + _.each(remoteMatches, function(remoteMatch) { + var isDuplicate; + isDuplicate = _.some(matchesWithBackfill, function(match) { + return that.dupDetector(remoteMatch, match); + }); + !isDuplicate && matchesWithBackfill.push(remoteMatch); + return matchesWithBackfill.length < that.limit; + }); + cb && cb(that.sorter(matchesWithBackfill)); + } + }, + clear: function clear() { + this.index.reset(); + }, + clearPrefetchCache: function clearPrefetchCache() { + this.storage && this.storage.clear(); + }, + clearRemoteCache: function clearRemoteCache() { + this.transport && Transport.resetCache(); + }, + ttAdapter: function ttAdapter() { + return _.bind(this.get, this); + } + }); + return Bloodhound; + function getSorter(sortFn) { + return _.isFunction(sortFn) ? sort : noSort; + function sort(array) { + return array.sort(sortFn); + } + function noSort(array) { + return array; + } + } + function ignoreDuplicates() { + return false; + } + })(this); + var html = { + wrapper: '', + dropdown: '', + dataset: '
        ', + suggestions: '', + suggestion: '
        ' + }; + var css = { + wrapper: { + position: "relative", + display: "inline-block" + }, + hint: { + position: "absolute", + top: "0", + left: "0", + borderColor: "transparent", + boxShadow: "none" + }, + input: { + position: "relative", + verticalAlign: "top", + backgroundColor: "transparent" + }, + inputWithNoHint: { + position: "relative", + verticalAlign: "top" + }, + dropdown: { + position: "absolute", + top: "100%", + left: "0", + zIndex: "100", + display: "none" + }, + suggestions: { + display: "block" + }, + suggestion: { + whiteSpace: "nowrap", + cursor: "pointer" + }, + suggestionChild: { + whiteSpace: "normal" + }, + ltr: { + left: "0", + right: "auto" + }, + rtl: { + left: "auto", + right: " 0" + } + }; + if (_.isMsie()) { + _.mixin(css.input, { + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" + }); + } + if (_.isMsie() && _.isMsie() <= 7) { + _.mixin(css.input, { + marginTop: "-1px" + }); + } + var EventBus = function() { + var namespace = "typeahead:"; + function EventBus(o) { + if (!o || !o.el) { + $.error("EventBus initialized without el"); + } + this.$el = $(o.el); + } + _.mixin(EventBus.prototype, { + trigger: function(type) { + var args = [].slice.call(arguments, 1); + this.$el.trigger(namespace + type, args); + } + }); + return EventBus; + }(); + var EventEmitter = function() { + var splitter = /\s+/, nextTick = getNextTick(); + return { + onSync: onSync, + onAsync: onAsync, + off: off, + trigger: trigger + }; + function on(method, types, cb, context) { + var type; + if (!cb) { + return this; + } + types = types.split(splitter); + cb = context ? bindContext(cb, context) : cb; + this._callbacks = this._callbacks || {}; + while (type = types.shift()) { + this._callbacks[type] = this._callbacks[type] || { + sync: [], + async: [] + }; + this._callbacks[type][method].push(cb); + } + return this; + } + function onAsync(types, cb, context) { + return on.call(this, "async", types, cb, context); + } + function onSync(types, cb, context) { + return on.call(this, "sync", types, cb, context); + } + function off(types) { + var type; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + while (type = types.shift()) { + delete this._callbacks[type]; + } + return this; + } + function trigger(types) { + var type, callbacks, args, syncFlush, asyncFlush; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + args = [].slice.call(arguments, 1); + while ((type = types.shift()) && (callbacks = this._callbacks[type])) { + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); + syncFlush() && nextTick(asyncFlush); + } + return this; + } + function getFlush(callbacks, context, args) { + return flush; + function flush() { + var cancelled; + for (var i = 0; !cancelled && i < callbacks.length; i += 1) { + cancelled = callbacks[i].apply(context, args) === false; + } + return !cancelled; + } + } + function getNextTick() { + var nextTickFn; + if (window.setImmediate) { + nextTickFn = function nextTickSetImmediate(fn) { + setImmediate(function() { + fn(); + }); + }; + } else { + nextTickFn = function nextTickSetTimeout(fn) { + setTimeout(function() { + fn(); + }, 0); + }; + } + return nextTickFn; + } + function bindContext(fn, context) { + return fn.bind ? fn.bind(context) : function() { + fn.apply(context, [].slice.call(arguments, 0)); + }; + } + }(); + var highlight = function(doc) { + var defaults = { + node: null, + pattern: null, + tagName: "strong", + className: null, + wordsOnly: false, + caseSensitive: false + }; + return function hightlight(o) { + var regex; + o = _.mixin({}, defaults, o); + if (!o.node || !o.pattern) { + return; + } + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly); + traverse(o.node, hightlightTextNode); + function hightlightTextNode(textNode) { + var match, patternNode; + if (match = regex.exec(textNode.data)) { + wrapperNode = doc.createElement(o.tagName); + o.className && (wrapperNode.className = o.className); + patternNode = textNode.splitText(match.index); + patternNode.splitText(match[0].length); + wrapperNode.appendChild(patternNode.cloneNode(true)); + textNode.parentNode.replaceChild(wrapperNode, patternNode); + } + return !!match; + } + function traverse(el, hightlightTextNode) { + var childNode, TEXT_NODE_TYPE = 3; + for (var i = 0; i < el.childNodes.length; i++) { + childNode = el.childNodes[i]; + if (childNode.nodeType === TEXT_NODE_TYPE) { + i += hightlightTextNode(childNode) ? 1 : 0; + } else { + traverse(childNode, hightlightTextNode); + } + } + } + }; + function getRegex(patterns, caseSensitive, wordsOnly) { + var escapedPatterns = [], regexStr; + for (var i = 0; i < patterns.length; i++) { + escapedPatterns.push(_.escapeRegExChars(patterns[i])); + } + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); + } + }(window.document); + var Input = function() { + var specialKeyCodeMap; + specialKeyCodeMap = { + 9: "tab", + 27: "esc", + 37: "left", + 39: "right", + 13: "enter", + 38: "up", + 40: "down" + }; + function Input(o) { + var that = this, onBlur, onFocus, onKeydown, onInput; + o = o || {}; + if (!o.input) { + $.error("input is missing"); + } + onBlur = _.bind(this._onBlur, this); + onFocus = _.bind(this._onFocus, this); + onKeydown = _.bind(this._onKeydown, this); + onInput = _.bind(this._onInput, this); + this.$hint = $(o.hint); + this.$input = $(o.input).on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); + if (this.$hint.length === 0) { + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; + } + if (!_.isMsie()) { + this.$input.on("input.tt", onInput); + } else { + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { + if (specialKeyCodeMap[$e.which || $e.keyCode]) { + return; + } + _.defer(_.bind(that._onInput, that, $e)); + }); + } + this.query = this.$input.val(); + this.$overflowHelper = buildOverflowHelper(this.$input); + } + Input.normalizeQuery = function(str) { + return (str || "").replace(/^\s*/g, "").replace(/\s{2,}/g, " "); + }; + _.mixin(Input.prototype, EventEmitter, { + _onBlur: function onBlur() { + this.resetInputValue(); + this.trigger("blurred"); + }, + _onFocus: function onFocus() { + this.trigger("focused"); + }, + _onKeydown: function onKeydown($e) { + var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; + this._managePreventDefault(keyName, $e); + if (keyName && this._shouldTrigger(keyName, $e)) { + this.trigger(keyName + "Keyed", $e); + } + }, + _onInput: function onInput() { + this._checkInputValue(); + }, + _managePreventDefault: function managePreventDefault(keyName, $e) { + var preventDefault, hintValue, inputValue; + switch (keyName) { + case "tab": + hintValue = this.getHint(); + inputValue = this.getInputValue(); + preventDefault = hintValue && hintValue !== inputValue && !withModifier($e); + break; + + case "up": + case "down": + preventDefault = !withModifier($e); + break; + + default: + preventDefault = false; + } + preventDefault && $e.preventDefault(); + }, + _shouldTrigger: function shouldTrigger(keyName, $e) { + var trigger; + switch (keyName) { + case "tab": + trigger = !withModifier($e); + break; + + default: + trigger = true; + } + return trigger; + }, + _checkInputValue: function checkInputValue() { + var inputValue, areEquivalent, hasDifferentWhitespace; + inputValue = this.getInputValue(); + areEquivalent = areQueriesEquivalent(inputValue, this.query); + hasDifferentWhitespace = areEquivalent ? this.query.length !== inputValue.length : false; + if (!areEquivalent) { + this.trigger("queryChanged", this.query = inputValue); + } else if (hasDifferentWhitespace) { + this.trigger("whitespaceChanged", this.query); + } + }, + focus: function focus() { + this.$input.focus(); + }, + blur: function blur() { + this.$input.blur(); + }, + getQuery: function getQuery() { + return this.query; + }, + setQuery: function setQuery(query) { + this.query = query; + }, + getInputValue: function getInputValue() { + return this.$input.val(); + }, + setInputValue: function setInputValue(value, silent) { + this.$input.val(value); + silent ? this.clearHint() : this._checkInputValue(); + }, + resetInputValue: function resetInputValue() { + this.setInputValue(this.query, true); + }, + getHint: function getHint() { + return this.$hint.val(); + }, + setHint: function setHint(value) { + this.$hint.val(value); + }, + clearHint: function clearHint() { + this.setHint(""); + }, + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint, isValid; + val = this.getInputValue(); + hint = this.getHint(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); + !isValid && this.clearHint(); + }, + getLanguageDirection: function getLanguageDirection() { + return (this.$input.css("direction") || "ltr").toLowerCase(); + }, + hasOverflow: function hasOverflow() { + var constraint = this.$input.width() - 2; + this.$overflowHelper.text(this.getInputValue()); + return this.$overflowHelper.width() >= constraint; + }, + isCursorAtEnd: function() { + var valueLength, selectionStart, range; + valueLength = this.$input.val().length; + selectionStart = this.$input[0].selectionStart; + if (_.isNumber(selectionStart)) { + return selectionStart === valueLength; + } else if (document.selection) { + range = document.selection.createRange(); + range.moveStart("character", -valueLength); + return valueLength === range.text.length; + } + return true; + }, + destroy: function destroy() { + this.$hint.off(".tt"); + this.$input.off(".tt"); + this.$hint = this.$input = this.$overflowHelper = null; + } + }); + return Input; + function buildOverflowHelper($input) { + return $('
        ').css({
        +                position: "absolute",
        +                visibility: "hidden",
        +                whiteSpace: "pre",
        +                fontFamily: $input.css("font-family"),
        +                fontSize: $input.css("font-size"),
        +                fontStyle: $input.css("font-style"),
        +                fontVariant: $input.css("font-variant"),
        +                fontWeight: $input.css("font-weight"),
        +                wordSpacing: $input.css("word-spacing"),
        +                letterSpacing: $input.css("letter-spacing"),
        +                textIndent: $input.css("text-indent"),
        +                textRendering: $input.css("text-rendering"),
        +                textTransform: $input.css("text-transform")
        +            }).insertAfter($input);
        +        }
        +        function areQueriesEquivalent(a, b) {
        +            return Input.normalizeQuery(a) === Input.normalizeQuery(b);
        +        }
        +        function withModifier($e) {
        +            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
        +        }
        +    }();
        +    var Dataset = function() {
        +        var datasetKey = "ttDataset", valueKey = "ttValue", datumKey = "ttDatum";
        +        function Dataset(o) {
        +            o = o || {};
        +            o.templates = o.templates || {};
        +            if (!o.source) {
        +                $.error("missing source");
        +            }
        +            if (o.name && !isValidName(o.name)) {
        +                $.error("invalid dataset name: " + o.name);
        +            }
        +            this.query = null;
        +            this.highlight = !!o.highlight;
        +            this.name = o.name || _.getUniqueId();
        +            this.source = o.source;
        +            this.displayFn = getDisplayFn(o.display || o.displayKey);
        +            this.templates = getTemplates(o.templates, this.displayFn);
        +            this.$el = $(html.dataset.replace("%CLASS%", this.name));
        +        }
        +        Dataset.extractDatasetName = function extractDatasetName(el) {
        +            return $(el).data(datasetKey);
        +        };
        +        Dataset.extractValue = function extractDatum(el) {
        +            return $(el).data(valueKey);
        +        };
        +        Dataset.extractDatum = function extractDatum(el) {
        +            return $(el).data(datumKey);
        +        };
        +        _.mixin(Dataset.prototype, EventEmitter, {
        +            _render: function render(query, suggestions) {
        +                if (!this.$el) {
        +                    return;
        +                }
        +                var that = this, hasSuggestions;
        +                this.$el.empty();
        +                hasSuggestions = suggestions && suggestions.length;
        +                if (!hasSuggestions && this.templates.empty) {
        +                    this.$el.html(getEmptyHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
        +                } else if (hasSuggestions) {
        +                    this.$el.html(getSuggestionsHtml()).prepend(that.templates.header ? getHeaderHtml() : null).append(that.templates.footer ? getFooterHtml() : null);
        +                }
        +                this.trigger("rendered");
        +                function getEmptyHtml() {
        +                    return that.templates.empty({
        +                        query: query,
        +                        isEmpty: true
        +                    });
        +                }
        +                function getSuggestionsHtml() {
        +                    var $suggestions, nodes;
        +                    $suggestions = $(html.suggestions).css(css.suggestions);
        +                    nodes = _.map(suggestions, getSuggestionNode);
        +                    $suggestions.append.apply($suggestions, nodes);
        +                    that.highlight && highlight({
        +                        node: $suggestions[0],
        +                        pattern: query
        +                    });
        +                    return $suggestions;
        +                    function getSuggestionNode(suggestion) {
        +                        var $el;
        +                        $el = $(html.suggestion).append(that.templates.suggestion(suggestion)).data(datasetKey, that.name).data(valueKey, that.displayFn(suggestion)).data(datumKey, suggestion);
        +                        $el.children().each(function() {
        +                            $(this).css(css.suggestionChild);
        +                        });
        +                        return $el;
        +                    }
        +                }
        +                function getHeaderHtml() {
        +                    return that.templates.header({
        +                        query: query,
        +                        isEmpty: !hasSuggestions
        +                    });
        +                }
        +                function getFooterHtml() {
        +                    return that.templates.footer({
        +                        query: query,
        +                        isEmpty: !hasSuggestions
        +                    });
        +                }
        +            },
        +            getRoot: function getRoot() {
        +                return this.$el;
        +            },
        +            update: function update(query) {
        +                var that = this;
        +                this.query = query;
        +                this.canceled = false;
        +                this.source(query, render);
        +                function render(suggestions) {
        +                    if (!that.canceled && query === that.query) {
        +                        that._render(query, suggestions);
        +                    }
        +                }
        +            },
        +            cancel: function cancel() {
        +                this.canceled = true;
        +            },
        +            clear: function clear() {
        +                this.cancel();
        +                this.$el.empty();
        +                this.trigger("rendered");
        +            },
        +            isEmpty: function isEmpty() {
        +                return this.$el.is(":empty");
        +            },
        +            destroy: function destroy() {
        +                this.$el = null;
        +            }
        +        });
        +        return Dataset;
        +        function getDisplayFn(display) {
        +            display = display || "value";
        +            return _.isFunction(display) ? display : displayFn;
        +            function displayFn(obj) {
        +                return obj[display];
        +            }
        +        }
        +        function getTemplates(templates, displayFn) {
        +            return {
        +                empty: templates.empty && _.templatify(templates.empty),
        +                header: templates.header && _.templatify(templates.header),
        +                footer: templates.footer && _.templatify(templates.footer),
        +                suggestion: templates.suggestion || suggestionTemplate
        +            };
        +            function suggestionTemplate(context) {
        +                return "

        " + displayFn(context) + "

        "; + } + } + function isValidName(str) { + return /^[_a-zA-Z0-9-]+$/.test(str); + } + }(); + var Dropdown = function() { + function Dropdown(o) { + var that = this, onSuggestionClick, onSuggestionMouseEnter, onSuggestionMouseLeave; + o = o || {}; + if (!o.menu) { + $.error("menu is required"); + } + this.isOpen = false; + this.isEmpty = true; + this.datasets = _.map(o.datasets, initializeDataset); + onSuggestionClick = _.bind(this._onSuggestionClick, this); + onSuggestionMouseEnter = _.bind(this._onSuggestionMouseEnter, this); + onSuggestionMouseLeave = _.bind(this._onSuggestionMouseLeave, this); + this.$menu = $(o.menu).on("click.tt", ".tt-suggestion", onSuggestionClick).on("mouseenter.tt", ".tt-suggestion", onSuggestionMouseEnter).on("mouseleave.tt", ".tt-suggestion", onSuggestionMouseLeave); + _.each(this.datasets, function(dataset) { + that.$menu.append(dataset.getRoot()); + dataset.onSync("rendered", that._onRendered, that); + }); + } + _.mixin(Dropdown.prototype, EventEmitter, { + _onSuggestionClick: function onSuggestionClick($e) { + this.trigger("suggestionClicked", $($e.currentTarget)); + }, + _onSuggestionMouseEnter: function onSuggestionMouseEnter($e) { + this._removeCursor(); + this._setCursor($($e.currentTarget), true); + }, + _onSuggestionMouseLeave: function onSuggestionMouseLeave() { + this._removeCursor(); + }, + _onRendered: function onRendered() { + this.isEmpty = _.every(this.datasets, isDatasetEmpty); + this.isEmpty ? this._hide() : this.isOpen && this._show(); + this.trigger("datasetRendered"); + function isDatasetEmpty(dataset) { + return dataset.isEmpty(); + } + }, + _hide: function() { + this.$menu.hide(); + }, + _show: function() { + this.$menu.css("display", "block"); + }, + _getSuggestions: function getSuggestions() { + return this.$menu.find(".tt-suggestion"); + }, + _getCursor: function getCursor() { + return this.$menu.find(".tt-cursor").first(); + }, + _setCursor: function setCursor($el, silent) { + $el.first().addClass("tt-cursor"); + !silent && this.trigger("cursorMoved"); + }, + _removeCursor: function removeCursor() { + this._getCursor().removeClass("tt-cursor"); + }, + _moveCursor: function moveCursor(increment) { + var $suggestions, $oldCursor, newCursorIndex, $newCursor; + if (!this.isOpen) { + return; + } + $oldCursor = this._getCursor(); + $suggestions = this._getSuggestions(); + this._removeCursor(); + newCursorIndex = $suggestions.index($oldCursor) + increment; + newCursorIndex = (newCursorIndex + 1) % ($suggestions.length + 1) - 1; + if (newCursorIndex === -1) { + this.trigger("cursorRemoved"); + return; + } else if (newCursorIndex < -1) { + newCursorIndex = $suggestions.length - 1; + } + this._setCursor($newCursor = $suggestions.eq(newCursorIndex)); + this._ensureVisible($newCursor); + }, + _ensureVisible: function ensureVisible($el) { + var elTop, elBottom, menuScrollTop, menuHeight; + elTop = $el.position().top; + elBottom = elTop + $el.outerHeight(true); + menuScrollTop = this.$menu.scrollTop(); + menuHeight = this.$menu.height() + parseInt(this.$menu.css("paddingTop"), 10) + parseInt(this.$menu.css("paddingBottom"), 10); + if (elTop < 0) { + this.$menu.scrollTop(menuScrollTop + elTop); + } else if (menuHeight < elBottom) { + this.$menu.scrollTop(menuScrollTop + (elBottom - menuHeight)); + } + }, + close: function close() { + if (this.isOpen) { + this.isOpen = false; + this._removeCursor(); + this._hide(); + this.trigger("closed"); + } + }, + open: function open() { + if (!this.isOpen) { + this.isOpen = true; + !this.isEmpty && this._show(); + this.trigger("opened"); + } + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$menu.css(dir === "ltr" ? css.ltr : css.rtl); + }, + moveCursorUp: function moveCursorUp() { + this._moveCursor(-1); + }, + moveCursorDown: function moveCursorDown() { + this._moveCursor(+1); + }, + getDatumForSuggestion: function getDatumForSuggestion($el) { + var datum = null; + if ($el.length) { + datum = { + raw: Dataset.extractDatum($el), + value: Dataset.extractValue($el), + datasetName: Dataset.extractDatasetName($el) + }; + } + return datum; + }, + getDatumForCursor: function getDatumForCursor() { + return this.getDatumForSuggestion(this._getCursor().first()); + }, + getDatumForTopSuggestion: function getDatumForTopSuggestion() { + return this.getDatumForSuggestion(this._getSuggestions().first()); + }, + update: function update(query) { + _.each(this.datasets, updateDataset); + function updateDataset(dataset) { + dataset.update(query); + } + }, + empty: function empty() { + _.each(this.datasets, clearDataset); + this.isEmpty = true; + function clearDataset(dataset) { + dataset.clear(); + } + }, + isVisible: function isVisible() { + return this.isOpen && !this.isEmpty; + }, + destroy: function destroy() { + this.$menu.off(".tt"); + this.$menu = null; + _.each(this.datasets, destroyDataset); + function destroyDataset(dataset) { + dataset.destroy(); + } + } + }); + return Dropdown; + function initializeDataset(oDataset) { + return new Dataset(oDataset); + } + }(); + var Typeahead = function() { + var attrsKey = "ttAttrs"; + function Typeahead(o) { + var $menu, $input, $hint; + o = o || {}; + if (!o.input) { + $.error("missing input"); + } + this.isActivated = false; + this.autoselect = !!o.autoselect; + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; + this.$node = buildDomStructure(o.input, o.withHint); + $menu = this.$node.find(".tt-dropdown-menu"); + $input = this.$node.find(".tt-input"); + $hint = this.$node.find(".tt-hint"); + $input.on("blur.tt", function($e) { + var active, isActive, hasActive; + active = document.activeElement; + isActive = $menu.is(active); + hasActive = $menu.has(active).length > 0; + if (_.isMsie() && (isActive || hasActive)) { + $e.preventDefault(); + $e.stopImmediatePropagation(); + _.defer(function() { + $input.focus(); + }); + } + }); + $menu.on("mousedown.tt", function($e) { + $e.preventDefault(); + }); + this.eventBus = o.eventBus || new EventBus({ + el: $input + }); + this.dropdown = new Dropdown({ + menu: $menu, + datasets: o.datasets + }).onSync("suggestionClicked", this._onSuggestionClicked, this).onSync("cursorMoved", this._onCursorMoved, this).onSync("cursorRemoved", this._onCursorRemoved, this).onSync("opened", this._onOpened, this).onSync("closed", this._onClosed, this).onAsync("datasetRendered", this._onDatasetRendered, this); + this.input = new Input({ + input: $input, + hint: $hint + }).onSync("focused", this._onFocused, this).onSync("blurred", this._onBlurred, this).onSync("enterKeyed", this._onEnterKeyed, this).onSync("tabKeyed", this._onTabKeyed, this).onSync("escKeyed", this._onEscKeyed, this).onSync("upKeyed", this._onUpKeyed, this).onSync("downKeyed", this._onDownKeyed, this).onSync("leftKeyed", this._onLeftKeyed, this).onSync("rightKeyed", this._onRightKeyed, this).onSync("queryChanged", this._onQueryChanged, this).onSync("whitespaceChanged", this._onWhitespaceChanged, this); + this._setLanguageDirection(); + } + _.mixin(Typeahead.prototype, { + _onSuggestionClicked: function onSuggestionClicked(type, $el) { + var datum; + if (datum = this.dropdown.getDatumForSuggestion($el)) { + this._select(datum); + } + }, + _onCursorMoved: function onCursorMoved() { + var datum = this.dropdown.getDatumForCursor(); + this.input.setInputValue(datum.value, true); + this.eventBus.trigger("cursorchanged", datum.raw, datum.datasetName); + }, + _onCursorRemoved: function onCursorRemoved() { + this.input.resetInputValue(); + this._updateHint(); + }, + _onDatasetRendered: function onDatasetRendered() { + this._updateHint(); + }, + _onOpened: function onOpened() { + this._updateHint(); + this.eventBus.trigger("opened"); + }, + _onClosed: function onClosed() { + this.input.clearHint(); + this.eventBus.trigger("closed"); + }, + _onFocused: function onFocused() { + this.isActivated = true; + this.dropdown.open(); + }, + _onBlurred: function onBlurred() { + this.isActivated = false; + this.dropdown.empty(); + this.dropdown.close(); + this.setVal("", true); //LM + }, + _onEnterKeyed: function onEnterKeyed(type, $e) { + var cursorDatum, topSuggestionDatum; + cursorDatum = this.dropdown.getDatumForCursor(); + topSuggestionDatum = this.dropdown.getDatumForTopSuggestion(); + if (cursorDatum) { + this._select(cursorDatum); + $e.preventDefault(); + } else if (this.autoselect && topSuggestionDatum) { + this._select(topSuggestionDatum); + $e.preventDefault(); + } + }, + _onTabKeyed: function onTabKeyed(type, $e) { + var datum; + if (datum = this.dropdown.getDatumForCursor()) { + this._select(datum); + $e.preventDefault(); + } else { + this._autocomplete(true); + } + }, + _onEscKeyed: function onEscKeyed() { + this.dropdown.close(); + this.input.resetInputValue(); + }, + _onUpKeyed: function onUpKeyed() { + var query = this.input.getQuery(); + this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorUp(); + this.dropdown.open(); + }, + _onDownKeyed: function onDownKeyed() { + var query = this.input.getQuery(); + this.dropdown.isEmpty && query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.moveCursorDown(); + this.dropdown.open(); + }, + _onLeftKeyed: function onLeftKeyed() { + this.dir === "rtl" && this._autocomplete(); + }, + _onRightKeyed: function onRightKeyed() { + this.dir === "ltr" && this._autocomplete(); + }, + _onQueryChanged: function onQueryChanged(e, query) { + this.input.clearHintIfInvalid(); + query.length >= this.minLength ? this.dropdown.update(query) : this.dropdown.empty(); + this.dropdown.open(); + this._setLanguageDirection(); + }, + _onWhitespaceChanged: function onWhitespaceChanged() { + this._updateHint(); + this.dropdown.open(); + }, + _setLanguageDirection: function setLanguageDirection() { + var dir; + if (this.dir !== (dir = this.input.getLanguageDirection())) { + this.dir = dir; + this.$node.css("direction", dir); + this.dropdown.setLanguageDirection(dir); + } + }, + _updateHint: function updateHint() { + var datum, val, query, escapedQuery, frontMatchRegEx, match; + datum = this.dropdown.getDatumForTopSuggestion(); + if (datum && this.dropdown.isVisible() && !this.input.hasOverflow()) { + val = this.input.getInputValue(); + query = Input.normalizeQuery(val); + escapedQuery = _.escapeRegExChars(query); + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); + match = frontMatchRegEx.exec(datum.value); + match ? this.input.setHint(val + match[1]) : this.input.clearHint(); + } else { + this.input.clearHint(); + } + }, + _autocomplete: function autocomplete(laxCursor) { + var hint, query, isCursorAtEnd, datum; + hint = this.input.getHint(); + query = this.input.getQuery(); + isCursorAtEnd = laxCursor || this.input.isCursorAtEnd(); + if (hint && query !== hint && isCursorAtEnd) { + datum = this.dropdown.getDatumForTopSuggestion(); + datum && this.input.setInputValue(datum.value); + this.eventBus.trigger("autocompleted", datum.raw, datum.datasetName); + } + }, + _select: function select(datum) { + this.input.setQuery(datum.value); + this.input.setInputValue(datum.value, true); + this._setLanguageDirection(); + this.eventBus.trigger("selected", datum.raw, datum.datasetName); + this.dropdown.close(); + _.defer(_.bind(this.dropdown.empty, this.dropdown)); + }, + open: function open() { + this.dropdown.open(); + }, + close: function close() { + this.dropdown.close(); + }, + setVal: function setVal(val) { + if (this.isActivated) { + this.input.setInputValue(val); + } else { + this.input.setQuery(val); + this.input.setInputValue(val, true); + } + this._setLanguageDirection(); + }, + getVal: function getVal() { + return this.input.getQuery(); + }, + destroy: function destroy() { + this.input.destroy(); + this.dropdown.destroy(); + destroyDomStructure(this.$node); + this.$node = null; + } + }); + return Typeahead; + function buildDomStructure(input, withHint) { + var $input, $wrapper, $dropdown, $hint; + $input = $(input); + $wrapper = $(html.wrapper).css(css.wrapper); + $dropdown = $(html.dropdown).css(css.dropdown); + $hint = $input.clone().css(css.hint).css(getBackgroundStyles($input)); + $hint.val("").removeData().addClass("tt-hint").removeAttr("id name placeholder").prop("disabled", true).attr({ + autocomplete: "off", + spellcheck: "false" + }); + $input.data(attrsKey, { + dir: $input.attr("dir"), + autocomplete: $input.attr("autocomplete"), + spellcheck: $input.attr("spellcheck"), + style: $input.attr("style") + }); + $input.addClass("tt-input").attr({ + autocomplete: "off", + spellcheck: false + }).css(withHint ? css.input : css.inputWithNoHint); + try { + !$input.attr("dir") && $input.attr("dir", "auto"); + } catch (e) {} + return $input.wrap($wrapper).parent().prepend(withHint ? $hint : null).append($dropdown); + } + function getBackgroundStyles($el) { + return { + backgroundAttachment: $el.css("background-attachment"), + backgroundClip: $el.css("background-clip"), + backgroundColor: $el.css("background-color"), + backgroundImage: $el.css("background-image"), + backgroundOrigin: $el.css("background-origin"), + backgroundPosition: $el.css("background-position"), + backgroundRepeat: $el.css("background-repeat"), + backgroundSize: $el.css("background-size") + }; + } + function destroyDomStructure($node) { + var $input = $node.find(".tt-input"); + _.each($input.data(attrsKey), function(val, key) { + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); + }); + $input.detach().removeData(attrsKey).removeClass("tt-input").insertAfter($node); + $node.remove(); + } + }(); + (function() { + var old, typeaheadKey, methods; + old = $.fn.typeahead; + typeaheadKey = "ttTypeahead"; + methods = { + initialize: function initialize(o, datasets) { + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); + o = o || {}; + return this.each(attach); + function attach() { + var $input = $(this), eventBus, typeahead; + _.each(datasets, function(d) { + d.highlight = !!o.highlight; + }); + typeahead = new Typeahead({ + input: $input, + eventBus: eventBus = new EventBus({ + el: $input + }), + withHint: _.isUndefined(o.hint) ? true : !!o.hint, + minLength: o.minLength, + autoselect: o.autoselect, + datasets: datasets + }); + $input.data(typeaheadKey, typeahead); + } + }, + open: function open() { + return this.each(openTypeahead); + function openTypeahead() { + var $input = $(this), typeahead; + if (typeahead = $input.data(typeaheadKey)) { + typeahead.open(); + } + } + }, + close: function close() { + return this.each(closeTypeahead); + function closeTypeahead() { + var $input = $(this), typeahead; + if (typeahead = $input.data(typeaheadKey)) { + typeahead.close(); + } + } + }, + val: function val(newVal) { + return !arguments.length ? getVal(this.first()) : this.each(setVal); + function setVal() { + var $input = $(this), typeahead; + if (typeahead = $input.data(typeaheadKey)) { + typeahead.setVal(newVal); + } + } + function getVal($input) { + var typeahead, query; + if (typeahead = $input.data(typeaheadKey)) { + query = typeahead.getVal(); + } + return query; + } + }, + destroy: function destroy() { + return this.each(unattach); + function unattach() { + var $input = $(this), typeahead; + if (typeahead = $input.data(typeaheadKey)) { + typeahead.destroy(); + $input.removeData(typeaheadKey); + } + } + } + }; + $.fn.typeahead = function(method) { + if (methods[method]) { + return methods[method].apply(this, [].slice.call(arguments, 1)); + } else { + return methods.initialize.apply(this, arguments); + } + }; + $.fn.typeahead.noConflict = function noConflict() { + $.fn.typeahead = old; + return this; + }; + })(); + + + +//})(window.jQuery); + + +}); +define('searchView',[ + 'App', + // Templates + 'text!tpl/search.html', + 'text!tpl/search_suggestion.html', + // Tools + 'typeahead' +], function(App, searchTpl, suggestionTpl) { + + var searchView = Backbone.View.extend({ + el: '#search', + /** + * Init. + */ + init: function() { + var tpl = _.template(searchTpl); + var className = 'form-control input-lg'; + var placeholder = 'Search reference'; + this.searchHtml = tpl({ + 'placeholder': placeholder, + 'className': className + }); + this.items = App.classes.concat(App.allItems); + + return this; + }, + /** + * Render input field with Typehead activated. + */ + render: function() { + // Append the view to the dom + this.$el.append(this.searchHtml); + + // Render Typeahead + var $searchInput = this.$el.find('input[type=text]'); + this.typeaheadRender($searchInput); + this.typeaheadEvents($searchInput); + + return this; + }, + /** + * Apply Twitter Typeahead to the search input field. + * @param {jquery} $input + */ + typeaheadRender: function($input) { + var self = this; + $input.typeahead(null, { + 'displayKey': 'name', + 'minLength': 2, + //'highlight': true, + 'source': self.substringMatcher(this.items), + 'templates': { + 'empty': '

        Unable to find any item that match the current query

        ', + 'suggestion': _.template(suggestionTpl) + } + }); + }, + /** + * Setup typeahead custom events (item selected). + */ + typeaheadEvents: function($input) { + var self = this; + $input.on('typeahead:selected', function(e, item, datasetName) { + var selectedItem = self.items[item.idx]; + select(selectedItem); + }); + $input.on('keydown', function(e) { + if (e.which === 13) { // enter + var txt = $input.val(); + var f = _.find(self.items, function(it) { return it.name == txt; }); + if (f) { + select(f); + } + } else if (e.which === 27) { + $input.blur(); + } + }); + + function select(selectedItem) { + var hash = App.router.getHash(selectedItem);// + App.router.navigate(hash, {'trigger': true}); + $('#item').focus(); + } + }, + /** + * substringMatcher function for Typehead (search for strings in an array). + * @param {array} array + * @returns {Function} + */ + substringMatcher: function(array) { + return function findMatches(query, callback) { + var matches = [], substrRegex, arrayLength = array.length; + + // regex used to determine if a string contains the substring `query` + substrRegex = new RegExp(query, 'i'); + + // iterate through the pool of strings and for any string that + // contains the substring `query`, add it to the `matches` array + for (var i=0; i < arrayLength; i++) { + var item = array[i]; + if (substrRegex.test(item.name)) { + // typeahead expects suggestions to be a js object + matches.push({ + 'itemtype': item.itemtype, + 'name': item.name, + 'className': item.class, + 'is_constructor': !!item.is_constructor, + 'final': item.final, + 'idx': i + }); + } + } + + callback(matches); + }; + } + + }); + + return searchView; + +}); + + +define('text!tpl/list.html',[],function () { return '<% _.each(groups, function(group){ %>\r\n
        \r\n

        <%=group.name%>

        \r\n
        \r\n <% _.each(group.subgroups, function(subgroup, ind) { %>\r\n
        \r\n <% if (subgroup.name !== \'0\') { %>\r\n

        <%=subgroup.name%>

        \r\n <% } %>\r\n
          \r\n <% _.each(subgroup.items, function(item) { %>\r\n
        • <%=item.name%><% if (item.itemtype === \'method\') { %>()<%}%>
        • \r\n <% }); %>\r\n
        \r\n
        \r\n <% }); %>\r\n
        \r\n
        \r\n<% }); %>\r\n';}); + +define('listView',[ + 'App', + // Templates + 'text!tpl/list.html' +], function (App, listTpl) { + var striptags = function(html) { + var div = document.createElement('div'); + div.innerHTML = html; + return div.textContent; + }; + + var listView = Backbone.View.extend({ + el: '#list', + events: {}, + /** + * Init. + */ + init: function () { + this.listTpl = _.template(listTpl); + + return this; + }, + /** + * Render the list. + */ + render: function (items, listCollection) { + if (items && listCollection) { + var self = this; + + // Render items and group them by module + // module === group + this.groups = {}; + _.each(items, function (item, i) { + + if (!item.private && item.file.indexOf('addons') === -1) { //addons don't get displayed on main page + + var group = item.module || '_'; + var subgroup = item.submodule || '_'; + if (group === subgroup) { + subgroup = '0'; + } + var hash = App.router.getHash(item); + + // fixes broken links for #/p5/> and #/p5/>= + item.hash = item.hash.replace('>', '>'); + + // Create a group list + if (!self.groups[group]) { + self.groups[group] = { + name: group.replace('_', ' '), + subgroups: {} + }; + } + + // Create a subgroup list + if (!self.groups[group].subgroups[subgroup]) { + self.groups[group].subgroups[subgroup] = { + name: subgroup.replace('_', ' '), + items: [] + }; + } + + // hide the un-interesting constants + if (group === 'Constants' && !item.example) + return; + + if (item.class === 'p5') { + + self.groups[group].subgroups[subgroup].items.push(item); + + } else { + + var found = _.find(self.groups[group].subgroups[subgroup].items, + function(i){ return i.name == item.class; }); + + if (!found) { + + // FIX TO INVISIBLE OBJECTS: DH (see also router.js) + var ind = hash.lastIndexOf('/'); + hash = item.hash.substring(0, ind).replace('p5/','p5.'); + self.groups[group].subgroups[subgroup].items.push({ + name: item.class, + hash: hash + }); + } + + } + } + }); + + // Put the
      • items html into the list
          + var listHtml = self.listTpl({ + 'striptags': striptags, + 'title': self.capitalizeFirst(listCollection), + 'groups': self.groups, + 'listCollection': listCollection + }); + + // Render the view + this.$el.html(listHtml); + } + + var renderEvent = new Event('reference-rendered'); + window.dispatchEvent(renderEvent); + + return this; + }, + /** + * Show a list of items. + * @param {array} items Array of item objects. + * @returns {object} This view. + */ + show: function (listGroup) { + if (App[listGroup]) { + this.render(App[listGroup], listGroup); + } + App.pageView.hideContentViews(); + + this.$el.show(); + + return this; + }, + /** + * Helper method to capitalize the first letter of a string + * @param {string} str + * @returns {string} Returns the string. + */ + capitalizeFirst: function (str) { + return str.substr(0, 1).toUpperCase() + str.substr(1); + } + + + + }); + + return listView; + +}); + + +define('text!tpl/item.html',[],function () { return '

          <%=item.name%><% if (item.isMethod) { %>()<% } %>

          \r\n\r\n<% if (item.example) { %>\r\n
          \r\n

          Examples

          \r\n\r\n
          \r\n <% _.each(item.example, function(example, i){ %>\r\n <%= example %>\r\n <% }); %>\r\n
          \r\n
          \r\n<% } %>\r\n\r\n
          \r\n\r\n

          Description

          \r\n\r\n <% if (item.deprecated) { %>\r\n

          \r\n Deprecated: <%=item.name%><% if (item.isMethod) { %>()<% } %> is deprecated and will be removed in a future version of p5. <% if (item.deprecationMessage) { %><%=item.deprecationMessage%><% } %>\r\n

          \r\n <% } %>\r\n\r\n\r\n <%= item.description %>\r\n\r\n <% if (item.extends) { %>\r\n

          Extends <%=item.extends%>

          \r\n <% } %>\r\n\r\n <% if (item.module === \'p5.sound\') { %>\r\n

          This function requires you include the p5.sound library. Add the following into the head of your index.html file:\r\n

          <script src="path/to/p5.sound.js"></script>
          \r\n

          \r\n <% } %>\r\n\r\n <% if (item.constRefs) { %>\r\n

          Used by:\r\n <%\r\n var refs = item.constRefs;\r\n for (var i = 0; i < refs.length; i ++) {\r\n var ref = refs[i];\r\n var name = ref;\r\n if (name.substr(0, 3) === \'p5.\') {\r\n name = name.substr(3);\r\n }\r\n if (i !== 0) {\r\n if (i == refs.length - 1) {\r\n %> and <%\r\n } else {\r\n %>, <%\r\n }\r\n }\r\n %><%= name %>()<%\r\n }\r\n %>\r\n

          \r\n <% } %>\r\n
          \r\n\r\n<% if (isConstructor || !isClass) { %>\r\n\r\n
          \r\n

          Syntax

          \r\n

          \r\n <% syntaxes.forEach(function(syntax) { %>\r\n

          <%= syntax %>
          \r\n <% }) %>\r\n

          \r\n
          \r\n\r\n\r\n<% if (item.params) { %>\r\n
          \r\n

          Parameters

          \r\n
            \r\n <% for (var i=0; i\r\n <% var p = item.params[i] %>\r\n
          • \r\n
            <%=p.name%>
            \r\n <% if (p.type) { %>\r\n
            \r\n <% var type = p.type.replace(/(p5\\.[A-Z][A-Za-z]*)/, \'$1\'); %>\r\n <%=type%>: <%=p.description%>\r\n <% if (p.optional) { %> (Optional)<% } %>\r\n
            \r\n <% } %>\r\n
          • \r\n <% } %>\r\n
          \r\n
          \r\n<% } %>\r\n\r\n<% if (item.return && item.return.type) { %>\r\n
          \r\n

          Returns

          \r\n

          <%=item.return.type%>: <%= item.return.description %>

          \r\n
          \r\n<% } %>\r\n\r\n<% } %>\r\n';}); + + +define('text!tpl/class.html',[],function () { return '\r\n<% if (typeof constructor !== \'undefined\') { %>\r\n
          \r\n <%=constructor%>\r\n
          \r\n<% } %>\r\n\r\n<% let fields = _.filter(things, function(item) { return item.itemtype === \'property\' && item.access !== \'private\' }); %>\r\n<% if (fields.length > 0) { %>\r\n

          Fields

          \r\n
            \r\n <% _.each(fields, function(item) { %>\r\n
          • \r\n
            class="addon"<% } %>><%=item.name%>
            \r\n
            <%= item.description %>
            \r\n
          • \r\n <% }); %>\r\n
          \r\n<% } %>\r\n\r\n<% let methods = _.filter(things, function(item) { return item.itemtype === \'method\' && item.access !== \'private\' }); %>\r\n<% if (methods.length > 0) { %>\r\n

          Methods

          \r\n
            \r\n <% _.each(methods, function(item) { %>\r\n
          • \r\n
            class="addon"<% } %>><%=item.name%><% if (item.itemtype === \'method\') { %>()<%}%>
            \r\n
            <%= item.description %>
            \r\n
          • \r\n <% }); %>\r\n
          \r\n<% } %>\r\n';}); + + +define('text!tpl/itemEnd.html',[],function () { return '\r\n

          \r\n\r\n
          \r\n<% if (item.file && item.line) { %>\r\nNotice any errors or typos? Please let us know. Please feel free to edit <%= item.file %> and issue a pull request!\r\n<% } %>\r\n
          \r\n\r\ncreative commons logo\r\n

          \r\n';}); + +// Copyright (C) 2006 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +/** + * @fileoverview + * some functions for browser-side pretty printing of code contained in html. + * + *

          + * For a fairly comprehensive set of languages see the + * README + * file that came with this source. At a minimum, the lexer should work on a + * number of languages including C and friends, Java, Python, Bash, SQL, HTML, + * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk + * and a subset of Perl, but, because of commenting conventions, doesn't work on + * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. + *

          + * Usage:

            + *
          1. include this source file in an html page via + * {@code } + *
          2. define style rules. See the example page for examples. + *
          3. mark the {@code