#container

video#bgVideo( crossOrigin="anonymous" muted style="display:none" autoplay playsinline )

#cover
	svg(width='1024', height='1024', viewBox='0 0 1280 1280', fill='none', xmlns='http://www.w3.org/2000/svg')
		rect(width='1280', height='1280', fill='#D01012')
		path(fill-rule='evenodd', clip-rule='evenodd', d='M1022.84 485.207C1009.12 471.459 990.025 465.529 968.507 465.259H949.948C920.629 465.259 895.076 476.042 873.827 496.528C873.289 495.719 872.751 494.911 871.944 494.102L871.675 493.832L871.406 493.563C856.344 474.424 834.287 465.799 807.928 465.799H789.368C757.629 465.799 730.731 477.659 708.944 500.032C706.523 495.45 703.565 491.137 699.799 487.094C685.812 471.998 665.908 465.799 643.314 465.799H624.754C597.588 465.799 573.918 474.694 554.013 491.137C553.475 490.598 553.206 490.059 552.668 489.52C536.53 472.807 513.398 465.799 486.231 465.799H467.672C445.346 465.799 425.442 471.729 408.228 483.05C407.421 482.242 406.883 481.433 406.076 480.624C396.124 470.651 382.675 466.338 368.15 466.338H329.686C286.65 466.338 252.759 488.172 228.013 528.605C216.178 548.013 205.688 573.891 196.005 606.238L215.371 533.457C220.213 515.667 219.137 497.876 206.764 483.859C196.274 471.19 181.48 466.338 165.61 466.338C149.741 466.338 134.947 471.19 121.229 480.894C105.897 491.676 95.9451 506.502 91.1035 524.562V524.832C81.9583 559.604 74.9649 585.212 70.6612 601.386C68.5094 609.472 66.8956 615.403 65.8197 618.907C65.5507 619.985 65.2817 621.063 65.0127 621.602C65.0127 621.872 64.7437 622.411 64.7437 622.681C56.6744 652.332 52.6398 677.67 52.6398 697.617C52.6398 721.338 58.0193 742.094 71.7372 757.19C85.724 772.285 105.628 778.485 128.222 778.485H165.341C181.211 778.485 195.467 773.902 207.84 765.276C220.751 774.441 236.889 778.485 254.911 778.485H292.029C310.32 778.485 326.459 772.554 339.638 761.233C353.356 773.633 371.647 778.754 392.358 778.754H410.917C439.429 778.754 465.52 769.05 487.845 749.912C489.459 752.338 491.342 754.764 493.493 757.19C507.48 772.285 527.384 778.485 549.979 778.485H568.538C600.008 778.485 626.906 766.624 648.693 744.52C651.114 749.103 654.342 753.685 657.838 757.459C671.825 772.554 691.73 778.754 714.324 778.754H733.152C756.015 778.754 777.264 772.554 796.362 760.155C797.976 762.042 799.858 763.659 801.741 765.276C811.962 773.363 824.066 777.406 837.784 777.406C853.116 777.406 867.641 772.824 880.821 763.659C883.241 762.042 885.393 760.155 887.545 758.537C889.428 761.233 891.849 763.659 894.538 765.815C904.491 774.441 916.864 777.945 930.043 777.945C942.954 777.945 955.058 774.98 966.355 768.781C975.501 774.98 986.529 777.945 998.095 777.945C1014.23 777.945 1029.3 773.093 1043.01 763.389C1050.01 758.537 1055.92 752.607 1060.5 746.138C1063.19 753.685 1067.49 760.424 1074.22 765.815C1084.44 773.902 1096.54 777.945 1110.26 777.945C1126.4 777.945 1141.46 773.093 1155.18 763.389C1169.97 752.607 1179.92 737.781 1184.76 719.721L1234.79 532.918C1236.68 526.718 1237.22 521.058 1237.22 515.397C1237.22 501.111 1232.1 488.172 1221.08 478.737C1210.86 470.111 1198.21 466.068 1184.5 466.068C1158.67 466.068 1138.23 478.198 1122.36 499.493C1119.67 490.598 1114.83 482.781 1107.3 476.581C1097.89 469.033 1085.78 466.068 1073.41 466.068C1057.54 466.068 1042.48 470.92 1028.49 480.894H1028.22H1027.95C1026.34 482.511 1024.45 483.859 1022.84 485.207Z', fill='#FFF200')
		path(d='M190.356 668.505C201.922 668.505 210.798 671.74 216.985 677.94C222.902 684.14 225.861 692.226 225.861 701.661C225.861 715.947 220.482 729.425 209.453 741.555C197.618 755.033 182.825 761.772 165.341 761.772H128.222C88.6827 761.772 68.7784 740.207 68.7784 697.078C68.7784 679.018 72.5441 655.297 80.3445 626.185C79.2685 630.498 88.1448 597.881 106.704 528.336C110.739 513.78 118.539 502.189 130.643 493.563C141.671 485.746 153.237 481.972 165.61 481.972C178.252 481.972 187.935 485.746 194.66 493.563C202.191 502.189 203.805 513.78 199.77 528.336L175.024 621.602C168.3 645.863 165.61 661.497 166.417 668.505C167.762 668.505 175.831 668.505 190.356 668.505Z', fill='black')
		path(d='M317.044 668.505C328.611 668.505 337.487 671.74 343.673 677.94C349.591 684.14 352.549 692.226 352.549 701.661C352.549 715.947 347.17 729.425 336.142 741.555C324.307 755.033 309.513 761.772 292.03 761.772H254.911C215.371 761.772 195.467 740.207 195.467 697.348C195.467 679.288 199.77 653.949 208.109 621.872C218.33 584.673 229.627 556.1 241.731 536.153C264.056 499.763 293.374 481.702 329.686 481.702H367.074C378.64 481.702 387.517 484.937 393.703 491.137C399.62 497.337 402.579 505.423 402.579 515.127C402.579 529.684 397.2 542.892 386.172 555.022C374.337 568.5 359.543 575.239 342.059 575.239C353.625 575.239 362.502 578.473 368.688 584.673C374.606 590.873 377.564 598.96 377.564 608.394C377.564 622.681 372.185 636.158 361.157 648.289C349.322 661.766 334.528 668.505 317.044 668.505Z', fill='black')
		path(d='M527.384 629.959C527.384 636.698 526.577 643.167 524.695 649.906L517.163 677.94C512.322 696 501.832 713.252 485.155 729.964C463.637 751.529 438.622 762.042 410.917 762.042H392.358C352.818 762.042 332.914 740.477 332.914 697.348C332.914 679.018 337.217 653.949 345.556 621.872C355.777 584.404 367.074 555.831 379.178 535.883C401.503 499.493 430.822 481.433 467.133 481.433H485.693C510.439 481.433 528.729 487.633 540.564 500.032C549.172 509.467 553.744 521.058 553.744 534.805C553.744 539.388 553.206 543.161 552.13 546.666C546.751 567.152 533.571 581.438 512.591 589.795C522.543 599.499 527.384 612.977 527.384 629.959Z', fill='black')
		path(d='M702.758 546.126C702.758 564.456 698.454 589.525 689.578 621.602C679.626 659.071 668.598 687.644 656.494 707.591C634.169 743.712 604.85 761.772 568.538 761.772H549.979C510.439 761.772 490.535 740.207 490.535 697.078C490.535 678.748 494.839 653.68 503.177 621.602C513.398 584.134 524.695 555.561 536.799 535.614C559.124 499.493 588.443 481.433 624.755 481.433H643.314C683.123 481.433 702.758 502.997 702.758 546.126Z', fill='black')
		path(d='M804.969 631.306C815.19 631.306 823.798 634.272 830.791 640.202C837.784 646.132 841.281 654.219 841.281 664.732C841.281 669.044 840.743 673.357 839.398 677.94C834.557 696 824.067 713.252 807.39 729.964C785.872 751.529 760.857 762.042 733.152 762.042H714.324C674.784 762.042 654.88 740.477 654.88 697.348C654.88 679.018 659.184 653.949 667.522 621.872C677.743 584.404 689.04 555.831 701.144 535.883C723.738 499.493 753.057 481.433 789.368 481.433H807.928C830.522 481.433 847.468 488.711 858.765 502.997C867.372 514.588 871.944 528.875 871.944 546.127C871.944 553.405 871.138 559.874 869.793 565.535C865.758 579.821 857.958 591.143 846.392 599.499C834.826 607.855 822.722 611.898 810.08 611.898C800.397 611.898 792.327 609.203 785.872 603.812C779.416 598.421 775.92 590.603 775.113 580.091C771.078 588.447 766.505 602.464 761.395 621.602C756.284 640.741 753.595 654.758 753.057 663.114C765.429 642.089 782.913 631.306 804.969 631.306Z', fill='black')
		path(d='M1027.68 546.396C1027.68 564.456 1023.92 587.908 1016.12 617.02C1007.51 649.636 1002.94 666.079 1002.67 666.079L989.487 715.139C985.453 729.695 977.653 741.286 965.549 749.911C954.52 757.729 942.686 761.502 930.044 761.502C919.822 761.502 911.484 758.807 905.029 753.146C897.766 747.216 894.27 738.86 894.27 728.347C894.27 724.843 894.808 721.069 895.883 717.026C891.311 731.043 883.242 742.094 871.675 750.181C861.185 757.459 849.888 760.963 837.784 760.963C827.563 760.963 818.956 757.998 811.963 752.338C804.969 746.677 801.472 738.59 801.472 728.077C801.472 723.764 802.01 719.452 803.355 714.6L829.446 616.75C853.654 526.179 893.732 480.894 949.679 480.894H968.238C1007.78 481.433 1027.68 502.997 1027.68 546.396Z', fill='black')
		path(d='M1184.5 481.702C1194.99 481.702 1203.59 484.668 1210.59 490.598C1217.58 496.528 1221.08 504.615 1221.08 514.858C1221.08 519.171 1220.54 523.484 1219.19 528.066L1169.16 715.139C1165.4 729.695 1157.6 741.286 1145.76 749.911C1134.74 757.729 1122.9 761.502 1110.26 761.502C1100.04 761.502 1091.43 758.537 1084.44 752.877C1077.44 747.216 1073.95 739.129 1073.95 728.886C1073.95 724.304 1074.48 719.721 1075.83 715.139L1078.79 704.356C1072.33 705.704 1066.15 705.704 1060.23 704.356L1057.54 715.139C1053.5 729.695 1045.7 741.286 1033.6 749.911C1022.57 757.729 1010.74 761.502 998.095 761.502C987.874 761.502 979.266 758.537 972.273 752.877C965.279 747.216 961.783 739.129 961.783 728.886C961.783 724.304 962.321 719.721 963.666 715.139L1013.7 528.066C1017.73 513.78 1025.53 502.458 1037.63 493.563C1049.2 485.476 1061.04 481.702 1073.41 481.702C1093.58 481.702 1105.15 491.137 1108.38 509.736L1113.22 540.466L1134.47 509.736C1147.92 491.137 1164.32 481.702 1184.5 481.702Z', fill='black')
		path(d='M170.183 742.903C180.673 742.903 189.28 739.129 196.274 731.312C203.267 723.765 206.764 715.408 206.764 706.782C206.764 693.574 199.77 687.105 185.514 687.105H166.417C159.424 687.105 154.851 686.296 152.161 684.948C148.665 682.792 146.782 678.209 146.782 670.662C146.782 661.227 149.74 645.323 155.927 623.22C156.196 622.95 156.196 622.681 156.196 622.411C156.734 620.794 158.617 614.055 161.844 601.925C168.569 577.126 175.293 552.596 181.749 528.336C182.556 525.371 182.825 522.675 182.825 519.98C182.825 507.041 175.562 500.571 161.038 500.571C153.506 500.571 146.513 502.728 140.057 507.31C132.795 512.432 127.953 519.44 125.533 528.336L99.7107 623.759C91.9104 652.871 87.8757 675.783 87.8757 692.766C87.8757 726.46 102.938 743.173 132.795 743.173H170.183V742.903Z', fill='white')
		path(d='M296.872 742.903C307.362 742.903 315.969 739.129 322.962 731.312C329.956 723.765 333.452 715.408 333.452 706.782C333.452 693.574 326.459 687.105 312.203 687.105H293.644C286.381 687.105 281.54 686.566 279.119 685.218C275.084 683.331 273.202 678.749 273.202 671.74C273.202 667.158 274.008 661.497 275.353 654.219L275.622 653.41C276.16 651.254 277.774 649.906 280.733 649.636H321.886C332.377 649.636 340.984 645.863 347.977 638.045C354.971 630.228 358.467 622.142 358.467 613.246C358.467 600.038 351.474 593.299 337.218 593.299H295.527C292.837 593.029 291.761 591.682 292.568 589.525L292.837 588.717C297.678 573.891 302.789 564.187 308.976 559.874C313.01 557.178 319.466 555.831 328.88 555.831H347.17C357.66 555.831 366.268 552.057 373.261 544.24C380.254 536.692 383.751 528.336 383.751 519.71C383.751 506.502 376.758 500.032 362.502 500.032H325.114C299.561 500.032 278.312 512.162 261.636 536.153C248.994 554.483 237.428 582.786 226.937 621.063C218.868 651.254 214.833 674.705 214.833 691.957C214.833 725.382 229.896 742.364 259.753 742.364H296.872V742.903Z', fill='white')
		path(d='M506.136 649.636C507.75 643.976 508.826 638.585 508.826 633.463C508.826 621.063 504.522 611.09 496.184 603.542C488.383 596.803 479.238 593.568 468.21 593.568C459.603 593.568 451.534 595.995 444.271 600.847C437.009 605.699 432.167 612.707 429.746 621.602C429.208 624.028 428.939 626.454 428.939 628.611C428.939 640.471 434.588 647.21 445.616 649.367C447.768 649.636 448.844 651.254 448.844 654.219C448.844 653.949 446.692 661.766 442.388 677.94C440.774 683.6 434.857 686.835 424.098 687.374C415.491 686.566 410.918 681.175 410.918 670.931C410.918 661.497 413.877 645.054 419.794 621.602C427.864 591.951 435.126 573.082 441.85 564.456C446.692 558.796 453.954 555.831 464.175 555.831C470.093 555.831 474.397 556.639 476.817 557.987C478.7 569.308 485.694 574.7 497.26 574.7C505.06 574.7 512.322 572.274 519.316 567.152C526.309 562.03 530.882 555.291 533.034 546.666C533.572 544.509 533.841 541.814 533.841 539.118C533.841 529.144 530.613 520.788 524.157 514.049C515.281 504.615 500.756 499.763 480.583 499.763H462.024C436.471 499.763 415.222 511.893 398.545 536.153C385.903 554.483 374.337 583.056 363.847 621.333C355.778 651.523 352.012 675.244 352.012 692.496C352.012 726.19 366.806 742.903 396.662 742.903H415.222C439.161 742.903 459.603 733.199 476.817 713.791C488.114 701.122 495.108 688.992 498.067 677.401L506.136 649.636Z', fill='white')
		path(d='M638.741 500.032H620.182C594.629 500.032 573.38 512.162 556.703 536.422C544.061 554.752 532.495 583.325 522.005 621.602C513.936 651.793 510.17 675.514 510.17 692.765C510.17 726.46 524.964 743.173 554.82 743.173H573.38C598.932 743.173 620.182 731.043 636.858 706.782C649.5 688.453 661.066 659.879 671.287 621.602C679.626 591.412 683.66 567.691 683.66 550.439C683.391 517.014 668.598 500.032 638.741 500.032ZM615.071 621.602C608.347 646.671 602.16 663.923 596.781 673.088C591.939 681.174 586.291 685.487 579.297 686.566C572.304 685.218 568.807 680.096 568.807 670.392C568.807 660.958 571.766 644.515 577.683 621.333C584.677 596.264 590.863 579.012 596.243 569.848C601.084 561.761 606.733 557.448 613.726 556.37C620.72 557.717 624.216 563.109 624.216 572.543C624.485 582.247 621.258 598.421 615.071 621.602Z', fill='white')
		path(d='M799.32 714.06C810.617 701.391 817.61 689.261 820.569 677.67C821.376 674.705 821.645 672.01 821.645 669.314C821.645 656.375 814.383 649.906 800.127 649.906C792.595 649.906 785.602 652.062 779.147 656.645C771.884 661.766 767.043 668.775 764.622 677.67C763.008 683.331 757.091 686.566 746.331 687.105C737.724 686.296 733.152 680.905 733.152 670.662C733.152 661.227 736.11 644.784 742.028 621.602C749.29 594.916 755.746 576.856 761.932 567.691C766.774 560.413 773.229 556.639 781.298 556.1C790.444 556.639 795.016 558.796 795.016 562.839C795.016 563.917 794.747 565.535 794.209 567.961C793.671 570.387 793.402 572.274 793.402 573.891C793.402 587.099 800.665 593.569 814.921 593.569C822.452 593.569 829.445 591.142 836.439 586.29C843.163 581.438 848.005 574.7 850.426 565.804C851.501 562.03 852.039 557.448 852.039 551.518C852.039 517.284 835.632 500.302 802.817 500.302H784.257C758.704 500.302 737.455 512.432 720.779 536.692C708.137 555.022 696.571 583.595 686.081 621.872C678.011 652.062 674.246 675.783 674.246 693.035C674.246 726.73 689.039 743.442 718.896 743.442H737.455C761.663 743.173 782.374 733.469 799.32 714.06Z', fill='white')
		path(d='M963.397 500.032H944.837C919.284 500.032 898.304 511.893 881.896 535.614C868.985 553.944 857.42 582.247 847.467 619.716L821.915 715.139C821.108 718.104 820.839 720.799 820.839 723.495C820.839 736.434 828.101 742.903 842.626 742.903C850.426 742.903 857.688 740.477 864.413 735.625C871.406 730.773 875.71 724.034 878.131 715.139L893.731 656.375C895.076 651.793 897.766 649.636 902.07 649.636H926.278C930.581 649.636 931.926 651.793 930.85 656.375L915.25 715.139C914.174 718.104 913.905 720.799 913.905 723.225C913.905 736.164 921.167 742.634 935.423 742.634C942.954 742.634 949.948 740.207 956.941 735.355C963.666 730.503 968.507 723.765 970.928 714.869L995.943 621.333L996.75 619.446C1004.55 590.334 1008.32 567.152 1008.32 550.17C1008.32 517.014 993.253 500.032 963.397 500.032ZM947.796 586.021C946.451 590.873 943.492 593.299 938.382 593.569H919.822C914.712 593.299 912.829 590.873 913.905 586.021C919.015 566.882 927.354 557.178 938.651 557.178C946.182 557.178 949.948 562.569 949.948 573.352C949.679 577.126 949.141 581.438 947.796 586.021Z', fill='white')
		path(d='M1200.63 528.066C1201.44 525.371 1201.71 522.675 1201.71 520.249C1201.71 514.049 1199.56 509.197 1195.52 505.423C1191.49 501.919 1186.38 500.032 1179.92 500.032C1167.82 500.032 1157.6 505.693 1149.8 516.745L1103.26 584.134C1103 584.943 1102.46 585.212 1101.38 584.943C1100.57 584.943 1100.31 584.673 1100.31 584.134L1089.55 516.745C1087.93 505.423 1080.94 500.032 1068.57 500.032C1061.04 500.032 1053.77 502.458 1047.05 507.58C1040.06 512.701 1035.48 519.44 1032.79 528.066L982.763 715.139C981.956 718.104 981.687 720.799 981.687 723.495C981.687 736.434 988.949 742.903 1003.74 742.903C1011.27 742.903 1018.27 740.477 1025.26 735.625C1032.25 730.773 1036.83 724.034 1039.25 715.139L1050.81 671.47C1051.08 670.662 1051.35 670.123 1051.89 669.584C1052.7 669.044 1053.23 669.314 1053.5 670.392C1055.12 681.714 1062.38 687.105 1074.75 687.105C1086.86 687.105 1097.08 681.444 1104.88 670.392C1105.15 669.584 1105.69 669.314 1106.49 669.584C1107.03 669.584 1107.03 670.123 1106.76 671.47L1094.66 715.139C1093.85 718.104 1093.58 720.799 1093.58 723.495C1093.58 736.434 1100.84 742.903 1115.64 742.903C1123.17 742.903 1130.16 740.477 1137.16 735.625C1143.88 730.773 1148.45 724.034 1150.87 715.139L1200.63 528.066Z', fill='white')





