2회차 준비 파일

_homepage_project.zip

_homepage_project_2.zip

_homepage_project_3.zip

_homepage_project_4.zip

2회차 완성 파일

2회차.zip

파일명 : index.html

<!------- 메인 화면 ------->

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
    **<!-- 백그라운드 비디오 시작 -->
    <div class="video-background">
        <div class="video-foreground">
            <iframe frameborder="0" height="100%" width="100%"
                src="<https://www.youtube.com/embed/c1mzlGjb0gQ?controls=0&mute=1&loop=1&autoplay=1&rel=0&controls=0&showinfo=0&playlist=c1mzlGjb0gQ>"
                title="YouTube video player" frameborder="0"
                allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                allowfullscreen>
            </iframe>
        </div>
    </div>
    <!-- 백그라운드 비디오 끝 -->
    <div class="cont">
        <div class="tit">FACE ID 구현하기</div>
        <div class="webcam-empty">
            <span>
                [인증 시작] 버튼을 눌러
                <br>
                인증을 시작하세요!
            </span>
        </div>
        <div id="webcam-container"></div>
        <button type="button" onclick="init()" class="btn-start">인증 시작</button>
        <strong class="title_result">인증 결과</strong>
        <div id="label-container"></div>
    </div>
    <div class="cover">
        <img src="loading.gif" alt="">
    </div>

    <script src="myScript.js"></script>**

    <script src="<https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js>"></script>
    <script src="<https://cdn.jsdelivr.net/npm/@teachablemachine/[email protected]/dist/teachablemachine-image.min.js>"></script>
    <script type="text/javascript">
        // More API functions here:
        // <https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/image>

        // the link to your model provided by Teachable Machine export panel
        const URL = "./my_model/";

        let model, webcam, labelContainer, maxPredictions;

        // Load the image model and setup the webcam
        async function init() {
            const modelURL = URL + "model.json";
            const metadataURL = URL + "metadata.json";

            // load the model and metadata
            // Refer to tmImage.loadFromFiles() in the API to support files from a file picker
            // or files from your local hard drive
            // Note: the pose library adds "tmImage" object to your window (window.tmImage)
            model = await tmImage.load(modelURL, metadataURL);
            maxPredictions = model.getTotalClasses();

            // Convenience function to setup a webcam
            const flip = true; // whether to flip the webcam
            webcam = new tmImage.Webcam(390, 390, flip); // width, height, flip
            await webcam.setup(); // request access to the webcam
            await webcam.play();
            window.requestAnimationFrame(loop);

            // append elements to the DOM
            document.getElementById("webcam-container").appendChild(webcam.canvas);
            labelContainer = document.getElementById("label-container");
            for (let i = 0; i < maxPredictions; i++) { // and class labels
                labelContainer.appendChild(document.createElement("div"));
            }
        }

        async function loop() {
            webcam.update(); // update the webcam frame
            await predict();
            window.requestAnimationFrame(loop);
        }

        // run the webcam image through the image model
        async function predict() {
            // predict can take in an image, video or canvas html element
            const prediction = await model.predict(webcam.canvas);

            if (prediction[0].className == 'myFace' && prediction[0].probability.toFixed(2) > 0.80) {
                window.location.href = "./success.html";
            } else {
                window.location.href = "./fail.html";
            }
        }
    </script>
</body>

</html>

파일명 : sucess.html

<!------- 인증 성공 화면 ------->

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body class="cont-card">
    <div class="item-card">
        <span class="txt-result">인증이 완료되었습니다!</span>
        <a href="teacherable.html" class="link-return">다시 인증하기</a>
        <a href="#none" class="link-return">블로그로 이동하기</a>
    </div>
</body>
<script>
    setTimeout(function () {
        document.body.classList.add('id-card-active');
    }, 100);
</script>

</html>

파일명 : fail.html

<!------- 인증 실패 화면 ------->

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>

<body class="cont-card fail">
    <div class="item-card">
        <span class="txt-result">인증에 실패했습니다!</span>
        <a href="teacherable.html" class="link-return">다시 인증하기</a>
    </div>
</body>
<script>
    setTimeout(function () {
        document.body.classList.add('id-card-active');
    }, 100);
</script>

</html>

파일명 : style.css

/************* 스타일 파일 **************/

