0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

生成AIに関する記事を書こう!
Qiita Engineer Festa20242024年7月17日まで開催中!

Claudeに生成してもらったReactアプリをClaudeにHTML+CSS+JavaScriptのみに変換してもらった

Last updated at Posted at 2024-07-11

image.png

抽選の結果、『』さんがプレゼン者に選ばれました

はじめに

前回の記事「ClaudeのGPT-4o超え」って意外と本当かもと驚いた!!!で生成したルーレット・アプリは、Reactを使用したアプリでした。

せっかく生成したもらっておいて失礼ですが笑、Reactを使うまでもないシンプルなアプリなので、シンプルに、HTML+CSS+JavaScriptだけを使ったアプリに書き換えてください、とお願いしてみました。

文句ひとつ言わず、数秒でやってくれました。

もし、私がこんな依頼を受けたなら、もう、文句ブーブーです :sunglasses:
ていうか、何時間かかるんだろう:sweat_smile:

レッツ・トライ!

早速始めます。

プロンプト1

Claudeに生成してもらったReactをHTML+CSS+JavaScriptのみに変換するためのプロンプトを入力します。

prompt
ソースコードをHTML+CSS+JavaScriptのみで書き換えてください

何やらエラーが発生しました。

image.png

無料枠の回数制限は確実に残っている(理由:本日使用1回目ですので)と思いましたが、よく見ると、length limitとありますので、コンテキストサイズがオーバーしたようです。

ソースコード自体はそれほど大きくないのですが、これまでのやり取りが全てコンテキストに含まれているようで、その結果、length limitに引っかかったようです。

ならばと思い、次に試したのは、こんなプロンプトです。

プロンプト2

そうならばと思い、次に試したのは、こんなプロンプトです。

prompt
以下のソースコードをHTML+CSS+JavaScriptのみで書き換えてください

import React, { useState, useEffect, useRef } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

const PresenterRoulette = () => {
  const [presenters, setPresenters] = useState([]);
  const [newPresenter, setNewPresenter] = useState('');
  
(以下省略)

指示プロンプトの下に、生成されたソースコードを全てペーストしてみました。

結果は、こちらの通り、15秒前後でコンバートしてくれました。すごすぎる。。。
image.png

プロンプト3

実は、ちょっと気になったことがありました。
プレゼン者を入力した後に、いつもの癖で、enterキーを押してしまうのですが、このアプリでは、enterキーでは追加してくれず、必ず[追加]ボタンを押す必要があります。
image.png
細かいことですが、enterキーでもプレゼン者リストに追加されるようにお願いしてみます。

prompt
プレゼン者の追加は、追加ボタンのほかに、キーボードのenterキーも有効にしてください

あっという間に、コードを修正してくれました。
image.png

それでは実際に試してみます。
enterキーでプレゼン者リストに追加されました。

生成されたHTML

生成されたHTML+CSS+JavaScriptを共有いたします。
ライブラリを必要としませんので、すぐに試せますね。
Simple is best.

html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>プレゼン者ルーレットアプリ</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 400px;
            margin: 0 auto;
            padding: 20px;
        }
        h1 {
            font-size: 24px;
            margin-bottom: 20px;
        }
        .input-container {
            display: flex;
            margin-bottom: 20px;
        }
        input {
            flex-grow: 1;
            margin-right: 10px;
            padding: 5px;
        }
        button {
            padding: 5px 10px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        ul {
            list-style-type: disc;
            padding-left: 20px;
        }
        canvas {
            display: block;
            margin: 0 auto;
        }
        #result {
            text-align: center;
            padding: 15px;
            background-color: #e6f3ff;
            border-radius: 5px;
            margin-top: 20px;
        }
        #selectedPresenter {
            font-size: 24px;
            color: #0066cc;
            font-weight: bold;
        }
    </style>