script#vertexShader(type="x-shader/x-vertex").
	attribute float size;
	varying vec4 mvPosition;
	//-
	void main() {
		//vColor = customColor;
		mvPosition = modelViewMatrix * vec4( position, 1.0 );
		gl_PointSize = size;
		gl_Position = projectionMatrix * mvPosition;
	}

script#fragmentShader(type="x-shader/x-fragment").
	varying vec4 mvPosition;
	uniform vec2 resolution;
	uniform sampler2D texture;
	uniform sampler2D textureShadow;
	uniform sampler2D textureLight;
	uniform sampler2D image;
	uniform vec2 texture_size;
	uniform bool colorize;
	uniform float contrastLevel;
	
	uniform vec2 whiteLimits;
	uniform float blackLimits;
	
	uniform vec2 redLimits;
	uniform vec2 yellowLimits;
	uniform vec3 blueLimits;
	
	
	//- Multiply
	vec4 blendMultiply(vec4 base, vec4 blend) {
		return base*blend;
	}
	vec4 blendMultiply(vec4 base, vec4 blend, float opacity) {
		return (blendMultiply(base, blend) * opacity + base * (1.0 - opacity));
	}
	
	//- Screen
	float blendScreen(float base, float blend) {
		return 1.0-((1.0-base)*(1.0-blend));
	}
	vec4 blendScreen(vec4 base, vec4 blend) {
		return vec4(blendScreen(base.r,blend.r),blendScreen(base.g,blend.g),blendScreen(base.b,blend.b), blendScreen(base.a,blend.a));
	}
	vec4 blendScreen(in vec4 base, in vec4 blend, in float opacity) {
		return (blendScreen(base, blend) * opacity + base * (1.0 - opacity));
	}
	
	// - Contrast
	vec4 contrast( in vec4 color, in float adjust ) {
		return vec4( ( color.rgb - vec3(0.5) ) * adjust + vec3(0.5), 1.0 );
	}
	
	//- RGB 2 HSV
	vec3 RGBtoHSV(in vec3 rgbColor) {
		float r = rgbColor[0];
		float g = rgbColor[1];
		float b = rgbColor[2];
		float colorMax = max(max(r,g), b);
		float colorMin = min(min(r,g), b);
		float delta = colorMax - colorMin;
		float h = 0.0;
		float s = 0.0;
		float v = colorMax;
		vec3 hsv = vec3(0.0);
		if (colorMax != 0.0) {
			s = (colorMax - colorMin ) / colorMax;
		}
		if (delta != 0.0) {
			if (r == colorMax) {
				h = (g - b) / delta;
			} else if (g == colorMax) {        
				h = 2.0 + (b - r) / delta;
			} else {    
				h = 4.0 + (r - g) / delta;
			}
			h *= 60.0;
			if (h < 0.0) {
				h += 360.0;
			}
		}
		hsv[0] = h;
		hsv[1] = s;
		hsv[2] = v;
		return hsv;
	}
	
	//-
	void main() {
		vec2 st = (gl_FragCoord.xy / resolution.xy );
		//-
		vec2 imgCoords = mvPosition.xy;
		imgCoords += (texture_size * 0.5);
		//imgCoords.y += (texture_size.y * 0.5);
		imgCoords = imgCoords / (texture_size.xy);
											
		vec4 pix1 = texture2D(image, imgCoords );
		// - 
		pix1 = contrast( pix1, contrastLevel );
	
		if( colorize ){
			//-	Color palette 
			vec3 hsv = RGBtoHSV(pix1.rgb);
			// -
			pix1.rgb = vec3(0.0);
			
			// -
			if(( hsv[0] > yellowLimits.x && hsv[0] < yellowLimits.y ) ){ //- Yellow
				pix1.rgb = vec3(1, 0.867, 0.133);
			}
			if(( hsv[0] < redLimits.x || hsv[0] > redLimits.y) ){ //- Red
				pix1.rgb = vec3(0.761, 0.059, 0);
			}
			if(( hsv[0] > blueLimits.x && hsv[0] < blueLimits.y) && hsv[1] > blueLimits.z ){ //- Blue
				pix1.rgb = vec3(0.137, 0.455, 0.776);
			}
			
			if( hsv[2] < blackLimits ){ // - Black
				pix1.rgb = vec3(0.0);
			}
			if( hsv[2] > whiteLimits.x && hsv[1] < whiteLimits.y ){ //- White
				pix1.rgb = vec3(1.0);
			}
		}
		
		//-
		vec4 origColor = vec4( pix1.rgb, 1.0 );
		origColor = origColor * texture2D( texture, gl_PointCoord );
		
		//-
		vec4 light = texture2D( textureLight, gl_PointCoord );
		vec4 shadow = texture2D( textureShadow, gl_PointCoord );
		//-
		
		vec4 newCol = origColor; 
		newCol = blendScreen(newCol, light, 0.98);
		newCol = blendMultiply(newCol, shadow, 0.7);
		
		//-
		gl_FragColor = newCol;
	}
