Full Code of tholman/texter for AI

master b03e4859fe35 cached
4 files
14.8 KB
4.2k tokens
2 symbols
1 requests
Download .txt
Repository: tholman/texter
Branch: master
Commit: b03e4859fe35
Files: 4
Total size: 14.8 KB

Directory structure:
gitextract_j3q82qwt/

├── css/
│   └── style.css
├── index.html
└── js/
    ├── header.js
    └── texter.js

================================================
FILE CONTENTS
================================================

================================================
FILE: css/style.css
================================================
html, body {
  width: 100%;
  height: 100%;
  margin: 0px;
  overflow: hidden;
}

canvas {
  position: absolute;
  cursor: crosshair;
  -webkit-user-select: none;
}

/* ----- INFO & SHARING -----  */

#back {
    font-family: Helvetica, Arial, "Lucida Grande";            
    position: fixed;
    top: 7px;
    width: 190px;
    height: 36px;
    box-shadow: 0px 0px 4px 0px #888;
    line-height: 10px;
    left: -153px;
    background: #fff;
    z-index: 1000;
    
    -webkit-transition: left 250ms; 
       -moz-transition: left 250ms; 
         -o-transition: left 250ms;
          -ms-trantion: left 250ms;
            transition: left 250ms;
}

#back.open {
    left: 0px;
}

#back a {
    color: #1C86EE;
    margin-left: 0px;
    margin-right: 0px;
    padding: 13px;
    padding-right: 0px;
    position: absolute;
}

#back a:hover {
    color: hotpink; 
}

#back span {
    font-size: 50px;
    line-height: 0px;
    color: #444;
    text-decoration: none;
    font-family: Times;
    position: absolute;
    right: 10px;
    top: 17px;
    -webkit-margin-before: -3px;
}

#info-tab * {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box
}

#info-tab {

    font-family: Helvetica, Arial, "Lucida Grande";

    -webkit-box-shadow: 0px 0px 4px 0px #888;
    box-shadow: 0px 0px 4px 0px #888;

    -webkit-transition: left 300ms, -webkit-box-shadow 500ms; 
       -moz-transition: left 300ms, -moz-box-shadow 500ms; 
         -o-transition: left 300ms, -o-box-shadow 500ms;
          -ms-trantion: left 300ms, -ms-box-shadow 500ms;
            transition: left 300ms, box-shadow 500ms;

    background-color: #ffffff;
    height: 150px;
    position: fixed;
    padding-left: 5px;
    line-height: 36px;
    width: 630px;
    margin-top: 11px;
    font-size: 17px;
    color: #444;
    left: -598px;
    z-index: 1000;
    top: 40px;
}

#info-tab.open {
    left: 0px;
}

#info-tab.highlight {
     -webkit-box-shadow: 0px 0px 12px 0px #222;
    box-shadow: 0px 0px 12px 0px #222;   
}

#info-tab.open #title {
    opacity: 0;
}


#info-tab #title {
    -webkit-transition: opacity 300ms; 
       -moz-transition: opacity 300ms; 
         -o-transition: opacity 300ms;
          -ms-trantion: opacity 300ms;
            transition: opacity 300ms; 


    -webkit-transform: rotate( 90deg ) translateZ(0px); 
       -moz-transform: rotate( 90deg ) translateZ(0px); 
        -ms-transform: rotate( 90deg ) translateZ(0px); 
         -o-transform: rotate( 90deg ) translateZ(0px); 
            transform: rotate( 90deg ) translateZ(0px);

    -webkit-transform-origin: 100% 0%;
       -moz-transform-origin: 100% 0%;
        -ms-transform-origin: 100% 0%;
         -o-transform-origin: 100% 0%;
            transform-origin: 100% 0%;

    float: right;
    width: 150px;
    height: 30px;
    position: absolute;
    text-align: center;
    right: 0px;
    bottom: -30px;
}

#info-tab .info {
    margin-left: 18px;
    font-size: 14px;

    line-height: 16px;
    height: 110px;
    width: 282px;
    float: left;
    padding-right: 18px;
    margin-top: 20px;
    margin-bottom: 20px;
    color: #111;
    margin-right: 5px;
    position: relative;
}

#info-tab .first {
    border-right: 1px solid #ddd;   
}

