


Membina pengalaman penjejakan mata masa nyata dengan Supabase dan WebGazer.js
TL;DR:
- Dibina dengan Supabase, React, WebGazer.js, Motion One, anime.js, Audio Stabil
- Memanfaatkan Kehadiran & Siaran Masa Nyata Supabase (tiada jadual pangkalan data digunakan sama sekali!)
- Repositori GitHub
- Tapak web
- Video demo
Satu lagi Hackathon Minggu Pelancaran Supabase dan satu lagi projek percubaan, yang dipanggil Merenung ke dalam Abyss. Ini akhirnya menjadi salah satu projek paling mudah dan kompleks pada masa yang sama. Nasib baik saya telah menikmati Cursor agak baru-baru ini, jadi saya mempunyai beberapa bantuan untuk berjaya! Saya juga ingin mengesahkan soalan dalam fikiran saya: adakah mungkin untuk menggunakan hanya ciri masa nyata daripada Supabase tanpa sebarang jadual pangkalan data? Jawapannya (mungkin agak jelas) ialah: ya, ya (sayangi awak, pasukan Realtime ♥️). Jadi mari kita menyelami sedikit lebih mendalam tentang pelaksanaannya.
Idea
Saya hanya satu hari secara rawak hanya memikirkan petikan Nietzsche tentang jurang dan bahawa adalah bagus (dan sejuk) untuk benar-benar memvisualisasikannya entah bagaimana: anda merenung ke dalam skrin gelap dan sesuatu merenung anda kembali. Tiada apa-apa lagi!
Membina projek
Pada mulanya saya mempunyai idea bahawa saya akan menggunakan Three.js untuk membuat projek ini, namun saya menyedari ini bermakna saya perlu mencipta atau mencari beberapa aset percuma untuk mata 3D. Saya memutuskan bahawa ia agak terlalu banyak, terutamanya kerana saya tidak mempunyai terlalu banyak masa untuk mengerjakan projek itu sendiri, dan sebaliknya memutuskan untuk melakukannya dalam 2D dengan SVG.
Saya juga tidak mahu ia hanya visual: ia akan menjadi pengalaman yang lebih baik dengan beberapa audio juga. Jadi saya mempunyai idea bahawa ia akan menjadi hebat jika peserta boleh bercakap dengan mikrofon dan orang lain boleh mendengarnya sebagai bisikan yang tidak layak atau angin yang berlalu. Ini, bagaimanapun, ternyata sangat mencabar dan memutuskan untuk menggugurkannya sepenuhnya kerana saya tidak dapat menyambungkan WebAudio dan WebRTC bersama-sama dengan baik. Saya mempunyai komponen sisa dalam pangkalan kod yang mendengar mikrofon tempatan dan mencetuskan "bunyi angin" untuk pengguna semasa jika anda ingin melihatnya. Mungkin sesuatu untuk ditambah pada masa hadapan?
Bilik masa nyata
Sebelum mengerjakan sebarang bahan visual, saya ingin menguji persediaan masa nyata yang saya fikirkan. Memandangkan terdapat beberapa batasan dalam ciri masa nyata, saya mahu ia berfungsi supaya:
- Terdapat maks. 10 peserta dalam satu saluran pada satu masa
- bermakna anda perlu menyertai saluran baharu jika saluran itu penuh
- Anda sepatutnya hanya melihat mata peserta lain
Untuk ini saya menghasilkan persediaan useEffect di mana ia bergabung secara rekursif ke saluran masa nyata seperti:
JoinRoom ini tinggal di dalam cangkuk useEffect dan dipanggil apabila komponen bilik dipasang. Satu kaveat yang saya dapati semasa mengusahakan ciri ini ialah param currentPresences tidak mengandungi sebarang nilai dalam acara sertai walaupun ia tersedia. Saya tidak pasti sama ada ia adalah pepijat dalam pelaksanaan atau berfungsi seperti yang dimaksudkan. Oleh itu perlu melakukan pengambilan bilik secara manual.presenceState untuk mendapatkan bilangan peserta dalam bilik apabila pengguna menyertainya.
Kami menyemak kiraan peserta dan sama ada berhenti melanggan bilik semasa dan cuba menyertai bilik lain, atau kemudian meneruskan dengan bilik semasa. Kami melakukan ini dalam acara sertai kerana penyegerakan akan terlambat (ia tercetus selepas menyertai atau meninggalkan acara).
Saya telah menguji pelaksanaan ini dengan membuka banyak tab dalam penyemak imbas saya dan semuanya kelihatan membengkak!
Selepas itu saya ingin menyahpepijat penyelesaian dengan kemas kini kedudukan tetikus dan dengan cepat menghadapi beberapa isu menghantar terlalu banyak mesej dalam saluran! Penyelesaian: pendikit panggilan.
/** * Creates a throttled version of a function that can only be called at most once * in the specified time period. */ function createThrottledFunction<t extends unknown> unknown>( functionToThrottle: T, waitTimeMs: number ): (...args: Parameters<t>) => void { let isWaitingToExecute = false return function throttledFunction(...args: Parameters<t>) { if (!isWaitingToExecute) { functionToThrottle.apply(this, args) isWaitingToExecute = true setTimeout(() => { isWaitingToExecute = false }, waitTimeMs) } } } </t></t></t>
Kursor muncul dengan pencipta fungsi pendikit kecil ini dan saya menggunakannya dengan siaran penjejakan mata seperti ini:
const throttledBroadcast = createThrottledFunction((data: EyeTrackingData) => { if (currentChannel) { currentChannel.send({ type: 'broadcast', event: 'eye_tracking', payload: data }) } }, THROTTLE_MS) throttledBroadcast({ userId: userId.current, isBlinking: isCurrentlyBlinking, gazeX, gazeY })
Ini banyak membantu! Selain itu, dalam versi awal saya mempunyai mesej penjejakan mata yang dihantar dengan kehadiran namun siaran membenarkan lebih banyak mesej sesaat, jadi saya menukar pelaksanaan kepada itu. Ia amat penting dalam penjejakan mata kerana kamera akan merakam segala-galanya sepanjang masa.
Penjejakan mata
Saya telah berjumpa dengan WebGazer.js suatu ketika dahulu apabila saya mula-mula mendapat idea untuk projek ini. Ia adalah projek yang sangat menarik dan berfungsi dengan baik!
Keupayaan pengesanan mata keseluruhan dilakukan dalam satu fungsi dalam cangkuk useEffect:
window.webgazer .setGazeListener(async (data: any) => { if (data == null || !currentChannel || !ctxRef.current) return try { // Get normalized gaze coordinates const gazeX = data.x / windowSize.width const gazeY = data.y / windowSize.height // Get video element const videoElement = document.getElementById('webgazerVideoFeed') as HTMLVideoElement if (!videoElement) { console.error('WebGazer video element not found') return } // Set canvas size to match video imageCanvasRef.current.width = videoElement.videoWidth imageCanvasRef.current.height = videoElement.videoHeight // Draw current frame to canvas ctxRef.current?.drawImage(videoElement, 0, 0) // Get eye patches const tracker = window.webgazer.getTracker() const patches = await tracker.getEyePatches( videoElement, imageCanvasRef.current, videoElement.videoWidth, videoElement.videoHeight ) if (!patches?.right?.patch?.data || !patches?.left?.patch?.data) { console.error('No eye patches detected') return } // Calculate brightness for each eye const calculateBrightness = (imageData: ImageData) => { let total = 0 for (let i = 0; i = SAMPLES_SIZE) { brightnessSamples.current.shift() // Remove oldest sample } brightnessSamples.current.push(avgBrightness) // Calculate dynamic threshold from rolling average const rollingAverage = brightnessSamples.current.reduce((a, b) => a + b, 0) / brightnessSamples.current.length const dynamicThreshold = rollingAverage * THRESHOLD_MULTIPLIER // Detect blink using dynamic threshold const blinkDetected = avgBrightness > dynamicThreshold // Debounce blink detection to avoid rapid changes if (blinkDetected !== isCurrentlyBlinking) { const now = Date.now() if (now - lastBlinkTime > 100) { // Minimum time between blink state changes isCurrentlyBlinking = blinkDetected lastBlinkTime = now } } // Use throttled broadcast instead of direct send throttledBroadcast({ userId: userId.current, isBlinking: isCurrentlyBlinking, gazeX, gazeY }) } catch (error) { console.error('Error processing gaze data:', error) } })
Mendapatkan maklumat di mana pengguna melihat adalah mudah dan berfungsi seperti mendapatkan kedudukan tetikus pada skrin. Walau bagaimanapun, saya juga ingin menambahkan pengesanan kelipan sebagai ciri (sejuk), yang memerlukan melompat melalui beberapa gelung.
Apabila anda menggoogle maklumat tentang WebGazer dan pengesanan berkelip, anda boleh melihat beberapa baki pelaksanaan awal. Seperti terdapat komen keluar kod dalam sumber walaupun. Malangnya keupayaan seperti ini tidak keluar di perpustakaan. Anda perlu melakukannya secara manual.
Selepas banyak percubaan dan ralat, Cursor dan saya dapat menghasilkan penyelesaian yang mengira piksel & tahap kecerahan daripada data patch mata untuk menentukan masa pengguna berkelip. Ia juga mempunyai beberapa pelarasan pencahayaan dinamik kerana saya perhatikan bahawa (sekurang-kurangnya bagi saya) kamera web tidak selalu mengenali apabila anda berkelip bergantung pada pencahayaan anda. Bagi saya ia berfungsi lebih teruk apabila gambar/bilik saya lebih terang dan lebih baik dalam pencahayaan yang lebih gelap (pergi angka).
Semasa menyahpepijat keupayaan penjejakan mata (WebGazer mempunyai panggilan .setPredictionPoints yang sangat bagus yang memaparkan titik merah pada skrin untuk menggambarkan di mana anda sedang melihat), saya mendapati penjejakan itu tidak begitu tepat melainkan anda menentukur itu. Yang mana projek meminta anda lakukan sebelum menyertai mana-mana bilik.
/** * Creates a throttled version of a function that can only be called at most once * in the specified time period. */ function createThrottledFunction<t extends unknown> unknown>( functionToThrottle: T, waitTimeMs: number ): (...args: Parameters<t>) => void { let isWaitingToExecute = false return function throttledFunction(...args: Parameters<t>) { if (!isWaitingToExecute) { functionToThrottle.apply(this, args) isWaitingToExecute = true setTimeout(() => { isWaitingToExecute = false }, waitTimeMs) } } } </t></t></t>
Ia adalah pengalaman yang sangat menarik untuk melihat ini dalam tindakan! Saya menggunakan pendekatan yang sama pada garisan sekeliling dan mengarahkan Kursor untuk "meruntuhkan"nya ke arah tengah: yang ia lakukan hampir sekali dengan sekali jalan!
Mata kemudiannya akan dipaparkan dalam grid CSS ringkas dengan sel dijajarkan supaya bilik penuh kelihatan seperti mata besar.
const throttledBroadcast = createThrottledFunction((data: EyeTrackingData) => { if (currentChannel) { currentChannel.send({ type: 'broadcast', event: 'eye_tracking', payload: data }) } }, THROTTLE_MS) throttledBroadcast({ userId: userId.current, isBlinking: isCurrentlyBlinking, gazeX, gazeY })
Sentuhan akhir
Kemudian tampar beberapa skrin pengenalan dan muzik latar belakang yang bagus dan projek itu boleh dilaksanakan!
Audio sentiasa meningkatkan pengalaman semasa anda mengerjakan perkara seperti ini, jadi saya menggunakan Audio Stabil untuk menjana muzik latar belakang apabila pengguna "memasuki jurang". Gesaan yang saya gunakan untuk muzik itu ialah yang berikut:
Ambien, menyeramkan, muzik latar belakang, bunyi bisikan, angin, tempo perlahan, ngeri, jurang
Saya juga berpendapat bahawa skrin hitam biasa agak membosankan, jadi saya menambah beberapa bahan penapis SVG animasi pada latar belakang. Selain itu, saya menambah bulatan gelap dan kabur di tengah-tengah skrin untuk mempunyai kesan pudar yang bagus. Saya mungkin boleh melakukan ini dengan penapis SVG, namun saya tidak mahu menghabiskan terlalu banyak masa untuk perkara ini. Kemudian untuk mempunyai lebih banyak pergerakan, saya membuat latar belakang berputar pada paksinya. Kadangkala membuat animasi dengan penapis SVG agak sukar, jadi saya memutuskan untuk melakukannya dengan cara ini.
<div> <h2> Kesimpulan </h2> <p>Jadi begitulah: lihat secara lurus ke hadapan tentang cara melaksanakan penjejakan mata yang digayakan dengan keupayaan masa nyata Supabase. Secara peribadi saya dapati percubaan ini sangat menarik dan tidak mengalami terlalu banyak gangguan semasa mengerjakannya. Dan yang menghairankan saya tidak perlu melakukan sepanjang malam untuk malam terakhir sebelum menyerahkan projek!</p> <p>Sila lihat projek atau video demo bagaimana hasilnya. Mungkin terdapat beberapa isu jika sekumpulan orang menggunakannya pada masa yang sama (sangat sukar untuk diuji kerana memerlukan berbilang peranti & kamera web untuk melakukannya dengan betul), tetapi saya rasa itu dalam fesyen projek hackathon? Dan jika anda mengujinya, ingat bahawa jika anda melihat mata, ia adalah orang lain yang memerhati anda di suatu tempat melalui internet!</p> </div>
Atas ialah kandungan terperinci Membina pengalaman penjejakan mata masa nyata dengan Supabase dan WebGazer.js. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Node.js cemerlang pada I/O yang cekap, sebahagian besarnya terima kasih kepada aliran. Aliran memproses data secara berperingkat, mengelakkan beban memori-ideal untuk fail besar, tugas rangkaian, dan aplikasi masa nyata. Menggabungkan sungai dengan keselamatan jenis typescript mencipta powe

Perbezaan prestasi dan kecekapan antara Python dan JavaScript terutamanya dicerminkan dalam: 1) sebagai bahasa yang ditafsirkan, Python berjalan perlahan tetapi mempunyai kecekapan pembangunan yang tinggi dan sesuai untuk pembangunan prototaip pesat; 2) JavaScript adalah terhad kepada benang tunggal dalam penyemak imbas, tetapi I/O multi-threading dan asynchronous boleh digunakan untuk meningkatkan prestasi dalam node.js, dan kedua-duanya mempunyai kelebihan dalam projek sebenar.

JavaScript berasal pada tahun 1995 dan dicipta oleh Brandon Ike, dan menyedari bahasa itu menjadi C. 1.C Language menyediakan keupayaan pengaturcaraan prestasi tinggi dan sistem untuk JavaScript. 2. Pengurusan memori JavaScript dan pengoptimuman prestasi bergantung pada bahasa C. 3. Ciri lintas platform bahasa C membantu JavaScript berjalan dengan cekap pada sistem operasi yang berbeza.

JavaScript berjalan dalam penyemak imbas dan persekitaran Node.js dan bergantung pada enjin JavaScript untuk menghuraikan dan melaksanakan kod. 1) menjana pokok sintaks abstrak (AST) di peringkat parsing; 2) menukar AST ke bytecode atau kod mesin dalam peringkat penyusunan; 3) Laksanakan kod yang disusun dalam peringkat pelaksanaan.