View Compiled
html,
body
	overflow hidden

body
	margin 0
	background-color #000
	
.dg.ac
	z-index 999 !important
	
#container
	overflow hidden
	
	display flex
	flex-flow row
	align-items center
	justify-content center
	
#cover
	position absolute
	width 1024px
	height 1024px
	top 0
	left 0
	display flex
	flex-flow row
	align-items center
	justify-content center
	//display none
	visibility hidden
	z-index -1
	
#image
	position absolute
	bottom 0px
	right 0px
	z-index 1001
	width 160px
	height 160px
	img
		width 100%
		
video
	position absolute
	z-index 1330
	opacity 1
	top 0%
	left 0%
	width 1280px
	height 1280px
View Compiled
var WIDTH = window.innerWidth,
		HEIGHT = window.innerHeight;
//-
var camera, scene, renderer;
var knot, video, videoTexture;
var now, then = Date.now(), elapsed;
var startTime = then;

// -
var gui,
		guiParams 	= { w: 		1,
										h: 		1,
									 	fps: 	24,
									 	frustum: 1200,
									 	colorize: false,
									 	contrast: 1.0,
									 	
									 	whiteMin: 0.5,
									 	whiteSaturation: 0.5,
									  blackMin: 0.5,
									 	
									 	redMin: 0.0,
									 	redMax: 0.0,
									 	yellowMin: 0.0,
									 	yellowMax: 0.0,
									 	blueMin: 0.0,
									 	blueMax: 0.0,
									 	blueSaturation: 0.0,
									 	screenshot: function(){
												try {
														var imgData = renderer.domElement.toDataURL( 'image/png' );
														saveFile(imgData, 'legocam_screenshot.jpg');
												} catch (e) {
														console.log(e);
														return;
												}
										}
									};