</head>
<body>
    <h1>プレゼン者ルーレットアプリ</h1>
    <div class="input-container">
        <input type="text" id="newPresenter" placeholder="プレゼン者の名前を入力">
        <button onclick="addPresenter()">追加</button>
    </div>
    <div>
        <h2>プレゼン者リスト:</h2>
        <ul id="presenterList"></ul>
    </div>
    <canvas id="roulette" width="300" height="300"></canvas>
    <button id="spinButton" onclick="spinRoulette()">ルーレットを回す</button>
    <div id="result" style="display: none;">
        <h2>選ばれたプレゼン者:</h2>
        <p id="selectedPresenter"></p>
    </div>

    <script>
        const presenters = [];
        let isSpinning = false;
        const canvas = document.getElementById('roulette');
        const ctx = canvas.getContext('2d');
        const spinButton = document.getElementById('spinButton');
        const newPresenterInput = document.getElementById('newPresenter');

        // Enterキーのイベントリスナーを追加
        newPresenterInput.addEventListener('keypress', function(event) {
            if (event.key === 'Enter') {
                addPresenter();
            }
        });

        function addPresenter() {
            const newPresenter = newPresenterInput.value.trim();
            if (newPresenter !== '') {
                presenters.push(newPresenter);
                newPresenterInput.value = '';
                updatePresenterList();
                drawRoulette(0);
            }
        }

        function updatePresenterList() {
            const list = document.getElementById('presenterList');
            list.innerHTML = '';
            presenters.forEach(presenter => {
                const li = document.createElement('li');
                li.textContent = presenter;
                list.appendChild(li);
            });
        }

        function spinRoulette() {
            if (presenters.length > 0 && !isSpinning) {
                isSpinning = true;
                spinButton.disabled = true;
                spinButton.textContent = 'ルーレット回転中...';
                const minSpins = 5;
                const maxSpins = 10;
                const spins = minSpins + Math.random() * (maxSpins - minSpins);
                const minDuration = 4000;
                const maxDuration = 8000;
                const duration = minDuration + Math.random() * (maxDuration - minDuration);
                let currentRotation = 0;
                const startTime = Date.now();

                const sliceAngle = 360 / presenters.length;
                const additionalRotation = Math.random() * 360;

                function animate() {
                    const elapsedTime = Date.now() - startTime;
                    const progress = Math.min(elapsedTime / duration, 1);
                    const easeOut = 1 - Math.pow(1 - progress, 3);
                    
                    currentRotation = easeOut * spins * 360 + additionalRotation;
                    drawRoulette(currentRotation);

                    if (progress < 1) {
                        requestAnimationFrame(animate);
                    } else {
                        isSpinning = false;
                        spinButton.disabled = false;
                        spinButton.textContent = 'ルーレットを回す';
                        selectPresenter(currentRotation);
                    }
                }

                animate();
            }
        }

        function selectPresenter(finalRotation) {
            const normalizedRotation = finalRotation % 360;
            const sliceAngle = 360 / presenters.length;
            const selectedIndex = (presenters.length - Math.floor(normalizedRotation / sliceAngle) - 1) % presenters.length;
            const selectedPresenter = presenters[selectedIndex];
            
            document.getElementById('result').style.display = 'block';
            document.getElementById('selectedPresenter').textContent = selectedPresenter;
        }

        function drawRoulette(rotation) {
            const centerX = canvas.width / 2;
            const centerY = canvas.height / 2;
            const radius = Math.min(centerX, centerY) - 10;

            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.save();
            ctx.translate(centerX, centerY);
            ctx.rotate((rotation * Math.PI) / 180);

            const sliceAngle = (2 * Math.PI) / presenters.length;
            const colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8'];

            presenters.forEach((presenter, index) => {
                const startAngle = index * sliceAngle;
                const endAngle = startAngle + sliceAngle;

                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.arc(0, 0, radius, startAngle, endAngle);
                ctx.closePath();
                ctx.fillStyle = colors[index % colors.length];
                ctx.fill();

                ctx.save();
                ctx.rotate(startAngle + sliceAngle / 2);
                ctx.textAlign = 'right';
                ctx.fillStyle = '#000';
                ctx.font = 'bold 28px Arial';
                ctx.fillText(presenter, radius - 30, 0);
                ctx.restore();
            });

            ctx.restore();

            // Draw arrow
            ctx.beginPath();
            ctx.moveTo(centerX + radius, centerY);
            ctx.lineTo(centerX + radius + 20, centerY - 10);
            ctx.lineTo(centerX + radius + 20, centerY + 10);
            ctx.closePath();
            ctx.fillStyle = '#333';
            ctx.fill();
        }

        // 初期描画
        drawRoulette(0);
    </script>
</body>
</html>

終わりに

もう、ただただ、便利です。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?