#info-tab p {
    position: absolute;
    bottom: 0px;
    font-size: 12px;
    margin: 0px;
}

#info-tab a {
    color: #1C86EE;
}

#info-tab a:hover {
    color: hotpink;
}

#info-tab iframe {
    vertical-align: bottom;
}

================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html>
  <head>
    <title>Texter - Draw with Words</title>
    <meta name="description" content="A creative tool that allows you to draw with words.">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- CSS -->
    <link href="css/style.css" rel="stylesheet" type="text/css" />

    <!-- JS -->
    <script type="text/javascript" src="js/libs/dat.gui.min.js"></script>
    <script type="text/javascript" src="js/texter.js"></script>
  </head>

  <body>
    <!-- Header -->
    <div id="info-tab">
      <div class="info first">
        <b>Texter</b> is a little javascript experiment that lets you explore
        your creativity by drawing with words. This app is an extension of a
        demo from this <a href="http://generative-gestaltung.de/">book</a>
        <p>
          Made by: <a href="http://tholman.com"> Tim Holman </a> -
          <a
            href="http://twitter.com/twholman"
            title="You'll love my tweets, I promise ;)"
          >
            @twholman
          </a>
        </p>
      </div>
      <div class="info">
        This has been made using <i> Javascript </i> and the HTML5
        <i> canvas </i> element. You can find the source on
        <a href="http://github.com/tholman/texter">Github</a>. If you feel like supporting me, you can always <a href="https://ko-fi.com/tholman" target="_blank">buy me a coffee</a>.
        <p>
          <a
            href="https://twitter.com/share"
            class="twitter-share-button"
            data-url="http://tholman.com/texter"
            data-text="Texter - Draw pictures with text! - by @twholman -"
          >
            Tweet
          </a>
          <iframe
            src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Ftholman.com%2Fexperiments%2Fhtml5%2Ftexter&amp;send=false&amp;layout=button_count&amp;width=450&amp;show_faces=false&amp;action=like&amp;colorscheme=light&amp;font&amp;height=21"
            scrolling="no"
            frameborder="0"
            style="
              border: none;
              overflow: hidden;
              width: 107px;
              height: 21px;
              margin-bottom: -1px;
            "
            allowTransparency="true"
          ></iframe>
        </p>
      </div>
      <div id="title">Texter</div>
    </div>
    <div id="back">
      <a href="/experiments"> More experiments </a> <span>&lsaquo;</span>
    </div>
    <script type="text/javascript" src="js/header.js"></script>

    <!-- APP -->
    <canvas id="canvas"></canvas>
    <script>
      var texter = new Texter();
      texter.initialize();

      var gui = new dat.GUI();
      gui
        .add(texter, "text")
        .name("Text")
        .onChange(function () {
          texter.onTextChange();
        });
      gui.add(texter, "minFontSize", 3, 100).name("Minimum Size");
      gui.add(texter, "maxFontSize", 3, 400).name("Maximum Size");
      gui.add(texter, "angleDistortion", 0, 2).step(0.1).name("Random Angle");
      gui
        .addColor(texter, "textColor")
        .name("Text Color")
        .onChange(function (value) {
          texter.applyNewColor(value);
        });
      gui
        .addColor(texter, "bgColor")
        .name("Background Color")
        .onChange(function (value) {
          texter.setBackground(value);
        });
      gui.add(texter, "clear").name("Clear");
      gui.add(texter, "save").name("Save");
    </script>

    <!-- Misc -->
    <script>
      !(function (d, s, id) {
        var js,
          fjs = d.getElementsByTagName(s)[0];
        if (!d.getElementById(id)) {
          js = d.createElement(s);
          js.id = id;
          js.src = "http://platform.twitter.com/widgets.js";
          fjs.parentNode.insertBefore(js, fjs);
        }
      })(document, "script", "twitter-wjs");
    </script>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(["_setAccount", "UA-22825241-1"]);
      _gaq.push(["_trackPageview"]);

      (function () {
        var ga = document.createElement("script");
        ga.type = "text/javascript";
        ga.async = true;
        ga.src =
          ("https:" == document.location.protocol
            ? "https://ssl"
            : "http://www") + ".google-analytics.com/ga.js";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(ga, s);
      })();
    </script>
  </body>
</html>