// -
var wCam 				= 1280,
		hCam 				= 1280,
		fpsInterval = 1000,
		sizeBrick 	= 32,
		bricks, shaderMaterial;
var wBrick 			= sizeBrick,
		hBrick 			= sizeBrick;
	
//-
var uniforms = {
		resolution: 	{ type: "v2", value: new THREE.Vector2(1.0, 1.0) },
		texture: 			{ value: null },
		textureShadow: { value: null },
		textureLight: { value: null },
		image: 				{ value: null },
		texture_size: { type: "v2", value: new THREE.Vector2( guiParams.w, guiParams.h ) },
		colorize: 		{ type: "bool", value: guiParams.colorize },
		contrastLevel:{ type: "f", value: guiParams.contrast },

		whiteLimits: 	{ type: "v2", value: new THREE.Vector2( guiParams.whiteMin, guiParams.whiteSaturation ) },
		blackLimits: 	{ type: "f", value: guiParams.blackMin },

		redLimits: { type: "v2", value: new THREE.Vector2( guiParams.redMin, guiParams.redMax ) },
		yellowLimits: { type: "v2", value: new THREE.Vector2( guiParams.yellowMin, guiParams.yellowMax ) },
		blueLimits: { type: "v3", value: new THREE.Vector2( guiParams.blueMin, guiParams.blueMax, guiParams.blueBright ) },
};
//-