Trend masa depan Python dan JavaScript termasuk: 1. Kedua -duanya akan terus mengembangkan senario aplikasi dalam bidang masing -masing dan membuat lebih banyak penemuan dalam prestasi.

Kedua -dua pilihan Python dan JavaScript dalam persekitaran pembangunan adalah penting. 1) Persekitaran pembangunan Python termasuk Pycharm, Jupyternotebook dan Anaconda, yang sesuai untuk sains data dan prototaip cepat. 2) Persekitaran pembangunan JavaScript termasuk node.js, vscode dan webpack, yang sesuai untuk pembangunan front-end dan back-end. Memilih alat yang betul mengikut keperluan projek dapat meningkatkan kecekapan pembangunan dan kadar kejayaan projek.

Ya, teras enjin JavaScript ditulis dalam C. 1) Bahasa C menyediakan prestasi yang efisien dan kawalan asas, yang sesuai untuk pembangunan enjin JavaScript. 2) Mengambil enjin V8 sebagai contoh, terasnya ditulis dalam C, menggabungkan kecekapan dan ciri-ciri berorientasikan objek C. 3) Prinsip kerja enjin JavaScript termasuk parsing, penyusun dan pelaksanaan, dan bahasa C memainkan peranan penting dalam proses ini.

JavaScript adalah di tengah -tengah laman web moden kerana ia meningkatkan interaktiviti dan dinamik laman web. 1) Ia membolehkan untuk menukar kandungan tanpa menyegarkan halaman, 2) memanipulasi laman web melalui Domapi, 3) menyokong kesan interaktif kompleks seperti animasi dan drag-and-drop, 4) mengoptimumkan prestasi dan amalan terbaik untuk meningkatkan pengalaman pengguna.


Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

