├── .github └── FUNDING.yml ├── LICENSE ├── README.md ├── fonts.css ├── index.html ├── parameters.json ├── styles.css └── tc.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: letterror 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Erik van Blokland 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeCooker 2 | 3 | A small web tool for creating recipes for sketching and exploring type. 4 | 5 | This is the code running with very nice fonts on http://typecooker.com. 6 | A local copy is here: http://letterror.github.io/TypeCooker 7 | Follow @TypeCooker 8 | -------------------------------------------------------------------------------- /fonts.css: -------------------------------------------------------------------------------- 1 | 2 | /* font-face declarations */ 3 | 4 | /*@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:600,300); 5 | */ 6 | 7 | @font-face { 8 | font-family: 'lighterSans'; 9 | font-style: normal; 10 | font-weight: 300; 11 | src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), url(https://fonts.gstatic.com/s/sourcesanspro/v9/toadOcfmlt9b38dHJxOBGPS42wKzre0cxmO5m5GyTsY.ttf) format('truetype'); 12 | } 13 | @font-face { 14 | font-family: 'heavierSans'; 15 | font-style: normal; 16 | font-weight: 600; 17 | src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), url(https://fonts.gstatic.com/s/sourcesanspro/v9/toadOcfmlt9b38dHJxOBGBRq_IsDXucKYMk4-diqPEc.ttf) format('truetype'); 18 | } 19 | 20 | body{ 21 | line-height: 120%; 22 | font-size: 6vw; 23 | } 24 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | TypeCooker 4 | 5 | 6 | 7 | 8 | 9 | 10 |
TypeCooker:
11 |
12 |
Starter Easy Class Experienced Pro
13 | 14 |
15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "application":[ 3 | { 4 | "url":"parameters.html#intendedapplication", 5 | "level":3, 6 | "name":"unknown", 7 | "weight":2, 8 | "description":"It is not clear how this typeface is to be used." 9 | }, 10 | { 11 | "url":"parameters.html#intendedapplication", 12 | "level":3, 13 | "name":"multi-purpose", 14 | "weight":10, 15 | "description":"This typeface must do well in all sorts of sizes and media." 16 | }, 17 | { 18 | "url":"parameters.html#intendedapplication", 19 | "level":3, 20 | "name":"newsprint", 21 | "weight":10, 22 | "description":"This typeface must work well on rough paper." 23 | }, 24 | { 25 | "url":"parameters.html#intendedapplication", 26 | "level":3, 27 | "name":"smooth offset printing", 28 | "weight":10, 29 | "description":"This typeface must work well on smooth paper." 30 | }, 31 | { 32 | "url":"parameters.html#intendedapplication", 33 | "level":4, 34 | "name":"engraving", 35 | "weight":5, 36 | "description":"This typeface needs to be engraved into something." 37 | }, 38 | { 39 | "url":"parameters.html#intendedapplication", 40 | "level":3, 41 | "name":"signage", 42 | "weight":10, 43 | "description":"This typeface will be used on signage." 44 | }, 45 | { 46 | "url":"parameters.html#intendedapplication", 47 | "level":4, 48 | "name":"packaging", 49 | "weight":5, 50 | "description":"This typeface will be used on packaging." 51 | }, 52 | { 53 | "url":"parameters.html#intendedapplication", 54 | "level":5, 55 | "name":"subtitles on television", 56 | "weight":2, 57 | "description":"This typeface will be used on television." 58 | }, 59 | { 60 | "url":"parameters.html#intendedapplication", 61 | "level":5, 62 | "name":"antialiased bitmaps", 63 | "weight":2, 64 | "description":"This typeface will be used as antialiased bitmaps." 65 | }, 66 | { 67 | "url":"parameters.html#intendedapplication", 68 | "level":5, 69 | "name":"rubber stamps", 70 | "weight":2, 71 | "description":"This typeface will be used on rubber stamps." 72 | } 73 | ], 74 | "weight":[ 75 | { 76 | "url":"parameters.html#strokeweight", 77 | "level":4, 78 | "name":"hairline", 79 | "weight":2, 80 | "description":"All strokes are as thin as possible." 81 | }, 82 | { 83 | "url":"parameters.html#strokeweight", 84 | "level":4, 85 | "name":"very thin", 86 | "weight":3, 87 | "description":"All strokes are very thin." 88 | }, 89 | { 90 | "url":"parameters.html#strokeweight", 91 | "level":3, 92 | "name":"thin", 93 | "weight":4, 94 | "description":"All strokes are thin." 95 | }, 96 | { 97 | "url":"parameters.html#strokeweight", 98 | "level":3, 99 | "name":"extra light", 100 | "weight":5, 101 | "description":"All strokes are light, but not extremely." 102 | }, 103 | { 104 | "url":"parameters.html#strokeweight", 105 | "level":1, 106 | "name":"light", 107 | "weight":5, 108 | "description":"All strokes are light, but not extremely." 109 | }, 110 | { 111 | "url":"parameters.html#strokeweight", 112 | "level":2, 113 | "name":"book", 114 | "weight":6, 115 | "description":"All strokes are such that they're readable at arms' length." 116 | }, 117 | { 118 | "url":"parameters.html#strokeweight", 119 | "level":1, 120 | "name":"plain", 121 | "weight":7, 122 | "description":"All strokes are plain. Not too light, not too heavy." 123 | }, 124 | { 125 | "url":"parameters.html#strokeweight", 126 | "level":3, 127 | "name":"medium", 128 | "weight":6, 129 | "description":"All strokes are heavier than normal, not bold." 130 | }, 131 | { 132 | "url":"parameters.html#strokeweight", 133 | "level":3, 134 | "name":"semi bold", 135 | "weight":5, 136 | "description":"All strokes are heavier than normal, not bold." 137 | }, 138 | { 139 | "url":"parameters.html#strokeweight", 140 | "level":1, 141 | "name":"bold", 142 | "weight":4, 143 | "description":"All strokes are heavy." 144 | }, 145 | { 146 | "url":"parameters.html#strokeweight", 147 | "description":"All strokes are heavier than bold.", 148 | "name":"extra bold", 149 | "weight":3, 150 | "level":3 151 | }, 152 | { 153 | "url":"parameters.html#strokeweight", 154 | "level":4, 155 | "name":"black", 156 | "weight":2, 157 | "description":"All strokes are as heavy as they can be." 158 | } 159 | ], 160 | "keys":[ 161 | "width", 162 | "weight", 163 | "construction", 164 | "stroke endings", 165 | "ascender", 166 | "descender", 167 | "contrast type", 168 | "contrast amount", 169 | "stems", 170 | "application", 171 | "size", 172 | "special", 173 | "also" 174 | ], 175 | "stroke endings":[ 176 | { 177 | "url":"parameters.html#strokeendings", 178 | "level":1, 179 | "name":"straight, no serif", 180 | "weight":10, 181 | "description":"The strokes do not end in serifs." 182 | }, 183 | { 184 | "url":"parameters.html#strokeendings", 185 | "level":1, 186 | "name":"serifs", 187 | "weight":10, 188 | "description":"The strokes end in serifs." 189 | }, 190 | { 191 | "url":"parameters.html#strokeendings", 192 | "level":3, 193 | "name":"rounded, no serif", 194 | "weight":5, 195 | "description":"The strokes are rounded at the end." 196 | }, 197 | { 198 | "url":"parameters.html#strokeendings", 199 | "level":3, 200 | "name":"bracketed serif", 201 | "weight":5, 202 | "description":"The strokes end in bracketed serifs." 203 | }, 204 | { 205 | "url":"parameters.html#strokeendings", 206 | "level":4, 207 | "name":"asymmetric serif", 208 | "weight":5, 209 | "description":"The strokes end in asymmetric serifs." 210 | }, 211 | { 212 | "url":"parameters.html#strokeendings", 213 | "level":4, 214 | "name":"wedge serif", 215 | "weight":10, 216 | "description":"The strokes end in triangular serifs." 217 | }, 218 | { 219 | "url":"parameters.html#strokeendings", 220 | "level":3, 221 | "name":"slab serif", 222 | "weight":5, 223 | "description":"The strokes end in rectangular serifs." 224 | } 225 | ], 226 | "ascender":[ 227 | { 228 | "url":"parameters.html#ascender", 229 | "level":3, 230 | "name":"longer than normal", 231 | "weight":5, 232 | "description":"The ascenders should be longer than normal. But what is normal?" 233 | }, 234 | { 235 | "url":"parameters.html#ascender", 236 | "level":3, 237 | "name":"shorter than normal", 238 | "weight":5, 239 | "description":"The ascenders should be shorter than normal. But what is normal?" 240 | }, 241 | { 242 | "url":"parameters.html#ascender", 243 | "level":4, 244 | "name":"much shorter than normal", 245 | "weight":2, 246 | "description":"The ascenders should be much shorter than normal. But what is normal?" 247 | }, 248 | { 249 | "url":"parameters.html#ascender", 250 | "level":4, 251 | "name":"much longer than normal", 252 | "weight":2, 253 | "description":"The ascenders should be much longer than normal. But what is normal?" 254 | }, 255 | { 256 | "url":"parameters.html#ascender", 257 | "level":5, 258 | "name":"none at all", 259 | "weight":1, 260 | "description":"There is no room for ascenders." 261 | } 262 | ], 263 | "construction":[ 264 | { 265 | "url":"parameters.html#construction", 266 | "level":1, 267 | "name":"roman", 268 | "weight":10, 269 | "description":"Construct the letters as lowercase romans." 270 | }, 271 | { 272 | "url":"parameters.html#construction", 273 | "level":1, 274 | "name":"capitals", 275 | "weight":10, 276 | "description":"Construct the letters as capitals." 277 | }, 278 | { 279 | "url":"parameters.html#construction", 280 | "level":2, 281 | "name":"italic", 282 | "weight":10, 283 | "description":"Construct the letters as cursive italics." 284 | }, 285 | { 286 | "url":"parameters.html#construction", 287 | "level":4, 288 | "name":"caps and smallcaps", 289 | "weight":2, 290 | "description":"Construct the letters with an initial capital, then followed by smallcaps." 291 | }, 292 | { 293 | "url":"parameters.html#construction", 294 | "level":3, 295 | "name":"roman + capitals", 296 | "weight":5, 297 | "description":"Construct the letters with an initial capital, then followed by lowercase roman." 298 | }, 299 | { 300 | "url":"parameters.html#construction", 301 | "level":3, 302 | "name":"italic + capitals", 303 | "weight":5, 304 | "description":"Construct the letters with an initial capital, then followed by lowercase italic." 305 | }, 306 | { 307 | "url":"parameters.html#construction", 308 | "level":3, 309 | "name":"proportional oldstyle figures", 310 | "weight":2, 311 | "description":"Old style (non-lining) figures with proportional widths." 312 | }, 313 | { 314 | "url":"parameters.html#construction", 315 | "level":3, 316 | "name":"tabular oldstyle figures", 317 | "weight":2, 318 | "description":"Old style (non-lining) figures with tabular widths." 319 | }, 320 | { 321 | "url":"parameters.html#construction", 322 | "level":3, 323 | "name":"proportional lining figures", 324 | "weight":2, 325 | "description":"Lining figures with proportional widths." 326 | }, 327 | { 328 | "url":"parameters.html#construction", 329 | "level":3, 330 | "name":"tabular lining figures", 331 | "weight":2, 332 | "description":"Lining figures with tabular widths." 333 | }, 334 | { 335 | "url":"parameters.html#construction", 336 | "level":3, 337 | "name":"smallcaps figures", 338 | "weight":2, 339 | "description":"Figures fitting to smallcap size. Add a regular capital to get a sense of the proportions." 340 | } 341 | ], 342 | "stems":[ 343 | { 344 | "url":"parameters.html#stems", 345 | "level":3, 346 | "name":"straight", 347 | "weight":10, 348 | "description":"The stems are perfectly straight." 349 | }, 350 | { 351 | "url":"parameters.html#stems", 352 | "level":3, 353 | "name":"slightly concave", 354 | "weight":4, 355 | "description":"The stems are slightly curved inward. Reversed entasis." 356 | }, 357 | { 358 | "url":"parameters.html#stems", 359 | "level":4, 360 | "name":"visibly concave", 361 | "weight":4, 362 | "description":"The stems are visibly curved inward. Reversed entasis." 363 | }, 364 | { 365 | "url":"parameters.html#stems", 366 | "level":4, 367 | "name":"flaring", 368 | "weight":4, 369 | "description":"The stems are very much curved inward. Might involve serifs." 370 | }, 371 | { 372 | "url":"parameters.html#stems", 373 | "level":5, 374 | "name":"convex", 375 | "weight":2, 376 | "description":"The stems are very much curved outward. Entasis." 377 | } 378 | ], 379 | "special":[ 380 | { 381 | "url":"parameters.html#special", 382 | "level":4, 383 | "name":"only straight lines", 384 | "weight":5, 385 | "description":"Use no curves. Curves are overrated." 386 | }, 387 | { 388 | "url":"parameters.html#special", 389 | "level":4, 390 | "name":"curves as octagonals", 391 | "weight":5, 392 | "description":"Eight segments to make an oval." 393 | }, 394 | { 395 | "url":"parameters.html#special", 396 | "level":4, 397 | "name":"rough contours", 398 | "weight":2, 399 | "description":"The contours are rought. Should not be that difficult." 400 | }, 401 | { 402 | "url":"parameters.html#special", 403 | "level":4, 404 | "name":"casual", 405 | "weight":2, 406 | "description":"Displays a casual approach to construction and finish." 407 | }, 408 | { 409 | "url":"parameters.html#special", 410 | "level":4, 411 | "name":"sketchy", 412 | "weight":2, 413 | "description":"Letters appear sketchy." 414 | }, 415 | { 416 | "url":"parameters.html#special", 417 | "level":4, 418 | "name":"cut as a stencil", 419 | "weight":5, 420 | "description":"Make sure the contours do not drop out." 421 | }, 422 | { 423 | "url":"parameters.html#special", 424 | "level":4, 425 | "name":"at least 1 ligature", 426 | "weight":8, 427 | "description":"Two letters must form a ligature." 428 | }, 429 | { 430 | "url":"parameters.html#special", 431 | "level":4, 432 | "name":"at least 2 ligatures", 433 | "weight":8, 434 | "description":"Two pairs of letters must form a ligature." 435 | }, 436 | { 437 | "url":"parameters.html#special", 438 | "level":4, 439 | "name":"inktraps for white corners", 440 | "weight":4, 441 | "description":"Open sharp white corners a bit." 442 | }, 443 | { 444 | "url":"parameters.html#special", 445 | "level":4, 446 | "name":"inktraps for black corners", 447 | "weight":4, 448 | "description":"Prevent sharp black corners from rounding." 449 | }, 450 | { 451 | "url":"parameters.html#special", 452 | "level":4, 453 | "name":"initial and final swashes", 454 | "weight":5, 455 | "description":"Add unnecessary but pretty frivolities to first and last letters." 456 | } 457 | ], 458 | "contrast type":[ 459 | { 460 | "url":"parameters.html#contrasttype", 461 | "level":2, 462 | "name":"translation", 463 | "weight":5, 464 | "description":"The contrast produced by a broad nib pen." 465 | }, 466 | { 467 | "url":"parameters.html#contrasttype", 468 | "level":2, 469 | "name":"expansion", 470 | "weight":5, 471 | "description":"The contrast produced by a flexible or pointed nib pen." 472 | }, 473 | { 474 | "url":"parameters.html#contrasttype", 475 | "level":4, 476 | "name":"transitional", 477 | "weight":5, 478 | "description":"A historical mix of broad nib and pointed nib influences." 479 | }, 480 | { 481 | "url":"parameters.html#contrasttype", 482 | "level":4, 483 | "name":"between translation and transitional", 484 | "weight":5, 485 | "description":"A historical mix of broad nib and pointed nib influences." 486 | }, 487 | { 488 | "url":"parameters.html#contrasttype", 489 | "level":4, 490 | "name":"between expansion and transitional", 491 | "weight":5, 492 | "description":"A historical mix of broad nib and pointed nib influences." 493 | }, 494 | { 495 | "url":"parameters.html#contrasttype", 496 | "level":4, 497 | "name":"speedball", 498 | "weight":2, 499 | "description":"Very low contrast as produced by the Speedball pen." 500 | }, 501 | { 502 | "url":"parameters.html#contrasttype", 503 | "level":4, 504 | "name":"brush", 505 | "weight":2, 506 | "description":"Largely translation, but incorporating rotation and pressure." 507 | }, 508 | { 509 | "url":"parameters.html#contrasttype", 510 | "level":5, 511 | "name":"can't be determined", 512 | "weight":2, 513 | "description":"The contrast is rather difficult to identify. That does not mean is has no contrast!" 514 | } 515 | ], 516 | "also":[ 517 | { 518 | "url":"parameters.html#special", 519 | "level":4, 520 | "name":"as a bold", 521 | "weight":2, 522 | "description":"As defined by the other parameters, but then also some letters as a bold." 523 | }, 524 | { 525 | "url":"parameters.html#special", 526 | "level":4, 527 | "name":"as a hairline", 528 | "weight":2, 529 | "description":"As defined by the other parameters, but then also some letters as a hairline." 530 | }, 531 | { 532 | "url":"parameters.html#special", 533 | "level":4, 534 | "name":"as a black", 535 | "weight":2, 536 | "description":"As defined by the other parameters, but then also some letters as a black." 537 | }, 538 | { 539 | "url":"parameters.html#special", 540 | "level":4, 541 | "name":"as reversed contrast", 542 | "weight":1, 543 | "description":"As defined by the other parameters, but then also some letters with reversed contrast." 544 | }, 545 | { 546 | "url":"parameters.html#special", 547 | "level":4, 548 | "name":"as an italic", 549 | "weight":1, 550 | "description":"As defined by the other parameters, but then also some italic letters." 551 | }, 552 | { 553 | "url":"parameters.html#special", 554 | "level":4, 555 | "name":"with some smallcaps", 556 | "weight":1, 557 | "description":"As defined by the other parameters, but then also some smallcaps." 558 | } 559 | ], 560 | "descender":[ 561 | { 562 | "url":"parameters.html#descender", 563 | "level":3, 564 | "name":"longer than normal", 565 | "weight":5, 566 | "description":"The descenders should be longer than normal. But what is normal?" 567 | }, 568 | { 569 | "url":"parameters.html#descender", 570 | "level":3, 571 | "name":"shorter than normal", 572 | "weight":5, 573 | "description":"The descenders should be shorter than normal. But what is normal?" 574 | }, 575 | { 576 | "url":"parameters.html#descender", 577 | "level":4, 578 | "name":"much shorter than normal", 579 | "weight":2, 580 | "description":"The descenders should be much shorter than normal. But what is normal?" 581 | }, 582 | { 583 | "url":"parameters.html#descender", 584 | "level":5, 585 | "name":"none", 586 | "weight":1, 587 | "description":"There is no room for descenders." 588 | } 589 | ], 590 | "contrast amount":[ 591 | { 592 | "url":"parameters.html#contrastamount", 593 | "level":5, 594 | "name":"inverted", 595 | "weight":10, 596 | "description":"Thicks are thins and thins are thick." 597 | }, 598 | { 599 | "url":"parameters.html#contrastamount", 600 | "level":5, 601 | "name":"slightly inverted", 602 | "weight":10, 603 | "description":"Thicks are thins and thins are thick. But try to be subtle." 604 | }, 605 | { 606 | "url":"parameters.html#contrastamount", 607 | "level":4, 608 | "name":"no contrast at all", 609 | "weight":10, 610 | "description":"Thick equals thin. There is no contrast, even when you really need it." 611 | }, 612 | { 613 | "url":"parameters.html#contrastamount", 614 | "level":3, 615 | "name":"not visible", 616 | "weight":10, 617 | "description":"Thick looks like thin. There appears to be no contrast." 618 | }, 619 | { 620 | "url":"parameters.html#contrastamount", 621 | "level":3, 622 | "name":"very low", 623 | "weight":10, 624 | "description":"Thicks are similar to thins." 625 | }, 626 | { 627 | "url":"parameters.html#contrastamount", 628 | "level":1, 629 | "name":"low", 630 | "weight":10, 631 | "description":"Thicks are similar to thins." 632 | }, 633 | { 634 | "url":"parameters.html#contrastamount", 635 | "level":1, 636 | "name":"some", 637 | "weight":10, 638 | "description":"Thicks are similar to thins but you can tell the difference." 639 | }, 640 | { 641 | "url":"parameters.html#contrastamount", 642 | "level":2, 643 | "name":"visible", 644 | "weight":10, 645 | "description":"Thicks are visibly thicker than the thins." 646 | }, 647 | { 648 | "url":"parameters.html#contrastamount", 649 | "level":2, 650 | "name":"quite some contrast", 651 | "weight":10, 652 | "description":"Thicks are visibly thicker than the thins." 653 | }, 654 | { 655 | "url":"parameters.html#contrastamount", 656 | "level":1, 657 | "name":"a lot", 658 | "weight":10, 659 | "description":"Thicks are a lot thicker than the thins." 660 | }, 661 | { 662 | "url":"parameters.html#contrastamount", 663 | "level":2, 664 | "name":"high", 665 | "weight":10, 666 | "description":"A lot of difference between the thicks and the thins." 667 | }, 668 | { 669 | "url":"parameters.html#contrastamount", 670 | "level":4, 671 | "name":"very high", 672 | "weight":10, 673 | "description":"A lot of difference between the thicks and the thins." 674 | }, 675 | { 676 | "url":"parameters.html#contrastamount", 677 | "level":5, 678 | "name":"extreme", 679 | "weight":10, 680 | "description":"The thicks and thins are as different as you can make them." 681 | } 682 | ], 683 | "width":[ 684 | { 685 | "url":"parameters.html#width", 686 | "level":4, 687 | "name":"compressed", 688 | "weight":2, 689 | "description":"The overall width is as small as possible." 690 | }, 691 | { 692 | "url":"parameters.html#width", 693 | "level":3, 694 | "name":"extra condensed", 695 | "weight":3, 696 | "description":"The overall width is really small, almost no room for counters." 697 | }, 698 | { 699 | "level":2, 700 | "name":"condensed", 701 | "weight":3, 702 | "description":"The overall width is small, but not uncomfortably so." 703 | }, 704 | { 705 | "url":"parameters.html#width", 706 | "level":1, 707 | "name":"narrow", 708 | "weight":4, 709 | "description":"Not much overall width." 710 | }, 711 | { 712 | "url":"parameters.html#width", 713 | "level":1, 714 | "name":"normal", 715 | "weight":5, 716 | "description":"A normal width." 717 | }, 718 | { 719 | "url":"parameters.html#width", 720 | "level":1, 721 | "name":"extended", 722 | "weight":4, 723 | "description":"The overall width is larger than normal. (But what is normal)" 724 | }, 725 | { 726 | "url":"parameters.html#width", 727 | "level":2, 728 | "name":"wide", 729 | "weight":3, 730 | "description":"The overall width is definitely wide." 731 | }, 732 | { 733 | "url":"parameters.html#width", 734 | "level":2, 735 | "name":"very wide", 736 | "weight":2, 737 | "description":"The overall width is very large." 738 | }, 739 | { 740 | "url":"parameters.html#width", 741 | "level":3, 742 | "name":"extremely wide", 743 | "weight":1, 744 | "description":"Draw something really wide. Then make it twice as wide again." 745 | }, 746 | { 747 | "url":"parameters.html#width", 748 | "level":4, 749 | "name":"monospaced", 750 | "weight":2, 751 | "description":"All letters have the same width" 752 | }, 753 | { 754 | "url":"parameters.html#width", 755 | "level":4, 756 | "name":"monospaced condensed", 757 | "weight":2, 758 | "description":"All letters have the same, narrow, width" 759 | } 760 | ], 761 | "size":[ 762 | { 763 | "url":"parameters.html#intendedsize", 764 | "level":4, 765 | "name":"agate", 766 | "weight":2, 767 | "description":"Really small, really legible." 768 | }, 769 | { 770 | "url":"parameters.html#intendedsize", 771 | "level":4, 772 | "name":"reading", 773 | "weight":4, 774 | "description":"Really legible at arms length." 775 | }, 776 | { 777 | "url":"parameters.html#intendedsize", 778 | "level":4, 779 | "name":"phone reading", 780 | "weight":8, 781 | "description":"Anticipating contemporary web design, the type will be too small. Can the font help?" 782 | }, 783 | { 784 | "url":"parameters.html#intendedsize", 785 | "level":4, 786 | "name":"laptop reading", 787 | "weight":8, 788 | "description":"Reading continuous text on a laptop screen." 789 | }, 790 | { 791 | "url":"parameters.html#intendedsize", 792 | "level":4, 793 | "name":"wall television reading", 794 | "weight":8, 795 | "description":"Reading text on a wall mounted television." 796 | }, 797 | { 798 | "url":"parameters.html#intendedsize", 799 | "level":4, 800 | "name":"very large sizes", 801 | "weight":4, 802 | "description":"Huge text on a wall." 803 | }, 804 | { 805 | "url":"parameters.html#intendedsize", 806 | "level":4, 807 | "name":"most sizes", 808 | "weight":4, 809 | "description":"Can't be too specialised, it has to work well on a range of sizes." 810 | } 811 | ], 812 | "variable":[ 813 | { 814 | "url":"parameters.html#variable", 815 | "level":4, 816 | "name":"make width axis variations", 817 | "weight":2, 818 | "description":"Draw wider and narrower variations." 819 | }, 820 | { 821 | "url":"parameters.html#variable", 822 | "level":4, 823 | "name":"make weight axis variations", 824 | "weight":2, 825 | "description":"Draw lighter and heavier variations." 826 | }, 827 | { 828 | "url":"parameters.html#variable", 829 | "level":4, 830 | "name":"make optical axis variations", 831 | "weight":2, 832 | "description":"Draw variations for normal and smaller sizes." 833 | }, 834 | { 835 | "url":"parameters.html#variable", 836 | "level":5, 837 | "name":"make optical axis variations", 838 | "weight":2, 839 | "description":"Draw variations for normal and larger sizes." 840 | }, 841 | { 842 | "url":"parameters.html#variable", 843 | "level":5, 844 | "name":"make optical axis variations", 845 | "weight":2, 846 | "description":"Draw variations for smaller and larger sizes." 847 | } 848 | ] 849 | } 850 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color:rgba(197, 206, 225, 0.7); 3 | margin: 0; 4 | } 5 | #twitter{ 6 | background-color: #4099ff; 7 | width: 100%; 8 | color: white; 9 | margin:0; 10 | padding-left: 0.1em; 11 | padding-right: 0.1em; 12 | } 13 | #tc{ 14 | color: white; 15 | font-family: "heavierSans"; 16 | padding-left: 0.1em; 17 | background-color: #ff001b; 18 | font-style: normal; 19 | font-weight: normal; 20 | } 21 | .explainparameter{ 22 | display: none; 23 | background-color: blue; 24 | color: white; 25 | font-family: "heavierSans"; 26 | } 27 | #recipe{ 28 | width: 100vw; 29 | margin:0; 30 | } 31 | .selected{ 32 | color: white; 33 | font-family: "heavierSans"; 34 | padding-left: 0.1em; 35 | background-color: #ff001b; 36 | font-style: normal; 37 | font-weight: normal; 38 | } 39 | a{ 40 | cursor: pointer; /* force displaying pointer curser for a tags missing a href attribute */ 41 | text-decoration: none; 42 | color: white; 43 | padding-left: 0.05em; 44 | padding-right: 0.05em; 45 | } 46 | a:hover{ 47 | font-family: "heavierSans"; 48 | color: white; 49 | } 50 | .container{ 51 | background-color: rgba(255, 255, 255, 0.52); 52 | } 53 | .entry, .choice, .explain{ 54 | display: inline-block; 55 | font-family: "lighterSans"; 56 | font-style: normal; 57 | font-weight: normal; 58 | text-align: left; 59 | text-transform: capitalize; 60 | color: rgba(32, 31, 27, 0.95); 61 | padding: 0; 62 | } 63 | .entry{ 64 | background-color: #ffc400; 65 | color: white; 66 | } 67 | .entry:hover, .explaining{ 68 | /* background-color: #ffc400; 69 | color: white; 70 | */ 71 | color: #ffc400; 72 | } 73 | div.explaining{ 74 | background-color: #ffc400; 75 | color: red; 76 | } 77 | .choice{ 78 | display: inline-block; 79 | margin-right: 0.125em; 80 | padding-left: 0.125em; 81 | padding-right: 0.125em; 82 | } 83 | .explain{ 84 | display: none; 85 | background-color: black; 86 | color: white; 87 | text-transform: none; 88 | font-family: "lighterSans"; 89 | 90 | } 91 | #title, #explain{ 92 | font-family: "lighterSans"; 93 | text-align: left; 94 | color: white; 95 | padding-left: 0.1em; 96 | background-color: #ff001b; 97 | } 98 | #title{ 99 | text-transform: uppercase; 100 | } 101 | em{ 102 | font-style: normal; 103 | font-family: "lighterSans"; 104 | color: rgba(0, 0, 0, 0.4); 105 | text-transform: capitalize; 106 | padding-left: 0.1em; 107 | padding-right: 0.1em; 108 | background-color: #ffc400; 109 | } 110 | #footer{ 111 | font-family: "lighterSans"; 112 | color: white; 113 | } 114 | -------------------------------------------------------------------------------- /tc.js: -------------------------------------------------------------------------------- 1 | 2 | // The previous implementations relied on external frameworks to do the work. 3 | // It seems TypeCooker tends to outlive these frameworks. This makes maintenance 4 | // a bit more difficult. So instead, for this implementation, let's use only 5 | // canonical javascript. http://youmightnotneedjquery.com 6 | 7 | //Copyright (c) 2015, Erik van Blokland 8 | //All rights reserved. 9 | 10 | // Redistribution and use in source and binary forms, with or without 11 | // modification, are permitted provided that the following conditions are met: 12 | 13 | // 1. Redistributions of source code must retain the above copyright notice, this 14 | // list of conditions and the following disclaimer. 15 | // 2. Redistributions in binary form must reproduce the above copyright notice, 16 | // this list of conditions and the following disclaimer in the documentation 17 | // and/or other materials provided with the distribution. 18 | 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20 | // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 23 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // The views and conclusions contained in the software and documentation are those 31 | // of the authors and should not be interpreted as representing official policies, 32 | // either expressed or implied, of the FreeBSD Project. 33 | 34 | // stuff 35 | var parametersURL = "parameters.json"; 36 | var selectionLevel = 1; 37 | var currentExplained = null; 38 | var data = {}; 39 | var current = {}; // holds the generated parameter - value pairs 40 | 41 | // explain text 42 | var explainText = "Hi! If you don’t know what kind of letters to draw, TypeCooker can give you some ideas. Try to match as many parameters as you can.
@typecooker"; 43 | var explainOpen = false; 44 | 45 | // load the parameters 46 | var request = new XMLHttpRequest(); 47 | request.open('GET', parametersURL, true); 48 | var parameterData = {}; 49 | var selectionLevel = 2; 50 | var titleYellow = "#ffc400"; 51 | 52 | request.onload = function() { 53 | if (request.status >= 200 && request.status < 400) { 54 | // Success! 55 | parameterData = JSON.parse(request.responseText); 56 | console.log('succes!', parameterData); 57 | selectionLevel = getParameterByName('level'); 58 | console.log('selectionLevel', selectionLevel); 59 | if(selectionLevel==null){ 60 | selectionLevel=2; 61 | } 62 | el = document.getElementById("level"+selectionLevel); 63 | if (el.classList) { 64 | el.classList.add('selected'); 65 | } else { 66 | el.className += ' ' + 'selected'; 67 | } 68 | 69 | // if there is a hash fragment present in the url, rebuild the interface state 70 | // to match the options provided 71 | // else generate a new ranomd set of options 72 | if (window.location.hash) { 73 | console.log("rebuild"); 74 | var options = buildObjFromHash(window.location.hash); 75 | // "update" share link in the footer to match the current options 76 | var shareLink = window.location.href + window.location.hash; 77 | document.getElementById("share-link").setAttribute("href", shareLink); 78 | makeFromObject(options, parameterData); 79 | 80 | // then remove the hash form the url, so that a user that came via 81 | // a set link can still generate new sets 82 | window.location.hash = ""; 83 | } else { 84 | console.log("generate"); 85 | makeSelection(selectionLevel, parameterData); 86 | } 87 | } else { 88 | // We reached our target server, but it returned an error 89 | console.log("error loading", parametersURL); 90 | } 91 | }; 92 | request.onerror = function() { 93 | // There was a connection error of some sort 94 | console.log("can't load", parametersURL); 95 | }; 96 | 97 | // send the request 98 | request.send(); 99 | 100 | // http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array 101 | function shuffle(array) { 102 | var currentIndex = array.length, temporaryValue, randomIndex ; 103 | 104 | // While there remain elements to shuffle... 105 | while (0 !== currentIndex) { 106 | 107 | // Pick a remaining element... 108 | randomIndex = Math.floor(Math.random() * currentIndex); 109 | currentIndex -= 1; 110 | 111 | // And swap it with the current element. 112 | temporaryValue = array[currentIndex]; 113 | array[currentIndex] = array[randomIndex]; 114 | array[randomIndex] = temporaryValue; 115 | } 116 | return array; 117 | } 118 | 119 | //http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript 120 | function getParameterByName(name) { 121 | name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); 122 | var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), 123 | results = regex.exec(location.search); 124 | return results === null ? 2 : decodeURIComponent(results[1].replace(/\+/g, " ")); 125 | } 126 | 127 | function buildObjFromHash(hash) { 128 | // replace any possible starting # sign 129 | hash = hash.replace(/^#/, ""); 130 | 131 | // iterate though all & seperated paramater - value pairs 132 | var parts = hash.split("&"); 133 | var obj = {}; 134 | for (part in parts) { 135 | var components = parts[part].split("="); 136 | obj[decodeURIComponent(components[0])] = decodeURIComponent(components[1]); 137 | } 138 | return obj; 139 | } 140 | 141 | function buildHashFromObj(obj) { 142 | var hash = ""; 143 | for (property in obj) { 144 | hash += "&" + encodeURIComponent(property) + "=" + encodeURIComponent(obj[property]) 145 | } 146 | hash = hash.substring(1); // remove that first & 147 | return hash; 148 | } 149 | 150 | // build parameter unit 151 | var buildParameter = function(parameterName){ 152 | // build the structure for the parameter, but without any contents. 153 | var t = ""; 154 | var parameterNameAsClass = parameterName.replace(/\s+/g, ''); 155 | var parameterExplainAsClass = parameterNameAsClass+"explain"; 156 | var parameterChoiceAsClass = parameterNameAsClass+"choice"; 157 | t += "
"; 158 | t += "
"+"
"; 159 | t += "
"+"
"; 160 | t += "
"; 161 | t += "
"+"
"; 162 | //console.log("t", t); 163 | return t; 164 | } 165 | 166 | // show 167 | var explainParameter = function(parameterName){ 168 | console.log('--> explain', parameterName); 169 | if(currentExplained){ 170 | // we have a previous choice 171 | document.getElementById(currentExplained+"explain").style.display = "none"; 172 | document.getElementById(currentExplained).style.backgroundColor = titleYellow; 173 | document.getElementById(currentExplained+"choice").style.backgroundColor = "inherit"; 174 | document.getElementById(currentExplained+"choice").style.color = "black"; 175 | if(currentExplained==parameterName){ 176 | currentExplained = null; 177 | return; 178 | } 179 | } 180 | document.getElementById(parameterName+"explain").style.display = "block"; 181 | document.getElementById(parameterName+"explain").style.backgroundColor = "black"; 182 | document.getElementById(parameterName+"choice").style.backgroundColor = "black"; 183 | document.getElementById(parameterName+"choice").style.color = titleYellow; 184 | document.getElementById(parameterName).style.backgroundColor = "black"; 185 | currentExplained = parameterName; 186 | console.log("done with", currentExplained); 187 | } 188 | 189 | // show explanation 190 | var showExplain = function(){ 191 | if(explainOpen){ 192 | document.getElementById("explain").innerHTML = ""; 193 | explainOpen = false; 194 | } else { 195 | document.getElementById("explain").innerHTML = explainText; 196 | explainOpen = true; 197 | } 198 | } 199 | 200 | 201 | // build the "recipe" html for all parameterNames 202 | var buildRecipe = function (parameterNames) { 203 | for(var i=0;i"+thisName+""; 219 | el.innerHTML = thisNameLink+el.innerHTML; 220 | document.getElementById(parameterNameAsClass+"choice").innerHTML = selection.name; 221 | document.getElementById(parameterNameAsClass+"explain").innerHTML = d; 222 | } 223 | 224 | // got passed a hash on load, build the selection from an object and the passed 225 | // in json data 226 | var makeFromObject = function (obj, data) { 227 | var parameterNames = []; 228 | for(var key in data){ 229 | parameterNames.push(key); 230 | } 231 | buildRecipe(parameterNames); 232 | 233 | // remove the "keys" array form the json data to avoid having it 234 | // included as a new parameter listed as selected 235 | data.keys = undefined; 236 | 237 | // since the obj only contains the "name" value of the actual data 238 | // let's make an object that has all the data from the json 239 | var objectFromJson = obj; 240 | for (param in data) { 241 | for (index in data[param]) { 242 | if (data[param][index]["name"] == obj[param]) { 243 | objectFromJson[param] = data[param][index]; 244 | } 245 | } 246 | } 247 | 248 | // build the actual html for each parameter 249 | for (parameter in objectFromJson) { 250 | buildSelection(objectFromJson[parameter], parameter); 251 | } 252 | } 253 | 254 | // json loaded and no url has provided, make a new randomized selection 255 | var makeSelection = function(level, data){ 256 | var selectedItems = []; 257 | var parameterNames = []; 258 | for(var key in data){ 259 | parameterNames.push(key); 260 | } 261 | 262 | parameterNames = shuffle(parameterNames); 263 | buildRecipe(parameterNames); 264 | 265 | for(var i=0;ilevel){ 273 | // above our pay grade, skip. 274 | continue; 275 | } 276 | for(var t=0;t<=b.weight;t++){ 277 | // add this option according to weight 278 | optionsForThisName.push(b); 279 | } 280 | } 281 | if(optionsForThisName.length>0){ 282 | var selection = optionsForThisName[Math.floor(Math.random()*optionsForThisName.length)]; 283 | buildSelection(selection, thisName); 284 | current[thisName] = selection.name; 285 | } 286 | } 287 | } 288 | 289 | // Copy to clipboard as discussed here 290 | // http://stackoverflow.com/questions/400212/how-do-i-copy-to-the-clipboard-in-javascript 291 | function shareRecipe() { 292 | // Create footer share link to match the current options 293 | // remove and hash that might or might not have been in the location 294 | var shareLink = window.location.href.replace(/#$/, "") + "#" + buildHashFromObj(current); 295 | window.prompt("Save link to this recipe: Ctrl+C, Enter", shareLink); 296 | } 297 | 298 | // thank you for your attention. Now go draw something. --------------------------------------------------------------------------------