//- Data GUI
	gui = new dat.GUI({
		name:				'LegoCam',
		closeOnTop: true,
		closed: 		false
	});
	
	// - Width
	gui.add( guiParams, 'w', 8, 256).name('Number').step(1).listen().onChange(function(){
		guiParams.h = guiParams.w;
		sizeBrick 	= 32 / (guiParams.w/32);
		wBrick = hBrick = sizeBrick;
		uniforms.texture_size.value.x = guiParams.w * wBrick;
		uniforms.texture_size.value.y = guiParams.w * hBrick;
		updateScene();
	}).setValue(64);
	
	// - Frustum
	gui.add( guiParams, 'frustum', 200, 2500).name('Margin (Camera frustum)').step(1).onChange(function(){
		sizeBrick 	= 32 / (guiParams.w/32) * (1200/guiParams.frustum);
		wBrick = hBrick = sizeBrick;
		
		if(camera){
			camera.left 	= guiParams.frustum / - 2;
			camera.right 	= guiParams.frustum / 2;
			camera.top 		= guiParams.frustum / 2;
			camera.bottom = guiParams.frustum / - 2;
			camera.updateProjectionMatrix();
		}
	}).setValue(1200);

	// - FPS
	gui.add( guiParams, 'fps', 1, 60).name('FPS').step(1).onChange(function(){
		 fpsInterval = 1000 / guiParams.fps;
	}).setValue(12);
	
	
	var folderColor = gui.addFolder('Color');
	// - Contrast
	folderColor.add( guiParams, 'contrast', 0.0, 15.0).step(0.00001).name('Contrast').onChange(function(){
		 uniforms.contrastLevel.value = guiParams.contrast;
	}).setValue(0.65);

	// - Colorize
	folderColor.add( guiParams, 'colorize').name('Colorize').onChange(function(){
		 uniforms.colorize.value = guiParams.colorize;
	}).setValue(true);

	// - White limits
	folderColor.add( guiParams, 'whiteMin', 0.0, 1.0).step(0.000001).name('White (min)').onChange(function(){
		 uniforms.whiteLimits.value.x = 1.0 - guiParams.whiteMin;
	}).setValue(0.24);
	folderColor.add( guiParams, 'whiteSaturation', 0.0, 1.0).step(0.000001).name('White (saturation)').onChange(function(){
		 uniforms.whiteLimits.value.y = 1.0 - guiParams.whiteSaturation;
	}).setValue(0.8);
	// - Black limits
	folderColor.add( guiParams, 'blackMin', 0.0, 1.0).step(0.000001).name('Black (min)').onChange(function(){
		 uniforms.blackLimits.value = guiParams.blackMin;
	}).setValue(0.40);
	
	// - Red limits
	folderColor.add( guiParams, 'redMin', 0.0, 360.0).step(0.000001).name('Red (min)').onChange(function(){
		 uniforms.redLimits.value.x = guiParams.redMin;
	}).setValue(41.0);
	folderColor.add( guiParams, 'redMax', 0.0, 360.0).step(0.000001).name('Red (max)').onChange(function(){
		 uniforms.redLimits.value.y = guiParams.redMax;
	}).setValue(240.0);

	// - Yellow limits
	folderColor.add( guiParams, 'yellowMin', 0.0, 360.0).step(0.000001).name('Yellow (min)').onChange(function(){
		 uniforms.yellowLimits.value.x = guiParams.yellowMin;
	}).setValue(50.0);
	folderColor.add( guiParams, 'yellowMax', 0.0, 360.0).step(0.000001).name('Yellow (max)').onChange(function(){
		 uniforms.yellowLimits.value.y = guiParams.yellowMax;
	}).setValue(120.0);

	// - Blue limits
	folderColor.add( guiParams, 'blueMin', 0.0, 360.0).step(0.000001).name('Blue (min)').onChange(function(){
		 uniforms.blueLimits.value.x = guiParams.blueMin;
	}).setValue(139.0);
	folderColor.add( guiParams, 'blueMax', 0.0, 360.0).step(0.000001).name('Blue (max)').onChange(function(){
		 uniforms.blueLimits.value.y = guiParams.blueMax;
	}).setValue(254.0);
	folderColor.add( guiParams, 'blueSaturation', 0.0, 1.0).step(0.000001).name('Blue (saturation)').onChange(function(){
		 uniforms.blueLimits.value.z = guiParams.blueSaturation;
	}).setValue(0.24);

 gui.add(guiParams, 'screenshot').name('Take screenshot');