ZendStudio 13.5.1 Mac
Persekitaran pembangunan bersepadu PHP yang berkuasa

mPDF
mPDF ialah perpustakaan PHP yang boleh menjana fail PDF daripada HTML yang dikodkan UTF-8. Pengarang asal, Ian Back, menulis mPDF untuk mengeluarkan fail PDF "dengan cepat" dari tapak webnya dan mengendalikan bahasa yang berbeza. Ia lebih perlahan dan menghasilkan fail yang lebih besar apabila menggunakan fon Unicode daripada skrip asal seperti HTML2FPDF, tetapi menyokong gaya CSS dsb. dan mempunyai banyak peningkatan. Menyokong hampir semua bahasa, termasuk RTL (Arab dan Ibrani) dan CJK (Cina, Jepun dan Korea). Menyokong elemen peringkat blok bersarang (seperti P, DIV),

SecLists
SecLists ialah rakan penguji keselamatan muktamad. Ia ialah koleksi pelbagai jenis senarai yang kerap digunakan semasa penilaian keselamatan, semuanya di satu tempat. SecLists membantu menjadikan ujian keselamatan lebih cekap dan produktif dengan menyediakan semua senarai yang mungkin diperlukan oleh penguji keselamatan dengan mudah. Jenis senarai termasuk nama pengguna, kata laluan, URL, muatan kabur, corak data sensitif, cangkerang web dan banyak lagi. Penguji hanya boleh menarik repositori ini ke mesin ujian baharu dan dia akan mempunyai akses kepada setiap jenis senarai yang dia perlukan.

Penyesuai Pelayan SAP NetWeaver untuk Eclipse
Integrasikan Eclipse dengan pelayan aplikasi SAP NetWeaver.

MinGW - GNU Minimalis untuk Windows
Projek ini dalam proses untuk dipindahkan ke osdn.net/projects/mingw, anda boleh terus mengikuti kami di sana. MinGW: Port Windows asli bagi GNU Compiler Collection (GCC), perpustakaan import yang boleh diedarkan secara bebas dan fail pengepala untuk membina aplikasi Windows asli termasuk sambungan kepada masa jalan MSVC untuk menyokong fungsi C99. Semua perisian MinGW boleh dijalankan pada platform Windows 64-bit.
