Loopback

This is really lame :)

Uses QR encoding library from Project Nayuki (nayuki.io/)

Log in to post a comment.

/* 
 * QR Code generator library (JavaScript)
 * 
 * Copyright (c) Project Nayuki. (MIT License)
 * https://www.nayuki.io/page/qr-code-generator-library
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * - The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 * - The Software is provided "as is", without warranty of any kind, express or
 *   implied, including but not limited to the warranties of merchantability,
 *   fitness for a particular purpose and noninfringement. In no event shall the
 *   authors or copyright holders be liable for any claim, damages or other
 *   liability, whether in an action of contract, tort or otherwise, arising from,
 *   out of or in connection with the Software or the use or other dealings in the
 *   Software.
 */
var qrcodegen=new function(){this.QrCode=function(v,g,t,r){if(v<C||R<v)throw"Version value out of range";if(r<-1||7<r)throw"Mask value out of range";if(!(g instanceof N))throw"QrCode.Ecc expected";for(var u=4*v+17,e=[],n=0;n<u;n++)e.push(!1);var f=[],h=[];for(n=0;n<u;n++)f.push(e.slice()),h.push(e.slice());if(function(){for(var t=0;t<u;t++)l(6,t,t%2==0),l(t,6,t%2==0);s(3,3),s(u-4,3),s(3,u-4);for(var r=function(){{if(1==v)return[];for(var t=Math.floor(v/7)+2,r=32==v?26:2*Math.ceil((u-13)/(2*t-2)),e=[6],n=u-7;e.length<t;n-=r)e.splice(1,0,n);return e}}(),e=r.length,t=0;t<e;t++)for(var n=0;n<e;n++)0==t&&0==n||0==t&&n==e-1||t==e-1&&0==n||c(r[t],r[n]);i(0),function(){if(v<7)return;for(var t=v,r=0;r<12;r++)t=t<<1^7973*(t>>>11);var e=v<<12|t;if(e>>>18!=0)throw"Assertion error";for(var r=0;r<18;r++){var n=m(e,r),o=u-11+r%3,a=Math.floor(r/3);l(o,a,n),l(a,o,n)}}()}(),function(t){if(t.length!=Math.floor(p.getNumRawDataModules(v)/8))throw"Invalid argument";for(var r=0,e=u-1;1<=e;e-=2){6==e&&(e=5);for(var n=0;n<u;n++)for(var o=0;o<2;o++){var a=e-o,i=0==(e+1&2),s=i?u-1-n:n;!h[s][a]&&r<8*t.length&&(f[s][a]=m(t[r>>>3],7-(7&r)),r++)}}if(r!=8*t.length)throw"Assertion error"}(function(t){if(t.length!=p.getNumDataCodewords(v,g))throw"Invalid argument";for(var r=p.NUM_ERROR_CORRECTION_BLOCKS[g.ordinal][v],e=p.ECC_CODEWORDS_PER_BLOCK[g.ordinal][v],n=Math.floor(p.getNumRawDataModules(v)/8),o=r-n%r,a=Math.floor(n/r),i=[],s=new A(e),h=0,u=0;h<r;h++){var f=t.slice(u,u+a-e+(h<o?0:1));u+=f.length;var c=s.getRemainder(f);h<o&&f.push(0),i.push(f.concat(c))}for(var l=[],h=0;h<i[0].length;h++)for(var d=0;d<i.length;d++)(h!=a-e||o<=d)&&l.push(i[d][h]);if(l.length!=n)throw"Assertion error";return l}(t)),-1==r){var o=1/0;for(n=0;n<8;n++){d(n),i(n);var a=E();a<o&&(r=n,o=a),d(n)}}if(r<0||7<r)throw"Assertion error";function i(t){for(var r=g.formatBits<<3|t,e=r,n=0;n<10;n++)e=e<<1^1335*(e>>>9);var o=21522^(r<<10|e);if(o>>>15!=0)throw"Assertion error";for(n=0;n<=5;n++)l(8,n,m(o,n));l(8,7,m(o,6)),l(8,8,m(o,7)),l(7,8,m(o,8));for(n=9;n<15;n++)l(14-n,8,m(o,n));for(n=0;n<8;n++)l(u-1-n,8,m(o,n));for(n=8;n<15;n++)l(8,u-15+n,m(o,n));l(8,u-8,!0)}function s(t,r){for(var e=-4;e<=4;e++)for(var n=-4;n<=4;n++){var o=Math.max(Math.abs(n),Math.abs(e)),a=t+n,i=r+e;0<=a&&a<u&&0<=i&&i<u&&l(a,i,2!=o&&4!=o)}}function c(t,r){for(var e=-2;e<=2;e++)for(var n=-2;n<=2;n++)l(t+n,r+e,1!=Math.max(Math.abs(n),Math.abs(e)))}function l(t,r,e){f[r][t]=e,h[r][t]=!0}function d(t){if(t<0||7<t)throw"Mask value out of range";for(var r=0;r<u;r++)for(var e=0;e<u;e++){var n;switch(t){case 0:n=(e+r)%2==0;break;case 1:n=r%2==0;break;case 2:n=e%3==0;break;case 3:n=(e+r)%3==0;break;case 4:n=(Math.floor(e/3)+Math.floor(r/2))%2==0;break;case 5:n=e*r%2+e*r%3==0;break;case 6:n=(e*r%2+e*r%3)%2==0;break;case 7:n=((e+r)%2+e*r%3)%2==0;break;default:throw"Assertion error"}!h[r][e]&&n&&(f[r][e]=!f[r][e])}}function E(){for(var t=0,r=0;r<u;r++){for(var e=[0,0,0,0,0,0,0],n=!1,o=0,a=0;a<u;a++)f[r][a]==n?5==++o?t+=p.PENALTY_N1:5<o&&t++:(p.addRunToHistory(o,e),!n&&p.hasFinderLikePattern(e)&&(t+=p.PENALTY_N3),n=f[r][a],o=1);p.addRunToHistory(o,e),n&&p.addRunToHistory(0,e),p.hasFinderLikePattern(e)&&(t+=p.PENALTY_N3)}for(a=0;a<u;a++){e=[0,0,0,0,0,0,0],n=!1;var i=0;for(r=0;r<u;r++)f[r][a]==n?5==++i?t+=p.PENALTY_N1:5<i&&t++:(p.addRunToHistory(i,e),!n&&p.hasFinderLikePattern(e)&&(t+=p.PENALTY_N3),n=f[r][a],i=1);p.addRunToHistory(i,e),n&&p.addRunToHistory(0,e),p.hasFinderLikePattern(e)&&(t+=p.PENALTY_N3)}for(r=0;r<u-1;r++)for(a=0;a<u-1;a++){(n=f[r][a])==f[r][a+1]&&n==f[r+1][a]&&n==f[r+1][a+1]&&(t+=p.PENALTY_N2)}var s=0;f.forEach(function(t){t.forEach(function(t){t&&s++})});var h=u*u;return t+=(Math.ceil(Math.abs(20*s-10*h)/h)-1)*p.PENALTY_N4}function m(t,r){return 0!=(t>>>r&1)}d(r),i(r),h=null,Object.defineProperty(this,"version",{value:v}),Object.defineProperty(this,"size",{value:u}),Object.defineProperty(this,"errorCorrectionLevel",{value:g}),Object.defineProperty(this,"mask",{value:r}),this.getModule=function(t,r){return 0<=t&&t<u&&0<=r&&r<u&&f[r][t]}},this.QrCode.encodeText=function(t,r){var e=qrcodegen.QrSegment.makeSegments(t);return this.encodeSegments(e,r)},this.QrCode.encodeSegments=function(t,r,e,n,o,a){if(null==e&&(e=C),null==n&&(n=R),null==o&&(o=-1),null==a&&(a=!0),!(C<=e&&e<=n&&n<=R)||o<-1||7<o)throw"Invalid value";var i,s;for(i=e;;i++){var h=8*p.getNumDataCodewords(i,r);if((s=qrcodegen.QrSegment.getTotalBits(t,i))<=h)break;if(n<=i)throw"Data too long"}[this.Ecc.MEDIUM,this.Ecc.QUARTILE,this.Ecc.HIGH].forEach(function(t){a&&s<=8*p.getNumDataCodewords(i,t)&&(r=t)});var u=new l;if(t.forEach(function(t){u.appendBits(t.mode.modeBits,4),u.appendBits(t.numChars,t.mode.numCharCountBits(i)),t.getData().forEach(function(t){u.push(t)})}),u.length!=s)throw"Assertion error";h=8*p.getNumDataCodewords(i,r);if(u.length>h)throw"Assertion error";if(u.appendBits(0,Math.min(4,h-u.length)),u.appendBits(0,(8-u.length%8)%8),u.length%8!=0)throw"Assertion error";for(var f=236;u.length<h;f^=253)u.appendBits(f,8);for(var c=[];8*c.length<u.length;)c.push(0);return u.forEach(function(t,r){c[r>>>3]|=t<<7-(7&r)}),new this(i,r,c,o)};var p={getNumRawDataModules:function(t){if(t<C||R<t)throw"Version number out of range";var r=(16*t+128)*t+64;if(2<=t){var e=Math.floor(t/7)+2;r-=(25*e-10)*e-55,7<=t&&(r-=36)}return r},getNumDataCodewords:function(t,r){return Math.floor(p.getNumRawDataModules(t)/8)-p.ECC_CODEWORDS_PER_BLOCK[r.ordinal][t]*p.NUM_ERROR_CORRECTION_BLOCKS[r.ordinal][t]},addRunToHistory:function(t,r){r.pop(),r.unshift(t)},hasFinderLikePattern:function(t){var r=t[1];return 0<r&&t[2]==r&&t[4]==r&&t[5]==r&&t[3]==3*r&&Math.max(t[0],t[6])>=4*r}},C=1,R=40;function N(t,r){Object.defineProperty(this,"ordinal",{value:t}),Object.defineProperty(this,"formatBits",{value:r})}Object.defineProperty(this.QrCode,"MIN_VERSION",{value:C}),Object.defineProperty(this.QrCode,"MAX_VERSION",{value:R}),p.PENALTY_N1=3,p.PENALTY_N2=3,p.PENALTY_N3=40,p.PENALTY_N4=10,p.ECC_CODEWORDS_PER_BLOCK=[[null,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],[null,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],[null,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],[null,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]],p.NUM_ERROR_CORRECTION_BLOCKS=[[null,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],[null,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],[null,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],[null,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]],this.QrCode.Ecc={LOW:new N(0,1),MEDIUM:new N(1,0),QUARTILE:new N(2,3),HIGH:new N(3,2)},this.QrSegment=function(t,r,e){if(r<0||!(t instanceof n))throw"Invalid argument";e=e.slice(),Object.defineProperty(this,"mode",{value:t}),Object.defineProperty(this,"numChars",{value:r}),this.getData=function(){return e.slice()}},this.QrSegment.makeBytes=function(t){var r=new l;return t.forEach(function(t){r.appendBits(t,8)}),new this(this.Mode.BYTE,t.length,r)},this.QrSegment.makeNumeric=function(t){if(!this.NUMERIC_REGEX.test(t))throw"String contains non-numeric characters";for(var r=new l,e=0;e<t.length;){var n=Math.min(t.length-e,3);r.appendBits(parseInt(t.substring(e,e+n),10),3*n+1),e+=n}return new this(this.Mode.NUMERIC,t.length,r)},this.QrSegment.makeAlphanumeric=function(t){if(!this.ALPHANUMERIC_REGEX.test(t))throw"String contains unencodable characters in alphanumeric mode";var r,e=new l;for(r=0;r+2<=t.length;r+=2){var n=45*o.ALPHANUMERIC_CHARSET.indexOf(t.charAt(r));n+=o.ALPHANUMERIC_CHARSET.indexOf(t.charAt(r+1)),e.appendBits(n,11)}return r<t.length&&e.appendBits(o.ALPHANUMERIC_CHARSET.indexOf(t.charAt(r)),6),new this(this.Mode.ALPHANUMERIC,t.length,e)},this.QrSegment.makeSegments=function(t){return""==t?[]:this.NUMERIC_REGEX.test(t)?[this.makeNumeric(t)]:this.ALPHANUMERIC_REGEX.test(t)?[this.makeAlphanumeric(t)]:[this.makeBytes(function(t){t=encodeURI(t);for(var r=[],e=0;e<t.length;e++)"%"!=t.charAt(e)?r.push(t.charCodeAt(e)):(r.push(parseInt(t.substring(e+1,e+3),16)),e+=2);return r}(t))]},this.QrSegment.makeEci=function(t){var r=new l;if(t<0)throw"ECI assignment value out of range";if(t<128)r.appendBits(t,8);else if(t<16384)r.appendBits(2,2),r.appendBits(t,14);else{if(!(t<1e6))throw"ECI assignment value out of range";r.appendBits(6,3),r.appendBits(t,21)}return new this(this.Mode.ECI,0,r)},this.QrSegment.getTotalBits=function(t,r){for(var e=0,n=0;n<t.length;n++){var o=t[n],a=o.mode.numCharCountBits(r);if(o.numChars>=1<<a)return 1/0;e+=4+a+o.getData().length}return e};var o={};function n(t,r){Object.defineProperty(this,"modeBits",{value:t}),this.numCharCountBits=function(t){return r[Math.floor((t+7)/17)]}}function A(t){if(t<1||255<t)throw"Degree out of range";for(var r=[],e=0;e<t-1;e++)r.push(0);r.push(1);var n=1;for(e=0;e<t;e++){for(var o=0;o<r.length;o++)r[o]=A.multiply(r[o],n),o+1<r.length&&(r[o]^=r[o+1]);n=A.multiply(n,2)}this.getRemainder=function(t){var n=r.map(function(){return 0});return t.forEach(function(t){var e=t^n.shift();n.push(0),r.forEach(function(t,r){n[r]^=A.multiply(t,e)})}),n}}function l(){Array.call(this),this.appendBits=function(t,r){if(r<0||31<r||t>>>r!=0)throw"Value out of range";for(var e=r-1;0<=e;e--)this.push(t>>>e&1)}}this.QrSegment.NUMERIC_REGEX=/^[0-9]*$/,this.QrSegment.ALPHANUMERIC_REGEX=/^[A-Z0-9 $%*+.\/:-]*$/,o.ALPHANUMERIC_CHARSET="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:",this.QrSegment.Mode={NUMERIC:new n(1,[10,12,14]),ALPHANUMERIC:new n(2,[9,11,13]),BYTE:new n(4,[8,16,16]),KANJI:new n(8,[8,10,12]),ECI:new n(7,[0,0,0])},A.multiply=function(t,r){if(t>>>8!=0||r>>>8!=0)throw"Byte out of range";for(var e=0,n=7;0<=n;n--)e=e<<1^285*(e>>>7),e^=(r>>>n&1)*t;if(e>>>8!=0)throw"Assertion error";return e},(l.prototype=Object.create(Array.prototype)).constructor=l};

Canvas.setpenopacity(1);
const size = 100;
const step = 0.5;
let uri;
// Turtles run inside workers and the client page location isn't available in the scope :(
const qr = qrcodegen.QrCode.encodeText("https://turtletoy.net/turtle/db54395324", qrcodegen.QrCode.Ecc.MEDIUM);
const scale = size/qr.size;
let x = 0, y = -1;

Turtle.prototype.drawPixel = function(opacity, size) {
    this.pendown();
    this.seth(0);
    for (let i = size; i > 0; i-=0.25/opacity) {
        this.forward(size);
        this.right(90);
        this.forward(0.125/opacity);
        this.right(90);
        this.forward(size);
        this.left(90);
        this.forward(0.125/opacity);
        this.left(90);
    }
    this.penup();
}

const turtle = new Turtle();
turtle.seth(0);

function walk(i) {
    if (qr.getModule(x, y)) {
        turtle.penup();
        turtle.goto(-size+2*x*scale, -size+2*y*scale);
        turtle.pendown();
        turtle.drawPixel(1, 2*scale);
    }
    x = i%qr.size;
    if (i%qr.size==0) y++;
    return y < qr.size;
}