From b03a73b22bd252bbe4ab6098b83132a48de6cf37 Mon Sep 17 00:00:00 2001 From: sebastianmas-cyber Date: Thu, 15 Jan 2026 17:26:07 -0800 Subject: [PATCH 1/3] Added QR Code Scanner Extension --- scratch.qr.code.scanner.js | 112 +++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 scratch.qr.code.scanner.js diff --git a/scratch.qr.code.scanner.js b/scratch.qr.code.scanner.js new file mode 100644 index 0000000000..22ccfd0b5e --- /dev/null +++ b/scratch.qr.code.scanner.js @@ -0,0 +1,112 @@ +(function(Scratch) { + 'use strict'; + + // Load the jsQR library dynamically from a CDN + const script = document.createElement('script'); + script.src = 'https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js'; + document.head.appendChild(script); + + class QRCodeScanner { + constructor() { + this.lastResult = null; + this.detected = false; + this.isScanning = false; + } + + getInfo() { + return { + id: 'qrcodescanner', + name: 'QR Scanner', + color1: '#4C97FF', + color2: '#3373CC', + blocks: [ + { + opcode: 'scanScreen', + blockType: Scratch.BlockType.COMMAND, + text: 'scan screen for QR code' + }, + { + opcode: 'isDetected', + blockType: Scratch.BlockType.BOOLEAN, + text: 'is a QR code detected?' + }, + { + opcode: 'getData', + blockType: Scratch.BlockType.REPORTER, + text: 'QR code data' + } + ] + }; + } + + /** + * Captures the stage using a more robust "frame capture" method. + */ + scanScreen() { + if (typeof jsQR === 'undefined') { + console.warn('QR Scanner: jsQR library not loaded yet.'); + return; + } + + if (this.isScanning) return; + this.isScanning = true; + + const runtime = Scratch.vm.runtime; + const renderer = runtime.renderer; + + if (!renderer || !renderer.canvas) { + console.error('QR Scanner: Renderer or Canvas not found.'); + this.isScanning = false; + return; + } + + try { + const canvas = renderer.canvas; + const width = canvas.width; + const height = canvas.height; + + // Create the off-screen canvas once + const snapshotCanvas = document.createElement('canvas'); + snapshotCanvas.width = width; + snapshotCanvas.height = height; + const ctx = snapshotCanvas.getContext('2d'); + + // FORCE A RENDER: TurboWarp's canvas is often empty between frames. + // We tell the renderer to draw exactly now so the buffer is full. + renderer.draw(); + + // Grab the content immediately after the draw call + ctx.drawImage(canvas, 0, 0); + + const imageData = ctx.getImageData(0, 0, width, height); + + // Scan the pixels + const code = jsQR(imageData.data, width, height, { + inversionAttempts: "dontInvert" + }); + + if (code && code.data) { + this.lastResult = code.data; + this.detected = true; + } else { + this.detected = false; + } + } catch (e) { + console.error('QR Scanner Error:', e); + this.detected = false; + } + + this.isScanning = false; + } + + isDetected() { + return this.detected; + } + + getData() { + return this.detected ? this.lastResult : ""; + } + } + + Scratch.extensions.register(new QRCodeScanner()); +})(Scratch); \ No newline at end of file From 1220f2daa6c629031ccf1a018258dbbdb948d24c Mon Sep 17 00:00:00 2001 From: sebastianmas-cyber Date: Fri, 16 Jan 2026 11:05:44 -0800 Subject: [PATCH 2/3] Update scratch.qr.code.scanner.js Co-authored-by: Brackets-Coder <142950368+Brackets-Coder@users.noreply.github.com> --- scratch.qr.code.scanner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scratch.qr.code.scanner.js b/scratch.qr.code.scanner.js index 22ccfd0b5e..f60978694b 100644 --- a/scratch.qr.code.scanner.js +++ b/scratch.qr.code.scanner.js @@ -15,7 +15,7 @@ getInfo() { return { - id: 'qrcodescanner', + id: 'sweetsebiQR', name: 'QR Scanner', color1: '#4C97FF', color2: '#3373CC', From 86e22e4f876a79f5b7063a858198e645c805bfd7 Mon Sep 17 00:00:00 2001 From: sebastianmas-cyber Date: Fri, 16 Jan 2026 11:05:55 -0800 Subject: [PATCH 3/3] Update scratch.qr.code.scanner.js Co-authored-by: Brackets-Coder <142950368+Brackets-Coder@users.noreply.github.com> --- scratch.qr.code.scanner.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scratch.qr.code.scanner.js b/scratch.qr.code.scanner.js index f60978694b..aab28e8f0f 100644 --- a/scratch.qr.code.scanner.js +++ b/scratch.qr.code.scanner.js @@ -23,17 +23,17 @@ { opcode: 'scanScreen', blockType: Scratch.BlockType.COMMAND, - text: 'scan screen for QR code' + text: Scratch.translate('scan screen for QR code') }, { opcode: 'isDetected', blockType: Scratch.BlockType.BOOLEAN, - text: 'is a QR code detected?' + text: Scratch.translate('is a QR code detected?') }, { opcode: 'getData', blockType: Scratch.BlockType.REPORTER, - text: 'QR code data' + text: Scratch.translate('QR code data') } ] };