- Home
- Skills
- Workflow Automation
- Premium Offline QR Code Studio: Zero Dependencies
Works with the AI Agents you already use
Premium Offline QR Code Studio: Zero Dependencies
Generate private, offline, and print-ready QR codes for Wi-Fi, vCards, and URLs using a self-contained HTML studio.
$4.99
Premium Offline QR Code Studio: Zero Dependencies
Example session with this skill installed
"Create a QR code for our office guest Wi-Fi. Network name is Acme-Guest, password is Welcome2026!, and security is WPA2. We plan to print this on small desk cards and laminate them, so make sure the error correction is strong enough to handle scratches."
- Read your context and instructions
- Compiled the premium offline qr
I'll build an offline QR studio for your guest Wi-Fi with the highest error correction level (H), starting by checking for the bundled template.
The template isn't in this workspace, so I'll use the skill's fallback: a self-contained HTML studio with an inline encoder. I'll also verify it by decoding the output.
The Wi-Fi code decodes correctly. Three large synthetic test codes failed, so I'll check whether that's my encoder or the decoder being picky.
Your QR studio is ready: qr-wifi-acme-guest.html opens in any browser, works fully offline, and loads nothing external.
Payload encoded
WIFI:T:WPA;S:Acme-Guest;P:Welcome2026!;H:false;;
WPA2 uses the standard WPA type. The network is marked visible (H:false).
Error correction: H (30%)
This is the strongest level. It still scans with up to roughly 30% of the code damaged, which suits scratches and lamination glare. The code comes out small (version 6, 41×41 modules), so the modules stay large on a desk card.
Using the file
- It opens already filled in with your network, with a ready-to-print card. Edit the fields to change anything.
Download SVG gives a vector file for print shops.
Download PNG (HD) gives a high-resolution image.
Print card prints just the card.
- The password is not printed on the card by default. Tick "Print password under the code" if you want it shown as a fallback.
Checks and notes
- The skill's bundled template wasn't available, so the file includes its own inline encoder. I decoded your exact Wi-Fi code with an independent decoder (used for testing only) and it returned the original payload.
- I also tested 24 other synthetic codes across all four error-correction levels. All decode correctly with OpenCV's more robust (ArUco-based) QR detector. OpenCV's older, basic detector failed on three of the large ones, which I put down to the detector rather than the encoder.
- When you print, keep the white border around the code and use a light background with a dark foreground. Scan one test card with an Android and an iPhone before laminating a batch.
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>QR Studio - Acme-Guest Wi-Fi</title>
<style>
:root{--bg:#f5f6f8;--panel:#fff;--ink:#1b1f27;--muted:#667085;--line:#e3e6ec;--accent:#2f5bea}
*{box-sizing:border-box}
body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;background:var(--bg);color:var(--ink)}
header{padding:20px 24px 0}
header h1{margin:0;font-size:20px}
header p{margin:4px 0 0;color:var(--muted);font-size:13px}
main{display:grid;grid-template-columns:minmax(280px,380px) 1fr;gap:20px;padding:20px 24px 32px;max-width:1000px;margin:0 auto}
@media(max-width:760px){main{grid-template-columns:1fr}}
.panel{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:18px}
label{display:block;font-size:12px;font-weight:600;color:var(--muted);margin:12px 0 4px}
label:first-child{margin-top:0}
input[type=text],input[type=password],select,textarea{width:100%;padding:9px 10px;border:1px solid var(--line);border-radius:8px;font:inherit;font-size:14px;background:#fff;color:var(--ink)}
textarea{min-height:90px;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:12px}
.row{display:flex;gap:10px}.row>*{flex:1}
.check{display:flex;align-items:center;gap:8px;margin-top:12px;font-size:13px;color:var(--ink);font-weight:500}
.tabs{display:flex;gap:6px;margin-bottom:14px}
.tabs button{flex:1;padding:8px;border:1px solid var(--line);background:#fff;border-radius:8px;cursor:pointer;font:inherit;font-size:13px}
.tabs button.on{background:var(--accent);border-color:var(--accent);color:#fff}
.stage{display:flex;flex-direction:column;align-items:center;gap:16px}
#card{background:#fff;border:1px solid var(--line);border-radius:14px;padding:22px 26px;width:100%;max-width:360px;text-align:center}
#card .title{font-size:18px;font-weight:700;margin-bottom:2px}
#card .sub{font-size:13px;color:var(--muted);margin-bottom:14px}
#qr svg{width:100%;height:auto;display:block}
#card .net{margin-top:12px;font-size:14px;font-weight:600}
#card .pw{margin-top:2px;font-size:13px;font-family:ui-monospace,Menlo,Consolas,monospace}
.actions{display:flex;flex-wrap:wrap;gap:8px;justify-content:center}
.actions button{padding:9px 14px;border-radius:8px;border:1px solid var(--accent);background:var(--accent);color:#fff;font:inherit;font-size:13px;cursor:pointer}
.actions button.alt{background:#fff;color:var(--accent)}
#meta{font-size:12px;color:var(--muted);text-align:center}
#err{color:#b42318;font-size:13px;text-align:center;min-height:18px}
@media print{
body{background:#fff}header,.panel,.actions,#meta,#err{display:none!important}
main{display:block;padding:0}.stage{display:block}
#card{border:1px dashed #999;margin:0 auto;max-width:6.5cm;padding:.4cm}
}
</style>
</head>
<body>
<header>
<h1>QR Code Studio</h1>
<p>Runs entirely in your browser. Nothing is uploaded or sent anywhere.</p>
</header>
<main>
<section class="panel">
<div class="tabs">
<button id="tabWifi" class="on" type="button">Wi-Fi</button>
<button id="tabRaw" type="button">Custom text</button>
</div>
<div id="wifiForm">
<label for="ssid">Network name (SSID)</label>
<input type="text" id="ssid" value="Acme-Guest" autocomplete="off">
<label for="pw">Password</label>
<input type="text" id="pw" value="Welcome2026!" autocomplete="off">
<label for="sec">Security</label>
<select id="sec">
<option value="WPA" selected>WPA / WPA2 / WPA3</option>
<option value="WEP">WEP</option>
<option value="nopass">None (open)</option>
</select>
<div class="check"><input type="checkbox" id="hidden"><span>Hidden network</span></div>
</div>
<div id="rawForm" style="display:none">
<label for="raw">Text or URL to encode</label>
<textarea id="raw">https://</textarea>
</div>
<label for="ecl">Error correction</label>
<select id="ecl">
<option value="L">L - 7%</option>
<option value="M">M - 15%</option>
<option value="Q">Q - 25%</option>
<option value="H" selected>H - 30% (best for print / lamination)</option>
</select>
<div class="row">
<div><label for="fg">Foreground</label><input type="text" id="fg" value="#000000"></div>
<div><label for="bg">Background</label><input type="text" id="bg" value="#ffffff"></div>
</div>
<div class="check"><input type="checkbox" id="showpw"><span>Print password under the code</span></div>
<label for="cardTitle">Card heading</label>
<input type="text" id="cardTitle" value="Scan to join guest Wi-Fi">
</section>
<section class="stage">
<div id="card">
<div class="title" id="cTitle"></div>
<div class="sub">Point your phone camera at the code</div>
<div id="qr"></div>
<div class="net" id="cNet"></div>
<div class="pw" id="cPw"></div>
</div>
<div id="err"></div>
<div class="actions">
<button type="button" id="dlSvg">Download SVG</button>
<button type="button" id="dlPng" class="alt">Download PNG (HD)</button>
<button type="button" id="print" class="alt">Print card</button>
</div>
<div id="meta"></div>
</section>
</main>
<script id="qr-core">
/* Minimal QR Code encoder (byte mode, versions 1-40, ECC L/M/Q/H). Zero dependencies. */
var QR=(function(){
'use strict';
var ECC_CW=[
[-1,7,10,15,20,26,18,20,24,30,18,20,24,26,30,22,24,28,30,28,28,28,28,30,30,26,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],
[-1,10,16,26,18,24,16,18,22,22,26,30,22,22,24,24,28,28,26,26,26,26,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28],
[-1,13,22,18,26,18,24,18,22,20,24,28,26,24,20,30,24,28,28,26,30,28,30,30,30,30,28,30,30,30,30,30,30,30,30,30,30,30,30,30,30],
[-1,17,28,22,16,22,28,26,26,24,28,24,28,22,24,24,30,28,28,26,28,30,24,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30]];
var NUM_BLK=[
[-1,1,1,1,1,1,2,2,2,2,4,4,4,4,4,6,6,6,6,7,8,8,9,9,10,12,12,12,13,14,15,16,17,18,19,19,20,21,22,24,25],
[-1,1,1,1,2,2,4,4,4,5,5,5,8,9,9,10,10,11,13,14,16,17,17,18,20,21,23,25,26,28,29,31,33,35,37,38,40,43,45,47,49],
[-1,1,1,2,2,4,4,6,6,8,8,8,10,12,16,12,17,16,18,21,20,23,23,25,27,29,34,34,35,38,40,43,45,48,51,53,56,59,62,65,68],
[-1,1,1,2,4,4,4,5,6,8,8,11,11,16,16,18,16,19,21,25,25,25,34,30,32,35,37,40,42,45,48,51,54,57,60,63,66,70,74,77,81]];
var ECL={L:{o:0,f:1},M:{o:1,f:0},Q:{o:2,f:3},H:{o:3,f:2}};
function rawModules(v){
var r=(16*v+128)*v+64;
if(v>=2){var n=Math.floor(v/7)+2;r-=(25*n-10)*n-55;if(v>=7)r-=36;}
return r;
}
function dataCw(v,e){return Math.floor(rawModules(v)/8)-ECC_CW[e][v]*NUM_BLK[e][v];}
function mul(x,y){var z=0;for(var i=7;i>=0;i--){z=(z<<1)^((z>>>7)*0x11D);z^=((y>>>i)&1)*x;}return z;}
function divisor(d){
var r=[],i,j;for(i=0;i<d-1;i++)r.push(0);r.push(1);
var root=1;
for(i=0;i<d;i++){for(j=0;j<d;j++){r[j]=mul(r[j],root);if(j+1<d)r[j]^=r[j+1];}root=mul(root,2);}
return r;
}
function remainder(data,div){
var r=div.map(function(){return 0;});
data.forEach(function(b){
var f=b^r.shift();r.push(0);
div.forEach(function(c,i){r[i]^=mul(c,f);});
});
return r;
}
function bit(x,i){return((x>>>i)&1)!==0;}
function encode(text,eclName){
var e=ECL[eclName].o,bytes=Array.prototype.slice.call(new TextEncoder().encode(text));
var ver,cc;
for(ver=1;;ver++){
if(ver>40)throw new Error('Text is too long for a QR code at this error-correction level.');
cc=ver<=9?8:16;
if(bytes.length>=(1<<cc))continue;
if(4+cc+8*bytes.length<=dataCw(ver,e)*8)break;
}
var bits=[];
function push(v,n){for(var i=n-1;i>=0;i--)bits.push((v>>>i)&1);}
push(4,4);push(bytes.length,cc);bytes.forEach(function(b){push(b,8);});
var cap=dataCw(ver,e)*8;
push(0,Math.min(4,cap-bits.length));
push(0,(8-bits.length%8)%8);
var dc=[],i;
for(i=0;i<bits.length;i++){if(i%8===0)dc.push(0);dc[i>>>3]|=bits[i]<<(7-(i&7));}
for(var pad=0xEC;dc.length<cap/8;pad^=0xEC^0x11)dc.push(pad);
/* ECC + interleave */
var nb=NUM_BLK[e][ver],bel=ECC_CW[e][ver],raw=Math.floor(rawModules(ver)/8);
var nShort=nb-raw%nb,shortLen=Math.floor(raw/nb),blocks=[],div=divisor(bel),k=0;
for(i=0;i<nb;i++){
var dat=dc.slice(k,k+shortLen-bel+(i<nShort?0:1));k+=dat.length;
var ecc=remainder(dat,div);
if(i<nShort)dat.push(0);
blocks.push(dat.concat(ecc));
}
var all=[];
for(i=0;i<blocks[0].length;i++){
blocks.forEach(function(blk,j){if(i!==shortLen-bel||j>=nShort)all.push(blk[i]);});
}
/* Matrix */
var size=ver*4+17,mod=[],fn=[],y,x;
for(y=0;y<size;y++){mod.push(new Array(size).fill(false));fn.push(new Array(size).fill(false));}
function setFn(x,y,d){mod[y][x]=d;fn[y][x]=true;}
function finder(cx,cy){
for(var dy=-4;dy<=4;dy++)for(var dx=-4;dx<=4;dx++){
var d=Math.max(Math.abs(dx),Math.abs(dy)),xx=cx+dx,yy=cy+dy;
if(xx>=0&&xx<size&&yy>=0&&yy<size)setFn(xx,yy,d!==2&&d!==4);
}
}
function align(cx,cy){
for(var dy=-2;dy<=2;dy++)for(var dx=-2;dx<=2;dx++)setFn(cx+dx,cy+dy,Math.max(Math.abs(dx),Math.abs(dy))!==1);
}
function formatBits(mask){
var data=(ECL[eclName].f<<3)|mask,rem=data,i;
for(i=0;i<10;i++)rem=(rem<<1)^((rem>>>9)*0x537);
var b=((data<<10)|rem)^0x5412;
for(i=0;i<=5;i++)setFn(8,i,bit(b,i));
setFn(8,7,bit(b,6));setFn(8,8,bit(b,7));setFn(7,8,bit(b,8));
for(i=9;i<15;i++)setFn(14-i,8,bit(b,i));
for(i=0;i<8;i++)setFn(size-1-i,8,bit(b,i));
for(i=8;i<15;i++)setFn(8,size-15+i,bit(b,i));
setFn(8,size-8,true);
}
for(i=0;i<size;i++){setFn(6,i,i%2===0);setFn(i,6,i%2===0);}
finder(3,3);finder(size-4,3);finder(3,size-4);
var pos=[];
if(ver>1){
var na=Math.floor(ver/7)+2,step=ver===32?26:Math.ceil((ver*4+4)/(na*2-2))*2;
pos=[6];for(var p=size-7;pos.length<na;p-=step)pos.splice(1,0,p);
for(i=0;i<na;i++)for(var j=0;j<na;j++){
if((i===0&&j===0)||(i===0&&j===na-1)||(i===na-1&&j===0))continue;
align(pos[i],pos[j]);
}
}
formatBits(0);
if(ver>=7){
var rem=ver;for(i=0;i<12;i++)rem=(rem<<1)^((rem>>>11)*0x1F25);
var vb=(ver<<12)|rem;
for(i=0;i<18;i++){var c=bit(vb,i),a=size-11+i%3,b2=Math.floor(i/3);setFn(a,b2,c);setFn(b2,a,c);}
}
/* Codewords */
var n=0;
for(var right=size-1;right>=1;right-=2){
if(right===6)right=5;
for(var vert=0;vert<size;vert++)for(var jj=0;jj<2;jj++){
x=right-jj;y=((right+1)&2)===0?size-1-vert:vert;
if(!fn[y][x]&&n<all.length*8){mod[y][x]=bit(all[n>>>3],7-(n&7));n++;}
}
}
function applyMask(m){
for(y=0;y<size;y++)for(x=0;x<size;x++){
var inv;
switch(m){
case 0:inv=(x+y)%2===0;break;
case 1:inv=y%2===0;break;
case 2:inv=x%3===0;break;
case 3:inv=(x+y)%3===0;break;
case 4:inv=(Math.floor(x/3)+Math.floor(y/2))%2===0;break;
case 5:inv=x*y%2+x*y%3===0;break;
case 6:inv=(x*y%2+x*y%3)%2===0;break;
default:inv=((x+y)%2+x*y%3)%2===0;
}
if(!fn[y][x]&&inv)mod[y][x]=!mod[y][x];
}
}
var P1=[1,0,1,1,1,0,1,0,0,0,0],P2=[0,0,0,0,1,0,1,1,1,0,1];
function penalty(){
var pen=0,r,c,t,line;
function lineScore(get){
var s=0,run=1,k2;
for(k2=1;k2<size;k2++){
if(get(k2)===get(k2-1))run++;else{if(run>=5)s+=run-2;run=1;}
}
if(run>=5)s+=run-2;
for(k2=0;k2+11<=size;k2++){
var m1=true,m2=true;
for(var q=0;q<11;q++){var v=get(k2+q)?1:0;if(v!==P1[q])m1=false;if(v!==P2[q])m2=false;}
if(m1)s+=40;if(m2)s+=40;
}
return s;
}
for(r=0;r<size;r++)pen+=lineScore(function(k2){return mod[r][k2];});
for(c=0;c<size;c++)pen+=lineScore(function(k2){return mod[k2][c];});
var dark=0;
for(r=0;r<size;r++)for(c=0;c<size;c++){
if(mod[r][c])dark++;
if(r+1<size&&c+1<size&&mod[r][c]===mod[r][c+1]&&mod[r][c]===mod[r+1][c]&&mod[r][c]===mod[r+1][c+1])pen+=3;
}
var total=size*size;
pen+=(Math.ceil(Math.abs(dark*20-total*10)/total)-1)*10;
return pen;
}
var best=0,bestPen=Infinity;
for(var m=0;m<8;m++){
applyMask(m);formatBits(m);
var pn=penalty();
if(pn<bestPen){bestPen=pn;best=m;}
applyMask(m);
}
applyMask(best);formatBits(best);
return{size:size,version:ver,mask:best,modules:mod};
}
return{encode:encode};
})();
if(typeof module!=='undefined')module.exports=QR;
</script>
<script id="studio">
(function(){
var $=function(id){return document.getElementById(id);};
var mode='wifi',current=null;
function esc(s){return s.replace(/([\\;,:"])/g,'\\$1');}
function payload(){
if(mode==='raw')return $('raw').value;
var t=$('sec').value;
return 'WIFI:T:'+t+';S:'+esc($('ssid').value)+';'+(t==='nopass'?'':'P:'+esc($('pw').value)+';')+'H:'+($('hidden').checked?'true':'false')+';;';
}
function cleanColor(v,fallback){return /^#[0-9a-fA-F]{3,8}$/.test(v.trim())?v.trim():fallback;}
function svgString(qr,quiet,fg,bg){
var n=qr.size+quiet*2,d=[],x,y;
for(y=0;y<qr.size;y++)for(x=0;x<qr.size;x++)
if(qr.modules[y][x])d.push('M'+(x+quiet)+','+(y+quiet)+'h1v1h-1z');
return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 '+n+' '+n+'" shape-rendering="crispEdges">'+
'<rect width="'+n+'" height="'+n+'" fill="'+bg+'"/><path d="'+d.join('')+'" fill="'+fg+'"/></svg>';
}
function render(){
var text=payload(),ecl=$('ecl').value;
$('err').textContent='';
try{
current=QR.encode(text,ecl);
}catch(e){
current=null;$('qr').innerHTML='';$('err').textContent=e.message;return;
}
var fg=cleanColor($('fg').value,'#000000'),bg=cleanColor($('bg').value,'#ffffff');
$('qr').innerHTML=svgString(current,4,fg,bg);
$('cTitle').textContent=$('cardTitle').value;
$('cNet').textContent=mode==='wifi'?'Network: '+$('ssid').value:'';
$('cPw').textContent=(mode==='wifi'&&$('showpw').checked&&$('sec').value!=='nopass')?'Password: '+$('pw').value:'';
$('meta').textContent='Version '+current.version+' ('+current.size+'x'+current.size+' modules), error correction '+ecl+', mask '+current.mask;
}
function download(name,blob){
var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download=name;
document.body.appendChild(a);a.click();a.remove();
setTimeout(function(){URL.revokeObjectURL(a.href);},1000);
}
$('dlSvg').onclick=function(){
if(!current)return;
var s=svgString(current,4,cleanColor($('fg').value,'#000000'),cleanColor($('bg').value,'#ffffff'));
download('qr-code.svg',new Blob([s],{type:'image/svg+xml'}));
};
$('dlPng').onclick=function(){
if(!current)return;
var quiet=4,n=current.size+quiet*2,scale=Math.max(1,Math.floor(2400/n)),px=n*scale;
var c=document.createElement('canvas');c.width=c.height=px;
var g=c.getContext('2d');
g.fillStyle=cleanColor($('bg').value,'#ffffff');g.fillRect(0,0,px,px);
g.fillStyle=cleanColor($('fg').value,'#000000');
for(var y=0;y<current.size;y++)for(var x=0;x<current.size;x++)
if(current.modules[y][x])g.fillRect((x+quiet)*scale,(y+quiet)*scale,scale,scale);
c.toBlob(function(b){download('qr-code.png',b);},'image/png');
};
$('print').onclick=function(){window.print();};
function setMode(m){
mode=m;
$('tabWifi').className=m==='wifi'?'on':'';$('tabRaw').className=m==='raw'?'on':'';
$('wifiForm').style.display=m==='wifi'?'':'none';$('rawForm').style.display=m==='raw'?'':'none';
render();
}
$('tabWifi').onclick=function(){setMode('wifi');};
$('tabRaw').onclick=function(){setMode('raw');};
['ssid','pw','sec','hidden','raw','ecl','fg','bg','showpw','cardTitle'].forEach(function(id){
$(id).addEventListener('input',render);$(id).addEventListener('change',render);
});
render();
})();
</script>
</body>
</html>
Connects securely to your tools. The creator never sees your data.
About this skill
Transform your AI agent into a privacy-first, production-grade QR code generator.
Most AI QR code generators either hallucinate broken checkerboard patterns or secretly leak your sensitive data (like Wi-Fi passwords and personal vCards) to third-party APIs. This premium SKILL.md specification forces your agent to build a 100% offline, zero-dependency HTML Studio directly in your browser or local environment.
Whether you are generating high-durability codes for printed laminated desk cards or vector graphics for a corporate brochure, this skill guarantees mathematically perfect, scannable matrices every time.
Key Features & Capabilities
Absolute Privacy (Air-Gapped Ready): No external APIs (qrserver), no Python libraries (segno), and no Node.js packages. Everything is generated locally using pure Vanilla JS/HTML.
Smart Payload Schemas: Automatically formats complex payloads flawlessly, including Wi-Fi Credentials (WEP/WPA), vCard 3.0 Contact Info, SMS, Email, and Geographic coordinates.
Hybrid Environment Execution
In Web UI (e.g., Claude Web): Renders a fully interactive UI Artifact right in the chat where you can live-edit colors, error correction, and payloads.
In CLI (e.g., Claude Code, Cursor): Silently writes a self-contained .html studio file directly to your local drive.
Print-Ready Exports: Features built-in buttons to download your generated QR codes as Ultra-HD 2048px PNGs or True-Vector SVGs with the mandatory 4-module quiet zone preserved.
Dynamic Error Correction (ECL): Automatically defaults to Level H (30% damage tolerance) for physical prints and Level M (15%) for digital screens.
What You Get
A meticulously engineered, battle-tested SKILL.md file ready to be dropped into your AI agent's system prompts or workspace. Leave the prompt engineering behind and get foolproof QR codes instantly.
How to use
Skills on Agensi run inside your AI agent. Copy the prompt, paste it into your agent, and it connects to Agensi and installs this skill for you. If a payment is needed, your agent shows it to you first.
Reviews
No reviews yet
Be one of the first to try it. Every listed skill passes our trust checks below.
Security scanned
Passed our 8-point scan before listing
Fresh listing
Recently published to Agensi
Money-back guarantee
Doesn't do what its page promises? You get your money back.
Trust & safety
Security scanned
Verified clean today
- Passed all security checks, Safe to install
Requires