================================================
FILE: js/header.js
================================================
var headers = [
    document.getElementById("back"),
    document.getElementById("info-tab"),
];
var headerMouseDown = false;
var headerToggleTimeOut = [];

document.addEventListener(
    "mousedown",
    function () {
        headerMouseDown = true;
    },
    false
);

document.addEventListener(
    "mouseup",
    function () {
        headerMouseDown = false;
    },
    false
);

for (var i = 0; i < headers.length; i++) {
    headerToggleTimeOut.push(-1);

    headers[i].addEventListener(
        "mouseover",
        function () {
            if (!headerMouseDown) {
                interval = clearInterval(interval);

                var _this = this;

                clearTimeout(headerToggleTimeOut);

                headerToggleTimeOut[i] = setTimeout(function () {
                    _this.setAttribute("class", "open");
                }, 50);
            }
        },
        false
    );

    headers[i].addEventListener(
        "mouseout",
        function () {
            var _this = this;

            clearTimeout(headerToggleTimeOut);

            headerToggleTimeOut[i] = setTimeout(function () {
                _this.setAttribute("class", "");
            }, 50);
        },
        false
    );
}

function pulseHeader() {
    if (interval == undefined) {
        return;
    }
    headers[1].setAttribute("class", "highlight");

    setTimeout(function () {
        if (interval == undefined) {
            return;
        }
        headers[1].setAttribute("class", "");

        setTimeout(function () {
            if (interval == undefined) {
                return;
            }
            headers[1].setAttribute("class", "highlight");

            setTimeout(function () {
                if (interval == undefined) {
                    return;
                }
                headers[1].setAttribute("class", "");
            }, 400);
        }, 400);
    }, 400);
}

var interval = setInterval(function () {
    pulseHeader();
}, 10000);


================================================
FILE: js/texter.js
================================================
/*
 *  Texter - Drawing with Text.
 *  - Ported from demo in Generative Design book - http://www.generative-gestaltung.de
 *  - generative-gestalung.de original licence: http://www.apache.org/licenses/LICENSE-2.0
 *
 *  - Modified and maintained by Tim Holman - tholman.com - @twholman
 */