var center,
		positions, colors, sizes,
		textures = {
			tex: {src:'https://res.cloudinary.com/grooo/image/upload/v1597854531/LegoBrick_yk1wpt.png'},
			overlay: {src:'https://res.cloudinary.com/grooo/image/upload/v1597782474/LegoBrick_light_rlz23e.png'},
			shadow: {src:'https://res.cloudinary.com/grooo/image/upload/v1597782478/LegoBrick_shadow_obrk1c.png'},
			image: {src: null}
		},
		allTextures = [textures.tex, textures.shadow, textures.overlay, textures.image];




//- Cover 
function paintCover(){
	if( !video ){
		var svg = document.getElementById("cover").querySelector("svg");
		var svgData = (new XMLSerializer()).serializeToString(svg);

		var canvasCover = document.createElement("canvas");
		var svgSize = svg.getBoundingClientRect();
		canvasCover.width = svgSize.width;
		canvasCover.height = svgSize.height;
		var ctxCover = canvasCover.getContext("2d");

		var imgCover = document.createElement("img");
		imgCover.setAttribute("src", "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgData))) );
		imgCover.onload = function() {
			if( !video ){
				ctxCover.drawImage(imgCover, 0, 0);
				// -
				textures.image.tex = new THREE.Texture(canvasCover);
				textures.image.tex.needsUpdate = true;
				createScene();
				uniforms.image = { value: textures.image.tex };
			}
		}
	}
}




// - Init
function init() {
	renderer = new THREE.WebGLRenderer({
			antialias: true,
			preserveDrawingBuffer: true /* imprescindible para hacer screenshoots */
		});
	renderer.setPixelRatio( window.devicePixelRatio / 1 );
	$('#container').append( renderer.domElement );
	scene = new THREE.Scene();
	//scene.background = new THREE.Color( 0x222222 );
	//-
	camera = new THREE.OrthographicCamera(guiParams.frustum / - 2, guiParams.frustum / 2, guiParams.frustum / 2, guiParams.frustum / - 2, 10, 1000 );
	//-
	scene.add( new THREE.AmbientLight( 0xffcccc ) );
	//-
	var light1 = new THREE.DirectionalLight( 0xffffff, 1.0 );
	light1.position.set( 0.8, -1, 1 );
	scene.add( light1 );
	//-
	window.addEventListener( 'resize', onWindowResize, false );
	onWindowResize();

	//- Load Textures
	loadTexture( textures.tex );
	loadTexture( textures.shadow );
	loadTexture( textures.overlay );
	
	// - Cover (screenshot)
	paintCover();

	setTimeout(function(){	
		//- Webcam texture
		if ( navigator.mediaDevices && navigator.mediaDevices.getUserMedia ) {
			var constraints = { video: { width: wCam, height: hCam, facingMode: 'user' }, audio: false };
			navigator.mediaDevices.getUserMedia( constraints ).then( function ( stream ) {
				video = document.getElementById( 'bgVideo' );
				videoTexture = new THREE.VideoTexture( video );
				video.srcObject = stream;
				video.play();
				// -
				textures.image.tex = videoTexture;
				textures.image.needsUpdate = true;
				createScene();
				uniforms.image = { value: textures.image.tex };
			} ).catch( function ( error ) {
				console.error( 'Unable to access the camera/webcam.', error );
			} );
		} else {
			console.error( 'MediaDevices interface not available.' );
		}
	}, 2000 );
}


//- All textures Loaded?
function loadTexture( _obj ){
	var textureLoader = new THREE.TextureLoader();
	textureLoader.crossOrigin = '';
	textureLoader.load( _obj.src, function( _tex ){
		_obj.tex = _tex;
		//-
		createScene();
	});
}

function isTexturesLoaded( _array ){
	var ok = true;
	$.each( _array, function( index, value ) {
		if( !value.tex ){
			ok = false;
		};
	});
	return ok;
}

//-
function createScene() {
	if( isTexturesLoaded(allTextures) && !bricks ){
		uniforms.texture = { value: textures.tex.tex };
		uniforms.textureShadow = { value: textures.shadow.tex };
		uniforms.textureLight = { value: textures.overlay.tex };
		uniforms.image = { value: textures.image.tex };
	
		//-
		shaderMaterial = new THREE.ShaderMaterial( {
			uniforms:       uniforms,
			vertexShader:   document.getElementById( 'vertexShader' ).textContent,
			fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
			//- blending:   THREE.AdditiveBlending,
			depthTest:      false,
			transparent:    true
		});

		// - 
		bricks = new THREE.Points( new THREE.BufferGeometry(), shaderMaterial );
		bricks.rotateX( THREE.Math.degToRad( -90 ) );
		scene.add( bricks );
		// -
		updateScene();
	}
}

function updateScene(){
	if(bricks){
		//- Geometry
		positions 	= []
		colors 			= [];
		color 			= new THREE.Color( 0xffffff );
		sizes 			= [];
		var i 			= 0, 
				i3 			= 0;
		center = new THREE.Vector2((wBrick *guiParams.w) / 2, (wBrick * guiParams.h) / 2);
		//-
		for ( var y = 0; y <= guiParams.h; y++ ) {
			for ( var x = 0; x <= guiParams.w; x++ ) {
				color = new THREE.Color();
				color.setHSL( ( x / guiParams.w ), 1.0, 0.7 );
				//-
				colors.push(color.r);
				colors.push(color.g);
				colors.push(color.b);
				// -
				positions.push( center.x - (x * wBrick) );
				positions.push( 150.0 );
				positions.push( center.y - (y * hBrick) );
				//-
				sizes[ i ] = sizeBrick;

				//-
				i3 += 3;
				i++;
			}
		}
		//-
		bricks.geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positions, 3 ) );		
		bricks.geometry.setAttribute( 'customColor', new THREE.Float32BufferAttribute( colors, 3 ) );
		bricks.geometry.setAttribute( 'size', new THREE.Float32BufferAttribute( sizes, 1 ) );
	}
}

//-
function onWindowResize() {
	WIDTH = window.innerWidth;
	HEIGHT = window.innerHeight;
	//-
	if( renderer ){
		camera.updateProjectionMatrix();
		renderer.setSize( HEIGHT, HEIGHT );
		//-
		uniforms.resolution.value.x = renderer.domElement.width;
		uniforms.resolution.value.y = renderer.domElement.height;
	}
}

function animate( time ) {
	requestAnimationFrame( animate );
	now = Date.now();
	elapsed = now - then;
	//-
	if (elapsed > fpsInterval) {
		then = now - (elapsed % fpsInterval);
		// -
		renderer.render( scene, camera );
	}
}

$(document).ready(function(){
	init();
	animate();
});


//- Functions
function saveFile(strData, filename) {
    var link = document.createElement('a');
    if (typeof link.download === 'string') {
        document.body.appendChild(link); //Firefox requires the link to be in the body
        link.download = filename;
        link.href = strData;
        link.click();
        document.body.removeChild(link); //remove the link when done
    } else {
        location.replace(uri);
    }
};

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.7/dat.gui.min.js