1. 자유로운 웹사이트 코드펜 작업

image.png

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>랜덤 영어 회화 문장</title>
  <style>
    body {
      font-family: 'Segoe UI', sans-serif;
      background: #f4f6f8;
      color: #222;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      margin: 0;
    }
    .container {
      background: #ffffffcc;
      backdrop-filter: blur(8px);
      padding: 30px 40px;
      border-radius: 12px;
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
      text-align: center;
      max-width: 600px;
    }
    h1 {
      font-size: 22px;
      margin-bottom: 25px;
      color: #333;
    }
    .quote {
      font-size: 20px;
      font-weight: 500;
      color: #111;
      margin-bottom: 10px;
    }
    .translation {
      font-size: 16px;
      color: #444;
      margin-bottom: 25px;
    }
    button {
      background-color: #3b82f6;
      color: white;
      border: none;
      padding: 10px 18px;
      border-radius: 8px;
      font-size: 16px;
      cursor: pointer;
      transition: background-color 0.3s;
    }
    button:hover {
      background-color: #2563eb;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>랜덤 영어 회화 문장</h1>
    <div class="quote" id="quote">Click the button to get a sentence!</div>
    <div class="translation" id="translation">버튼을 눌러 문장을 생성하세요.</div>
    <button onclick="newQuote()">새로운 문장</button>
  </div>

  <script>
    const sentences = [
      {en: "Could you give me a hand with this?", ko: "이것 좀 도와주시겠어요?"},
      {en: "I'm just looking around, thanks.", ko: "그냥 둘러보고 있어요, 감사합니다."},
      {en: "That sounds like a great idea!", ko: "좋은 생각인 것 같아요!"},
      {en: "Do you happen to know where the nearest subway is?", ko: "가장 가까운 지하철이 어디 있는지 아시나요?"},
      {en: "I'm not sure, but I can find out for you.", ko: "잘 모르겠지만 알아봐드릴게요."},
      {en: "Could I get this to go, please?", ko: "이거 포장해주실 수 있나요?"},
      {en: "What brings you here?", ko: "여긴 어떻게 오셨어요?"},
      {en: "It’s been ages since we last met!", ko: "우리 마지막으로 만난 지 정말 오래됐어요!"},
      {en: "I’ll take care of it.", ko: "제가 처리할게요."},
      {en: "That’s not quite what I meant.", ko: "그건 제가 말하려던 게 아니에요."},
      {en: "I’ll be right back.", ko: "금방 돌아올게요."},
      {en: "I can’t complain.", ko: "불평할 건 없어요."},
      {en: "I’m not really into spicy food.", ko: "저는 매운 음식을 별로 좋아하지 않아요."},
      {en: "Let’s call it a day.", ko: "오늘은 여기까지 하죠."},
      {en: "Don’t take it personally.", ko: "개인적으로 받아들이지 마세요."},
      {en: "Can I get a refill, please?", ko: "리필해주실 수 있나요?"},
      {en: "It’s on the tip of my tongue.", ko: "입 안에서 맴돌고 있는데 생각이 안 나요."},
      {en: "Sorry for the short notice.", ko: "갑작스럽게 알려드려서 죄송해요."},
      {en: "That’s easier said than done.", ko: "말은 쉽죠."},
      {en: "Let me double-check that.", ko: "그걸 다시 한 번 확인해볼게요."},
      {en: "I didn’t catch that. Could you repeat?", ko: "잘 못 들었어요. 다시 말씀해주시겠어요?"},
      {en: "I’ll keep that in mind.", ko: "명심할게요."},
      {en: "You read my mind!", ko: "제 생각을 딱 맞추셨네요!"},
      {en: "Don’t mention it.", ko: "별말씀을요."},
      {en: "I owe you one.", ko: "신세졌어요."},
      {en: "No worries, it happens.", ko: "괜찮아요, 그럴 수도 있죠."},
      {en: "Let’s grab a bite.", ko: "뭐 좀 먹으러 가요."},
      {en: "I couldn’t agree more.", ko: "전적으로 동의해요."},
      {en: "That’s not my cup of tea.", ko: "그건 제 취향이 아니에요."},
      {en: "I’ll think about it.", ko: "생각해볼게요."},
      {en: "You’ve got a point.", ko: "일리가 있네요."},
      {en: "Let me sleep on it.", ko: "하룻밤 생각해볼게요."},
      {en: "You can’t be serious!", ko: "진심이 아니죠!"},
      {en: "I’m starving!", ko: "배고파 죽겠어요!"},
      {en: "I’m running late.", ko: "늦고 있어요."},
      {en: "That’s a tough call.", ko: "어려운 결정이네요."},
      {en: "Keep in touch.", ko: "연락하고 지내요."},
      {en: "Take it easy.", ko: "편하게 지내요."},
      {en: "It’s not a big deal.", ko: "별일 아니에요."},
      {en: "Let me get this straight.", ko: "정확히 이해한 게 맞는지 확인할게요."},
      {en: "You nailed it!", ko: "완벽했어요!"},
      {en: "It’s up to you.", ko: "당신에게 달렸어요."},
      {en: "Don’t get me wrong.", ko: "오해하지 마세요."},
      {en: "It’s worth a try.", ko: "시도해볼 만해요."},
      {en: "I’m on my way.", ko: "가는 중이에요."},
      {en: "Better late than never.", ko: "안 하는 것보단 늦는 게 낫죠."},
      {en: "You’ve got to be kidding!", ko: "농담이죠?"},
      {en: "That’s a relief.", ko: "다행이에요."},
      {en: "That explains a lot.", ko: "이제 이해가 되네요."},
      {en: "You made my day.", ko: "당신 덕분에 기분 좋아졌어요."},
      {en: "Let’s keep our fingers crossed.", ko: "행운을 빌어요."},
      {en: "It’s not worth it.", ko: "그럴 가치 없어요."},
      {en: "That’s not what I heard.", ko: "제가 들은 건 그게 아니에요."},
      {en: "I’m in the mood for pizza.", ko: "피자 먹고 싶은 기분이에요."},
      {en: "Can’t complain about that!", ko: "그건 불평할 수 없죠!"},
      {en: "I’m feeling under the weather.", ko: "몸이 좀 안 좋아요."},
      {en: "It slipped my mind.", ko: "깜빡했어요."},
      {en: "What are you up to?", ko: "요즘 뭐하고 지내요?"},
      {en: "I’ll catch up with you later.", ko: "나중에 다시 연락할게요."},
      {en: "Let’s call it even.", ko: "이제 퉁치죠."},
      {en: "Fingers crossed!", ko: "잘 되길 빌어요!"},
      {en: "You’re pulling my leg!", ko: "놀리는 거죠!"},
      {en: "It’s not my fault.", ko: "제 잘못이 아니에요."},
      {en: "That’s the spirit!", ko: "그거죠, 바로 그 자세예요!"},
      {en: "I’m just killing time.", ko: "시간 때우는 중이에요."},
      {en: "That’s a good one!", ko: "그거 웃기네요!"},
      {en: "Long time no see!", ko: "오랜만이에요!"},
      {en: "It’s not what it looks like.", ko: "보이는 게 다가 아니에요."},
      {en: "You can say that again!", ko: "정말 그래요!"},
      {en: "It’s a piece of cake.", ko: "식은 죽 먹기예요."},
      {en: "That rings a bell.", ko: "어디서 들어본 것 같아요."},
      {en: "I’m broke.", ko: "지금 돈이 없어요."},
      {en: "Let’s hit the road.", ko: "출발하죠."},
      {en: "That’s a no-brainer.", ko: "생각할 것도 없죠."},
      {en: "I’ll pass.", ko: "이번엔 패스할게요."},
      {en: "You never know.", ko: "모르는 일이죠."},
      {en: "It’s about time.", ko: "이제야 됐네요."},
      {en: "You’ve gone too far.", ko: "너무 나갔어요."},
      {en: "I’m all ears.", ko: "귀 기울여 듣고 있어요."},
      {en: "Suit yourself.", ko: "좋을 대로 하세요."},
      {en: "Don’t push your luck.", ko: "운을 너무 믿지 마세요."},
      {en: "What’s the catch?", ko: "함정이 뭐예요?"},
      {en: "Let’s get to the point.", ko: "본론으로 들어가죠."},
      {en: "Take your time.", ko: "천천히 하세요."},
      {en: "No hard feelings.", ko: "섭섭하게 생각하지 마세요."},
      {en: "You made it!", ko: "드디어 왔네요!"},
      {en: "It’s not the end of the world.", ko: "세상의 끝은 아니잖아요."},
      {en: "That’s more like it.", ko: "이제 좀 낫네요."},
      {en: "I can tell.", ko: "그건 알겠어요."},
      {en: "Don’t jump to conclusions.", ko: "성급하게 판단하지 마세요."},
      {en: "Let’s take a break.", ko: "잠깐 쉬어요."},
      {en: "You get the idea.", ko: "무슨 말인지 알죠?"},
      {en: "You never fail to impress me.", ko: "늘 감탄하게 돼요."},
      {en: "That makes sense.", ko: "그건 말이 되네요."},
      {en: "I can’t make it today.", ko: "오늘은 못 갈 것 같아요."},
      {en: "I’ll be in touch.", ko: "연락드릴게요."},
      {en: "Let’s call it off.", ko: "그만두죠."},
      {en: "You should get some rest.", ko: "좀 쉬는 게 좋겠어요."},
      {en: "I really appreciate it.", ko: "정말 감사해요."},
      {en: "Let’s not jump ahead.", ko: "너무 앞서 나가지 말죠."}
    ];

    function newQuote() {
      const random = sentences[Math.floor(Math.random() * sentences.length)];
      document.getElementById('quote').textContent = random.en;
      document.getElementById('translation').textContent = random.ko;
    }
  </script>
</body>
</html>

2. ai를 활용한 인식 관련된 웹사이트 코드펜 작업

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OX 상식 퀴즈 (손 제스처 인식)</title>
<style>
    body {
        font-family: 'Segoe UI', sans-serif;
        display: flex;
        flex-direction: column;
        align-items: center;
        background-color: #f9f9f9;
        color: #222;
        margin: 0;
        padding: 20px;
    }
    h1 { margin-bottom: 20px; }
    .game-container {
        background-color: #fff;
        border-radius: 12px;
        padding: 20px;
        box-shadow: 0 8px 20px rgba(0,0,0,0.1);
        width: 90%;
        max-width: 700px;
        text-align: center;
    }
    video, canvas { width: 100%; border-radius: 8px; }
    #question { font-size: 1.3em; margin: 20px 0; }
    #feedback { font-size: 1.2em; margin-top: 10px; }
    #score { margin-top: 15px; font-weight: bold; }
    #nextButton { margin-top: 20px; padding: 10px 20px; font-size: 1em; border-radius: 8px; border:none; background:#007bff; color:white; cursor:pointer; }
    #nextButton:hover { background:#0056b3; }
</style>
</head>
<body>

<h1>OX 상식 퀴즈</h1>
<div class="game-container">
    <div class="video-wrapper">
        <video id="webcamVideo" autoplay playsinline></video>
        <canvas id="outputCanvas"></canvas>
    </div>
    <div id="question">퀴즈 준비 중...</div>
    <div id="feedback"></div>
    <div id="score"></div>
    <button id="nextButton">다음 문제</button>
</div>

<script src="<https://cdn.jsdelivr.net/npm/@mediapipe/hands@0.4/hands.js>"></script>
<script src="<https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils@0.3/drawing_utils.js>"></script>
<script src="<https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils@0.1/camera_utils.js>"></script>

<script>
const videoElement = document.getElementById('webcamVideo');
const canvasElement = document.getElementById('outputCanvas');
const ctx = canvasElement.getContext('2d');
const questionEl = document.getElementById('question');
const feedbackEl = document.getElementById('feedback');
const scoreEl = document.getElementById('score');
const nextButton = document.getElementById('nextButton');

const questions = [
    {q:"서울은 대한민국에서 가장 인구가 많은 도시이다.", a:"O"},
    {q:"대한민국의 수도는 부산이다.", a:"X"},
    {q:"지구는 태양을 중심으로 돈다.", a:"O"},
    {q:"달은 스스로 빛을 낼 수 있다.", a:"X"},
    {q:"아마존 강은 세계에서 가장 긴 강이다.", a:"X"},
    {q:"대한민국의 국기는 태극기이다.", a:"O"},
    {q:"펭귄은 북극에 서식한다.", a:"X"},
    {q:"전기는 전자의 흐름으로 만들어진다.", a:"O"},
    {q:"수은은 상온에서 액체 상태이다.", a:"O"},
    {q:"금은 산소와 쉽게 반응하여 녹슨다.", a:"X"},
    {q:"인간의 몸에서 가장 큰 장기는 간이다.", a:"X"},
    {q:"코끼리는 쥐를 무서워한다.", a:"X"},
    {q:"빛의 속도는 약 30만 km/s이다.", a:"O"},
    {q:"사자는 초식동물이다.", a:"X"},
    {q:"화성은 붉은색을 띤다.", a:"O"},
    {q:"물은 0도에서 얼고 100도에서 끓는다.", a:"O"},
    {q:"나폴레옹은 키가 매우 작았다.", a:"X"},
    {q:"나일 강은 아프리카를 흐른다.", a:"O"},
    {q:"해마는 암수가 새끼를 낳는다.", a:"O"},
    {q:"피라미드는 이집트에만 존재한다.", a:"X"},
];

let currentIndex = 0;
let score = 0;
let answered = false;

// MediaPipe Hands 초기화
const hands = new Hands({
    locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/hands@0.4/${file}`
});
hands.setOptions({
    maxNumHands: 2,
    modelComplexity: 1,
    minDetectionConfidence: 0.7,
    minTrackingConfidence: 0.7
});
hands.onResults(onResults);

const camera = new Camera(videoElement, {
    onFrame: async () => { await hands.send({image: videoElement}); },
    width: 640,
    height: 480
});
camera.start();

canvasElement.width = 640;
canvasElement.height = 480;

function onResults(results) {
    ctx.save();
    ctx.clearRect(0,0,canvasElement.width,canvasElement.height);
    ctx.drawImage(results.image,0,0,canvasElement.width,canvasElement.height);
    if(results.multiHandLandmarks) {
        for(const landmarks of results.multiHandLandmarks){
            drawConnectors(ctx, landmarks, HAND_CONNECTIONS,{color:'#00FF00', lineWidth:4});
            drawLandmarks(ctx, landmarks,{color:'#FF0000', lineWidth:2});
            if(!answered){
                const gesture = recognizeOX(landmarks);
                if(gesture){
                    checkAnswer(gesture);
                    answered = true;
                }
            }
        }
    }
    ctx.restore();
}

function recognizeOX(landmarks){
    // 엄지만 펴진 경우 O, 검지+중지만 펴진 경우 X
    const thumbUp = landmarks[4].y < landmarks[3].y;
    const indexUp = landmarks[8].y < landmarks[6].y;
    const middleUp = landmarks[12].y < landmarks[10].y;
    const ringUp = landmarks[16].y < landmarks[14].y;
    const pinkyUp = landmarks[20].y < landmarks[18].y;

    if(thumbUp && !indexUp && !middleUp && !ringUp && !pinkyUp) return "O";
    if(!thumbUp && indexUp && middleUp && !ringUp && !pinkyUp) return "X";
    return null;
}

function showQuestion(){
    if(currentIndex >= questions.length){
        questionEl.textContent = "퀴즈 종료! 점수: "+score+"/"+questions.length;
        feedbackEl.textContent = "";
        nextButton.disabled = true;
        return;
    }
    questionEl.textContent = "Q"+(currentIndex+1)+": "+questions[currentIndex].q;
    feedbackEl.textContent = "손 제스처로 O 또는 X를 보여주세요";
    answered = false;
}

function checkAnswer(gesture){
    const correct = questions[currentIndex].a;
    if(gesture === correct){
        feedbackEl.textContent = "정답! ✅";
        score++;
    } else {
        feedbackEl.textContent = "오답 ❌ 정답: "+correct;
    }
    scoreEl.textContent = "현재 점수: "+score;
}

nextButton.addEventListener('click', ()=>{
    currentIndex++;
    showQuestion();
});

// 초기화
showQuestion();
</script>

</body>
</html>

image.png