рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдкрд┐рдХреНрд╕реЗрд▓ рдЖрд░реНрдЯ рдореЗрдХрд░ рд▓рд┐рдЦрдирд╛



рд╢реБрдн рджрд┐рди, рджреЛрд╕реНрддреЛрдВ!

рдкреНрд░рд╕реНрддрд╛рд╡рдирд╛


рдПрдХ рдмрд╛рд░ рдЬрдм рд╡реЗрдм рд╕рд░реНрдлрд┐рдВрдЧ рдореБрдЭреЗ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдиреЗрддреГрддреНрд╡ рдЗрд╕ ред

рдмрд╛рдж рдореЗрдВ рдореИрдВрдиреЗ рдПрдХ рд▓реЗрдЦ рдХреА рдЦреЛрдЬ рдХреА рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред

рдРрд╕рд╛ рдкреНрд░рддреАрдд рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдХреБрдЫ рднреА рдЦрд╛рд╕ рдирд╣реАрдВ рд╣реИ - рдкреАрдХрд╛рдЪреВ, рд╕реАрдПрд╕рдПрд╕ рдХреЗ рд╕рд╛рде рдЦреАрдВрдЪрд╛ рдЧрдпрд╛ред рдЗрд╕ рддрдХрдиреАрдХ рдХреЛ рдкрд┐рдХреНрд╕реЗрд▓ рдЖрд░реНрдЯ (рдкрд┐рдХреНрд╕реЗрд▓ рдХрд▓рд╛?) рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдореБрдЭреЗ рдЗрд╕ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХреА рдЬрдЯрд┐рд▓рддрд╛ рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рд╛ред рдкреНрд░рддреНрдпреЗрдХ рд╕реЗрд▓ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдЪрд┐рддреНрд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ, рд▓рдЧрднрдЧ, рдЪреВрдВрдХрд┐ рдкреНрд░реАрдкреНрд░реЛрд╕реЗрд╕рд░ рд╣реИрдВ; рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рд╕рд╛рд╕)ред рдмреЗрд╢рдХ, рд╕реБрдВрджрд░рддрд╛ рдХреЗ рд▓рд┐рдП рдмрд▓рд┐рджрд╛рди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рд╣рд╛рд▓рд╛рдВрдХрд┐, рдбреЗрд╡рд▓рдкрд░ рдПрдХ рдЖрд▓рд╕реА рдкреНрд░рд╛рдгреА рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВрдиреЗ рд╕реНрд╡рдЪрд╛рд▓рди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реЛрдЪрд╛ред рдЗрд╕рд▓рд┐рдП рдореИрдВрдиреЗ рдЬрд┐рд╕реЗ Pixel Art Maker рдХрд╣рд╛ рдерд╛, рд╡рд╣ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ред

рд╢рд░реНрддреЗрдБ


рд╣рдо рдХреНрдпрд╛ рдкрд╛рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ?

рд╣рдореЗрдВ рдПрдХ рдРрд╕реЗ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЬреЛ рджреА рдЧрдИ рд╕рдВрдЦреНрдпрд╛ рдХреЛ рдордирдорд╛рдиреЗ рд░рдВрдЧреЛрдВ рд╕реЗ рд░рдВрдЧрдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХреЗ рд╕рд╛рде рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИред

рдпрд╣рд╛рдБ рд╡реЗрдм рд╕реЗ рдХреБрдЫ рдЙрджрд╛рд╣рд░рдг рджрд┐рдП рдЧрдП рд╣реИрдВ:


рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░рдХрд╛рд░реНрдп:

  • рдХреЛрд╢рд┐рдХрд╛ рдЖрдХреГрддрд┐ - рд╡рд░реНрдЧ рдпрд╛ рд╡реГрддреНрдд
  • рдкрд┐рдХреНрд╕рд▓ рдореЗрдВ рд╕реЗрд▓ рдХреА рдЪреМрдбрд╝рд╛рдИ
  • рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреА рд╕рдВрдЦреНрдпрд╛
  • рдкреАрдЫреЗ рдХрд╛ рд░рдВрдЧ
  • рд░рдВрдЧ рдХреЗ рд▓рд┐рдП рд░рдВрдЧ
  • рдХреИрдирд╡рд╛рд╕ рдирд┐рд░реНрдорд╛рдг рд╕рдорд╛рд░реЛрд╣
  • рд╕реЗрд▓ рдирдВрдмрд░ рдкреНрд░рджрд░реНрд╢рди рд╕рдорд╛рд░реЛрд╣
  • рдЗрдореЗрдЬ рд╕реЗрд╡ / рдбрд┐рд▓реАрдЯ рдлрдВрдХреНрд╢рди
  • рдХреИрдирд╡рд╛рд╕ рд╕рдлрд╛рдИ рд╕рдорд╛рд░реЛрд╣
  • рдХреИрдирд╡рд╛рд╕ рд╣рдЯрд╛рдиреЗ рдХрд╛ рдХрд╛рд░реНрдп

рд╣рдо рдХреЛрдбрд┐рдВрдЧ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рдЫреЛрдЯреЗ рд╡рд┐рд╡рд░рдгреЛрдВ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░реЗрдВрдЧреЗред

рддреЛ рдЪрд▓рддреЗ рд╣реИрдВред

рдорд╛рд░реНрдХрдЕрдк


рдЖрд╡рд╢реНрдпрдХ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ HTML рдХреЛ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрдирд╛ рдЪрд╛рд╣рд┐рдП:

<!--     -->
<div class="tools">

    <!--      () -->
    <div>
        <p>Shape Form</p>
        <select>
            <!--  -->
            <option value="squares">Square</option>

            <!--  -->
            <option value="circles">Circle</option>
        </select>
    </div>

    <!--        -->
    <div class="numbers">
        <!--  -->
        <div>
            <!--    10  50 ( ) -->
            <p>Shape Width <br> <span>(from 10 to 50)</span></p>
            <input type="number" value="20" class="shapeWidth">
        </div>

        <!--  -->
        <div>
            <!--    -->
            <p>Shape Number <br> <span>(from 10 to 50)</span></p>
            <input type="number" value="30" class="shapeNumber">
        </div>
    </div>

    <!--     -->
    <div class="colors">
        <!--   -->
        <div>
            <p>Background Color</p>
            <input type="color" value="#ffff00" required class="backColor">
        </div>

        <!--   ( ) -->
        <div>
            <p>Shape Color</p>
            <input type="color" value="#0000ff" class="shapeColor">
        </div>
    </div>

    <!--     -->
    <div class="buttons">
        <!--     -->
        <input type="button" value="Generate Canvas" class="generate">

        <!--   /   () -->
        <input type="button" value="Show/Hide Numbers" class="show">

        <!--  /  () -->
        <input type="button" value="Save/Delete Image" class="save">

        <!--           -->
        <input type="button" value="Clear Canvas" class="clear">

        <!--      -->
        <input type="button" value="Delete Canvas" class="delete">
    </div>
</div>

<!--  -->
<canvas></canvas>

рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреА рдЪреМрдбрд╝рд╛рдИ рдФрд░ рд╕рдВрдЦреНрдпрд╛ рдХреЗ рд▓рд┐рдП рдореВрд▓реНрдпреЛрдВ рдХреА рд╕реАрдорд╛ (рд╕реАрдорд╛) рдХреЛ рдЖрдиреБрднрд╡рд┐рдХ рд░реВрдк рд╕реЗ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдкреНрд░рдпреЛрдЧреЛрдВ рд╕реЗ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рдЫреЛрдЯреЗ / рдмрдбрд╝реЗ рдореВрд▓реНрдп рдЕрддреНрдпрдзрд┐рдХ рд╡рд┐рд╕реНрддрд╛рд░ рдХреЗ рдХрд╛рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП рдЕрд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд╣реИрдВ (рдореВрд▓реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП <10 рдЪреМрдбрд╝рд╛рдИ рдХреЗ рд▓рд┐рдП), рдШрдЯреЗ рд╣реБрдП рдкреНрд░рджрд░реНрд╢рди (рдореВрд▓реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП> рдорд╛рддреНрд░рд╛ рдХреЗ рд▓рд┐рдП 50), рдЖрджрд┐ред