function Texter() {
  var _this = this;

  // Application variables
  position = { x: 0, y: window.innerHeight / 2 };
  textIndex = 0;
  this.textColor = "#000000";
  this.bgColor = "#ffffff";
  this.minFontSize = 8;
  this.maxFontSize = 300;
  this.angleDistortion = 0.01;

  var queryString = window.location.search;
  var urlParams = new URLSearchParams(queryString);
  var urlText = urlParams.get('text')

  this.text = urlText || 
    "There was a table set out under a tree in front of the house, and the March Hare and the Hatter were having tea at it: a Dormouse was sitting between them, fast asleep, and the other two were using it as a cushion, resting their elbows on it, and talking over its head. 'Very uncomfortable for the Dormouse,' thought Alice; 'only, as it's asleep, I suppose it doesn't mind.'";

  // Drawing Variables
  canvas = null;
  context = null;
  mouse = { x: 0, y: 0, down: false };

  bgCanvas = null;
  bgContext = null;

  this.initialize = function () {
    canvas = document.getElementById("canvas");
    context = canvas.getContext("2d");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    canvas.addEventListener("mousemove", onMove, false);
    canvas.addEventListener("mousedown", onDown, false);
    canvas.addEventListener("mouseup", onUp, false);
    canvas.addEventListener("mouseout", onUp, false);

    canvas.addEventListener("touchstart", onDown, false);
    canvas.addEventListener("touchmove", onMove, false);
    canvas.addEventListener("touchend", onUp, false);
    canvas.addEventListener("touchcancel", onUp, false);

    bgCanvas = document.createElement("canvas");
    bgContext = bgCanvas.getContext("2d");
    bgCanvas.width = canvas.width;
    bgCanvas.height = canvas.height;
    _this.setBackground(_this.bgColor);

    window.onresize = function (event) {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      bgCanvas.width = window.innerWidth;
      bgCanvas.height = window.innerHeight;
      _this.setBackground(_this.bgColor);
      _this.clear();
    };

    update();
  };

  var update = function () {
    requestAnimationFrame(update);
    draw();
  };

  var draw = function () {
    if (mouse.down) {
      var newDistance = distance(position, mouse);
      var fontSize = _this.minFontSize + newDistance / 2;

      if (fontSize > _this.maxFontSize) {
        fontSize = _this.maxFontSize;
      }

      var letter = _this.text[textIndex];
      var stepSize = textWidth(letter, fontSize);

      if (newDistance > stepSize) {
        var angle = Math.atan2(mouse.y - position.y, mouse.x - position.x);

        context.font = fontSize + "px Georgia";

        context.save();
        context.translate(position.x, position.y);
        context.rotate(
          angle +
            (Math.random() * (_this.angleDistortion * 2) -
              _this.angleDistortion)
        );
        context.fillText(letter, 0, 0);
        context.restore();

        textIndex++;
        if (textIndex > _this.text.length - 1) {
          textIndex = 0;
        }

        position.x = position.x + Math.cos(angle) * stepSize;
        position.y = position.y + Math.sin(angle) * stepSize;
      }
    }
  };

  var distance = function (pt, pt2) {
    var xs = 0;
    var ys = 0;

    xs = pt2.x - pt.x;
    xs = xs * xs;

    ys = pt2.y - pt.y;
    ys = ys * ys;

    return Math.sqrt(xs + ys);
  };

  var onDown = function (event) {
    const eventObject = event.touches && event.touches.item(0) || event
    mouse.down = true;
    position.x = eventObject.pageX;
    position.y = eventObject.pageY;
    mouse.x = eventObject.pageX;
    mouse.y = eventObject.pageY;
  };

  var onUp = function () {
    mouse.down = false;
  };

  var onMove = function (event) {
    const eventObject = event.touches && event.touches.item(0) || event
    mouse.x = eventObject.pageX;
    mouse.y = eventObject.pageY;
    draw();
  };

  var textWidth = function (string, size) {
    context.font = size + "px Georgia";

    if (context.fillText) {
      return context.measureText(string).width;
    } else if (context.mozDrawText) {
      return context.mozMeasureText(string);
    }
  };

  this.clear = function () {
    canvas.width = canvas.width;
    context.fillStyle = _this.textColor;
  };

  this.applyNewColor = function (value) {
    _this.textColor = value;
    context.fillStyle = _this.textColor;
  };

  this.setBackground = function (value) {
    _this.bgColor = value;
    canvas.style.backgroundColor = value;
  };

  this.onTextChange = function () {
    textIndex = 0;
  };

  this.save = function () {
    // Prepare the background canvas's color
    bgContext.rect(0, 0, bgCanvas.width, bgCanvas.height);
    bgContext.fillStyle = _this.bgColor;
    bgContext.fill();

    // Draw the front canvas onto the bg canvas
    bgContext.drawImage(canvas, 0, 0);

    // Open in a new window
    window.open(bgCanvas.toDataURL("image/png"), "mywindow");
  };
}
Download .txt
gitextract_j3q82qwt/

├── css/
│   └── style.css
├── index.html
└── js/
    ├── header.js
    └── texter.js
Download .txt
SYMBOL INDEX (2 symbols across 2 files)

FILE: js/header.js
  function pulseHeader (line 60) | function pulseHeader() {

FILE: js/texter.js
  function Texter (line 9) | function Texter() {
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (16K chars).
[
  {
    "path": "css/style.css",
    "chars": 3489,
    "preview": "html, body {\n  width: 100%;\n  height: 100%;\n  margin: 0px;\n  overflow: hidden;\n}\n\ncanvas {\n  position: absolute;\n  curso"
  },
  {
    "path": "index.html",
    "chars": 4437,
    "preview": "<!DOCTYPE html>\n<html>\n  <head>\n    <title>Texter - Draw with Words</title>\n    <meta name=\"description\" content=\"A crea"
  },
  {
    "path": "js/header.js",
    "chars": 1984,
    "preview": "var headers = [\n    document.getElementById(\"back\"),\n    document.getElementById(\"info-tab\"),\n];\nvar headerMouseDown = f"
  },
  {
    "path": "js/texter.js",
    "chars": 5283,
    "preview": "/*\n *  Texter - Drawing with Text.\n *  - Ported from demo in Generative Design book - http://www.generative-gestaltung.d"
  }
]

About this extraction

This page contains the full source code of the tholman/texter GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (14.8 KB), approximately 4.2k tokens, and a symbol index with 2 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!