/*  */
@charset "utf-8";

.cont{
    display: inline-block;
    position: relative;
    top:117px;
    left:50%;
    transform: translateX(-50%);
    margin:0 auto;
    text-align: center;
}
.cont .tit{
    font-weight: 900;
    font-size: 24px;
    line-height: 28px;
    color:#F2994A;
    margin-bottom:30px;
}

.cont .webcam-empty{
    width:390px;
    height:390px;
    background: #F2F2F2;
    border: 2px solid #828282;
    box-sizing: border-box;
    border-radius: 10px;;
    text-align: center;
}
.cont .webcam-empty span{
    position: relative;
    top:50%;
    transform:translateY(-50%);
    color:#828282;
}

.cont .btn-start{
    margin-top:20px;
    display: block;
    width:100%;
    height: 60px;
    background: #F2994A;
    border-radius: 10px;
    font-size:20px;
    color:#fff;
    transition: 0.15s;
}
.cont .btn-start:hover{
    transform:scale(1.1);
    cursor: pointer;
}
.title_result{
    display: none;
}
.cont-card{
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100vw;
    height: 100vh;
    perspective: 800px;
}
.item-card{
    width: 390px;
    height: 500px;
    background:#F2994A;
    color:#fff;
    text-align: center;
    position: relative;
    transform: scale(0.01) rotateY(720deg);
    transform-style: preserve-3d;
    transition: 1.2s;
    font-size:24px;
    border-radius: 10px;
}

.id-card-active .item-card {
    transform: scale(1) rotateY(0deg);
}

.fail .item-card{
    transform: scale(0.01) rotateZ(720deg);
    background:#828282;
}

.id-card-active.fail .item-card {
    animation-duration: 1s, 1s;
    animation-name: animation-fail, animation-fail-finish;
    animation-delay: 0s, 1s;
    animation-fill-mode: forwards;
}

.cover{
    position: fixed;
    top:0;
    left:0;
    right:0;
    bottom:0;
    background:black;
    display: none;
}

.cover img{
    display: block;
    position: relative;
    width: 100px;
    margin:0 auto;
    position:relative;
    top:50%;
    transform:translateY(-50%);
}
.cont-card .txt-result{
    display: inline-block;
    margin-top:200px;
    margin:200px 0 100px;
}
.cont-card .link-return{
    display: block;
    height:50px;
    line-height:50px;
    width:80%;
    margin:0 auto 20px;
    text-decoration: none;
    background:#fff;
    border-radius: 10px;
    font-weight:bold;
    color:black;
}

.cont-card.id-card-active .item-card:hover{
    background: #ea124f;
	transform: scale(1.1) rotateZ(3deg);
	cursor: pointer;
}

@keyframes animation-fail {
    100%{
        transform: scale(1) rotateZ(-50deg);
    }
}

@keyframes animation-fail-finish {
    0%{
        transform: scale(1) rotateZ(-50deg);
    }
    10%{
        transform: scaleY(1.3) scaleX(0.7) rotateZ(2deg); 
    }
    40%{
        transform: scale(1) rotateZ(-40deg); 
    }
    50%{
        transform: scale(1.2) scaleX(0.8) rotateZ(0deg); 
    }
    65%{
        transform: scale(1) rotateZ(-30deg); 
    }
    75%{
        transform: scale(1.1) scaleX(0.9) rotateZ(0deg);
    }
    85%{
        transform: scale(1) rotateZ(-10deg);
    }
    90%{
        transform: scale(1) rotateZ(0deg);
    }
    95%{
        transform: scale(1) rotateZ(-5deg);
    }
    97%{
        transform: scale(1) rotateZ(0deg);
    }
    99%{
        transform: scale(1) rotateZ(-2deg);
    }
    100%{
        transform: scale(1) rotateZ(0deg);
    }
}

/* 영상 배경 스타일 */
.video-background {
    background: #000;
    position: fixed;
    top: 0; right: 0; bottom: 0; left: 0;
    z-index: -99;
  }
  .video-foreground,
  .video-background iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
  }

  @media (min-aspect-ratio: 16/9) {
    .video-foreground { height: 300%; top: -100%; }
  }
  
  @media (max-aspect-ratio: 16/9) {
    .video-foreground { width: 300%; left: -100%; }
  }