рд╢реИрд▓рд┐рдпрд╛рдБ


рд╢реИрд▓рд┐рдпреЛрдВ рдореЗрдВ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдХреБрдЫ рд╡рд┐рд╢реЗрд╖ рдирд╣реАрдВ рд╣реИред

рд╕реАрдПрд╕рдПрд╕:
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    align-content: flex-start;
}

h1 {
    width: 100%;
    text-align: center;
    font-size: 2.4em;
    color: #222;
}

.tools {
    height: 100%;
    display: inherit;
    flex-direction: column;
    margin: 0;
    font-size: 1.1em;
}

.buttons {
    display: inherit;
    flex-direction: column;
    align-items: center;
}

div {
    margin: .25em;
    text-align: center;
}

p {
    margin: .25em 0;
    user-select: none;
}

select {
    padding: .25em .5em;
    font-size: .8em;
}

input,
select {
    outline: none;
    cursor: pointer;
}

input[type="number"] {
    width: 30%;
    padding: .25em 0;
    text-align: center;
    font-size: .8em;
}

input[type="color"] {
    width: 30px;
    height: 30px;
}

.buttons input {
    width: 80%;
    padding: .5em;
    margin-bottom: .5em;
    font-size: .8em;
}

.examples {
    position: absolute;
    top: 0;
    right: 0;
}

a {
    display: block;
}

span {
    font-size: .8em;
}

canvas {
    display: none;
    margin: 1em;
    cursor: pointer;
    box-shadow: 0 0 1px #222;
}

рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ


рдХреИрдирд╡рд╛рд╕ рдФрд░ рдЙрд╕рдХреЗ рд╕рдВрджрд░реНрдн рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ (2D рдбреНрд░рд╛рдЗрдВрдЧ рд╕рдВрджрд░реНрдн):

let c = document.querySelector('canvas'),
    $ = c.getContext('2d')

рд╣рдо рдХреИрдирд╡рд╛рд╕ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдЯрди рдвреВрдВрдврддреЗ рд╣реИрдВ рдФрд░ рдЙрд╕ рдкрд░ рдХреНрд▓рд┐рдХ рдИрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рд▓рдЯрдХрд╛рддреЗ рд╣реИрдВ:

document.querySelector('.generate').onclick = generateCanvas

рдЖрдЧреЗ рдХреЗ рд╕рднреА рдХреЛрдб рдЬрдирд░реЗрдЯ рдлрдВрдХреНрд╢рди рдореЗрдВ рд╣реЛрдВрдЧреЗ:

function generateCanvas(){
    ...
}

рд╣рдо рдЖрдХрд╛рд░, рдЪреМрдбрд╝рд╛рдИ, рдХреНрд╖реИрддрд┐рдЬ рд░рд╛рд╢рд┐ рдФрд░ рдХреБрд▓ рд░рд╛рд╢рд┐ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ (рдХреИрдирд╡рд╛рд╕ рдХреНрд╖реИрддрд┐рдЬ рдФрд░ рд▓рдВрдмрд╡рдд рд░реВрдк рд╕реЗ рдХреЛрд╢рд┐рдХрд╛рдУрдВ рдХреА рд╕рдорд╛рди рд╕рдВрдЦреНрдпрд╛ рдХрд╛ рдкреНрд░рддрд┐рдирд┐рдзрд┐рддреНрд╡ рдХрд░рддрд╛ рд╣реИ), рд╕рд╛рде рд╣реА рд╕рд╛рде рдкреГрд╖реНрдарднреВрдорд┐ рдХрд╛ рд░рдВрдЧ:

// 
let shapeForm = document.querySelector('select').value
//  (  )
let shapeWidth = parseInt(document.querySelector('.shapeWidth').value)
//    (  )
let shapeNumber = parseInt(document.querySelector('.shapeNumber').value)
//   (   )
let shapeAmount = Math.pow(shapeNumber, 2)
//  
let backColor = document.querySelector('.backColor').value

