File size: 7,183 Bytes
a566fb0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>🕵️‍♂️ Secret Agent Motion Detector</title>
    <style>

        /* CSS: Making it look cool */

        body {

            background-color: #1a1a1a; /* Dark spy background */

            color: #00ff41; /* Hacker green text */

            font-family: 'Courier New', Courier, monospace; /* Typewriter font */

            display: flex;

            flex-direction: column;

            align-items: center;

            min-height: 100vh;

            margin: 0;

            padding: 20px;

        }



        h1 {

            text-shadow: 0 0 10px #00ff41;

            margin-bottom: 10px;

        }



        .instructions {

            background: #222;

            padding: 15px;

            border-radius: 10px;

            border: 1px solid #444;

            max-width: 600px;

            text-align: center;

            margin-bottom: 20px;

            color: #ddd;

        }



        /* The canvas where the magic happens */

        #canvasFinal {

            border: 4px solid #00ff41;

            border-radius: 8px;

            box-shadow: 0 0 20px rgba(0, 255, 65, 0.3);

            background-color: #000;

            max-width: 100%;

            display: none; /* Hidden until camera starts */

        }



        /* Hide the raw video stream and processing canvas */

        #camStream, #canvasHidden {

            display: none;

        }



        button {

            background-color: #00ff41;

            color: #000;

            border: none;

            padding: 15px 30px;

            font-size: 1.2rem;

            font-weight: bold;

            font-family: inherit;

            cursor: pointer;

            border-radius: 5px;

            margin-bottom: 20px;

            transition: all 0.3s;

        }



        button:hover {

            background-color: #fff;

            box-shadow: 0 0 15px #fff;

        }



        .status {

            margin-top: 10px;

            font-size: 0.9rem;

            color: #888;

        }

    </style>
</head>
<body>

    <button id="startBtn" onclick="startSpyCamera()">🚀 Activate Movement Detection Mode</button>
    
    <p class="status" id="statusText">Waiting for activation...</p>

    <!-- These are the HTML elements that handle the video -->
    <video id="camStream" playsinline autoplay></video>
    <canvas id="canvasHidden"></canvas>
    <canvas id="canvasFinal"></canvas>

    <script>

        // JAVASCRIPT: The Brains of the Operation



        // 1. Grab our HTML elements so we can control them

        const video = document.getElementById('camStream');

        const hiddenCanvas = document.getElementById('canvasHidden');

        const finalCanvas = document.getElementById('canvasFinal');

        const startBtn = document.getElementById('startBtn');

        const statusText = document.getElementById('statusText');



        // Contexts are like the "paintbrushes" for the canvas

        const hiddenCtx = hiddenCanvas.getContext('2d');

        const finalCtx = finalCanvas.getContext('2d');



        // We need a place to store the "previous" frame to compare against

        let previousFrameData = null;



        async function startSpyCamera() {

            try {

                // 2. Ask the browser for permission to use the camera

                const stream = await navigator.mediaDevices.getUserMedia({ video: true });

                

                // Connect the camera stream to our hidden video element

                video.srcObject = stream;

                

                // Update the UI

                statusText.innerText = "System Active. Scanning for movement...";

                startBtn.style.display = "none"; // Hide button

                finalCanvas.style.display = "block"; // Show screen



                // Start the loop!

                requestAnimationFrame(processVideo);



            } catch (err) {

                // If they say no or don't have a camera

                statusText.innerText = "⚠️ Error: Could not access camera. Please allow permission.";

                console.error(err);

            }

        }



        function processVideo() {

            // Check if the video is ready and playing

            if (video.readyState === video.HAVE_ENOUGH_DATA) {

                

                // Set canvas sizes to match the video size

                const width = video.videoWidth;

                const height = video.videoHeight;

                hiddenCanvas.width = width;

                hiddenCanvas.height = height;

                finalCanvas.width = width;

                finalCanvas.height = height;



                // 3. Draw the current video frame onto the hidden canvas

                hiddenCtx.drawImage(video, 0, 0, width, height);



                // 4. Get the pixel data (the raw numbers for every color)

                const currentFrame = hiddenCtx.getImageData(0, 0, width, height);

                const currentData = currentFrame.data;

                

                // Create a new image for the result

                const outputImage = finalCtx.createImageData(width, height);

                const outputData = outputImage.data;



                // 5. THE ALGORITHM: Compare this frame to the previous one

                if (previousFrameData) {

                    const prevData = previousFrameData.data;



                    // Loop through every pixel (pixels are groups of 4: Red, Green, Blue, Alpha)

                    for (let i = 0; i < currentData.length; i += 4) {

                        

                        // This math calculates the difference between old and new

                        // If pixels are the same, it turns GREY. 

                        // If they are different, it creates high contrast colors.

                        

                        outputData[i] = 0.5 * (255 - currentData[i]) + 0.5 * prevData[i];     // Red

                        outputData[i+1] = 0.5 * (255 - currentData[i+1]) + 0.5 * prevData[i+1]; // Green

                        outputData[i+2] = 0.5 * (255 - currentData[i+2]) + 0.5 * prevData[i+2]; // Blue

                        outputData[i+3] = 255; // Alpha (Opacity) is always 100%

                    }



                    // Draw the result to the main screen

                    finalCtx.putImageData(outputImage, 0, 0);

                }



                // 6. Save the current frame to be the "previous" frame for next time

                // We clone it so we don't overwrite it immediately

                previousFrameData = new ImageData(

                    new Uint8ClampedArray(currentFrame.data),

                    currentFrame.width,

                    currentFrame.height

                );

            }



            // Repeat this function as fast as the screen can refresh

            requestAnimationFrame(processVideo);

        }

    </script>
</body>
</html>