рд╣рдо рдХреИрдирд╡рд╛рд╕ рдХреЗ рдЖрдХрд╛рд░ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВ (рдпрд╛рдж рд░рдЦреЗрдВ рдХрд┐ рд╕рд╣реА рдХреИрдирд╡рд╛рд╕ рдХрд╛ рдЖрдХрд╛рд░ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ):

//  =  =   *    
let W = H = shapeWidth * shapeNumber
c.setAttribute('width', W)
c.setAttribute('height', H)

рдХреБрдЫ рдЕрддрд┐рд░рд┐рдХреНрдд рд╕реЗрдЯрд┐рдВрдЧреНрд╕:

//  
let border = 1
//  
let borderColor = 'rgba(0,0,0,.4)'
//      
let isShown = false

//    
//    
//  
//         
if (shapeWidth < 10 || shapeWidth > 50 || shapeNumber < 10 || shapeNumber > 50 || isNaN(shapeWidth) || isNaN(shapeNumber)) {
    throw new Error(alert('wrong number'))
} else if (shapeForm == 'squares') {
    c.style.display = 'block'
    squares()
} else {
    c.style.display = 'block'
    circles()
}

рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд╡рд░реНрдЧреЛрдВ рд╕рдорд╛рд░реЛрд╣ рдХреА рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

function squares() {
    //   
    let x = y = 0

    //  
    let squares = []

    //     ()
    let w = h = shapeWidth

    //    
    addSquares()

    // -
    function Square(x, y) {
        //   
        this.x = x
        //  y 
        this.y = y
        //   =  
        this.color = backColor
        //     
        this.isSelected = false
    }

    //   
    function addSquares() {
        //     
        for (let i = 0; i < shapeAmount; i++) {
            //  
            let square = new Square(x, y)

            //    
            //        
            x += w

            //       
            //   y   
            //      
            //   
            if (x == W) {
                y += h
                x = 0
            }

            //    
            squares.push(square)
        }
        //    
        drawSquares()
    }

    //   
    function drawSquares() {
        //  
        $.clearRect(0, 0, W, H)

        //    
        for (let i = 0; i < squares.length; i++) {
            //    
            let square = squares[i]
            //  
            $.beginPath()
            //  ,   
            $.rect(square.x, square.y, w, h)
            //  
            $.fillStyle = square.color
            //  
            $.lineWidth = border
            //  
            $.strokeStyle = borderColor
            //  
            $.fill()
            //  
            $.stroke()

            //       
            if (isShown) {
                $.beginPath()
                //  
                $.font = '8pt Calibri'
                //  
                $.fillStyle = 'rgba(0,0,0,.6)'
                //  ,    
                $.fillText(i + 1, square.x, (square.y + 8))
            }
        }
    }

    //      ""
    c.onclick = select
    //   
    function select(e) {
        //   
        let clickX = e.pageX - c.offsetLeft,
            clickY = e.pageY - c.offsetTop

        //    
        for (let i = 0; i < squares.length; i++) {
            let square = squares[i]

            //  ,   
            //  
            // ,    
            if (clickX > square.x && clickX < (square.x + w) && clickY > square.y && clickY < (square.y + h)) {
                //  ,   ,  
                //        ( )
                if (square.isSelected == false) {
                    square.isSelected = true
                    square.color = document.querySelector('.shapeColor').value
                } else {
                    square.isSelected = false
                    square.color = backColor
                }
                //  
                //  ,     ,   
                //  ,     ,  
                // ,      
                drawSquares()
            }
        }
    }

    //             ""
    document.querySelector('.show').onclick = showNumbers
    //    
    function showNumbers() {
        if (!isShown) {
            isShown = true
            //     
            for (let i = 0; i < squares.length; i++) {
                let square = squares[i]
                $.beginPath()
                //   
                $.font = '8pt Calibri'
                //   
                $.fillStyle = 'rgba(0,0,0,.6)'
                //  ,    
                $.fillText(i + 1, square.x, (square.y + 8))
            }
        } else {
            isShown = false
        }
        //  
        drawSquares()
    }
}

рд╕рд░реНрдХрд▓ рдлрд╝рдВрдХреНрд╢рди рдмрд╣реБрдд рдХреБрдЫ рд╕реНрдХреНрд╡рд╛рдпрд░ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд╕рдорд╛рди рд╣реИред

рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ:
function circles() {
    //  
    let r = shapeWidth / 2

    let x = y = r

    let circles = []

    addCircles()

    function Circle(x, y) {
        this.x = x
        this.y = y
        this.color = backColor
        this.isSelected = false
    }

    function addCircles() {
        for (let i = 0; i < shapeAmount; i++) {
            let circle = new Circle(x, y)
            //      
            x += shapeWidth
            //           
            //      
            //      
            if (x == W + r) {
                y += shapeWidth
                x = r
            }
            circles.push(circle)
        }
        drawCircles()
    }

    function drawCircles() {
        $.clearRect(0, 0, W, H)

        for (let i = 0; i < circles.length; i++) {
            let circle = circles[i]
            $.beginPath()
            //  
            $.arc(circle.x, circle.y, r, 0, Math.PI * 2)
            $.fillStyle = circle.color
            $.strokeStyle = borderColor
            $.lineWidth = border
            $.fill()
            $.stroke()
            if (isShown) {
                $.beginPath()
                $.font = '8pt Calibri'
                $.fillStyle = 'rgba(0,0,0,.6)'
                $.fillText(i + 1, (circle.x - 8), circle.y)
            }
        }
    }

    c.onclick = select
    function select(e) {
        let clickX = e.pageX - c.offsetLeft,
            clickY = e.pageY - c.offsetTop

        for (let i = 0; i < circles.length; i++) {
            let circle = circles[i]

            //  ,   
            let distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2))

            if (distanceFromCenter <= r) {
                if (circle.isSelected == false) {
                    circle.isSelected = true
                    circle.color = document.querySelector('.shapeColor').value
                } else {
                    circle.isSelected = false
                    circle.color = backColor
                }
                drawCircles()
            }
        }
    }

    document.querySelector('.show').onclick = showNumbers
    function showNumbers() {
        if (!isShown) {
            isShown = true
            for (let i = 0; i < circles.length; i++) {
                let circle = circles[i]
                $.beginPath()
                $.font = '8pt Calibri'
                $.fillStyle = 'rgba(0,0,0,.6)'
                $.fillText(i + 1, (circle.x - 8), circle.y)
            }
        } else {
            isShown = false
        }
        drawCircles()
    }
}

рд╣рдо рдкрд░рд┐рдгрд╛рдо (рдЫрд╡рд┐) рдХреЛ рдмрдЪрд╛рдиреЗ / рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдЯрди рдвреВрдВрдврддреЗ рд╣реИрдВ рдФрд░ рдЙрд╕ рдкрд░ рдХреНрд▓рд┐рдХ рдЗрд╡реЗрдВрдЯ рд╣реИрдВрдбрд▓рд░ рд▓рдЯрдХрд╛рддреЗ рд╣реИрдВ:

document.querySelector('.save').onclick = () => {
    //  
    let img = document.querySelector('img')

    //   , 
    //  , 
    img == null ? document.body.appendChild(document.createElement('img')).src = c.toDataURL() : document.body.removeChild(img)
}

рд╣рдо рдХреИрдирд╡рд╛рд╕ рдХреА рд╕рдлрд╛рдИ рдХреЗ рд▓рд┐рдП рдмрдЯрди рдвреВрдВрдврддреЗ рд╣реИрдВ рдФрд░ ...:

document.querySelector('.clear').onclick = () => {
    //    
    $.clearRect(0, 0, W, H)
    generateCanvas()
}

рдХреИрдирд╡рд╛рд╕ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдЯрди рдвреВрдВрдвреЗрдВ рдФрд░ ...:

document.querySelector('.delete').onclick = () => {
    $.clearRect(0, 0, W, H)
    c.style.display = 'none'
}

рдЗрд╕ рддрд░рд╣ рдкрд░рд┐рдгрд╛рдо рджрд┐рдЦрддрд╛ рд╣реИ:



Codepen (рдЙрдкрдпреЛрдЧ рдХреЗ рдорд╛рдорд▓реЛрдВ рдХреА рдПрдХ рдЬреЛрдбрд╝реА рдЬреЛрдбрд╝рд╛)

Github

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рджред

All Articles