diff --git a/.gitignore b/.gitignore index e43b0f988..4f83dfc29 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +.sass-cache +node_modules diff --git a/Gruntfile.coffee b/Gruntfile.coffee new file mode 100644 index 000000000..7fc0fe10a --- /dev/null +++ b/Gruntfile.coffee @@ -0,0 +1,116 @@ +### +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +######################################################################################################################## + +module.exports = (grunt)-> + + grunt.loadTasks tasks for tasks in grunt.file.expand './node_modules/grunt-*/tasks' + + grunt.config.init + browserify: + main: + options: + ignore: ['jade'] + transform: ['coffeeify'] + browserifyOptions: + debug: false + extensions: ['.coffee'] + files: + './dist/js/main.js': ['./src/scripts/main.coffee'] + test: + options: + transform: ['coffeeify'] + browserifyOptions: + debug: true + extensions: ['.coffee'] + files: + './dist/js/test.js': ['./test/test.coffee'] + when: + options: + browserifyOptions: + debug: false + standalone: 'w' + files: + './dist/js/when.js': ['./node_modules/when/when.js'] + + clean: + dist: ['./dist'] + + copy: + data: + files: [expand:true, cwd:'./src/data', src:'**/*.json', dest:'./dist/data'] + fonts: + files: [expand:true, cwd:'./src/fonts', src:'**/*.ttf', dest:'./dist/fonts'] + images: + files: [expand:true, cwd:'./src/images/', src:['**/*.png', '**/*.jpg'], dest:'./dist/images'] + mocha_styles: + files: + './dist/css/mocha.css': ['./node_modules/mocha/mocha.css'] + scripts: + files: + './dist/js/backbone.js': ['./node_modules/backbone/backbone.js'] + './dist/js/chai.js': ['./node_modules/chai/chai.js'] + './dist/js/jade.js': ['./node_modules/jade/runtime.js'] + './dist/js/jquery.js': ['./node_modules/jquery/dist/jquery.js'] + './dist/js/mocha.js': ['./node_modules/mocha/mocha.js'] + './dist/js/underscore.js': ['./node_modules/backbone/node_modules/underscore/underscore.js'] + styles: + files: [expand:true, cwd:'./src/css', src:'**/*.scss', dest:'./dist/src/css'] + + jade: + pages: + options: + pretty: true + files: [ + expand: true + cwd: './src/pages' + src: '*.jade' + dest: './dist' + ext: '.html' + ] + + templates: + options: + client: true + node: true + pretty: true + processName: (f)-> + f = f.replace './src/templates/', '' + f = f.replace '_view', '' + f = f.replace '.jade', '' + f = f.replace /\//g, '_' + return f + files: + './src/scripts/views.js': ['./src/templates/**/*.jade'] + + sass: + main: + files: + './dist/css/main.css': ['./src/css/main.scss'] + + watch: + fonts: + files: ['./src/fonts/**/*'] + tasks: ['copy:fonts'] + images: + files: ['./src/images/**/*'] + tasks: ['copy:images'] + browserify: + files: ['./src/scripts/**/*.coffee', './test/**/*.coffee'] + tasks: ['browserify'] + pages: + files: ['./src/pages/**/*.jade'] + tasks: ['jade:pages'] + templates: + files: ['./src/templates/**/*.jade'] + tasks: ['jade:templates', 'browserify:main'] + sass: + files: ['./src/css/**/*.scss'] + tasks: ['sass', 'copy:styles'] + + grunt.registerTask 'default', 'build' + + grunt.registerTask 'build', ['copy', 'sass', 'jade', 'browserify'] diff --git a/dist/css/main.css b/dist/css/main.css new file mode 100644 index 000000000..81de61d13 --- /dev/null +++ b/dist/css/main.css @@ -0,0 +1,219 @@ +/* +Crafting Guide - main.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +/* +Crafting Guide - mixins.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +a, abbr, acronym, address, applet, article, aside, audio, b, big, blockquote, body, canvas, caption, center, cite, code, dd, del, details, dfn, dialog, div, dl, dt, em, embed, fieldset, figcaption, figure, font, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, html, i, iframe, img, ins, kbd, label, legend, li, mark, menu, meter, nav, object, ol, output, p, pre, progress, q, rp, rt, ruby, s, samp, section, small, span, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, time, tr, tt, u, ul, var, video, xmp { + border: 0; + margin: 0; + padding: 0; + font-size: 100%; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; } + +html, body { + height: 100%; } + +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + display: block; } + +b, strong { + font-weight: bold; } + +img { + color: transparent; + vertical-align: middle; + -ms-interpolation-mode: bicubic; } + +ol, ul { + list-style: none; } + +li { + display: list-item; } + +table { + border-collapse: collapse; + border-spacing: 0; } + +th, td, caption { + font-weight: normal; + vertical-align: top; + text-align: left; } + +q { + quotes: none; } + +q:before, q:after { + content: ''; + content: none; } + +sub, sup, small { + font-size: 75%; } + +sub, sup { + line-height: 0; + position: relative; + vertical-align: baseline; } + +sub { + bottom: -0.25em; } + +sup { + top: -0.5em; } + +svg { + overflow: hidden; } + +@font-face { + font-family: 'PressStart'; + font-style: normal; + font-weight: 400; + src: url("/fonts/press_start.ttf") format("truetype"); } +body { + background: #AAC9FF url("/images/ice.png"); + font-size: 10px; } + +h1 { + margin-bottom: 1em; } + h1 * { + display: inline; } + h1 img { + position: relative; + height: 10em; + width: 10em; + margin-right: 1em; + vertical-align: bottom; } + h1 p { + font-family: PressStart; + font-size: 3em; + position: relative; + top: -0.5em; } + +h2 { + margin-bottom: 1em; } + h2 * { + display: inline; } + h2 img { + position: relative; + height: 7.5em; + width: 7.5em; + margin-right: 1em; + vertical-align: bottom; } + h2 p { + font-family: PressStart; + font-size: 2em; + position: relative; + top: -0.25em; } + +.centered { + text-align: center; } + +.content { + background: rgba(230, 230, 230, 0.9); + box-shadow: 10px 10px 20px #666; + margin: 2em auto; + max-width: 96em; + position: relative; + width: 100%; } + +.view__footer { + background: #3D1D09; + color: white; + margin-top: 2em; } + .view__footer a { + color: white; } + .view__footer .divider { + position: relative; + height: 3.2em; + width: 100%; + clear: both; } + .view__footer .divider.top { + background: #906647 url("/images/grass_side.png"); } + .view__footer .left, .view__footer .center, .view__footer .right { + position: relative; + width: 33%; + float: left; + padding: 2em; } + .view__footer .left p, .view__footer .center p, .view__footer .right p { + font-family: sans-serif; + font-size: 1.25em; + padding-bottom: 1.0em; } + .view__footer .left p:last-child, .view__footer .center p:last-child, .view__footer .right p:last-child { + padding-bottom: 0; } + .view__footer .left h2, .view__footer .center h2, .view__footer .right h2 { + padding-bottom: 1.0em; } + .view__footer .left h2 p, .view__footer .center h2 p, .view__footer .right h2 p { + font-family: PressStart; + font-size: 1.5em; } + .view__footer .divider.bottom { + background: #0A0A0A url("/images/bedrock.png"); } + +.view__header { + background: #D9D9D9 url("/images/stone_brick_light.png"); + position: relative; + height: 10em; + margin: 5em 0 2em 0; } + .view__header h1 { + position: relative; + top: -3em; + left: -3em; } + .view__header .divider { + background: #7A7A7A url("/images/stone_brick.png"); + position: absolute; + bottom: 0; + height: 3.2em; + width: 100%; } + +/* +Crafting Guide - templates/index.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +/* +Crafting Guide - recipe_books.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ +.view__recipe_catalog { + position: relative; + width: 100%; + padding: 0 2em; } + .view__recipe_catalog button { + position: absolute; + top: 50%; + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -webkit-transform: translateY(-50%); + transform: translateY(-50%); + position: absolute; + right: 1em; } + .view__recipe_catalog input { + border: 0; + width: 90%; } + .view__recipe_catalog table { + background: white; + margin: 0 auto; + width: 98%; } + .view__recipe_catalog table td { + height: 3em; + padding: 0 1em; + position: relative; + vertical-align: middle; } + .view__recipe_catalog table td:nth-child(1) { + width: 30%; } + .view__recipe_catalog table td:nth-child(2) { + width: 70%; + border-left: 0.1em solid #D9D9D9; } + +/*# sourceMappingURL=main.css.map */ diff --git a/dist/css/main.css.map b/dist/css/main.css.map new file mode 100644 index 000000000..b09c1f4f4 --- /dev/null +++ b/dist/css/main.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": ";;;;;;;;;;;;AAAA,0hBAAmc;EAC/b,MAAM,EAAE,CAAC;EACT,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,SAAS,EAAE,IAAI;ECIjB,eAAe,EDHO,UAAU;ECIhC,kBAAkB,EDJI,UAAU;ECKhC,UAAU,EDLY,UAAU;;AAGlC,UAAU;EACN,MAAM,EAAE,IAAI;;AAGhB,uFAA8E;EAC1E,OAAO,EAAE,KAAK;;AAGlB,SAAS;EACL,WAAW,EAAE,IAAI;;AAGrB,GAAI;EACA,KAAK,EAAE,WAAW;EAClB,cAAc,EAAE,MAAM;EACtB,sBAAsB,EAAE,OAAO;;AAGnC,MAAM;EACF,UAAU,EAAE,IAAI;;AAGpB,EAAG;EACC,OAAO,EAAE,SAAS;;AAGtB,KAAM;EACF,eAAe,EAAE,QAAQ;EACzB,cAAc,EAAE,CAAC;;AAGrB,eAAc;EACV,WAAW,EAAE,MAAM;EACnB,cAAc,EAAE,GAAG;EACnB,UAAU,EAAE,IAAI;;AAGpB,CAAE;EACE,MAAM,EAAE,IAAI;;AAGhB,iBAAiB;EACb,OAAO,EAAE,EAAE;EACX,OAAO,EAAE,IAAI;;AAGjB,eAAc;EACV,SAAS,EAAE,GAAG;;AAGlB,QAAQ;EACJ,WAAW,EAAE,CAAC;EACd,QAAQ,EAAE,QAAQ;EAClB,cAAc,EAAE,QAAQ;;AAG5B,GAAI;EACA,MAAM,EAAE,OAAO;;AAGnB,GAAI;EACA,GAAG,EAAE,MAAM;;AAGf,GAAI;EACA,QAAQ,EAAE,MAAM;;AElDpB,UAKC;EAJC,WAAW,EAAE,YAAY;EACzB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,gDAAgD;AAKvD,IAAK;EACD,UAAU,EAAE,8BAAwC;EACpD,SAAS,EAAE,IAAI;;AAGnB,EAAG;EACC,aAAa,EAAE,GAAG;EAElB,IAAE;IAAE,OAAO,EAAE,MAAM;EAEnB,MAAI;IACA,QAAQ,EAAE,QAAQ;IAAE,MAAM,EAAE,IAAI;IAAE,KAAK,EAAE,IAAI;IAC7C,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,MAAM;EAG1B,IAAE;IACE,WAAW,EAAE,UAAU;IACvB,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,QAAQ;IAAE,GAAG,EAAE,MAAM;;AAIvC,EAAG;EACC,aAAa,EAAE,GAAG;EAElB,IAAE;IAAE,OAAO,EAAE,MAAM;EAEnB,MAAI;IACA,QAAQ,EAAE,QAAQ;IAAE,MAAM,EAAE,KAAK;IAAE,KAAK,EAAE,KAAK;IAC/C,YAAY,EAAE,GAAG;IACjB,cAAc,EAAE,MAAM;EAG1B,IAAE;IACE,WAAW,EAAE,UAAU;IACvB,SAAS,EAAE,GAAG;IACd,QAAQ,EAAE,QAAQ;IAAE,GAAG,EAAE,OAAO;;AAIxC,SAAU;EACN,UAAU,EAAE,MAAM;;AAGtB,QAAS;EACL,UAAU,EAhEE,wBAAyB;EAiErC,UAAU,EAAE,mBAAmB;EAC/B,MAAM,EAAE,QAAQ;EAChB,SAAS,EAAE,IAAI;EACf,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;;AAKf,aAAc;EACV,UAAU,EAxEC,OAAO;EAyElB,KAAK,EAxEW,KAAK;EAyErB,UAAU,EAAE,GAAG;EAEf,eAAE;IACE,KAAK,EA5EO,KAAK;EA+ErB,sBAAS;IACL,QAAQ,EAAE,QAAQ;IAAE,MAAM,EAAE,KAAK;IAAE,KAAK,EAAE,IAAI;IAC9C,KAAK,EAAE,IAAI;EAGf,0BAAa;IACT,UAAU,EAAE,qCAAyC;EAGzD,gEAAwB;IACpB,QAAQ,EAAE,QAAQ;IAAE,KAAK,EAAE,GAAG;IAC9B,KAAK,EAAE,IAAI;IACX,OAAO,EAAE,GAAG;IAEZ,sEAAE;MACE,WAAW,EAAE,UAAU;MACvB,SAAS,EAAE,MAAM;MACjB,cAAc,EAAE,KAAK;MAErB,uGAAa;QACT,cAAc,EAAE,CAAC;IAIzB,yEAAG;MACC,cAAc,EAAE,KAAK;MAErB,+EAAE;QACE,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,KAAK;EAK5B,6BAAgB;IACZ,UAAU,EAAE,kCAAyC;;AAI7D,aAAc;EACV,UAAU,EAAE,4CAAuD;EACnE,QAAQ,EAAE,QAAQ;EAAE,MAAM,EAAE,IAAI;EAChC,MAAM,EAAE,WAAW;EAEnB,gBAAG;IAAE,QAAQ,EAAE,QAAQ;IAAE,GAAG,EAAE,IAAI;IAAE,IAAI,EAAE,IAAI;EAE9C,sBAAS;IACL,UAAU,EAAE,sCAAgD;IAC5D,QAAQ,EAAE,QAAQ;IAAE,MAAM,EAAE,CAAC;IAAE,MAAM,EAAE,KAAK;IAAE,KAAK,EAAE,IAAI;;;;;;;;;;;;;;AC1IjE,qBAAsB;EAClB,QAAQ,EAAE,QAAQ;EAAE,KAAK,EAAE,IAAI;EAC/B,OAAO,EAAE,KAAK;EAEd,4BAAO;IFGP,QAAQ,EAAE,QAAQ;IAClB,GAAG,EAAE,GAAG;IAKR,cAAc,EAAE,gBAAW;IAC3B,YAAY,EAAE,gBAAW;IACzB,aAAa,EAAE,gBAAW;IAC1B,iBAAiB,EAAE,gBAAW;IAC9B,SAAS,EAAE,gBAAW;IEXlB,QAAQ,EAAE,QAAQ;IAAE,KAAK,EAAE,GAAG;EAGlC,2BAAM;IAAE,MAAM,EAAE,CAAC;IAAE,KAAK,EAAE,GAAG;EAE7B,2BAAM;IACF,UAAU,EAAE,KAAK;IACjB,MAAM,EAAE,MAAM;IACd,KAAK,EAAE,GAAG;IAEV,8BAAG;MAAE,MAAM,EAAE,GAAG;MAAE,OAAO,EAAE,KAAK;MAAE,QAAQ,EAAE,QAAQ;MAAE,cAAc,EAAE,MAAM;IAC5E,2CAAgB;MAAE,KAAK,EAAE,GAAG;IAC5B,2CAAgB;MAAE,KAAK,EAAE,GAAG;MAAE,WAAW,EAAE,mBAA8B", +"sources": ["../../src/css/reset.scss","../../src/css/mixins.scss","../../src/css/main.scss","../../src/css/templates/recipe_catalog.scss"], +"names": [], +"file": "main.css" +} diff --git a/dist/css/mocha.css b/dist/css/mocha.css new file mode 100644 index 000000000..42b9798fa --- /dev/null +++ b/dist/css/mocha.css @@ -0,0 +1,270 @@ +@charset "utf-8"; + +body { + margin:0; +} + +#mocha { + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 60px 50px; +} + +#mocha ul, +#mocha li { + margin: 0; + padding: 0; +} + +#mocha ul { + list-style: none; +} + +#mocha h1, +#mocha h2 { + margin: 0; +} + +#mocha h1 { + margin-top: 15px; + font-size: 1em; + font-weight: 200; +} + +#mocha h1 a { + text-decoration: none; + color: inherit; +} + +#mocha h1 a:hover { + text-decoration: underline; +} + +#mocha .suite .suite h1 { + margin-top: 0; + font-size: .8em; +} + +#mocha .hidden { + display: none; +} + +#mocha h2 { + font-size: 12px; + font-weight: normal; + cursor: pointer; +} + +#mocha .suite { + margin-left: 15px; +} + +#mocha .test { + margin-left: 15px; + overflow: hidden; +} + +#mocha .test.pending:hover h2::after { + content: '(pending)'; + font-family: arial, sans-serif; +} + +#mocha .test.pass.medium .duration { + background: #c09853; +} + +#mocha .test.pass.slow .duration { + background: #b94a48; +} + +#mocha .test.pass::before { + content: '✓'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #00d6b2; +} + +#mocha .test.pass .duration { + font-size: 9px; + margin-left: 5px; + padding: 2px 5px; + color: #fff; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} + +#mocha .test.pass.fast .duration { + display: none; +} + +#mocha .test.pending { + color: #0b97c4; +} + +#mocha .test.pending::before { + content: '◦'; + color: #0b97c4; +} + +#mocha .test.fail { + color: #c00; +} + +#mocha .test.fail pre { + color: black; +} + +#mocha .test.fail::before { + content: '✖'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #c00; +} + +#mocha .test pre.error { + color: #c00; + max-height: 300px; + overflow: auto; +} + +/** + * (1): approximate for browsers not supporting calc + * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) + * ^^ seriously + */ +#mocha .test pre { + display: block; + float: left; + clear: left; + font: 12px/1.5 monaco, monospace; + margin: 5px; + padding: 15px; + border: 1px solid #eee; + max-width: 85%; /*(1)*/ + max-width: calc(100% - 42px); /*(2)*/ + word-wrap: break-word; + border-bottom-color: #ddd; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 3px #eee; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 3px #eee; + border-radius: 3px; +} + +#mocha .test h2 { + position: relative; +} + +#mocha .test a.replay { + position: absolute; + top: 3px; + right: 0; + text-decoration: none; + vertical-align: middle; + display: block; + width: 15px; + height: 15px; + line-height: 15px; + text-align: center; + background: #eee; + font-size: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + -webkit-transition: opacity 200ms; + -moz-transition: opacity 200ms; + transition: opacity 200ms; + opacity: 0.3; + color: #888; +} + +#mocha .test:hover a.replay { + opacity: 1; +} + +#mocha-report.pass .test.fail { + display: none; +} + +#mocha-report.fail .test.pass { + display: none; +} + +#mocha-report.pending .test.pass, +#mocha-report.pending .test.fail { + display: none; +} +#mocha-report.pending .test.pass.pending { + display: block; +} + +#mocha-error { + color: #c00; + font-size: 1.5em; + font-weight: 100; + letter-spacing: 1px; +} + +#mocha-stats { + position: fixed; + top: 15px; + right: 10px; + font-size: 12px; + margin: 0; + color: #888; + z-index: 1; +} + +#mocha-stats .progress { + float: right; + padding-top: 0; +} + +#mocha-stats em { + color: black; +} + +#mocha-stats a { + text-decoration: none; + color: inherit; +} + +#mocha-stats a:hover { + border-bottom: 1px solid #eee; +} + +#mocha-stats li { + display: inline-block; + margin: 0 5px; + list-style: none; + padding-top: 11px; +} + +#mocha-stats canvas { + width: 40px; + height: 40px; +} + +#mocha code .comment { color: #ddd; } +#mocha code .init { color: #2f6fad; } +#mocha code .string { color: #5890ad; } +#mocha code .keyword { color: #8a6343; } +#mocha code .number { color: #2f6fad; } + +@media screen and (max-device-width: 480px) { + #mocha { + margin: 60px 0px; + } + + #mocha #stats { + position: absolute; + } +} diff --git a/html/data/applied_energetics.json b/dist/data/applied_energetics.json similarity index 100% rename from html/data/applied_energetics.json rename to dist/data/applied_energetics.json diff --git a/html/data/buildcraft.json b/dist/data/buildcraft.json similarity index 100% rename from html/data/buildcraft.json rename to dist/data/buildcraft.json diff --git a/html/data/gravisuite.json b/dist/data/gravisuite.json similarity index 100% rename from html/data/gravisuite.json rename to dist/data/gravisuite.json diff --git a/html/data/industrial_craft.json b/dist/data/industrial_craft.json similarity index 100% rename from html/data/industrial_craft.json rename to dist/data/industrial_craft.json diff --git a/html/data/more_blocks.json b/dist/data/more_blocks.json similarity index 100% rename from html/data/more_blocks.json rename to dist/data/more_blocks.json diff --git a/html/data/thermal_expansion.json b/dist/data/thermal_expansion.json similarity index 100% rename from html/data/thermal_expansion.json rename to dist/data/thermal_expansion.json diff --git a/html/data/vanilla.json b/dist/data/vanilla.json similarity index 100% rename from html/data/vanilla.json rename to dist/data/vanilla.json diff --git a/dist/fonts/press_start.ttf b/dist/fonts/press_start.ttf new file mode 100644 index 000000000..1efa15873 Binary files /dev/null and b/dist/fonts/press_start.ttf differ diff --git a/dist/images/bedrock.png b/dist/images/bedrock.png new file mode 100644 index 000000000..79ac81cb9 Binary files /dev/null and b/dist/images/bedrock.png differ diff --git a/dist/images/bookshelf.png b/dist/images/bookshelf.png new file mode 100644 index 000000000..896c30e19 Binary files /dev/null and b/dist/images/bookshelf.png differ diff --git a/dist/images/dirt.png b/dist/images/dirt.png new file mode 100644 index 000000000..28f300b8a Binary files /dev/null and b/dist/images/dirt.png differ diff --git a/dist/images/grass_side.png b/dist/images/grass_side.png new file mode 100644 index 000000000..5d8809926 Binary files /dev/null and b/dist/images/grass_side.png differ diff --git a/dist/images/ice.png b/dist/images/ice.png new file mode 100644 index 000000000..97581e8b8 Binary files /dev/null and b/dist/images/ice.png differ diff --git a/dist/images/stone_brick.png b/dist/images/stone_brick.png new file mode 100644 index 000000000..f810cdeb7 Binary files /dev/null and b/dist/images/stone_brick.png differ diff --git a/dist/images/stone_brick_light.png b/dist/images/stone_brick_light.png new file mode 100644 index 000000000..aac7c0ee6 Binary files /dev/null and b/dist/images/stone_brick_light.png differ diff --git a/dist/images/wordmark.png b/dist/images/wordmark.png new file mode 100644 index 000000000..e538238ed Binary files /dev/null and b/dist/images/wordmark.png differ diff --git a/dist/images/workbench_front.png b/dist/images/workbench_front.png new file mode 100644 index 000000000..ec3ba9bf8 Binary files /dev/null and b/dist/images/workbench_front.png differ diff --git a/dist/images/workbench_top.png b/dist/images/workbench_top.png new file mode 100644 index 000000000..60d8026c3 Binary files /dev/null and b/dist/images/workbench_top.png differ diff --git a/dist/index.html b/dist/index.html new file mode 100644 index 000000000..4b6945368 --- /dev/null +++ b/dist/index.html @@ -0,0 +1,75 @@ + + + + Crafting Guide + + + + +
+
+

+

Crafting Guide

+

+
+
+
+ +
+ + + + + + + + + \ No newline at end of file diff --git a/dist/js/backbone.js b/dist/js/backbone.js new file mode 100644 index 000000000..24a550a0a --- /dev/null +++ b/dist/js/backbone.js @@ -0,0 +1,1608 @@ +// Backbone.js 1.1.2 + +// (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://backbonejs.org + +(function(root, factory) { + + // Set up Backbone appropriately for the environment. Start with AMD. + if (typeof define === 'function' && define.amd) { + define(['underscore', 'jquery', 'exports'], function(_, $, exports) { + // Export global even in AMD case in case this script is loaded with + // others that may still expect a global Backbone. + root.Backbone = factory(root, exports, _, $); + }); + + // Next for Node.js or CommonJS. jQuery may not be needed as a module. + } else if (typeof exports !== 'undefined') { + var _ = require('underscore'); + factory(root, exports, _); + + // Finally, as a browser global. + } else { + root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$)); + } + +}(this, function(root, Backbone, _, $) { + + // Initial Setup + // ------------- + + // Save the previous value of the `Backbone` variable, so that it can be + // restored later on, if `noConflict` is used. + var previousBackbone = root.Backbone; + + // Create local references to array methods we'll want to use later. + var array = []; + var push = array.push; + var slice = array.slice; + var splice = array.splice; + + // Current version of the library. Keep in sync with `package.json`. + Backbone.VERSION = '1.1.2'; + + // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns + // the `$` variable. + Backbone.$ = $; + + // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable + // to its previous owner. Returns a reference to this Backbone object. + Backbone.noConflict = function() { + root.Backbone = previousBackbone; + return this; + }; + + // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option + // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // set a `X-Http-Method-Override` header. + Backbone.emulateHTTP = false; + + // Turn on `emulateJSON` to support legacy servers that can't deal with direct + // `application/json` requests ... will encode the body as + // `application/x-www-form-urlencoded` instead and will send the model in a + // form param named `model`. + Backbone.emulateJSON = false; + + // Backbone.Events + // --------------- + + // A module that can be mixed in to *any object* in order to provide it with + // custom events. You may bind with `on` or remove with `off` callback + // functions to an event; `trigger`-ing an event fires all callbacks in + // succession. + // + // var object = {}; + // _.extend(object, Backbone.Events); + // object.on('expand', function(){ alert('expanded'); }); + // object.trigger('expand'); + // + var Events = Backbone.Events = { + + // Bind an event to a `callback` function. Passing `"all"` will bind + // the callback to all events fired. + on: function(name, callback, context) { + if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; + this._events || (this._events = {}); + var events = this._events[name] || (this._events[name] = []); + events.push({callback: callback, context: context, ctx: context || this}); + return this; + }, + + // Bind an event to only be triggered a single time. After the first time + // the callback is invoked, it will be removed. + once: function(name, callback, context) { + if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; + var self = this; + var once = _.once(function() { + self.off(name, once); + callback.apply(this, arguments); + }); + once._callback = callback; + return this.on(name, once, context); + }, + + // Remove one or many callbacks. If `context` is null, removes all + // callbacks with that function. If `callback` is null, removes all + // callbacks for the event. If `name` is null, removes all bound + // callbacks for all events. + off: function(name, callback, context) { + var retain, ev, events, names, i, l, j, k; + if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; + if (!name && !callback && !context) { + this._events = void 0; + return this; + } + names = name ? [name] : _.keys(this._events); + for (i = 0, l = names.length; i < l; i++) { + name = names[i]; + if (events = this._events[name]) { + this._events[name] = retain = []; + if (callback || context) { + for (j = 0, k = events.length; j < k; j++) { + ev = events[j]; + if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || + (context && context !== ev.context)) { + retain.push(ev); + } + } + } + if (!retain.length) delete this._events[name]; + } + } + + return this; + }, + + // Trigger one or many events, firing all bound callbacks. Callbacks are + // passed the same arguments as `trigger` is, apart from the event name + // (unless you're listening on `"all"`, which will cause your callback to + // receive the true name of the event as the first argument). + trigger: function(name) { + if (!this._events) return this; + var args = slice.call(arguments, 1); + if (!eventsApi(this, 'trigger', name, args)) return this; + var events = this._events[name]; + var allEvents = this._events.all; + if (events) triggerEvents(events, args); + if (allEvents) triggerEvents(allEvents, arguments); + return this; + }, + + // Tell this object to stop listening to either specific events ... or + // to every object it's currently listening to. + stopListening: function(obj, name, callback) { + var listeningTo = this._listeningTo; + if (!listeningTo) return this; + var remove = !name && !callback; + if (!callback && typeof name === 'object') callback = this; + if (obj) (listeningTo = {})[obj._listenId] = obj; + for (var id in listeningTo) { + obj = listeningTo[id]; + obj.off(name, callback, this); + if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; + } + return this; + } + + }; + + // Regular expression used to split event strings. + var eventSplitter = /\s+/; + + // Implement fancy features of the Events API such as multiple event + // names `"change blur"` and jQuery-style event maps `{change: action}` + // in terms of the existing API. + var eventsApi = function(obj, action, name, rest) { + if (!name) return true; + + // Handle event maps. + if (typeof name === 'object') { + for (var key in name) { + obj[action].apply(obj, [key, name[key]].concat(rest)); + } + return false; + } + + // Handle space separated event names. + if (eventSplitter.test(name)) { + var names = name.split(eventSplitter); + for (var i = 0, l = names.length; i < l; i++) { + obj[action].apply(obj, [names[i]].concat(rest)); + } + return false; + } + + return true; + }; + + // A difficult-to-believe, but optimized internal dispatch function for + // triggering events. Tries to keep the usual cases speedy (most internal + // Backbone events have 3 arguments). + var triggerEvents = function(events, args) { + var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; + switch (args.length) { + case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; + case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; + case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; + case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; + default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; + } + }; + + var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; + + // Inversion-of-control versions of `on` and `once`. Tell *this* object to + // listen to an event in another object ... keeping track of what it's + // listening to. + _.each(listenMethods, function(implementation, method) { + Events[method] = function(obj, name, callback) { + var listeningTo = this._listeningTo || (this._listeningTo = {}); + var id = obj._listenId || (obj._listenId = _.uniqueId('l')); + listeningTo[id] = obj; + if (!callback && typeof name === 'object') callback = this; + obj[implementation](name, callback, this); + return this; + }; + }); + + // Aliases for backwards compatibility. + Events.bind = Events.on; + Events.unbind = Events.off; + + // Allow the `Backbone` object to serve as a global event bus, for folks who + // want global "pubsub" in a convenient place. + _.extend(Backbone, Events); + + // Backbone.Model + // -------------- + + // Backbone **Models** are the basic data object in the framework -- + // frequently representing a row in a table in a database on your server. + // A discrete chunk of data and a bunch of useful, related methods for + // performing computations and transformations on that data. + + // Create a new model with the specified attributes. A client id (`cid`) + // is automatically generated and assigned for you. + var Model = Backbone.Model = function(attributes, options) { + var attrs = attributes || {}; + options || (options = {}); + this.cid = _.uniqueId('c'); + this.attributes = {}; + if (options.collection) this.collection = options.collection; + if (options.parse) attrs = this.parse(attrs, options) || {}; + attrs = _.defaults({}, attrs, _.result(this, 'defaults')); + this.set(attrs, options); + this.changed = {}; + this.initialize.apply(this, arguments); + }; + + // Attach all inheritable methods to the Model prototype. + _.extend(Model.prototype, Events, { + + // A hash of attributes whose current and previous value differ. + changed: null, + + // The value returned during the last failed validation. + validationError: null, + + // The default name for the JSON `id` attribute is `"id"`. MongoDB and + // CouchDB users may want to set this to `"_id"`. + idAttribute: 'id', + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Return a copy of the model's `attributes` object. + toJSON: function(options) { + return _.clone(this.attributes); + }, + + // Proxy `Backbone.sync` by default -- but override this if you need + // custom syncing semantics for *this* particular model. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Get the value of an attribute. + get: function(attr) { + return this.attributes[attr]; + }, + + // Get the HTML-escaped value of an attribute. + escape: function(attr) { + return _.escape(this.get(attr)); + }, + + // Returns `true` if the attribute contains a value that is not null + // or undefined. + has: function(attr) { + return this.get(attr) != null; + }, + + // Set a hash of model attributes on the object, firing `"change"`. This is + // the core primitive operation of a model, updating the data and notifying + // anyone who needs to know about the change in state. The heart of the beast. + set: function(key, val, options) { + var attr, attrs, unset, changes, silent, changing, prev, current; + if (key == null) return this; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options || (options = {}); + + // Run validation. + if (!this._validate(attrs, options)) return false; + + // Extract attributes and options. + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; + + if (!changing) { + this._previousAttributes = _.clone(this.attributes); + this.changed = {}; + } + current = this.attributes, prev = this._previousAttributes; + + // Check for changes of `id`. + if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; + + // For each `set` attribute, update or delete the current value. + for (attr in attrs) { + val = attrs[attr]; + if (!_.isEqual(current[attr], val)) changes.push(attr); + if (!_.isEqual(prev[attr], val)) { + this.changed[attr] = val; + } else { + delete this.changed[attr]; + } + unset ? delete current[attr] : current[attr] = val; + } + + // Trigger all relevant attribute changes. + if (!silent) { + if (changes.length) this._pending = options; + for (var i = 0, l = changes.length; i < l; i++) { + this.trigger('change:' + changes[i], this, current[changes[i]], options); + } + } + + // You might be wondering why there's a `while` loop here. Changes can + // be recursively nested within `"change"` events. + if (changing) return this; + if (!silent) { + while (this._pending) { + options = this._pending; + this._pending = false; + this.trigger('change', this, options); + } + } + this._pending = false; + this._changing = false; + return this; + }, + + // Remove an attribute from the model, firing `"change"`. `unset` is a noop + // if the attribute doesn't exist. + unset: function(attr, options) { + return this.set(attr, void 0, _.extend({}, options, {unset: true})); + }, + + // Clear all attributes on the model, firing `"change"`. + clear: function(options) { + var attrs = {}; + for (var key in this.attributes) attrs[key] = void 0; + return this.set(attrs, _.extend({}, options, {unset: true})); + }, + + // Determine if the model has changed since the last `"change"` event. + // If you specify an attribute name, determine if that attribute has changed. + hasChanged: function(attr) { + if (attr == null) return !_.isEmpty(this.changed); + return _.has(this.changed, attr); + }, + + // Return an object containing all the attributes that have changed, or + // false if there are no changed attributes. Useful for determining what + // parts of a view need to be updated and/or what attributes need to be + // persisted to the server. Unset attributes will be set to undefined. + // You can also pass an attributes object to diff against the model, + // determining if there *would be* a change. + changedAttributes: function(diff) { + if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; + var val, changed = false; + var old = this._changing ? this._previousAttributes : this.attributes; + for (var attr in diff) { + if (_.isEqual(old[attr], (val = diff[attr]))) continue; + (changed || (changed = {}))[attr] = val; + } + return changed; + }, + + // Get the previous value of an attribute, recorded at the time the last + // `"change"` event was fired. + previous: function(attr) { + if (attr == null || !this._previousAttributes) return null; + return this._previousAttributes[attr]; + }, + + // Get all of the attributes of the model at the time of the previous + // `"change"` event. + previousAttributes: function() { + return _.clone(this._previousAttributes); + }, + + // Fetch the model from the server. If the server's representation of the + // model differs from its current attributes, they will be overridden, + // triggering a `"change"` event. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + if (!model.set(model.parse(resp, options), options)) return false; + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Set a hash of model attributes, and sync the model to the server. + // If the server returns an attributes hash that differs, the model's + // state will be `set` again. + save: function(key, val, options) { + var attrs, method, xhr, attributes = this.attributes; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options = _.extend({validate: true}, options); + + // If we're not waiting and attributes exist, save acts as + // `set(attr).save(null, opts)` with validation. Otherwise, check if + // the model will be valid when the attributes, if any, are set. + if (attrs && !options.wait) { + if (!this.set(attrs, options)) return false; + } else { + if (!this._validate(attrs, options)) return false; + } + + // Set temporary attributes if `{wait: true}`. + if (attrs && options.wait) { + this.attributes = _.extend({}, attributes, attrs); + } + + // After a successful server-side save, the client is (optionally) + // updated with the server-side state. + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + // Ensure attributes are restored during synchronous saves. + model.attributes = attributes; + var serverAttrs = model.parse(resp, options); + if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); + if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { + return false; + } + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + + method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); + if (method === 'patch') options.attrs = attrs; + xhr = this.sync(method, this, options); + + // Restore attributes. + if (attrs && options.wait) this.attributes = attributes; + + return xhr; + }, + + // Destroy this model on the server if it was already persisted. + // Optimistically removes the model from its collection, if it has one. + // If `wait: true` is passed, waits for the server to respond before removal. + destroy: function(options) { + options = options ? _.clone(options) : {}; + var model = this; + var success = options.success; + + var destroy = function() { + model.trigger('destroy', model, model.collection, options); + }; + + options.success = function(resp) { + if (options.wait || model.isNew()) destroy(); + if (success) success(model, resp, options); + if (!model.isNew()) model.trigger('sync', model, resp, options); + }; + + if (this.isNew()) { + options.success(); + return false; + } + wrapError(this, options); + + var xhr = this.sync('delete', this, options); + if (!options.wait) destroy(); + return xhr; + }, + + // Default URL for the model's representation on the server -- if you're + // using Backbone's restful methods, override this to change the endpoint + // that will be called. + url: function() { + var base = + _.result(this, 'urlRoot') || + _.result(this.collection, 'url') || + urlError(); + if (this.isNew()) return base; + return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id); + }, + + // **parse** converts a response into the hash of attributes to be `set` on + // the model. The default implementation is just to pass the response along. + parse: function(resp, options) { + return resp; + }, + + // Create a new model with identical attributes to this one. + clone: function() { + return new this.constructor(this.attributes); + }, + + // A model is new if it has never been saved to the server, and lacks an id. + isNew: function() { + return !this.has(this.idAttribute); + }, + + // Check if the model is currently in a valid state. + isValid: function(options) { + return this._validate({}, _.extend(options || {}, { validate: true })); + }, + + // Run validation against the next complete set of model attributes, + // returning `true` if all is well. Otherwise, fire an `"invalid"` event. + _validate: function(attrs, options) { + if (!options.validate || !this.validate) return true; + attrs = _.extend({}, this.attributes, attrs); + var error = this.validationError = this.validate(attrs, options) || null; + if (!error) return true; + this.trigger('invalid', this, error, _.extend(options, {validationError: error})); + return false; + } + + }); + + // Underscore methods that we want to implement on the Model. + var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; + + // Mix in each Underscore method as a proxy to `Model#attributes`. + _.each(modelMethods, function(method) { + Model.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.attributes); + return _[method].apply(_, args); + }; + }); + + // Backbone.Collection + // ------------------- + + // If models tend to represent a single row of data, a Backbone Collection is + // more analagous to a table full of data ... or a small slice or page of that + // table, or a collection of rows that belong together for a particular reason + // -- all of the messages in this particular folder, all of the documents + // belonging to this particular author, and so on. Collections maintain + // indexes of their models, both in order, and for lookup by `id`. + + // Create a new **Collection**, perhaps to contain a specific type of `model`. + // If a `comparator` is specified, the Collection will maintain + // its models in sort order, as they're added and removed. + var Collection = Backbone.Collection = function(models, options) { + options || (options = {}); + if (options.model) this.model = options.model; + if (options.comparator !== void 0) this.comparator = options.comparator; + this._reset(); + this.initialize.apply(this, arguments); + if (models) this.reset(models, _.extend({silent: true}, options)); + }; + + // Default options for `Collection#set`. + var setOptions = {add: true, remove: true, merge: true}; + var addOptions = {add: true, remove: false}; + + // Define the Collection's inheritable methods. + _.extend(Collection.prototype, Events, { + + // The default model for a collection is just a **Backbone.Model**. + // This should be overridden in most cases. + model: Model, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // The JSON representation of a Collection is an array of the + // models' attributes. + toJSON: function(options) { + return this.map(function(model){ return model.toJSON(options); }); + }, + + // Proxy `Backbone.sync` by default. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Add a model, or list of models to the set. + add: function(models, options) { + return this.set(models, _.extend({merge: false}, options, addOptions)); + }, + + // Remove a model, or a list of models from the set. + remove: function(models, options) { + var singular = !_.isArray(models); + models = singular ? [models] : _.clone(models); + options || (options = {}); + var i, l, index, model; + for (i = 0, l = models.length; i < l; i++) { + model = models[i] = this.get(models[i]); + if (!model) continue; + delete this._byId[model.id]; + delete this._byId[model.cid]; + index = this.indexOf(model); + this.models.splice(index, 1); + this.length--; + if (!options.silent) { + options.index = index; + model.trigger('remove', model, this, options); + } + this._removeReference(model, options); + } + return singular ? models[0] : models; + }, + + // Update a collection by `set`-ing a new list of models, adding new ones, + // removing models that are no longer present, and merging models that + // already exist in the collection, as necessary. Similar to **Model#set**, + // the core operation for updating the data contained by the collection. + set: function(models, options) { + options = _.defaults({}, options, setOptions); + if (options.parse) models = this.parse(models, options); + var singular = !_.isArray(models); + models = singular ? (models ? [models] : []) : _.clone(models); + var i, l, id, model, attrs, existing, sort; + var at = options.at; + var targetModel = this.model; + var sortable = this.comparator && (at == null) && options.sort !== false; + var sortAttr = _.isString(this.comparator) ? this.comparator : null; + var toAdd = [], toRemove = [], modelMap = {}; + var add = options.add, merge = options.merge, remove = options.remove; + var order = !sortable && add && remove ? [] : false; + + // Turn bare objects into model references, and prevent invalid models + // from being added. + for (i = 0, l = models.length; i < l; i++) { + attrs = models[i] || {}; + if (attrs instanceof Model) { + id = model = attrs; + } else { + id = attrs[targetModel.prototype.idAttribute || 'id']; + } + + // If a duplicate is found, prevent it from being added and + // optionally merge it into the existing model. + if (existing = this.get(id)) { + if (remove) modelMap[existing.cid] = true; + if (merge) { + attrs = attrs === model ? model.attributes : attrs; + if (options.parse) attrs = existing.parse(attrs, options); + existing.set(attrs, options); + if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; + } + models[i] = existing; + + // If this is a new, valid model, push it to the `toAdd` list. + } else if (add) { + model = models[i] = this._prepareModel(attrs, options); + if (!model) continue; + toAdd.push(model); + this._addReference(model, options); + } + + // Do not add multiple models with the same `id`. + model = existing || model; + if (order && (model.isNew() || !modelMap[model.id])) order.push(model); + modelMap[model.id] = true; + } + + // Remove nonexistent models if appropriate. + if (remove) { + for (i = 0, l = this.length; i < l; ++i) { + if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); + } + if (toRemove.length) this.remove(toRemove, options); + } + + // See if sorting is needed, update `length` and splice in new models. + if (toAdd.length || (order && order.length)) { + if (sortable) sort = true; + this.length += toAdd.length; + if (at != null) { + for (i = 0, l = toAdd.length; i < l; i++) { + this.models.splice(at + i, 0, toAdd[i]); + } + } else { + if (order) this.models.length = 0; + var orderedModels = order || toAdd; + for (i = 0, l = orderedModels.length; i < l; i++) { + this.models.push(orderedModels[i]); + } + } + } + + // Silently sort the collection if appropriate. + if (sort) this.sort({silent: true}); + + // Unless silenced, it's time to fire all appropriate add/sort events. + if (!options.silent) { + for (i = 0, l = toAdd.length; i < l; i++) { + (model = toAdd[i]).trigger('add', model, this, options); + } + if (sort || (order && order.length)) this.trigger('sort', this, options); + } + + // Return the added (or merged) model (or models). + return singular ? models[0] : models; + }, + + // When you have more items than you want to add or remove individually, + // you can reset the entire set with a new list of models, without firing + // any granular `add` or `remove` events. Fires `reset` when finished. + // Useful for bulk operations and optimizations. + reset: function(models, options) { + options || (options = {}); + for (var i = 0, l = this.models.length; i < l; i++) { + this._removeReference(this.models[i], options); + } + options.previousModels = this.models; + this._reset(); + models = this.add(models, _.extend({silent: true}, options)); + if (!options.silent) this.trigger('reset', this, options); + return models; + }, + + // Add a model to the end of the collection. + push: function(model, options) { + return this.add(model, _.extend({at: this.length}, options)); + }, + + // Remove a model from the end of the collection. + pop: function(options) { + var model = this.at(this.length - 1); + this.remove(model, options); + return model; + }, + + // Add a model to the beginning of the collection. + unshift: function(model, options) { + return this.add(model, _.extend({at: 0}, options)); + }, + + // Remove a model from the beginning of the collection. + shift: function(options) { + var model = this.at(0); + this.remove(model, options); + return model; + }, + + // Slice out a sub-array of models from the collection. + slice: function() { + return slice.apply(this.models, arguments); + }, + + // Get a model from the set by id. + get: function(obj) { + if (obj == null) return void 0; + return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid]; + }, + + // Get the model at the given index. + at: function(index) { + return this.models[index]; + }, + + // Return models with matching attributes. Useful for simple cases of + // `filter`. + where: function(attrs, first) { + if (_.isEmpty(attrs)) return first ? void 0 : []; + return this[first ? 'find' : 'filter'](function(model) { + for (var key in attrs) { + if (attrs[key] !== model.get(key)) return false; + } + return true; + }); + }, + + // Return the first model with matching attributes. Useful for simple cases + // of `find`. + findWhere: function(attrs) { + return this.where(attrs, true); + }, + + // Force the collection to re-sort itself. You don't need to call this under + // normal circumstances, as the set will maintain sort order as each item + // is added. + sort: function(options) { + if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); + options || (options = {}); + + // Run sort based on type of `comparator`. + if (_.isString(this.comparator) || this.comparator.length === 1) { + this.models = this.sortBy(this.comparator, this); + } else { + this.models.sort(_.bind(this.comparator, this)); + } + + if (!options.silent) this.trigger('sort', this, options); + return this; + }, + + // Pluck an attribute from each model in the collection. + pluck: function(attr) { + return _.invoke(this.models, 'get', attr); + }, + + // Fetch the default set of models for this collection, resetting the + // collection when they arrive. If `reset: true` is passed, the response + // data will be passed through the `reset` method instead of `set`. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var success = options.success; + var collection = this; + options.success = function(resp) { + var method = options.reset ? 'reset' : 'set'; + collection[method](resp, options); + if (success) success(collection, resp, options); + collection.trigger('sync', collection, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Create a new instance of a model in this collection. Add the model to the + // collection immediately, unless `wait: true` is passed, in which case we + // wait for the server to agree. + create: function(model, options) { + options = options ? _.clone(options) : {}; + if (!(model = this._prepareModel(model, options))) return false; + if (!options.wait) this.add(model, options); + var collection = this; + var success = options.success; + options.success = function(model, resp) { + if (options.wait) collection.add(model, options); + if (success) success(model, resp, options); + }; + model.save(null, options); + return model; + }, + + // **parse** converts a response into a list of models to be added to the + // collection. The default implementation is just to pass it through. + parse: function(resp, options) { + return resp; + }, + + // Create a new collection with an identical list of models as this one. + clone: function() { + return new this.constructor(this.models); + }, + + // Private method to reset all internal state. Called when the collection + // is first initialized or reset. + _reset: function() { + this.length = 0; + this.models = []; + this._byId = {}; + }, + + // Prepare a hash of attributes (or other model) to be added to this + // collection. + _prepareModel: function(attrs, options) { + if (attrs instanceof Model) return attrs; + options = options ? _.clone(options) : {}; + options.collection = this; + var model = new this.model(attrs, options); + if (!model.validationError) return model; + this.trigger('invalid', this, model.validationError, options); + return false; + }, + + // Internal method to create a model's ties to a collection. + _addReference: function(model, options) { + this._byId[model.cid] = model; + if (model.id != null) this._byId[model.id] = model; + if (!model.collection) model.collection = this; + model.on('all', this._onModelEvent, this); + }, + + // Internal method to sever a model's ties to a collection. + _removeReference: function(model, options) { + if (this === model.collection) delete model.collection; + model.off('all', this._onModelEvent, this); + }, + + // Internal method called every time a model in the set fires an event. + // Sets need to update their indexes when models change ids. All other + // events simply proxy through. "add" and "remove" events that originate + // in other collections are ignored. + _onModelEvent: function(event, model, collection, options) { + if ((event === 'add' || event === 'remove') && collection !== this) return; + if (event === 'destroy') this.remove(model, options); + if (model && event === 'change:' + model.idAttribute) { + delete this._byId[model.previous(model.idAttribute)]; + if (model.id != null) this._byId[model.id] = model; + } + this.trigger.apply(this, arguments); + } + + }); + + // Underscore methods that we want to implement on the Collection. + // 90% of the core usefulness of Backbone Collections is actually implemented + // right here: + var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', + 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', + 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', + 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', + 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', + 'lastIndexOf', 'isEmpty', 'chain', 'sample']; + + // Mix in each Underscore method as a proxy to `Collection#models`. + _.each(methods, function(method) { + Collection.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.models); + return _[method].apply(_, args); + }; + }); + + // Underscore methods that take a property name as an argument. + var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; + + // Use attributes instead of properties. + _.each(attributeMethods, function(method) { + Collection.prototype[method] = function(value, context) { + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _[method](this.models, iterator, context); + }; + }); + + // Backbone.View + // ------------- + + // Backbone Views are almost more convention than they are actual code. A View + // is simply a JavaScript object that represents a logical chunk of UI in the + // DOM. This might be a single item, an entire list, a sidebar or panel, or + // even the surrounding frame which wraps your whole app. Defining a chunk of + // UI as a **View** allows you to define your DOM events declaratively, without + // having to worry about render order ... and makes it easy for the view to + // react to specific changes in the state of your models. + + // Creating a Backbone.View creates its initial element outside of the DOM, + // if an existing element is not provided... + var View = Backbone.View = function(options) { + this.cid = _.uniqueId('view'); + options || (options = {}); + _.extend(this, _.pick(options, viewOptions)); + this._ensureElement(); + this.initialize.apply(this, arguments); + this.delegateEvents(); + }; + + // Cached regex to split keys for `delegate`. + var delegateEventSplitter = /^(\S+)\s*(.*)$/; + + // List of view options to be merged as properties. + var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; + + // Set up all inheritable **Backbone.View** properties and methods. + _.extend(View.prototype, Events, { + + // The default `tagName` of a View's element is `"div"`. + tagName: 'div', + + // jQuery delegate for element lookup, scoped to DOM elements within the + // current view. This should be preferred to global lookups where possible. + $: function(selector) { + return this.$el.find(selector); + }, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // **render** is the core function that your view should override, in order + // to populate its element (`this.el`), with the appropriate HTML. The + // convention is for **render** to always return `this`. + render: function() { + return this; + }, + + // Remove this view by taking the element out of the DOM, and removing any + // applicable Backbone.Events listeners. + remove: function() { + this.$el.remove(); + this.stopListening(); + return this; + }, + + // Change the view's element (`this.el` property), including event + // re-delegation. + setElement: function(element, delegate) { + if (this.$el) this.undelegateEvents(); + this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); + this.el = this.$el[0]; + if (delegate !== false) this.delegateEvents(); + return this; + }, + + // Set callbacks, where `this.events` is a hash of + // + // *{"event selector": "callback"}* + // + // { + // 'mousedown .title': 'edit', + // 'click .button': 'save', + // 'click .open': function(e) { ... } + // } + // + // pairs. Callbacks will be bound to the view, with `this` set properly. + // Uses event delegation for efficiency. + // Omitting the selector binds the event to `this.el`. + // This only works for delegate-able events: not `focus`, `blur`, and + // not `change`, `submit`, and `reset` in Internet Explorer. + delegateEvents: function(events) { + if (!(events || (events = _.result(this, 'events')))) return this; + this.undelegateEvents(); + for (var key in events) { + var method = events[key]; + if (!_.isFunction(method)) method = this[events[key]]; + if (!method) continue; + + var match = key.match(delegateEventSplitter); + var eventName = match[1], selector = match[2]; + method = _.bind(method, this); + eventName += '.delegateEvents' + this.cid; + if (selector === '') { + this.$el.on(eventName, method); + } else { + this.$el.on(eventName, selector, method); + } + } + return this; + }, + + // Clears all callbacks previously bound to the view with `delegateEvents`. + // You usually don't need to use this, but may wish to if you have multiple + // Backbone views attached to the same DOM element. + undelegateEvents: function() { + this.$el.off('.delegateEvents' + this.cid); + return this; + }, + + // Ensure that the View has a DOM element to render into. + // If `this.el` is a string, pass it through `$()`, take the first + // matching element, and re-assign it to `el`. Otherwise, create + // an element from the `id`, `className` and `tagName` properties. + _ensureElement: function() { + if (!this.el) { + var attrs = _.extend({}, _.result(this, 'attributes')); + if (this.id) attrs.id = _.result(this, 'id'); + if (this.className) attrs['class'] = _.result(this, 'className'); + var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); + this.setElement($el, false); + } else { + this.setElement(_.result(this, 'el'), false); + } + } + + }); + + // Backbone.sync + // ------------- + + // Override this function to change the manner in which Backbone persists + // models to the server. You will be passed the type of request, and the + // model in question. By default, makes a RESTful Ajax request + // to the model's `url()`. Some possible customizations could be: + // + // * Use `setTimeout` to batch rapid-fire updates into a single request. + // * Send up the models as XML instead of JSON. + // * Persist models via WebSockets instead of Ajax. + // + // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests + // as `POST`, with a `_method` parameter containing the true HTTP method, + // as well as all requests with the body as `application/x-www-form-urlencoded` + // instead of `application/json` with the model in a param named `model`. + // Useful when interfacing with server-side languages like **PHP** that make + // it difficult to read the body of `PUT` requests. + Backbone.sync = function(method, model, options) { + var type = methodMap[method]; + + // Default options, unless specified. + _.defaults(options || (options = {}), { + emulateHTTP: Backbone.emulateHTTP, + emulateJSON: Backbone.emulateJSON + }); + + // Default JSON-request options. + var params = {type: type, dataType: 'json'}; + + // Ensure that we have a URL. + if (!options.url) { + params.url = _.result(model, 'url') || urlError(); + } + + // Ensure that we have the appropriate request data. + if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { + params.contentType = 'application/json'; + params.data = JSON.stringify(options.attrs || model.toJSON(options)); + } + + // For older servers, emulate JSON by encoding the request into an HTML-form. + if (options.emulateJSON) { + params.contentType = 'application/x-www-form-urlencoded'; + params.data = params.data ? {model: params.data} : {}; + } + + // For older servers, emulate HTTP by mimicking the HTTP method with `_method` + // And an `X-HTTP-Method-Override` header. + if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { + params.type = 'POST'; + if (options.emulateJSON) params.data._method = type; + var beforeSend = options.beforeSend; + options.beforeSend = function(xhr) { + xhr.setRequestHeader('X-HTTP-Method-Override', type); + if (beforeSend) return beforeSend.apply(this, arguments); + }; + } + + // Don't process data on a non-GET request. + if (params.type !== 'GET' && !options.emulateJSON) { + params.processData = false; + } + + // If we're sending a `PATCH` request, and we're in an old Internet Explorer + // that still has ActiveX enabled by default, override jQuery to use that + // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. + if (params.type === 'PATCH' && noXhrPatch) { + params.xhr = function() { + return new ActiveXObject("Microsoft.XMLHTTP"); + }; + } + + // Make the request, allowing the user to override any Ajax options. + var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); + model.trigger('request', model, xhr, options); + return xhr; + }; + + var noXhrPatch = + typeof window !== 'undefined' && !!window.ActiveXObject && + !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent); + + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. + var methodMap = { + 'create': 'POST', + 'update': 'PUT', + 'patch': 'PATCH', + 'delete': 'DELETE', + 'read': 'GET' + }; + + // Set the default implementation of `Backbone.ajax` to proxy through to `$`. + // Override this if you'd like to use a different library. + Backbone.ajax = function() { + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + + // Backbone.Router + // --------------- + + // Routers map faux-URLs to actions, and fire events when routes are + // matched. Creating a new one sets its `routes` hash, if not set statically. + var Router = Backbone.Router = function(options) { + options || (options = {}); + if (options.routes) this.routes = options.routes; + this._bindRoutes(); + this.initialize.apply(this, arguments); + }; + + // Cached regular expressions for matching named param parts and splatted + // parts of route strings. + var optionalParam = /\((.*?)\)/g; + var namedParam = /(\(\?)?:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; + + // Set up all inheritable **Backbone.Router** properties and methods. + _.extend(Router.prototype, Events, { + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Manually bind a single named route to a callback. For example: + // + // this.route('search/:query/p:num', 'search', function(query, num) { + // ... + // }); + // + route: function(route, name, callback) { + if (!_.isRegExp(route)) route = this._routeToRegExp(route); + if (_.isFunction(name)) { + callback = name; + name = ''; + } + if (!callback) callback = this[name]; + var router = this; + Backbone.history.route(route, function(fragment) { + var args = router._extractParameters(route, fragment); + router.execute(callback, args); + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); + }); + return this; + }, + + // Execute a route handler with the provided parameters. This is an + // excellent place to do pre-route setup or post-route cleanup. + execute: function(callback, args) { + if (callback) callback.apply(this, args); + }, + + // Simple proxy to `Backbone.history` to save a fragment into the history. + navigate: function(fragment, options) { + Backbone.history.navigate(fragment, options); + return this; + }, + + // Bind all defined routes to `Backbone.history`. We have to reverse the + // order of the routes here to support behavior where the most general + // routes can be defined at the bottom of the route map. + _bindRoutes: function() { + if (!this.routes) return; + this.routes = _.result(this, 'routes'); + var route, routes = _.keys(this.routes); + while ((route = routes.pop()) != null) { + this.route(route, this.routes[route]); + } + }, + + // Convert a route string into a regular expression, suitable for matching + // against the current location hash. + _routeToRegExp: function(route) { + route = route.replace(escapeRegExp, '\\$&') + .replace(optionalParam, '(?:$1)?') + .replace(namedParam, function(match, optional) { + return optional ? match : '([^/?]+)'; + }) + .replace(splatParam, '([^?]*?)'); + return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); + }, + + // Given a route, and a URL fragment that it matches, return the array of + // extracted decoded parameters. Empty or unmatched parameters will be + // treated as `null` to normalize cross-browser behavior. + _extractParameters: function(route, fragment) { + var params = route.exec(fragment).slice(1); + return _.map(params, function(param, i) { + // Don't decode the search params. + if (i === params.length - 1) return param || null; + return param ? decodeURIComponent(param) : null; + }); + } + + }); + + // Backbone.History + // ---------------- + + // Handles cross-browser history management, based on either + // [pushState](http://diveintohtml5.info/history.html) and real URLs, or + // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) + // and URL fragments. If the browser supports neither (old IE, natch), + // falls back to polling. + var History = Backbone.History = function() { + this.handlers = []; + _.bindAll(this, 'checkUrl'); + + // Ensure that `History` can be used outside of the browser. + if (typeof window !== 'undefined') { + this.location = window.location; + this.history = window.history; + } + }; + + // Cached regex for stripping a leading hash/slash and trailing space. + var routeStripper = /^[#\/]|\s+$/g; + + // Cached regex for stripping leading and trailing slashes. + var rootStripper = /^\/+|\/+$/g; + + // Cached regex for detecting MSIE. + var isExplorer = /msie [\w.]+/; + + // Cached regex for removing a trailing slash. + var trailingSlash = /\/$/; + + // Cached regex for stripping urls of hash. + var pathStripper = /#.*$/; + + // Has the history handling already been started? + History.started = false; + + // Set up all inheritable **Backbone.History** properties and methods. + _.extend(History.prototype, Events, { + + // The default interval to poll for hash changes, if necessary, is + // twenty times a second. + interval: 50, + + // Are we at the app root? + atRoot: function() { + return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root; + }, + + // Gets the true hash value. Cannot use location.hash directly due to bug + // in Firefox where location.hash will always be decoded. + getHash: function(window) { + var match = (window || this).location.href.match(/#(.*)$/); + return match ? match[1] : ''; + }, + + // Get the cross-browser normalized URL fragment, either from the URL, + // the hash, or the override. + getFragment: function(fragment, forcePushState) { + if (fragment == null) { + if (this._hasPushState || !this._wantsHashChange || forcePushState) { + fragment = decodeURI(this.location.pathname + this.location.search); + var root = this.root.replace(trailingSlash, ''); + if (!fragment.indexOf(root)) fragment = fragment.slice(root.length); + } else { + fragment = this.getHash(); + } + } + return fragment.replace(routeStripper, ''); + }, + + // Start the hash change handling, returning `true` if the current URL matches + // an existing route, and `false` otherwise. + start: function(options) { + if (History.started) throw new Error("Backbone.history has already been started"); + History.started = true; + + // Figure out the initial configuration. Do we need an iframe? + // Is pushState desired ... is it available? + this.options = _.extend({root: '/'}, this.options, options); + this.root = this.options.root; + this._wantsHashChange = this.options.hashChange !== false; + this._wantsPushState = !!this.options.pushState; + this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); + var fragment = this.getFragment(); + var docMode = document.documentMode; + var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); + + // Normalize root to always include a leading and trailing slash. + this.root = ('/' + this.root + '/').replace(rootStripper, '/'); + + if (oldIE && this._wantsHashChange) { + var frame = Backbone.$(' + + +
+ + + + + + + + + + + + \ No newline at end of file diff --git a/httpd.conf b/httpd.conf deleted file mode 100644 index aee56f5cc..000000000 --- a/httpd.conf +++ /dev/null @@ -1,16 +0,0 @@ - - ServerName www.crafting-guide.com - ErrorLog logs/crafting-guide.com-error_log - CustomLog logs/crafting-guide.com-access_log common - - DocumentRoot /home/crafting-guide/repo/html - - AllowOverride None - - - - Options Indexes - Order allow,deny - Allow from all - - diff --git a/package.json b/package.json new file mode 100644 index 000000000..975ac358c --- /dev/null +++ b/package.json @@ -0,0 +1,40 @@ +{ + "name": "crafting-guide", + "version": "1.0.0", + "description": "crafting-guide ==============", + "main": "site/scripts/main.js", + "scripts": { + "test": "test" + }, + "repository": { + "type": "git", + "url": "https://github.com/andrewminer/crafting-guide.git" + }, + "author": "Andrew Miner", + "license": "ISC", + "bugs": { + "url": "https://github.com/andrewminer/crafting-guide/issues" + }, + "homepage": "https://github.com/andrewminer/crafting-guide", + "devDependencies": { + "coffeeify": "^1.0.0", + "grunt": "^0.4.5", + "grunt-browserify": "^3.2.1", + "grunt-contrib-clean": "^0.6.0", + "grunt-contrib-copy": "^0.7.0", + "grunt-contrib-jade": "^0.13.0", + "grunt-contrib-sass": "^0.8.1", + "grunt-contrib-watch": "^0.6.1" + }, + "dependencies": { + "backbone": "^1.1.2", + "chai": "^1.10.0", + "d3": "^3.5.2", + "jade": "^1.8.2", + "jquery": "^2.1.3", + "mocha": "^2.0.1", + "sinon": "^1.12.2", + "sinon-chai": "^2.6.0", + "when": "^3.6.4" + } +} diff --git a/scripts/server b/scripts/server index fd9cd2f94..def829f47 100755 --- a/scripts/server +++ b/scripts/server @@ -1,6 +1,6 @@ #!/bin/bash -pushd html &>/dev/null +pushd dist &>/dev/null python -m SimpleHTTPServer popd &>/dev/null diff --git a/src/css/main.scss b/src/css/main.scss new file mode 100644 index 000000000..ba3bb22d0 --- /dev/null +++ b/src/css/main.scss @@ -0,0 +1,152 @@ +/* +Crafting Guide - main.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +@import 'mixins'; +@import 'reset'; + +// Constants /////////////////////////////////////////////////////////////////////////////////////////////////////////// + +$color-background: #AAC9FF; +$color-bedrock: #0A0A0A; +$color-content: rgba(230, 230, 230, 0.90); +$color-brick-dark: #7A7A7A; +$color-brick-light: #D9D9D9; +$color-footer: #3D1D09; +$color-footer-text: white; +$color-dirt: #906647; + +// Fonts /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +@font-face { + font-family: 'PressStart'; + font-style: normal; + font-weight: 400; + src: url('/fonts/press_start.ttf') format('truetype'); +} + +// Common ////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +body { + background: $color-background url('/images/ice.png'); + font-size: 10px; +} + +h1 { + margin-bottom: 1em; + + * { display: inline; } + + img { + position: relative; height: 10em; width: 10em; + margin-right: 1em; + vertical-align: bottom; + } + + p { + font-family: PressStart; + font-size: 3em; + position: relative; top: -0.5em; + } +} + +h2 { + margin-bottom: 1em; + + * { display: inline; } + + img { + position: relative; height: 7.5em; width: 7.5em; + margin-right: 1em; + vertical-align: bottom; + } + + p { + font-family: PressStart; + font-size: 2em; + position: relative; top: -0.25em; + } +} + +.centered { + text-align: center; +} + +.content { + background: $color-content; + box-shadow: 10px 10px 20px #666; + margin: 2em auto; + max-width: 96em; + position: relative; + width: 100%; +} + +// Views /////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +.view__footer { + background: $color-footer; + color: $color-footer-text; + margin-top: 2em; + + a { + color: $color-footer-text; + } + + .divider { + position: relative; height: 3.2em; width: 100%; + clear: both; + } + + .divider.top { + background: $color-dirt url('/images/grass_side.png'); + } + + .left, .center, .right { + position: relative; width: 33%; + float: left; + padding: 2em; + + p { + font-family: sans-serif; + font-size: 1.25em; + padding-bottom: 1.0em; + + &:last-child { + padding-bottom: 0; + } + } + + h2 { + padding-bottom: 1.0em; + + p { + font-family: PressStart; + font-size: 1.5em; + } + } + } + + .divider.bottom { + background: $color-bedrock url('/images/bedrock.png'); + } +} + +.view__header { + background: $color-brick-light url('/images/stone_brick_light.png'); + position: relative; height: 10em; + margin: 5em 0 2em 0; + + h1 { position: relative; top: -3em; left: -3em; } + + .divider { + background: $color-brick-dark url('/images/stone_brick.png'); + position: absolute; bottom: 0; height: 3.2em; width: 100%; + } +} + +// Child Stylesheets /////////////////////////////////////////////////////////////////////////////////////////////////// + +@import 'templates/index'; diff --git a/src/css/mixins.scss b/src/css/mixins.scss new file mode 100644 index 000000000..f17ac5f34 --- /dev/null +++ b/src/css/mixins.scss @@ -0,0 +1,26 @@ +/* +Crafting Guide - mixins.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +@mixin box-sizing($value) { + -moz-box-sizing: $value; + -webkit-box-sizing: $value; + box-sizing: $value; +} + +@mixin center-vertical { + position: absolute; + top: 50%; + @include transform(translateY(-50%)); +} + +@mixin transform($transforms) { + -moz-transform: $transforms; + -o-transform: $transforms; + -ms-transform: $transforms; + -webkit-transform: $transforms; + transform: $transforms; +} \ No newline at end of file diff --git a/src/css/reset.scss b/src/css/reset.scss new file mode 100644 index 000000000..e55d2ce26 --- /dev/null +++ b/src/css/reset.scss @@ -0,0 +1,75 @@ +a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,dialog,div,dl,dt,em,embed,fieldset,figcaption,figure,font,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,hr,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,meter,nav,object,ol,output,p,pre,progress,q,rp,rt,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video,xmp { + border: 0; + margin: 0; + padding: 0; + font-size: 100%; + @include box-sizing(border-box); +} + +html,body { + height: 100%; +} + +article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section { + display: block; +} + +b,strong { + font-weight: bold; +} + +img { + color: transparent; + vertical-align: middle; + -ms-interpolation-mode: bicubic; +} + +ol,ul { + list-style: none; +} + +li { + display: list-item; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +th,td,caption { + font-weight: normal; + vertical-align: top; + text-align: left; +} + +q { + quotes: none; +} + +q:before,q:after { + content: ''; + content: none; +} + +sub,sup,small { + font-size: 75%; +} + +sub,sup { + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +svg { + overflow: hidden; +} \ No newline at end of file diff --git a/src/css/templates/index.scss b/src/css/templates/index.scss new file mode 100644 index 000000000..748791869 --- /dev/null +++ b/src/css/templates/index.scss @@ -0,0 +1,8 @@ +/* +Crafting Guide - templates/index.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +@import 'recipe_catalog'; diff --git a/src/css/templates/recipe_catalog.scss b/src/css/templates/recipe_catalog.scss new file mode 100644 index 000000000..b28df4748 --- /dev/null +++ b/src/css/templates/recipe_catalog.scss @@ -0,0 +1,28 @@ +/* +Crafting Guide - recipe_books.scss + +Copyright (c) 2014 by Redwood Labs +All rights reserved. +*/ + +.view__recipe_catalog { + position: relative; width: 100%; + padding: 0 2em; + + button { + @include center-vertical; + position: absolute; right: 1em; + } + + input { border: 0; width: 90%; } + + table { + background: white; + margin: 0 auto; + width: 98%; + + td { height: 3em; padding: 0 1em; position: relative; vertical-align: middle; } + td:nth-child(1) { width: 30%; } + td:nth-child(2) { width: 70%; border-left: 0.1em solid $color-brick-light; } + } +} diff --git a/src/data/applied_energetics.json b/src/data/applied_energetics.json new file mode 100644 index 000000000..e152021e4 --- /dev/null +++ b/src/data/applied_energetics.json @@ -0,0 +1,333 @@ +{ + "name": "Applied Energetics", + "description": "Applied Energetics rv12-b, by AlgorithmX2", + "recipes": [ + + { + "output": [[1, "Grind Stone"]], + "input": [[3, "Certus Quartz Dust"], [3, "Stone"], [2, "Cobblestone"],[1, "Wooden Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quartz Cutting Knife"]], + "input": [[1, "Iron"], [2, "Stick"], [2, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Basic Processor Assembly"]], + "input": [[1, "Gold Ingot"], [2, "Redstone"], [1, "Silicon"]], + "tools": ["Crafting Table","Quartz Cutting Knife"] + }, { + "output": [[1, "Advanced Processor Assembly"]], + "input": [[1, "Diamond"], [2, "Redstone"], [1, "Silicon"]], + "tools": ["Crafting Table","Quartz Cutting Knife"] + }, { + "output": [[1, "Silicon"]], + "input": [[1, "Certus Quartz Dust"]], + "tools": ["Furnace"] + }, { + "output": [[1, "ME Basic Processor"]], + "input": [[1, "Basic Processor Assembly"]], + "tools": ["Furnace"] + }, { + "output": [[1, "ME Basic Processor"]], + "input": [[1, "Redstone Golden Chipset"], [1,"Silicon"], [1,"Fluix Dust"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "ME Advanced Processor"]], + "input": [[1, "Advanced Processor Assembly"]], + "tools": ["Furnace"] + }, { + "output": [[1, "ME Advanced Processor"]], + "input": [[1, "Redstone Diamond Chipset"], [1,"Silicon"], [1,"Fluix Dust"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Vibration Catalyst"]], + "input": [[1, "Iron Ingot"], [1, "ME Conversion Matrix"], [1, "Lava Bucket"],[1,"Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Entropy Accelerator"]], + "input": [[1, "Iron Ingot"], [1, "ME Conversion Matrix"], [1, "Ice"],[1,"Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tiny TNT"]], + "input": [[2, "Gunpowder"], [2, "Certus Quartz Dust"]], + "tools": [] + }, { + "output": [[8, "ME Cable - Blue"]], + "input": [[1, "Lapis Lazuli"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Black"]], + "input": [[1, "Ink Sac"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - White"]], + "input": [[1, "Bone Meal"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Brown"]], + "input": [[1, "Cocoa Beans"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Red"]], + "input": [[1, "Rose Red"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Yellow"]], + "input": [[1, "Dandelion Yellow"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Green"]], + "input": [[1, "Cactus Green"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "ME Cable - Green"]], + "input": [[1, "Cactus Green"],[8,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Pattern Provider"]], + "input": [[4, "Iron Ingot"],[1,"Crafting Table"],[2,"Conversion Matrix"],[1,"ME Advanced Processor"],[1,"Storage Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Controller"]], + "input": [[4, "Iron Ingot"], [4, "Fluix Crystal"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Drive"]], + "input": [[4, "Iron Ingot"], [2, "Glass"],[2,"ME Basic Processor"],[1,"Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Pattern Encoder"]], + "input": [[7, "Iron Ingot"],[1,"Crafting Table"],[1,"Conversion Matrix"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Wireless Access Point"]], + "input": [[4, "Iron Ingot"],[3,"Glass"],[1,"Wireless Receiver"],[1,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Access Terminal"]], + "input": [[4, "Iron Ingot"], [3, "Glass"],[1,"Conversion Matrix"],[1,"ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Chest"]], + "input": [[5, "Iron Ingot"], [1, "Chest"], [1, "Conversion Matrix"], [2, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Interface"]], + "input": [[4, "Iron Ingot"], [3, "Glass"],[1,"Conversion Matrix"],[1,"ME Cable"]], + "tools": ["Craftin Table"] + }, { + "output": [[1, "ME Partition Editor"]], + "input": [[5, "Iron Ingot"],[2,"Glass"],[1,"Conversion Matrix"],[1,"Crafting Table"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Precision Export Bus"]], + "input": [[1, "ME Basic Export Bus"],[1,"ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Precision Import Bus"]], + "input": [[1, "ME Basic Import Bus"],[1,"ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Crafting Terminal"]], + "input": [[4, "Iron Ingot"],[2,"Glass"],[1,"Crafting Table"],[1,"Storage Cell"],[1,"ME Access Terminal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Level Emitter"]], + "input": [[2, "Iron Ingot"], [1, "ME Basic Processor"], [1, "ME Cable"], [1, "Redstone Torch"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Crafting CPU"]], + "input": [[4, "Iron Ingot"],[2, "Certus Quartz"],[2, "Glowstone Dust"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Heat Vent"]], + "input": [[4, "Iron Ingot"],[4, "Iron Bars"],[1, "ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Assembler Containment Wall"]], + "input": [[4, "Iron Ingot"],[4, "Gold Ingot"],[1, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Dark Cable"]], + "input": [[2, "Redstone"],[2, "ME Cable"],[1, "Lever"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Storage Bus"]], + "input": [[1, "ME Cable"],[1, "ME Interface"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME IO Port"]], + "input": [[3, "Glass"],[2, "ME Drive"],[1, "ME Cable"],[2, "Iron Ingot"],[1, "ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Crafting Monitor"]], + "input": [[4, "Iron Ingot"],[3, "Glass"],[1, "ME Cable"],[1, "ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Storage Monitor"]], + "input": [[4, "Iron Ingot"],[3, "Glass"],[1, "ME Cable"],[1, "ME Level Emitter"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Covered Cable"]], + "input": [[1, "ME Cable"],[1, "Wool"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "ME Cable"]], + "input": [[6, "Glass"],[3, "Fluix Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Fuzzy Storage Bus"]], + "input": [[4, "Wool"],[1, "ME Storage Bus"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Fuzzy Export Bus"]], + "input": [[1, "ME Basic Export Bus"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Fuzzy Import Bus"]], + "input": [[1, "ME Basic Import Bus"],[1, "ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Basic Export Bus"]], + "input": [[1, "ME Cable"],[2, "Iron Ingot"],[1, "ME Interface"],[1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Basic Import Bus"]], + "input": [[1, "ME Cable"],[2, "Iron Ingot"],[1, "ME Interface"],[1, "Sticky Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Transition Plane"]], + "input": [[3, "Fluix Dust"],[4, "Iron Ingot"],[1, "Conversion Matrix"],[1, "ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Cell"]], + "input": [[4, "Iron Ingot"],[4, "Fluix Crystal"],[1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Power Relay"]], + "input": [[4, "Iron Ingot"],[4, "ME Cable"],[1, "Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Condenser"]], + "input": [[4, "Iron Ingot"],[4, "Glass"],[1, "Fluix Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Field Ring"]], + "input": [[4, "Iron Ingot"],[2, "ME Basic Processor"],[1, "ME Advanced Processor"],[1, "Energy Cell"],[1, "ME Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Link Chamber"]], + "input": [[4, "Quartz Glass"],[4, "Fluix Pearl"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Certus Quartz Block"]], + "input": [[4, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Quartz Glass"]], + "input": [[5, "Certus Quartz Dust"],[4, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Vibrant Quartz Glass"]], + "input": [[1, "Quartz Glass"],[2, "Glowstone Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 1k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Cell"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 4k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Segment"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 16k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Block"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME 64k Storage"]], + "input": [[2, "Glass"],[3, "Redstone"],[1, "Storage Cluster"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Conversion Matrix"]], + "input": [[4, "Iron Ingot"],[1, "Nether Quartz"],[2, "Fluix Dust"],[1, "ME Basic Processor"],[1, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Cell"]], + "input": [[4, "Redstone"],[4, "Certus Quartz"],[1, "ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Segment"]], + "input": [[4, "Redstone"],[3, "Storage Cell"],[1, "Glass"],[1,"ME Basic Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Block"]], + "input": [[4, "Glowstone"],[3, "Storage Segment"],[1, "Glass"],[1,"ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Storage Cluster"]], + "input": [[4, "Glowstone"],[3, "Storage Block"],[1, "Glass"],[1,"ME Advanced Processor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wireless Receiver"]], + "input": [[1, "Fluix Pearl"],[3, "Iron Ingot"],[1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wireless Booster"]], + "input": [[2, "Iron Ingot"],[1, "Redstone"],[1, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Crank"]], + "input": [[5, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Flour"]], + "input": [[1, "Wheat"]], + "tools": ["Pulverizer"] + }, { + "output": [[2, "Fluix Dust"]], + "input": [[1, "Redstone"],[1, "Certus Quartz Dust"],[1, "Nether Quartz Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Blank Pattern"]], + "input": [[2, "Glass"],[3, "Glowstone"],[1, "Certus Quartz"],[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nether Quartz Dust"]], + "input": [[1, "Nether Quartz"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Fluix Crystal"]], + "input": [[1, "Certus Quartz"],[1, "Nether Quartz"],[1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Fluix Pearl"]], + "input": [[4, "Fluix Dust"],[4, "Fluix Crystal"],[1, "Ender Pearl"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Matter Ball"]], + "input": [[256, "Cobblestone"]], + "tools": ["ME Condenser"] + }, { + "output": [[1, "Singularity"]], + "input": [[25600, "Cobblestone"]], + "tools": ["ME Condenser"] + }, { + "output": [[1, "Ender Pearl Dust"]], + "input": [[1, "Ender Pearl"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Quartz Wrench"]], + "input": [[5, "Certus Quartz"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "ME Wireless Access Terminal"]], + "input": [[1, "Wireless Receiver"],[1, "ME Access Terminal"],[1, "Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Matter Cannon"]], + "input": [[3, "Iron Ingot"],[1, "Conversion Matrix"],[1, "Storage Segment"],[1, "Energy Cell"]], + "tools": ["Crafting Table"] + } + ] +} + diff --git a/src/data/buildcraft.json b/src/data/buildcraft.json new file mode 100644 index 000000000..0c68485cc --- /dev/null +++ b/src/data/buildcraft.json @@ -0,0 +1,256 @@ +{ + "name": "BuildCraft", + "description": "Crafting recipes from BuildCraft 3, by SpaceToad", + "recipes": [ + { + "output": [[1, "Advanced Crafting Table"]], + "input": [[6, "Obsidian"], [1, "Crafting Table"], [1, "Chest"], [1, "Redstone Chipset"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Assembly Table"]], + "input": [[6, "Obsidian"], [1, "Diamond"], [1, "Diamond Gear"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Automatic Crafting Table"]], + "input": [[4, "Wooden Gear"], [1, "Crafting Table"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Basic Gate"]], + "input": [[1, "Redstone Chipset"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Blue Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Lapis Lazuli"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Chute"]], + "input": [[5, "Iron Ingot"], [1, "Cobblestone Gear"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cobblestone Conductive Pipe"]], + "input": [[1, "Cobblestone Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Cobblestone Gear"]], + "input": [[1, "Wooden Gear"], [4, "Cobblestone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Cobblestone Pipe"]], + "input": [[2, "Cobblestone"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cobblestone Waterproof Pipe"]], + "input": [[1, "Cobblestone Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Combustion Engine"]], + "input": [[3, "Iron Ingot"], [2, "Iron Gear"], [1, "Glass"], [1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond AND Gate"]], + "input": [[1, "Diamond Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"], [1, "Yellow Pipe Wire"], [1, "Green Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Diamond Chipset"]], + "input": [[1, "Redstone"], [1, "Diamond"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Diamond Pipe"]], + "input": [[2, "Diamond"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Conductive Pipe"]], + "input": [[1, "Diamond Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Diamond Gear"]], + "input": [[1, "Gold Gear"], [4, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond OR Gate"]], + "input": [[1, "Diamond Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"], [1, "Yellow Pipe Wire"], [1, "Green Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Emerald Pipe"]], + "input": [[2, "Emerald"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Emerald Waterproof Pipe"]], + "input": [[1, "Emerald Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Facade"]], + "input": [[3, "Structure Pipe"], [1, "source block"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Filler"]], + "input": [[2, "Dandelion Yellow"], [2, "Ink Sac"], [1, "Landmark"], [1, "Chest"], [1, "Crafting Table"], [2, "Gold Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold AND Gate"]], + "input": [[1, "Gold Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Gold Chipset"]], + "input": [[1, "Redstone"], [1, "Gold Ingot"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Gold Conductive Pipe"]], + "input": [[1, "Gold Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Gold Gear"]], + "input": [[1, "Iron Gear"], [4, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold OR Gate"]], + "input": [[1, "Gold Chipset"], [1, "Red Pipe Wire"], [1, "Blue Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Gold Pipe"]], + "input": [[2, "Gold Ingot"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Waterproof Pipe"]], + "input": [[1, "Gold Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[8, "Green Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Cactus Green"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Iron AND Gate"]], + "input": [[1, "Iron Chipset"], [1, "Red Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Iron Chipset"]], + "input": [[1, "Redstone"], [1, "Iron Ingot"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Iron Gear"]], + "input": [[1, "Cobblestone Gear"], [4, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron OR Gate"]], + "input": [[1, "Iron Chipset"], [1, "Red Pipe Wire"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[8, "Iron Pipe"]], + "input": [[2, "Iron Ingot"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Waterproof Pipe"]], + "input": [[1, "Iron Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Landmark"]], + "input": [[1, "Redstone Torch"], [1, "Lapis Lazuli"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Laser"]], + "input": [[5, "Redstone"], [2, "Diamond"], [2, "Obsidian"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mining Well"]], + "input": [[6, "Iron Ingot"], [1, "Iron Gear"], [1, "Iron Pickaxe"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Obsidian Pipe"]], + "input": [[2, "Obsidian"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Pipe Waterproof"]], + "input": [[1, "Cactus Green"]], + "tools": [] + }, { + "output": [[1, "Pump"]], + "input": [[1, "Mining Well"], [1, "Tank"]], + "tools": [] + }, { + "output": [[1, "Quarry"]], + "input": [[3, "Iron Gear"], [2, "Gold Gear"], [2, "Diamond Gear"], [1, "Diamond Pickaxe"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Red Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Rose Red"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Redstone Chipset"]], + "input": [[1, "Redstone"]], + "tools": ["Assembly Table", "Laser"] + }, { + "output": [[1, "Redstone Engine"]], + "input": [[3, "Oak Plank"], [2, "Wooden Gear"], [1, "Glass"], [1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Refinery"]], + "input": [[3, "Tank"], [2, "Redstone Torch"], [1, "Diamond Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Sandstone Pipe"]], + "input": [[2, "Sandstone"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Sandstone Waterproof Pipe"]], + "input": [[1, "Sandstone Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Stirling Engine"]], + "input": [[3, "Cobblestone"], [2, "Cobblestone Gear"], [1, "Glass"], [1, "Piston"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Conductive Pipe"]], + "input": [[1, "Stone Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[8, "Stone Pipe"]], + "input": [[2, "Stone"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Waterproof Pipe"]], + "input": [[1, "Stone Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[8, "Stripe Pipe"]], + "input": [[1, "Ink Sac"], [1, "Glass"], [1, "Dandelion Yellow"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Structure Pipe"]], + "input": [[1, "Cobblestone Pipe"], [1, "Gravel"]], + "tools": [] + }, { + "output": [[1, "Tank"]], + "input": [[8, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Conductive Pipe"]], + "input": [[1, "Wooden Pipe"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Wooden Gear"]], + "input": [[4, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Wooden Pipe"]], + "input": [[2, "Oak Plank"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Waterproof Pipe"]], + "input": [[1, "Wooden Pipe"], [1, "Pipe Waterproof"]], + "tools": [] + }, { + "output": [[1, "Wrench (buildcraft)"]], + "input": [[3, "Iron Ingot"], [1, "Cobblestone Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Void Pipe"]], + "input": [[1, "Ink Sac"], [1, "Glass"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Yellow Pipe Wire"]], + "input": [[1, "Iron Ingot"], [1, "Redstone"], [1, "Dandelion Yellow"]], + "tools": ["Assembly Table", "Laser"] + } + ] +} + diff --git a/src/data/gravisuite.json b/src/data/gravisuite.json new file mode 100644 index 000000000..dfedf77e0 --- /dev/null +++ b/src/data/gravisuite.json @@ -0,0 +1,67 @@ +{ + "name": "GraviSuite", + "description": "Crafting recipes from GraviSuite, by flotschi301", + "recipes": [ + { + "output": [[1, "GraviChestPlate"]], + "input": [[1, "Quantum Bodyarmor"], [1, "HV Transformer"], [1, "Ultimate Lappack"], [2, "Gravitation Engine"], [4, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Ultimate Lappack"]], + "input": [[6, "Lapotron Crystal"], [1, "Iridium Plate"], [1, "LapPack"], [1, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Superconductor"]], + "input": [[6, "Superconductor Cover"], [2, "Glass Fiber Cable"], [1, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Superconductor Cover"]], + "input": [[4, "Advanced Alloy"], [3, "Carbon Plate"], [2, "Iridium Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gravitation Engine"]], + "input": [[4, "Tesla Coil"], [2, "Superconductor"], [2, "Cooling Core"], [1, "HV Transformer"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cooling Core"]], + "input": [[4, "60K Cooling Cell"], [2, "Advanced Heat Exchanger"], [2, "Heat-Capacity Reactor Plating"], [1, "Iridium Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Chainsaw"]], + "input": [[1, "Diamond"], [3, "Overclocker Upgrade"], [1, "Chainsaw"], [2, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Diamond Drill"]], + "input": [[1, "Diamond Drill"], [3, "Overclocker Upgrade"], [2, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Electric Jetpack"]], + "input": [[2, "Carbon Plate"], [2, "Engine Booster"], [2, "Glass Fiber Cable"], [1, "Electric Jetpack"], [1, "Advanced Lappack"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Lappack"]], + "input": [[1, "LapPack"], [1, "Advanced Circuit"], [1, "Lapotron Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "GraviTool"]], + "input": [[2, "Carbon Plate"], [2, "Advanced Alloy"], [1, "Advanced Circuit"], [1, "Electric Wrench"], [1, "Electric Treetap"], [1, "Electric Hoe"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magnetron"]], + "input": [[4, "Refined Iron"], [4, "Copper Ingot"], [1, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Varja Core"]], + "input": [[1, "Magnetron"], [1, "Tesla Coil"], [1, "HV Transformer"], [2, "Iridium Plate"], [2, "Superconductor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Vajra"]], + "input": [[2, "Refined Iron"], [1, "Energy Crystal"], [1, "Varja Core"], [1, "Carbon Plate"], [2, "Advanced Alloy"], [1, "Lapotron Crystal"], [1, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Engine Booster"]], + "input": [[2, "Glowstone"], [2, "Advanced Circuit"], [3, "Advanced Alloy"], [1, "Overclocker Upgrade"], [1, "Advanced Heat Vent"]], + "tools": ["Crafting Table"] + } + ] +} diff --git a/src/data/industrial_craft.json b/src/data/industrial_craft.json new file mode 100644 index 000000000..00f9bddd1 --- /dev/null +++ b/src/data/industrial_craft.json @@ -0,0 +1,904 @@ +{ + "name": "Industrial Craft", + "description": "Crafting recipes from IndustrialCraft 2, by Alblaka", + "recipes": [ + { + "output": [[1, "Static Boots"]], + "input": [[4, "Iron Ingot"], [3, "Insulated Copper Cable"], [1, "Wool"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "CFPack"]], + "input": [[4, "Fuel Can"], [2, "CF Sprayer"], [1, "Electronic Circuit"], [1, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Tin Can"]], + "input": [[5, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Scrap Box"]], + "input": [[9, "Scrap"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Coin"]], + "input": [[4, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Treetap"]], + "input": [[5, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Toolbox"]], + "input": [[5, "Iron Ingot"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Painter"]], + "input": [[3, "Wool"], [2, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "EU Reader"]], + "input": [[4, "Insulated Copper Cable"], [1, "Electronic Circuit"], [1, "Glowstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cutter"]], + "input": [[5, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "CF Sprayer"]], + "input": [[4, "Cobblestone"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "FreqTrans"]], + "input": [[1, "Insulated Copper Cable"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Dynamite-O-Mote"]], + "input": [[2, "Tin Ingot"], [1, "Insulated Copper Cable"], [1, "Lapis Lazuli"], [1, "FreqTrans"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nano Saber"]], + "input": [[2, "Advanced Alloy"], [2, "Carbon Plate"], [2, "Glowstone"], [1, "Energy Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mining Laser"]], + "input": [[4, "Advanced Alloy"], [2, "Energy Crystal"], [1, "Redstone"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Wrench"]], + "input": [[1, "Wrench"], [1, "Electric Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Treetap"]], + "input": [[1, "Treetap"], [1, "Electric Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Drill"]], + "input": [[3, "Diamond"], [1, "Mining Drill"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mining Drill"]], + "input": [[5, "Refined Iron"], [1, "Electronic Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chainsaw"]], + "input": [[5, "Refined Iron"], [1, "Electronic Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Uranium Block"]], + "input": [[9, "Refined Uranium"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Refined Uranium"]], + "input": [[1, "Uranium"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Tin Block"]], + "input": [[9, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Block"]], + "input": [[9, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Copper Block"]], + "input": [[9, "Copper Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Rail Track"]], + "input": [[6, "Bronze"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Biofuel Cell"]], + "input": [[1, "Bio Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "Bio Cell"]], + "input": [[1, "Empty Cell"], [1, "Compressed Plantball"]], + "tools": [] + }, { + "output": [[8, "Sticky Dynamite"]], + "input": [[8, "Dynamite"], [1, "Resin"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Dynamite"]], + "input": [[1, "String"], [1, "Industrial TNT"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Industrial TNT"]], + "input": [[6, "Flint"], [3, "TNT"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Scaffold"]], + "input": [[3, "Oak Plank"], [3, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Rubber Trampoline"]], + "input": [[6, "Rubber"]], + "tools": ["Crafting Table"] + }, { + "output": [[7, "Reinforced Glass"]], + "input": [[7, "Glass"], [2, "Advanced Alloy"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Reinforced Door"]], + "input": [[6, "Reinforced Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Reinforced Stone"]], + "input": [[8, "Stone"], [1, "Advanced Alloy"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Iron Scaffold"]], + "input": [[3, "Reinfined Iron"], [3, "Iron Fence"]], + "tools": ["Crafting Table"] + }, { + "output": [[12, "Iron Fence"]], + "input": [[6, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Luminator"]], + "input": [[5, "Glass"], [2, "Reinforced Iron"], [1, "Insulated Copper Cable"], [1, "Tin Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Construction Foam"], [1, "Bucket"]], + "input": [[1, "Clay Dust"], [1, "Water Bucket"], [1, "Coal Dust"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Diamond (crafted)"]], + "input": [[1, "Coal Chunk"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Coal Chunk"]], + "input": [[8, "Compressed Coal Ball"], [1, "Obsidian"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Coal Chunk"]], + "input": [[8, "Compressed Coal Ball"], [1, "Brick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Coal Chunk"]], + "input": [[8, "Compressed Coal Ball"], [1, "Iron Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Compressed Coal Ball"]], + "input": [[1, "Coal Ball"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Coal Ball"]], + "input": [[8, "Coal Dust"], [1, "1 Flint"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Thick Neutron Reflector"]], + "input": [[4, "Neutron Reflector"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Neutron Reflector"]], + "input": [[4, "Tin Dust"], [4, "Coal Dust"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Depleted Isotope Cell"]], + "input": [[1, "Near-Depleted Uranium Cell"], [1, "Coal Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Near-Depleted Uranium Cell"]], + "input": [[8, "Empty Cell"], [1, "Uranium Fuel Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quad Uranium Cell"]], + "input": [[3, "Dense Copper Plate"], [2, "Dual Uranium Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Dual Uranium Cell"]], + "input": [[2, "Uranium Cell"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Uranium Cell"]], + "input": [[1, "Empty Cell"], [1, "Uranium Fuel Ingot"]], + "tools": [] + }, { + "output": [[1, "Heat-Capacity Reactor Plating"]], + "input": [[2, "Dense Copper Plate"], [1, "Reactor Plating"]], + "tools": [] + }, { + "output": [[1, "Containment Reactor Plating"]], + "input": [[2, "Advanced Alloy"], [1, "Reactor Plating"]], + "tools": [] + }, { + "output": [[1, "Reactor Plating"]], + "input": [[1, "Dense Copper Plate"], [1, "Advanced Alloy"]], + "tools": [] + }, { + "output": [[1, "Lava Cell"], [1, "Bucket"]], + "input": [[1, "Empty Cell"], [1, "Lava Bucket"]], + "tools": [] + }, { + "output": [[1, "Heating Cell"]], + "input": [[1, "Electronic Circuit"], [1, "Lava Cell"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Component Heat Exchanger"]], + "input": [[4, "Gold Ingot"], [1, "Heat Exchanger"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Core Heat Exchanger"]], + "input": [[2, "Dense Copper Plate"], [1, "Heat Exchanger"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Heat Exchanger"]], + "input": [[4, "Glass Fiber Cable"], [2, "Heat Exchanger"], [2, "Electronic Circuit"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "LZH-Condensator"]], + "input": [[4, "Redstone"], [2, "RSH-Condensator"], [1, "Reactor Heat Vent"], [1, "Core Heat Exchanger"], [1, "Lapis Lazuli Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Heat Exchanger"]], + "input": [[3, "Tin Ingot"], [1, "Electronic Circuit"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "RSH-Condensator"]], + "input": [[7, "Redstone"], [1, "Heat Vent"], [1, "Heat Exchanger"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Overclocked Heat Vent"]], + "input": [[2, "Gold Ingot"], [1, "Reactor Heat Vent"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Heat Vent"]], + "input": [[6, "Iron Bars"], [2, "Heat Vent"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Reactor Heat Vent"]], + "input": [[2, "Dense Copper Plate"], [1, "Heat Vent"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Heat Vent"]], + "input": [[4, "Refined Iron"], [4, "Iron Bars"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Trade-O-Mat"]], + "input": [[3, "Redstone"], [2, "Chest"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tesla Coil"]], + "input": [[5, "Redstone"], [2, "Refined Iron"], [1, "Electronic Circuit"], [1, "MV Transformer"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Mushroom"]], + "input": [[4, "Brown Mushroom"], [4, "Mycelium"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Irrigation"]], + "input": [[4, "Water Bucket"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Flatificator"]], + "input": [[4, "Dirt"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Desertification"]], + "input": [[4, "Sand"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Cultivation"]], + "input": [[4, "Seed"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Compression"]], + "input": [[4, "Stone"], [4, "Cobblestone"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TFBP - Chilling"]], + "input": [[4, "Snow"], [1, "Empty TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Empty TFBP"]], + "input": [[2, "Redstone"], [1, "Advanced Circuit"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Terraformer"]], + "input": [[4, "Glowstone"], [3, "Dirt"], [1, "Advanced Machine Block"], [1, "TFBP"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Personal Safe"]], + "input": [[1, "Electronic Circuit"], [1, "Machine Block"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magnetizer"]], + "input": [[6, "Redstone"], [1, "Iron Fence"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electrolyzer"]], + "input": [[4, "Insulated Copper Cable"], [2, "RE Battery"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Recycler"]], + "input": [[3, "Dirt"], [2, "Refined Iron"], [1, "Compressor"], [1, "Glowstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Mass Fabricator"]], + "input": [[4, "Glowstone"], [2, "Advanced Circuit"], [2, "Advanced Machine Block"], [1, "Lapotron Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[5, "Bone Meal"]], + "input": [[1, "Bone"]], + "tools": ["Macerator"] + }, { + "output": [[5, "Blaze Powder"]], + "input": [[1, "Blaze Rod"]], + "tools": ["Macerator"] + }, { + "output": [[3, "Coffee Powder"]], + "input": [[1, "Coffee Beans"]], + "tools": ["Macerator"] + }, { + "output": [[4, "String"]], + "input": [[1, "Wool"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Induction Furnace"]], + "input": [[7, "Copper Ingot"], [1, "Electric Furnace"], [1, "Advanced Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Biofuel Cell"]], + "input": [[1, "Bio Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "Electric Furnace"]], + "input": [[2, "Redstone"], [1, "Electronic Circuit"], [1, "Iron Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nether Brick"]], + "input": [[3, "Netherrack"]], + "tools": ["Compressor"] + }, { + "output": [[1, "CF Pellet"]], + "input": [[1, "Construction Foam"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Ice"]], + "input": [[1, "Snowball"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Snowball"]], + "input": [[1, "Water Cell"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Compressed Plantball"]], + "input": [[1, "Plantball"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Diamond (industrial)"]], + "input": [[1, "Coal Chunk"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Canning Machine"]], + "input": [[7, "Tin Ingot"], [1, "Electronic Circuit"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wind Mill"]], + "input": [[4, "Iron"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Water Mill"]], + "input": [[4, "Stick"], [4, "Oak Plank"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Alloy"]], + "input": [[1, "Mixed Metal Ingot"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Advanced Circuit"]], + "input": [[4, "Redstone"], [2, "Glowstone"], [2, "Lapis Lazuli"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "BatBox"]], + "input": [[3, "RE Battery"], [5, "Oak Plank"], [1, "Insulated Copper Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "BatPack"]], + "input": [[6, "RE Battery"], [1, "Electronic Circuit"], [1, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Axe"]], + "input": [[3, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Shovel"]], + "input": [[1, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Chestplate"]], + "input": [[8, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Block"]], + "input": [[9, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Boots"]], + "input": [[4, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Bronze Dust"]], + "input": [[3, "Copper Dust"], [1, "Tin Dust"]], + "tools": [] + }, { + "output": [[1, "Bronze Helm"]], + "input": [[5, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Hoe"]], + "input": [[2, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Ingot"]], + "input": [[1, "Bronze Dust"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Bronze Leggings"]], + "input": [[7, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Pickaxe"]], + "input": [[3, "Bronze Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bronze Sword"]], + "input": [[2, "Bronze Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Carbon Plate"]], + "input": [[1, "Raw Carbon Mesh"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Clay Dust"]], + "input": [[1, "Clay Block"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Coal Dust"]], + "input": [[1, "Coal"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Composite Armor Vest"]], + "input": [[1, "Advanced Alloy"], [1, "Iron Chestplate"], [1, "Leather Tunic"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Compressed Air Cell"]], + "input": [[1, "Empty Cell"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Compressor"]], + "input": [[6, "Stone"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[6, "Copper Cable"]], + "input": [[3, "Copper Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Copper Dust"]], + "input": [[1, "Copper Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Copper Ingot"]], + "input": [[1, "Copper Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Crop-Matron"]], + "input": [[5, "Crops"], [2, "Electronic Circuit"], [1, "Machine Block"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cropnalyzer"]], + "input": [[4, "Redstone"], [2, "Insulated Copper Cable"], [1, "Electronic Circuit"], [1, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Crops"]], + "input": [[4, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Hoe"]], + "input": [[2, "Refined Iron"], [1, "Electronic Circuit"], [1, "RE Battery"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electric Jetpack"]], + "input": [[4, "Refined Iron"], [2, "Glowstone"], [1, "BatBox"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electronic Circuit"]], + "input": [[6, "Insulated Copper Cable"], [2, "Redstone"], [1, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Empty Booze Barrel"]], + "input": [[2, "Oak Plank"], [1, "Rubber Wood Log"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Empty Cell"]], + "input": [[4, "Tin"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Crystal"]], + "input": [[8, "Redstone"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Extractor"]], + "input": [[4, "Tree Tap"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Fertilizer"]], + "input": [[2, "Scrap"], [1, "Fertilizer"]], + "tools": [] + }, { + "output": [[2, "Fertilizer"]], + "input": [[1, "Scrap"], [1, "Bonemeal"]], + "tools": [] + }, { + "output": [[1, "Fuel Can"]], + "input": [[7, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Fuel Can (filled)"]], + "input": [[6, "Coalfuel Cell"], [1, "Fuel Cell"]], + "tools": ["Canning Machine"] + }, { + "output": [[1, "Generator"]], + "input": [[1, "RE Battery"], [1, "Machine Block"], [1, "Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Generator"]], + "input": [[3, "Refined Iron"], [1, "RE Battery"], [1, "Iron Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Gold Dust"]], + "input": [[1, "Gold Ore"]], + "tools": ["Macerator"] + }, { + "output": [[2, "Grin Powder"]], + "input": [[1, "Spider Eye"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Hazmat Suit"]], + "input": [[6, "Rubber"], [2, "Orange Dye"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Hazmat Suit Leggings"]], + "input": [[6, "Rubber"], [1, "Orange Dye"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Hydration Cell"]], + "input": [[1, "Water Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "Insulated Copper Cable"]], + "input": [[1, "Copper Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "Iridium Ore"]], + "input": [[7, "UU Matter"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iridium Plate"]], + "input": [[4, "Iridium Ore"], [4, "Advanced Alloy"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Iron Dust"]], + "input": [[1, "Iron Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Iron Furnace"]], + "input": [[8, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Furnace"]], + "input": [[5, "Iron Ingot"], [1, "Furnace"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Jetpack"]], + "input": [[4, "Refined Iron"], [2, "Redstone"], [1, "Electronic Circuit"], [1, "Fuel Can"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lapotron Crystal"]], + "input": [[6, "Lapis Lazuli"], [2, "Electronic Circuit"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "LapPack"]], + "input": [[6, "Lapis Lazuli Block"], [1, "Advanced Circuit"], [1, "BatPack"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Macerator"]], + "input": [[3, "Flint"], [2, "Cobblestone"], [1, "Machine Block"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Machine Block"]], + "input": [[8, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Mixed Metal Ingot"]], + "input": [[3, "Refined Iron"], [3, "Bronze Ingot"], [3, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Bodyarmor"]], + "input": [[7, "Carbon Plate"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Boots"]], + "input": [[4, "Carbon Plate"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Helmet"]], + "input": [[3, "Carbon Plate"], [1, "Glass"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "NanoSuit Leggings"]], + "input": [[6, "Carbon Plate"], [1, "Energy Crystal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Bodyarmor"]], + "input": [[4, "Iridium Plate"], [3, "Advanced Alloy"], [1, "Lapotron Crystal"], [1, "NanoSuit Bodyarmor"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Boots"]], + "input": [[2, "Iridium Plate"], [2, "Rubber Boots"], [1, "Lapotron Crystal"], [1, "NanoSuit Boots"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Helmet"]], + "input": [[2, "Iridium Plate"], [2, "Advanced Circuit"], [1, "Reinforced Glass"], [1, "Lapotron Crystal"], [1, "NanoSuit Helmet"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Quantum Leggings"]], + "input": [[1, "Iridium Plate"], [2, "Machine Block"], [2, "Glowstone"], [1, "Lapotron Crystal"], [1, "NanoSuit Leggings"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Raw Carbon Fibers"]], + "input": [[4, "Coal Dust"]], + "tools": [] + }, { + "output": [[1, "Raw Carbon Mesh"]], + "input": [[2, "Raw Carbon Fibers"]], + "tools": [] + }, { + "output": [[1, "RE Battery"]], + "input": [[4, "Tin Ingot"], [2, "Redstone"], [1, "Insulated Copper Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Refined Iron"]], + "input": [[1, "Iron Ingot"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[7, "Reinforced Glass"]], + "input": [[7, "Glass"], [2, "Advanced Alloy"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Rubber"]], + "input": [[1, "Resin"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Rubber Boots"]], + "input": [[6, "Rubber"], [1, "Wool"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Scuba Helmet"]], + "input": [[4, "Rubber"], [1, "Orange Dye"], [1, "Glass"], [1, "Iron Bars"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Silver Dust"]], + "input": [[1, "Silver Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Silver Ingot"]], + "input": [[1, "Silver Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Solar Helmet"]], + "input": [[5, "Iron Ore"], [3, "Insulated Copper Cable"], [1, "Solar Panel"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Solar Panel"]], + "input": [[3, "Coal Dust"], [3, "Glass"], [2, "Electronic Circuit"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Mug"]], + "input": [[7, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Tin Dust"]], + "input": [[1, "Tin Ore"]], + "tools": ["Macerator"] + }, { + "output": [[1, "Tin Ingot"]], + "input": [[1, "Tin Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Tree Tap"]], + "input": [[5, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Water Cell"], [1, "Bucket"]], + "input": [[1, "Empty Cell"], [1, "Water Bucket"]], + "tools": [] + }, { + "output": [[1, "Weed-EX"]], + "input": [[1, "Empty Cell"], [1, "Grin Powder"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wrench (industrial craft)"]], + "input": [[6, "Bronze Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Detector Cable"]], + "input": [[3, "Redstone"], [1, "Electronic Circuit"], [1, "HV 3x Insulated Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "HV 3x Insulated Cable"]], + "input": [[1, "HV 2x Insulated Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "HV 2x Insulated Cable"]], + "input": [[1, "HV Insulated Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "HV Insulated Cable"]], + "input": [[1, "HV Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[12, "HV Cable"]], + "input": [[3, "Refined Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Glass Fiber Cable"]], + "input": [[6, "Glass"], [2, "Redstone"], [1, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[12, "Gold Cable"]], + "input": [[3, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Insulated Gold Cable"]], + "input": [[1, "Gold Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "2x Ins. Gold Cable"]], + "input": [[1, "Insulated Gold Cable"], [1, "Rubber"]], + "tools": [] + }, { + "output": [[1, "Splitter Cable"]], + "input": [[2, "HV 3x Insulated Cable"], [2, "Redstone"], [1, "Lever"]], + "tools": [] + }, { + "output": [[9, "Tin Cable"]], + "input": [[3, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "MFE"]], + "input": [[4, "2x Ins. Gold Cable"], [2, "Energy Crystal"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "MFSU"]], + "input": [[6, "Lapotron Crystal"], [1, "Advanced Machine Block"], [1, "MFE"], [1, "Advanced Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Advanced Machine Block"]], + "input": [[2, "Advanced Alloy"], [2, "Carbon Plate"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[5, "Single-Use Battery"]], + "input": [[1, "Insulated Copper Cable"], [1, "Redstone"], [1, "Coal Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Hydrated Coal Dust"], [1, "Bucket"]], + "input": [[8, "Coal Dust"], [1, "Water Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Compressed Hyd. Coalclump"]], + "input": [[1, "Hydrated Coal Dust"]], + "tools": ["Compressor"] + }, { + "output": [[1, "H. Coal Cell"]], + "input": [[1, "Compressed Hyd. Coalclump"], [1, "Empty Cell"]], + "tools": [] + }, { + "output": [[1, "Coalfuel Cell"]], + "input": [[1, "H. Coal Cell"]], + "tools": ["Extractor"] + }, { + "output": [[1, "HV Transformer"]], + "input": [[2, "HV 3x Insulated Cable"], [1, "MV Transformer"], [1, "Energy Crystal"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "MV Transformer"]], + "input": [[2, "2x Ins. Gold Cable"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "LV Transformer"]], + "input": [[4, "Oak Plank"], [3, "Copper Ingot"], [2, "Insulated Copper Cable"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Storage Upgrade"]], + "input": [[5, "Oak Plank"], [2, "Insulated Copper Cable"], [1, "RE Battery"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Overclocker Upgrade"]], + "input": [[3, "10K Cooling Cell"], [2, "Insulated Copper Cable"], [1, "Electronic Circuit"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "10K Cooling Cell"], [1, "Bucket"]], + "input": [[4, "Tin Ingot"], [1, "Water Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "30K Cooling Cell"]], + "input": [[6, "Tin Ingot"], [3, "10K Cooling Cell"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "60K Cooling Cell"]], + "input": [[6, "Tin Ingot"], [2, "30K Cooling Cell"], [1, "Dense Copper Plate"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Dense Copper Plate"]], + "input": [[8, "Copper Ingot"]], + "tools": ["Compressor"] + }, { + "output": [[1, "Reactor Chamber"]], + "input": [[4, "Dense Copper Plate"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Transformer Upgrade"]], + "input": [[5, "Glass"], [2, "2x Ins. Gold Cable"], [1, "Electronic Circuit"], [1, "MV Transformer"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Miner"]], + "input": [[2, "Electronic Circuit"], [2, "Mining Pipe"], [1, "Machine Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[8, "Mining Pipe"]], + "input": [[6, "Refined Iron"], [1, "Treetap"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "OD Scanner"]], + "input": [[3, "Insulated Copper Cable"], [2, "Electronic Circuit"], [1, "RE Battery"], [1, "Glowstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "OV Scanner"]], + "input": [[3, "Glowstone"], [2, "2x Ins. Gold Cable"], [1, "Advanced Circuit"], [1, "OD Scanner"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "OV Scanner"]], + "input": [[3, "Glowstone"], [2, "2x Ins. Gold Cable"], [1, "Advanced Circuit"], [1, "RE Battery (charged)"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "RE Battery (charged)"]], + "input": [[1, "RE Battery"], [10000, "EU"]], + "tools": ["Generator"] + }, { + "output": [[1, "Pump"]], + "input": [[4, "Empty Cell"], [2, "Mining Pipe"], [1, "Electronic Circuit"], [1, "Machine Block"], [1, "Treetap"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Geothermal Generator"]], + "input": [[4, "Glass"], [2, "Empty Cell"], [2, "Refined Iron"], [1, "Generator"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Nuclear Reactor"]], + "input": [[3, "Reactor Chamber"], [1, "Advanced Circuit"], [1, "Generator"]], + "tools": ["Crafting Table"] + } + ] +} + diff --git a/src/data/more_blocks.json b/src/data/more_blocks.json new file mode 100644 index 000000000..919adea09 --- /dev/null +++ b/src/data/more_blocks.json @@ -0,0 +1,123 @@ +{ + "name": "MoreBlocks", + "description": "Crafting recipes from More Blocks Mod, by MCE626", + "recipes": [ + { + "output": [[1, "Cement Block"]], + "input": [[1, "Gravel"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Healer"]], + "input": [[2, "Essence of Life"], [1, "Essence of Earth"], [1, "Essence of Fire"], [1, "Essence of Water"], [1, "Essence of Air"], [3, "Red Dye"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crying Obsidian"]], + "input": [[1, "Obsidian"], [1, "Water Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lava Cobblestone"]], + "input": [[1, "Cobblestone"], [1, "Lava Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lava Obsidian"]], + "input": [[1, "Obsidian"], [1, "Lava Bucket"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Block"]], + "input": [[9, "Crystal Gem"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Einsteinium Bomb"]], + "input": [[8, "Iron Ingot"], [1, "Einsteinium Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Neptunium Bomb"]], + "input": [[8, "Iron Ingot"], [1, "Neptunium Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Uranium Bomb"]], + "input": [[8, "Iron Ingot"], [1, "Uranium Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Ultimate Nuker"]], + "input": [[3, "Iron Ingot"], [1, "Einsteinium Ingot"], [1, "Neptunium"], [1, "Uranium Ingot"], [1, "Explosive Charge"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Einsteinium Ingot"]], + "input": [[1, "Einsteinium Ore"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Neptunium Ingot"]], + "input": [[1, "Neptunium Ore"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Uranium Ingot"]], + "input": [[1, "Uranium Ore"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Crystal Piece"]], + "input": [[7, "Crystal Dust"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Piece"]], + "input": [[1, "Crystal Nugget"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Nugget"]], + "input": [[5, "Crystal Piece"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Piece"]], + "input": [[1, "Crystal Gem"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Gem"]], + "input": [[7, "Crystal Nugget"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Gem"]], + "input": [[1, "Crystal Block"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Brick"]], + "input": [[1, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crystal Ball"]], + "input": [[4, "Crystal Gem"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Hard Crystal Ball"]], + "input": [[1, "Crystal Ball"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Essence of Life"]], + "input": [[1, "Flower"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Fire"]], + "input": [[1, "Lava Bucket"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Water"]], + "input": [[1, "Water Bucket"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Earth"]], + "input": [[1, "Dirt"], [1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Essence of Air"]], + "input": [[1, "Hard Crystal Ball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Popcorn"]], + "input": [[1, "Corn Seeds"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chisel"]], + "input": [[1, "Iron Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + } + ] +} diff --git a/src/data/thermal_expansion.json b/src/data/thermal_expansion.json new file mode 100644 index 000000000..92b66d3a7 --- /dev/null +++ b/src/data/thermal_expansion.json @@ -0,0 +1,211 @@ +{ + "name": "Thermal Expansion", + "description": "Crafting Recipes from Thermal Expansion, by King Lemming and the CoFH team", + "recipes": [ + { + "output": [[1, "Aqueous Accumulator"]], + "input": [[1, "Bucket"], [2, "Glass"], [1, "Machine Frame"], [1, "Pneumatic Servo"], [2, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Copper Gear"]], + "input": [[1, "Cobblestone Gear"], [4, "Copper Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crescent Hammer"]], + "input": [[3, "Iron Ingot"], [1, "Silver Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cyclic Assembler"]], + "input": [[1, "Chest"], [2, "Copper Ingot"], [1, "Machine Frame"], [1, "Redstone Reception Coil"], [2, "Tin Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Electrum Blend"]], + "input": [[1, "Gold Dust"], [1, "Silver Dust"]], + "tools": [] + }, { + "output": [[1, "Electrum Ingot"]], + "input": [[1, "Electrum Blend"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Energetic Infuser"]], + "input": [[2, "Copper Ingot"], [1, "Machine Frame"], [1, "Redstone Reception Coil"], [2, "Redstone Transmission Coil"], [1, "Shiny Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[250, "Energized Glowstone"]], + "input": [[1, "Glowstone Dust"]], + "tools": ["Magma Crucible"] + }, { + "output": [[1, "Energy Cell Frame (Empty)"]], + "input": [[1, "Diamond"], [4, "Electrum Ingot"], [4, "Hardened Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Cell Frame (Full)"]], + "input": [[1, "Energy Cell Frame (Empty)"], [1000, "Molten Redstone"]], + "tools": ["Liquid Transposer"] + }, { + "output": [[4, "Energy Conduit (Empty)"]], + "input": [[2, "Electrum Ingot"], [1, "Hardened Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Energy Tesseract"]], + "input": [[1, "Electrum Ingot"], [2, "Lead Ingot"], [1, "Redstone Conductance Coil"], [2, "Tin Ingot"], [1, "Unattuned Tesseract"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glacial Precipitator"]], + "input": [[2, "Copper Ingot"], [1, "Machine Frame"], [1, "Piston"], [1, "Redstone Reception Coil"], [2, "Snow (Block)"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glowstone Illuminator"]], + "input": [[1000, "Energized Glowstone"], [1, "Illuminator Frame"]], + "tools": ["Liquid Transposer"] + }, { + "output": [[1, "Hardened Glass"]], + "input": [[1, "Lead Ingot"], [2, "Pulverized Obsidian"]], + "tools": ["Induction Smelter"] + }, { + "output": [[1, "Igneous Extruder"]], + "input": [[2, "Glass"], [1, "Machine Frame"], [1, "Piston"], [1, "Pneumatic Servo"], [2, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Illuminator Frame"]], + "input": [[2, "Hardened Glass"], [1, "Nether Quartz"], [1, "Redstone Dust"], [1, "Silver Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Induction Smelter"]], + "input": [[1, "Bucket"], [2, "Copper Ingot"], [2, "Invar Ingot"], [1, "Machine Frame"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Invar Blend"]], + "input": [[2, "Iron Dust"], [1, "Pulverized Ferrous Dust"]], + "tools": [] + }, { + "output": [[1, "Invar Gear"]], + "input": [[4, "Invar Ingot"], [1, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Invar Ingot"]], + "input": [[1, "Invar Blend"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Item Tesseract"]], + "input": [[1, "Pneumatic Servo"], [2, "Silver Ingot"], [3, "Tin Ingot"], [1, "Unattuned Tesseract"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lead Ingot"]], + "input": [[1, "Lead Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Liquid Tesseract"]], + "input": [[1, "Copper Ingot"], [1, "Pneumatic Servo"], [2, "Silver Ingot"], [2, "Tin Ingot"], [1, "Unattuned Tesseract"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Liquid Transposer"]], + "input": [[1, "Bucket"], [2, "Copper Ingot"], [2, "Glass"], [1, "Machine Frame"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[4, "Liquiduct"]], + "input": [[2, "Copper Ingot"], [1, "Hardened Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Machine Frame"]], + "input": [[4, "Iron Ingot"], [4, "Glass"], [1, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magma Crucible"]], + "input": [[1, "Bucket"], [2, "Copper Ingot"], [1, "Machine Frame"], [2, "Nether Brick (block)"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Magmatic Engine"]], + "input": [[2, "Invar Gear"], [3, "Invar Ingot"], [1, "Piston"], [1, "Redstone Transmission Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[250, "Molten Ender"]], + "input": [[1, "Ender Pearl"]], + "tools": ["Magma Crucible"] + }, { + "output": [[25, "Molten Redstone"]], + "input": [[1, "Redstone Dust"]], + "tools": ["Magma Crucible"] + }, { + "output": [[1, "Multimeter"]], + "input": [[2, "Copper Ingot"], [2, "Lead Ingot"], [1, "Redstone Conductance Coil"], [1, "Tin Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Pneumatic Servo"]], + "input": [[2, "Glass"], [2, "Iron Ingot"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Portable Tank"]], + "input": [[4, "Hardened Glass"], [1, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Powered Furnace"]], + "input": [[2, "Bricks"], [2, "Copper Ingot"], [1, "Machine Frame"], [1, "Redstone"], [1, "Redstone Conductance Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Pulverized Ferrous Dust"]], + "input": [[1, "Ferrous Ore"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Pulverized Obsidian"]], + "input": [[1, "Obsidian"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Pulverizer"]], + "input": [[2, "Copper Ingot"], [2, "Flint"], [1, "Machine Frame"], [1, "Piston"], [1, "Redstone Reception Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Conductance Coil"]], + "input": [[2, "Redstone"], [1, "Electrum Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Energy Cell"]], + "input": [[3, "Electrum Ingot"], [1, "Energy Cell Frame (Full)"], [2, "Lead Ingot"], [1, "Redstone Conductance Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Energy Conduit"]], + "input": [[1, "Energy Conduit (Empty)"], [50, "Molten Redstone"]], + "tools": ["Liquid Transposer"] + }, { + "output": [[1, "Redstone Reception Coil"]], + "input": [[2, "Redstone"], [1, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Transmission Coil"]], + "input": [[2, "Redstone"], [1, "Silver Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Sawmill"]], + "input": [[2, "Copper Ingot"], [1, "Iron Axe"], [1, "Machine Frame"], [1, "Redstone Reception Coil"], [2, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Schematic"]], + "input": [[1, "Lapis Lazuli"], [3, "Paper"]], + "tools": [] + }, { + "output": [[1, "Shiny Dust"]], + "input": [[10, "Ferrous Ore"]], + "tools": ["Pulverizer"] + }, { + "output": [[1, "Shiny Ingot"]], + "input": [[1, "Shiny Dust"], [125, "milli-coal"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Steam Engine"]], + "input": [[2, "Copper Gear"], [3, "Copper Ingot"], [1, "Piston"], [1, "Redstone Transmission Coil"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tesseract Frame"]], + "input": [[1, "Diamond"], [4, "Hardened Glass"], [4, "Tin Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Tin Gear"]], + "input": [[4, "Tin Ingot"], [1, "Cobblestone Gear"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Unattuned Tesseract"]], + "input": [[1000, "Molten Ender"], [1, "Tesseract Frame"]], + "tools": ["Liquid Transposer"] + } + ] +} diff --git a/src/data/vanilla.json b/src/data/vanilla.json new file mode 100644 index 000000000..02cc20856 --- /dev/null +++ b/src/data/vanilla.json @@ -0,0 +1,564 @@ +{ + "name": "Vanilla Recipes", + "description": "Crafting recipes from vanilla Minecraft (in progress)", + "recipes": [ + { + "output": [[4, "Arrow"]], + "input": [[1, "Flint"], [1, "Stick"], [1, "Feather"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Baked Potato"]], + "input": [[1, "Potato"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Beacon"]], + "input": [[5, "Glass"], [3, "Obsidian"], [1, "Nether Star"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bed"]], + "input": [[3, "Wool"], [3, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Blaze Powder"]], + "input": [[1, "Blaze Rod"]], + "tools": [] + }, { + "output": [[1, "Boat"]], + "input": [[5, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[3, "Bone Meal"]], + "input": [[1, "Bone"]], + "tools": [] + }, { + "output": [[1, "Book"]], + "input": [[1, "Leather"], [3, "Paper"]], + "tools": [] + }, { + "output": [[1, "Book and Quill"]], + "input": [[1, "Book"], [1, "Ink Sac"], [1, "Feather"]], + "tools": [] + }, { + "output": [[1, "Bookshelf"]], + "input": [[6, "Oak Plank"], [3, "Book"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bow"]], + "input": [[3, "Stick"], [3, "String"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bowl"]], + "input": [[3, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Bread"]], + "input": [[3, "Wheat"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Brewing Stand"]], + "input": [[1, "Blaze Rod"], [3, "Cobblestone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Brick"]], + "input": [[1, "Clay"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Bricks"]], + "input": [[4, "Brick"]], + "tools": [] + }, { + "output": [[1, "Bucket"]], + "input": [[3, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Cactus Green"]], + "input": [[1, "Cactus"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cake"], [1, "Bucket"]], + "input": [[3, "Milk"], [2, "Sugar"], [3, "Wheat"], [1, "Egg"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Carrot on a Stick"]], + "input": [[1, "Fishing Rod"], [1, "Carrot"]], + "tools": [] + }, { + "output": [[1, "Cauldron"]], + "input": [[7, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Boots"]], + "input": [[4, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Chestplate"]], + "input": [[8, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Helmet"]], + "input": [[5, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Chain Leggings"]], + "input": [[7, "Fire"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Charcoal"]], + "input": [[1, "Oak Log"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Chest"]], + "input": [[8, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Clay Block"]], + "input": [[4, "Clay"]], + "tools": [] + }, { + "output": [[1, "Clock"]], + "input": [[4, "Gold Ingot"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Compass"]], + "input": [[4, "Iron Ingot"], [1, "Redstone"]], + "tools": [] + }, { + "output": [[1, "Cooked Chicken"]], + "input": [[1, "Raw Chicken"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cooked Fish"]], + "input": [[1, "Raw Fish"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cooked Porkchop"]], + "input": [[1, "Raw Porkchop"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Cookie"]], + "input": [[1, "Cocoa Beans"], [2, "Wheat"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Crafting Table"]], + "input": [[4, "Oak Plank"]], + "tools": [] + }, { + "output": [[2, "Cyan Dye"]], + "input": [[1, "Cactus Green"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[2, "Dandelion Yellow"]], + "input": [[1, "Dandelion"]], + "tools": [] + }, { + "output": [[1, "Diamond Axe"]], + "input": [[3, "Diamond"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Boots"]], + "input": [[4, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Chestplate"]], + "input": [[8, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Helm"]], + "input": [[5, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Hoe"]], + "input": [[2, "Diamond"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Leggings"]], + "input": [[7, "Diamond"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Pickaxe"]], + "input": [[3, "Diamond"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Diamond Sword"]], + "input": [[2, "Diamond"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Eye of Ender"]], + "input": [[1, "Ender Pearl"], [1, "Blaze Powder"]], + "tools": [] + }, { + "output": [[1, "Fermented Spider Eye"]], + "input": [[1, "Spider Eye"], [1, "Brown Mushroom"], [1, "Sugar"]], + "tools": [] + }, { + "output": [[3, "Fire Charge"]], + "input": [[1, "Blaze Powder"], [1, "Coal"], [1, "Gunpowder"]], + "tools": [] + }, { + "output": [[1, "Fishing Rod"]], + "input": [[3, "Stick"], [2, "String"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Flint and Steel"]], + "input": [[1, "Iron Ingot"], [1, "Flint"]], + "tools": [] + }, { + "output": [[1, "Furnace"]], + "input": [[8, "Cobblestone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glass"]], + "input": [[1, "Sand"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[3, "Glass Bottle"]], + "input": [[3, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Glass Panes"]], + "input": [[6, "Glass"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Glistering Melon"]], + "input": [[1, "Melon"], [8, "Gold Nugget"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Axe"]], + "input": [[3, "Gold Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Boots"]], + "input": [[4, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Chestplate"]], + "input": [[8, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Helm"]], + "input": [[5, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Hoe"]], + "input": [[2, "Gold Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Leggings"]], + "input": [[7, "Gold Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Ingot"]], + "input": [[1, "Gold Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[9, "Gold Nugget"]], + "input": [[1, "Gold Ingot"]], + "tools": [] + }, { + "output": [[1, "Gold Pickaxe"]], + "input": [[3, "Gold Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Gold Sword"]], + "input": [[2, "Gold Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Golden Apple"]], + "input": [[9, "Gold Ingot"], [1, "Apple"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Golden Carrot"]], + "input": [[8, "Gold Nugget"], [1, "Carrot"]], + "tools": ["Crafting Table"] + }, { + "output": [[2, "Gray Dye"]], + "input": [[1, "Bone Meal"], [1, "Ink Sac"]], + "tools": [] + }, { + "output": [[1, "Hopper"]], + "input": [[5, "Iron Ingot"], [1, "Chest"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Axe"]], + "input": [[3, "Iron Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[16, "Iron Bars"]], + "input": [[6, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Boots"]], + "input": [[4, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Chestplate"]], + "input": [[8, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Door"]], + "input": [[6, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Helm"]], + "input": [[5, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Hoe"]], + "input": [[2, "Iron Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Ingot"]], + "input": [[1, "Iron Ore"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Iron Leggings"]], + "input": [[7, "Iron Ingot"]], + "tools": ["Crafting Table"] + }, { + "output": [[9, "Iron Nugget"]], + "input": [[1, "Iron Ingot"]], + "tools": [] + }, { + "output": [[1, "Iron Pickaxe"]], + "input": [[3, "Iron Ingot"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Iron Sword"]], + "input": [[2, "Iron Ingot"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lapis Lazuli Block"]], + "input": [[9, "Lapis Lazuli"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lava Bucket"]], + "input": [[1, "Bucket"], [1, "Lava Source Block"]], + "tools": [] + }, { + "output": [[2, "Lead"]], + "input": [[4, "String"], [1, "Slimeball"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Leather Boots"]], + "input": [[4, "Leather"]], + "tools": [] + }, { + "output": [[1, "Leather Tunic"]], + "input": [[8, "Leather"]], + "tools": [] + }, { + "output": [[1, "Leather Helm"]], + "input": [[5, "Leather"]], + "tools": [] + }, { + "output": [[1, "Leather Leggings"]], + "input": [[7, "Leather"]], + "tools": [] + }, { + "output": [[2, "Light Blue Dye"]], + "input": [[1, "Bone Meal"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[3, "Light Gray Dye"]], + "input": [[2, "Bone Meal"], [1, "Ink Sac"]], + "tools": [] + }, { + "output": [[2, "Light Gray Dye"]], + "input": [[1, "Bone Meal"], [1, "Gray Dye"]], + "tools": [] + }, { + "output": [[2, "Lime Dye"]], + "input": [[1, "Bone Meal"], [1, "Cactus Green"]], + "tools": [] + }, { + "output": [[2, "Magenta Dye"]], + "input": [[1, "Pink Dye"], [1, "Purple Dye"]], + "tools": [] + }, { + "output": [[3, "Magenta Dye"]], + "input": [[1, "Rose Red"], [1, "Pink Dye"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[4, "Magenta Dye"]], + "input": [[2, "Rose Red"], [1, "Bone Meal"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[1, "Magma Cream"]], + "input": [[1, "Slimeball"], [1, "Blaze Powder"]], + "tools": [] + }, { + "output": [[1, "Melon Seeds"]], + "input": [[1, "Melon"]], + "tools": [] + }, { + "output": [[1, "Milk"]], + "input": [[1, "Bucket"]], + "tools": ["Cow"] + }, { + "output": [[1, "Minecart"]], + "input": [[5, "Iron"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Minecart with Chest"]], + "input": [[1, "Minecart"], [1, "Chest"]], + "tools": [] + }, { + "output": [[1, "Minecart with Furnace"]], + "input": [[1, "Minecart"], [1, "Furnace"]], + "tools": [] + }, { + "output": [[1, "Minecart with Hopper"]], + "input": [[1, "Minecart"], [1, "Hopper"]], + "tools": [] + }, { + "output": [[1, "Minecart with TNT"]], + "input": [[1, "Minecart"], [1, "TNT"]], + "tools": [] + }, { + "output": [[1, "Mushroom Stew"]], + "input": [[1, "Bowl"], [1, "Red Mushroom"], [1, "Brown Mushroom"]], + "tools": [] + }, { + "output": [[1, "Nether Brick (item)"]], + "input": [[1, "Netherrack"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Nether Brick (block)"]], + "input": [[4, "Nether Brick (item)"]], + "tools": [] + }, { + "output": [[4, "Oak Plank"]], + "input": [[1, "Oak Log"]], + "tools": [] + }, { + "output": [[2, "Orange Dye"]], + "input": [[1, "Dandelion Yellow"], [1, "Rose Red"]], + "tools": [] + }, { + "output": [[3, "Paper"]], + "input": [[3, "Sugar Cane"]], + "tools": [] + }, { + "output": [[2, "Pink Dye"]], + "input": [[1, "Bone Meal"], [1, "Rose Red"]], + "tools": [] + }, { + "output": [[1, "Piston"]], + "input": [[4, "Cobblestone"], [3, "Oak Plank"], [1, "Iron Ingot"], [1, "Redstone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Pumpkin Pie"]], + "input": [[1, "Sugar"], [1, "Pumpkin"], [1, "Egg"]], + "tools": [] + }, { + "output": [[4, "Pumpkin Seeds"]], + "input": [[1, "Pumpkin"]], + "tools": [] + }, { + "output": [[2, "Purple Dye"]], + "input": [[1, "Rose Red"], [1, "Lapis Lazuli"]], + "tools": [] + }, { + "output": [[1, "Redstone Comparator"]], + "input": [[3, "Redstone Torch"], [1, "Nether Quartz"], [3, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Repeater"]], + "input": [[2, "Redstone Torch"], [1, "Redstone"], [3, "Stone"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Redstone Torch"]], + "input": [[1, "Redstone"], [1, "Stick"]], + "tools": [] + }, { + "output": [[2, "Rose Red"]], + "input": [[1, "Rose"]], + "tools": [] + }, { + "output": [[1, "Shears"]], + "input": [[2, "Iron Ingot"]], + "tools": [] + }, { + "output": [[1, "Sign"]], + "input": [[6, "Oak Plank"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Steak"]], + "input": [[1, "Raw Beef"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[4, "Stick"]], + "input": [[2, "Oak Plank"]], + "tools": [] + }, { + "output": [[1, "Sticky Piston"]], + "input": [[1, "Piston"], [1, "Slimeball"]], + "tools": [] + }, { + "output": [[1, "Sugar"]], + "input": [[1, "Sugar Cane"]], + "tools": [] + }, { + "output": [[1, "Stone"]], + "input": [[1, "Cobblestone"], [125, "milli-coal"]], + "tools": ["Furnace"] + }, { + "output": [[1, "Stone Axe"]], + "input": [[3, "Cobblestone"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Button"]], + "input": [[1, "Stone"]], + "tools": [] + }, { + "output": [[1, "Stone Hoe"]], + "input": [[2, "Cobblestone"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Pickaxe"]], + "input": [[3, "Cobblestone"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Stone Sword"]], + "input": [[2, "Cobblestone"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "TNT"]], + "input": [[5, "Gunpowder"], [4, "Sand"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Water Bucket"]], + "input": [[1, "Bucket"], [1, "Water Source Block"]], + "tools": [] + }, { + "output": [[1, "Wooden Axe"]], + "input": [[3, "Oak Plank"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Button"]], + "input": [[1, "Oak Plank"]], + "tools": [] + }, { + "output": [[1, "Wooden Door"]], + "input": [[6, "Oak Plank"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Hoe"]], + "input": [[2, "Oak Plank"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Pickaxe"]], + "input": [[3, "Oak Plank"], [2, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Wooden Sword"]], + "input": [[2, "Oak Plank"], [1, "Stick"]], + "tools": ["Crafting Table"] + }, { + "output": [[1, "Lever"]], + "input": [[1, "Stick"], [1, "Cobblestone"]], + "tools": [] + } + ] +} + diff --git a/src/fonts/press_start.ttf b/src/fonts/press_start.ttf new file mode 100644 index 000000000..1efa15873 Binary files /dev/null and b/src/fonts/press_start.ttf differ diff --git a/src/images/bedrock.png b/src/images/bedrock.png new file mode 100755 index 000000000..79ac81cb9 Binary files /dev/null and b/src/images/bedrock.png differ diff --git a/src/images/bookshelf.png b/src/images/bookshelf.png new file mode 100755 index 000000000..896c30e19 Binary files /dev/null and b/src/images/bookshelf.png differ diff --git a/src/images/dirt.png b/src/images/dirt.png new file mode 100755 index 000000000..28f300b8a Binary files /dev/null and b/src/images/dirt.png differ diff --git a/src/images/grass_side.png b/src/images/grass_side.png new file mode 100755 index 000000000..5d8809926 Binary files /dev/null and b/src/images/grass_side.png differ diff --git a/src/images/ice.png b/src/images/ice.png new file mode 100755 index 000000000..97581e8b8 Binary files /dev/null and b/src/images/ice.png differ diff --git a/src/images/stone_brick.png b/src/images/stone_brick.png new file mode 100755 index 000000000..f810cdeb7 Binary files /dev/null and b/src/images/stone_brick.png differ diff --git a/src/images/stone_brick_light.png b/src/images/stone_brick_light.png new file mode 100755 index 000000000..aac7c0ee6 Binary files /dev/null and b/src/images/stone_brick_light.png differ diff --git a/src/images/wordmark.png b/src/images/wordmark.png new file mode 100644 index 000000000..e538238ed Binary files /dev/null and b/src/images/wordmark.png differ diff --git a/src/images/workbench_front.png b/src/images/workbench_front.png new file mode 100755 index 000000000..ec3ba9bf8 Binary files /dev/null and b/src/images/workbench_front.png differ diff --git a/src/images/workbench_top.png b/src/images/workbench_top.png new file mode 100755 index 000000000..60d8026c3 Binary files /dev/null and b/src/images/workbench_top.png differ diff --git a/src/pages/includes/_footer.jade b/src/pages/includes/_footer.jade new file mode 100644 index 000000000..0e61fb05e --- /dev/null +++ b/src/pages/includes/_footer.jade @@ -0,0 +1,33 @@ +//- +//- Crafting Guide - _footer.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__footer + .divider.top + .left + h2: p About + p Crafting Guide shows you what materials you need to craft even the most complex items, including all the tools + | you'd need (from a crafting table to an industrial centrifuge). + p If you have any questions, comments or requests, feel free to + | create an issue on GitHub or + | email me.

+ .center + h2: p Donate + p Crafting Guide is free for all, but if you find it helpful, donations in any amount are gratefully accepted. + form(action="https://www.paypal.com/cgi-bin/webscr", class="centered", method="post", target="_top") + input(type="hidden", name="cmd", value="_s-xclick") + input(type="hidden", name="hosted_button_id", value="GCB2TYZJYLAE6") + input(type="image", src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif", border="0", + name="submit" alt="PayPal - The safer, easier way to pay online!") + img(src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif", width="1", height="1") + .right + h2: p Get Involved + p Crafting Guide is completely open-source, and you can help! Whether you want to write a recipe book (all + | simple JSON), or implement new features, just head over to GitHub to get started. + .centered + iframe(src="http://ghbtns.com/github-btn.html?user=andrewminer&repo=crafting-guide&type=fork&size=large", + allowtransparency="true", frameborder="0", scrolling="0", width="100", height="32") + .divider.bottom diff --git a/src/pages/includes/_google_analytics.jade b/src/pages/includes/_google_analytics.jade new file mode 100644 index 000000000..b9d6b2716 --- /dev/null +++ b/src/pages/includes/_google_analytics.jade @@ -0,0 +1,15 @@ +//- +//- Crafting Guide - _google_analytics.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +script. + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) + })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + + ga('create', 'UA-5871323-4', 'crafting-guide.com'); + ga('send', 'pageview'); diff --git a/src/pages/includes/_header.jade b/src/pages/includes/_header.jade new file mode 100644 index 000000000..6241dece0 --- /dev/null +++ b/src/pages/includes/_header.jade @@ -0,0 +1,12 @@ +//- +//- Crafting Guide - _header.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__header + h1 + img(src="images/workbench_front.png") + p Crafting Guide + .divider.bottom diff --git a/src/pages/index.jade b/src/pages/index.jade new file mode 100644 index 000000000..db86abcee --- /dev/null +++ b/src/pages/index.jade @@ -0,0 +1,15 @@ +//- +//- Crafting Guide - index.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +extends ./layouts/basic + +block content + .page + +append scripts + script(src="/js/main.js") + include ./includes/_google_analytics.jade diff --git a/src/pages/layouts/basic.jade b/src/pages/layouts/basic.jade new file mode 100644 index 000000000..b46a4fc62 --- /dev/null +++ b/src/pages/layouts/basic.jade @@ -0,0 +1,33 @@ +//- +//- Crafting Guide - basic.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +block basic-vars + - var pageTitle = 'Crafting Guide' + +doctype html +html + head + title= pageTitle + meta(charset="UTF-8") + + block styles + link(rel="stylesheet", type="text/css", href="css/main.css") + + body + .content + include ../includes/_header.jade + + block content + + include ../includes/_footer.jade + + block scripts + script(src="/js/underscore.js") + script(src="/js/jquery.js") + script(src="/js/backbone.js") + script(src="/js/jade.js") + script(src="/js/when.js") diff --git a/src/pages/test.jade b/src/pages/test.jade new file mode 100644 index 000000000..e1b1343a6 --- /dev/null +++ b/src/pages/test.jade @@ -0,0 +1,20 @@ +//- +//- Crafting Guide - test.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +extend ./layouts/basic + +append styles + link(rel="stylesheet", type="text/css", href="css/mocha.css") + style #mocha-stats { position: absolute; top: 9em; } + +block content + #mocha + +append scripts + script(src="/js/mocha.js") + script(src="/js/chai.js") + script(src="/js/test.js") diff --git a/src/scripts/constants.coffee b/src/scripts/constants.coffee new file mode 100644 index 000000000..546023138 --- /dev/null +++ b/src/scripts/constants.coffee @@ -0,0 +1,24 @@ +### +# Crafting Guide - constants.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +exports.Duration = Duration = {} +Duration.snap = 100 +Duration.fast = Duration.snap * 2 +Duration.normal = Duration.fast * 2 +Duration.slow = Duration.normal * 2 + +exports.Opacity = Opacity = {} +Opacity.hidden = 1e-6 +Opacity.shown = 1 + +exports.Event = Event = {} +Event.book = {} +Event.book.load = {} +Event.book.load.started = 'book:load:started' # controller, url +Event.book.load.succeeded = 'book:load:succeeded' # controller, book +Event.book.load.failed = 'book:load:failed' # controller, error message +Event.book.load.finished = 'book:load:finished' # controller diff --git a/src/scripts/controllers/base_controller.coffee b/src/scripts/controllers/base_controller.coffee new file mode 100644 index 000000000..ee481fb6b --- /dev/null +++ b/src/scripts/controllers/base_controller.coffee @@ -0,0 +1,77 @@ +### +# Crafting Guide - base_controller.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +views = require '../views' + +######################################################################################################################## + +module.exports = class BaseController extends Backbone.View + + constructor: (options={})-> + @_rendered = false + @_parent = options.parent + @_children = [] + + @_loadTemplate options.templateName + super options + + # Public Methods ############################################################################### + + addChild: (Controller, atSelector, options={})-> + options.el = @$(atSelector)[0] + options.parent = this + + child = new Controller options + child.render() + @_children.push child + return child + + refresh: -> + logger.verbose "#{this} refreshing" + + # Event Methods ################################################################################ + + onWillRender: -> # do nothing + + onDidRender: -> + @refresh() + + # Backbone.View Overrides ###################################################################### + + render: (options={})-> + return this unless not @_rendered or options.force + + data = (@model?.toHash? and @model.toHash()) or @model or {} + + if not @_template? + logger.error "Default render called for #{@constructor.name} without a template" + return this + + logger.verbose "#{this} rendering with data: #{data}" + @onWillRender() + $oldEl = @$el + $newEl = Backbone.$(@_template(data)) + if $oldEl + $oldEl.replaceWith $newEl + $newEl.addClass $oldEl.attr 'class' + + @setElement $newEl + @_rendered = true + @onDidRender() + + return this + + # Object Overrides ############################################################################# + + toString: -> + return "#{@constructor.name}(#{@cid})" + + # Private Methods ############################################################################## + + _loadTemplate: (templateName)-> + if templateName? + @_template = views[templateName] diff --git a/src/scripts/controllers/landing_page_controller.coffee b/src/scripts/controllers/landing_page_controller.coffee new file mode 100644 index 000000000..c9052fa07 --- /dev/null +++ b/src/scripts/controllers/landing_page_controller.coffee @@ -0,0 +1,25 @@ +### +# Crafting Guide - crafting_guide_controller.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseController = require './base_controller' +LandingPage = require '../models/landing_page' +RecipeCatalogController = require './recipe_catalog_controller' + +######################################################################################################################## + +module.exports = class LandingPageController extends BaseController + + constructor: (options={})-> + options.model ?= new LandingPage + options.templateName = 'landing_page' + super options + + # BaseController Overrides ##################################################################### + + onDidRender: -> + @recipeBooksController = @addChild RecipeCatalogController, '.view__recipe_catalog' + super diff --git a/src/scripts/controllers/recipe_catalog_controller.coffee b/src/scripts/controllers/recipe_catalog_controller.coffee new file mode 100644 index 000000000..e20b8089d --- /dev/null +++ b/src/scripts/controllers/recipe_catalog_controller.coffee @@ -0,0 +1,16 @@ +### +# Crafting Guide - recipe_catalog_controller.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseController = require './base_controller' + +######################################################################################################################## + +module.exports = class RecipeCatalogController extends BaseController + + constructor: (options={})-> + options.templateName = 'recipe_catalog' + super options diff --git a/src/scripts/crafting_guide_router.coffee b/src/scripts/crafting_guide_router.coffee new file mode 100644 index 000000000..ce971d19e --- /dev/null +++ b/src/scripts/crafting_guide_router.coffee @@ -0,0 +1,57 @@ +### +# Crafting Guide - router.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +{Duration} = require './constants' +LandingPageController = require './controllers/landing_page_controller' +{Opacity} = require './constants' + +######################################################################################################################## + +module.exports = class CraftingGuideRouter extends Backbone.Router + + constructor: (options={})-> + @_page = null + @_pageControllers = {} + super options + + # Backbone.Router Overrides #################################################################### + + routes: + '': 'landing' + + # Route Methods ################################################################################ + + landing: -> + @_pageControllers.landing ?= new LandingPageController + @_setPage 'landing' + + # Private Methods ############################################################################## + + _setPage: (controllerName)-> + controller = @_pageControllers[controllerName] + if not controller? then throw new Error "cannot find controller named: #{controllerName}" + return if @_page is controller + + logger.info "changing to #{controllerName} page" + showDuration = Duration.normal + show = => + @_page = controller + + controller.render() + # controller.$el.css 'opacity', Opacity.hidden + + $pageContent = $('.page') + $pageContent.empty() + $pageContent.append controller.$el + + controller.$el.fadeIn showDuration + + if @_mainController? + showDuration = Duration.fast + @_page.$el.fadeOut Duration.fast, show + else + show() diff --git a/src/scripts/logger.coffee b/src/scripts/logger.coffee new file mode 100644 index 000000000..823eb2a19 --- /dev/null +++ b/src/scripts/logger.coffee @@ -0,0 +1,87 @@ +### +# Crafting Guide - logger.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +######################################################################################################################## + +module.exports = class Logger + + @TRACE = {name:'TRACE ', value:0} + @DEBUG = {name:'DEBUG ', value:1} + @VERBOSE = {name:'VERBOSE', value:2} + @INFO = {name:'INFO ', value:3} + @WARNING = {name:'WARNING', value:4} + @ERROR = {name:'ERROR ', value:5} + @FATAL = {name:'FATAL ', value:6} + + ALL_LEVELS = [@TRACE, @DEBUG, @VERBOSE, @INFO, @WARNING, @ERROR, @FATAL] + + constructor: (options={})-> + options.level ?= Logger.FATAL + @formatText = if options.format? then options.format else "<%= timestamp %> | <%= level %> | <%= message %>" + @level = @_parseLevel options + + @_format = _.template @formatText + + log: (level, message)-> + return unless level.value >= @level.value + message = message() if _.isFunction message + + entry = {timestamp:new Date(), level:level, message:message} + entry.level ?= @level + + lines = @_formatEntry entry + if entry.level.value < Logger.WARNING.value + console.log(line) for line in lines + else + console.error(line) for line in lines + + # Log Methods ################################################################################## + + trace: (message)-> @log Logger.TRACE, message + + debug: (message)-> @log Logger.DEBUG, message + + verbose: (message)-> @log Logger.VERBOSE, message + + info: (message)-> @log Logger.INFO, message + + warning: (message)-> @log Logger.WARNING, message + + error: (message)-> + message = "#{message.stack}" if message.stack? + @log Logger.ERROR, message + + fatal: (message)-> @log Logger.FATAL, message + + # Private Methods ############################################################################## + + _formatEntry: (entry, lines=[])-> + message = entry.message.replace /\\n/g, '\n' + for line in message.split '\n' + result = [] + result.push @_format + timestamp: "#{entry.timestamp}" + level: entry.level.name + message: line + lines.push result.join '' + return lines + + _parseLevel: (options)-> + return Logger.FATAL unless _(options).has 'level' + level = options.level + + if not level? + candidates = [] + else if _.isString level + candidates = (l for l in ALL_LEVELS when l.name.trim().toLowerCase() is level.trim().toLowerCase()) + else if _.isNumber level + candidates = (l for l in ALL_LEVELS when l.value is level) + else if level? + candidates = (l for l in ALL_LEVELS when l is level) + + throw new Error "invalid level: #{level}" unless candidates.length > 0 + return candidates[0] diff --git a/src/scripts/main.coffee b/src/scripts/main.coffee new file mode 100644 index 000000000..0a12c5a34 --- /dev/null +++ b/src/scripts/main.coffee @@ -0,0 +1,20 @@ +### +# Crafting Guide - main.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +views = require './views' +Logger = require './logger' +CraftingGuideRouter = require './crafting_guide_router' + +if typeof(global) is 'undefined' + window.global = window + +global.views = views +global.logger = new Logger level:Logger.TRACE +global.router = new CraftingGuideRouter + +logger.info "CraftingGuide is ready" +Backbone.history.start pushState:true diff --git a/src/scripts/models/base_model.coffee b/src/scripts/models/base_model.coffee new file mode 100644 index 000000000..73158ad6d --- /dev/null +++ b/src/scripts/models/base_model.coffee @@ -0,0 +1,28 @@ +### +# crafting_guide - base_model.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +######################################################################################################################## + +module.exports = class BaseModel extends Backbone.Model + + constructor: (attributes={}, options={})-> + super attributes, options + + makeGetter = (name)-> return -> @get name + makeSetter = (name)-> return (value)-> @set name, value + for name in _.keys attributes + continue if name is 'id' + Object.defineProperty this, name, get:makeGetter(name), set:makeSetter(name) + + # Backbone.Model Overrides ##################################################################### + + sync: -> # do nothing + + # Object Overrides ############################################################################# + + toString: -> + return "#{@constructor.name} (#{@cid})" diff --git a/src/scripts/models/item.coffee b/src/scripts/models/item.coffee new file mode 100644 index 000000000..463580620 --- /dev/null +++ b/src/scripts/models/item.coffee @@ -0,0 +1,19 @@ +### +# Crafting Guide - item.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' + +######################################################################################################################## + +module.exports = class Item extends BaseModel + + constructor: (attributes={}, options={})-> + attributes.name ?= '' + attributes.quantity ?= 1 + super attributes, options + + # Public Methods ############################################################################### \ No newline at end of file diff --git a/src/scripts/models/landing_page.coffee b/src/scripts/models/landing_page.coffee new file mode 100644 index 000000000..e252b8982 --- /dev/null +++ b/src/scripts/models/landing_page.coffee @@ -0,0 +1,17 @@ +### +# Crafting Guide - landing_page.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' +RecipeCatalog = require './recipe_catalog' + +######################################################################################################################## + +module.exports = class LandingPage extends BaseModel + + constructor: (attributes={}, options={})-> + attributes.catalog ?= new RecipeCatalog + super attributes, options diff --git a/src/scripts/models/parser_versions/v1.coffee b/src/scripts/models/parser_versions/v1.coffee new file mode 100644 index 000000000..9451f8b7b --- /dev/null +++ b/src/scripts/models/parser_versions/v1.coffee @@ -0,0 +1,81 @@ +### +# Crafting Guide - v1.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +Item = require '../item' +Recipe = require '../recipe' +RecipeBook = require '../recipe_book' + + +######################################################################################################################## + +module.exports = class V1 + + constructor: -> + @_errorLocation = 'the header information' + + parse: (data)-> + return @_parseRecipeBook data + + # Private Methods ############################################################################## + + _parseRecipeBook: (data)-> + if not data? then throw new Error 'recipe book data is missing' + if not data.version? then throw new Error 'version is required' + if not data.mod_name? then throw new Error 'mod_name is required' + if not data.mod_version? then throw new Error 'mod_version is required' + if not _.isArray(data.recipes) then throw new Error 'recipes must be an array' + + book = new RecipeBook version:data.version, modName:data.mod_name, modVersion:data.mod_version + book.description = data.description or '' + + for index in [0...data.recipes.length] + @_errorLocation = "recipe #{index + 1}" + recipeData = data.recipes[index] + book.recipes.push @_parseRecipe recipeData + + return book + + _parseRecipe: (data, options={})-> + if not data? then throw new Error "recipe data is missing for #{@_errorLocation}" + if not data.output? then throw new Error "#{@_errorLocation} is missing output" + if not data.input? then throw new Error "#{@_errorLocation} is missing input" + + output = @_parseItemList data.output, field:'output', canBeEmpty:false + @_errorLocation = "recipe for output[0].name" + + data.tools ?= [] + input = @_parseItemList data.input, field:'input', canBeEmpty:false + tools = @_parseItemList data.tools, field:'tools', canBeEmpty:true + + return new Recipe input:input, output:output, tools:tools + + _parseItemList: (data, options={})-> + if not data? then throw new Error "#{@_errorLocation} must have an #{options.field} field" + + if not _.isArray(data) then data = [data] + if data.length is 0 and not options.canBeEmpty + throw new Error "#{options.field} for #{@_errorLocation} cannot be empty" + + result = [] + for index in [0...data.length] + itemData = data[index] + result.push @_parseItem itemData, field:options.field, index:index + + return result + + _parseItem: (data, options={})-> + errorBase = "#{options.field} element #{options.index} for #{@_errorLocation}" + if not data? then throw new Error "#{errorBase} is missing" + + if _.isString(data) then data = [1, data] + if not _.isArray(data) then throw new Error "#{errorBase} must be an array" + + if data.length is 1 then data.unshift 1 + if data.length isnt 2 then throw new Error "#{errorBase} must have at least one element" + if not _.isNumber(data[0]) then throw new Error "#{errorBase} must start with a number" + + return new Item quantity:data[0], name:data[1] diff --git a/src/scripts/models/recipe.coffee b/src/scripts/models/recipe.coffee new file mode 100644 index 000000000..672d6aa51 --- /dev/null +++ b/src/scripts/models/recipe.coffee @@ -0,0 +1,17 @@ +### +# Crafting Guide - recipe.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' + +######################################################################################################################## + +module.exports = class Recipe extends BaseModel + + constructor: (attributes={}, options={})-> + super attributes, options + + Object.defineProperty this, 'name', get:-> @output[0].name diff --git a/src/scripts/models/recipe_book.coffee b/src/scripts/models/recipe_book.coffee new file mode 100644 index 000000000..02c0d7013 --- /dev/null +++ b/src/scripts/models/recipe_book.coffee @@ -0,0 +1,38 @@ +### +# Crafting Guide - recipe_book.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' + +######################################################################################################################## + +module.exports = class RecipeBook extends BaseModel + + constructor: (attributes={}, options={})-> + if _.isEmpty(attributes.modName) then throw new Error 'modName cannot be empty' + if _.isEmpty(attributes.modVersion) then throw new Error 'modVersion cannot be empty' + + attributes.description ?= '' + attributes.recipes ?= [] + super attributes, options + + # Public Methods ############################################################################### + + getRecipes: (name)-> + result = [] + for recipe in @recipes + if recipe.name is name + result.push recipe + + return result + + # Object Overrides ############################################################################# + + toString: -> + return "RecipeBook (#{@cid}) { + modName:#{@modName}, + modVersion:#{@modVersion}, + recipes:#{@recipes.length} items}" diff --git a/src/scripts/models/recipe_book_parser.coffee b/src/scripts/models/recipe_book_parser.coffee new file mode 100644 index 000000000..6376190ee --- /dev/null +++ b/src/scripts/models/recipe_book_parser.coffee @@ -0,0 +1,26 @@ +### +# Crafting Guide - recipe_book_parser.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +V1 = require './parser_versions/v1' + +######################################################################################################################## + +module.exports = class RecipeBookParser + + constructor: -> + @_parsers = + '1': new V1 + + parse: (data)-> + if not data? then throw new Error 'recipe book data is missing' + if not data.version? then throw new Error 'version is required' + + parser = @_parsers["#{data.version}"] + if not parser? + throw new Error "cannot parse version #{data.version} recipe books" + + return parser.parse data diff --git a/src/scripts/models/recipe_catalog.coffee b/src/scripts/models/recipe_catalog.coffee new file mode 100644 index 000000000..ad5a30f53 --- /dev/null +++ b/src/scripts/models/recipe_catalog.coffee @@ -0,0 +1,54 @@ +### +# Crafting Guide - recipe_catalog.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +BaseModel = require './base_model' +{Event} = require '../constants' +RecipeBookParser = require './recipe_book_parser' + +######################################################################################################################## + +module.exports = class RecipeCatalog extends BaseModel + + constructor: (attributes={}, options={})-> + attributes.books ?= [] + super attributes, options + + @_parser = new RecipeBookParser + + # Public Methods ############################################################################### + + loadBook: (url)-> + @trigger Event.book.load.started, this, url + $.ajax + url: url + dataType: 'json' + success: (data, status, xhr)=> @onBookLoaded(data, status, xhr) + error: (xhr, status, error)=> @onBookLoadFailed(error, status, xhr) + + # Event Methods ################################################################################ + + onBookLoaded: (data, status, xhr)-> + try + @books.push @_parser.parse data + _(@books).sortBy 'name' + + logger.info "loaded recipe book: #{book}" + @trigger Event.book.load.succeeded, this, book + @trigger Event.book.load.finished, this + catch e + @onBookLoadFailed error, status, xhr + + + onBookLoadFailed: (error, status, xhr)-> + logger.error "failed to load recipe book: #{error}" + @trigger Event.book.load.failed, this, error.message + @trigger Event.book.load.finished, this + + # Object Overrides ############################################################################# + + toString: -> + return "RecipeCatalog (#{@cid}) {books:#{@books.length} items}" diff --git a/src/scripts/views.js b/src/scripts/views.js new file mode 100644 index 000000000..d4d321650 --- /dev/null +++ b/src/scripts/views.js @@ -0,0 +1,32 @@ +var jade = jade || require('jade').runtime; + +this["JST"] = this["JST"] || {}; + +this["JST"]["landing_page"] = function template(locals) { +var buf = []; +var jade_mixins = {}; +var jade_interp; + +var jade_indent = []; +buf.push("\n
\n
\n
\n
");;return buf.join(""); +}; + +this["JST"]["recipe_catalog"] = function template(locals) { +var buf = []; +var jade_mixins = {}; +var jade_interp; + +var jade_indent = []; +buf.push("\n
\n

\n

Recipe Catalog

\n

\n \n \n \n \n \n
 \n \n \n
\n
\n

\n
\n
");;return buf.join(""); +}; + +this["JST"]["test"] = function template(locals) { +var buf = []; +var jade_mixins = {}; +var jade_interp; + +var jade_indent = []; +buf.push("\n

Hello world!

");;return buf.join(""); +}; + +if (typeof exports === 'object' && exports) {module.exports = this["JST"];} \ No newline at end of file diff --git a/src/templates/landing_page.jade b/src/templates/landing_page.jade new file mode 100644 index 000000000..d7c3f1bad --- /dev/null +++ b/src/templates/landing_page.jade @@ -0,0 +1,10 @@ +//- +//- Crafting Guide - landing_page.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__landing_page + .view__recipe_catalog + .view__crafter diff --git a/src/templates/recipe_catalog.jade b/src/templates/recipe_catalog.jade new file mode 100644 index 000000000..b7190380b --- /dev/null +++ b/src/templates/recipe_catalog.jade @@ -0,0 +1,19 @@ +//- +//- Crafting Guide - recipe_catalog.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +.view__recipe_catalog + h2 + img(src="/images/bookshelf.png") + p Recipe Catalog + + table.books + tr + td   + td + input.recipe_book_url(placeholder="enter a URL to load another recipe book...") + button.recipe_book_load_button Load + .load_error: p diff --git a/src/templates/test.jade b/src/templates/test.jade new file mode 100644 index 000000000..ac2fdc2ca --- /dev/null +++ b/src/templates/test.jade @@ -0,0 +1,8 @@ +//- +//- Crafting Guide - test.jade +//- +//- Copyright (c) 2014 by Redwood Labs +//- All rights reserved. +//- + +p Hello world! diff --git a/test/parser_versions/v1.test.coffee b/test/parser_versions/v1.test.coffee new file mode 100644 index 000000000..3234c25b2 --- /dev/null +++ b/test/parser_versions/v1.test.coffee @@ -0,0 +1,124 @@ +### +# Crafting Guide - v1.test.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +V1 = require '../../src/scripts/models/parser_versions/v1' + +######################################################################################################################## + +parser = null + +######################################################################################################################## + +describe 'RecipeBookParser.V1', -> + + before -> parser = new V1 + + describe '_parseRecipeBook', -> + + it 'requires a mod_name', -> + data = version:1, mod_version:'1.0', recipes:[] + expect(-> parser._parseRecipeBook data).to.throw Error, 'mod_name is required' + + it 'requires a mod_version', -> + data = version:1, mod_name:'Empty', recipes:[] + expect(-> parser._parseRecipeBook data).to.throw Error, 'mod_version is required' + + it 'can parse an empty recipe book', -> + data = + version: 1 + mod_name: 'Empty' + mod_version: '1.0' + recipes: [] + book = parser._parseRecipeBook data + book.modName.should.equal 'Empty' + book.modVersion.should.equal '1.0' + + it 'can parse a non-empty recipe book', -> + data = + version: 1 + mod_name: 'Minecraft' + mod_version: '1.7.10' + recipes: [ + { input:'sugar cane', output:'sugar' } + { input:[[3, 'wool'], [3, 'planks']], tools:'crafting table', output:'bed' } + ] + book = parser._parseRecipeBook data + book.modName.should.equal 'Minecraft' + book.modVersion.should.equal '1.7.10' + (r.name for r in book.recipes).sort().should.eql ['bed', 'sugar'] + + describe '_parseRecipe', -> + + it 'requires output to be defined', -> + parser._errorLocation = 'boat' + expect(-> parser._parseRecipe input:'wool').to.throw Error, 'boat is missing output' + + it 'requires input to be defined', -> + parser._errorLocation = 'boat' + expect(-> parser._parseRecipe output:'wool').to.throw Error, 'boat is missing input' + + it 'can parse a regular recipe', -> + data = + output: 'bed' + input: [[3, 'planks'], [3, 'wool']] + tools: 'crafting table' + recipe = parser._parseRecipe data + (i.name for i in recipe.output).should.eql ['bed'] + (i.name for i in recipe.input).sort().should.eql ['planks', 'wool'] + (i.name for i in recipe.tools).should.eql ['crafting table'] + + it 'can parse a recipe without tools', -> + recipe = parser._parseRecipe output:'sugar', input:'sugar cane' + (i.name for i in recipe.output).should.eql ['sugar'] + (i.name for i in recipe.input).sort().should.eql ['sugar cane'] + (i.name for i in recipe.tools).should.eql [] + + describe '_parseItemList', -> + + it 'can promote a single item to a list', -> + list = parser._parseItemList 'boat' + (i.name for i in list).should.eql ['boat'] + + it 'can require a list to be non-empty', -> + parser._errorLocation = 'boat' + options = field:'output', canBeEmpty:false + expect(-> parser._parseItemList [], options).to.throw Error, 'output for boat cannot be empty' + + it 'can allow an empty list', -> + list = parser._parseItemList [], canBeEmpty:true + list.length.should.equal 0 + + it 'can parse a non-empty list', -> + list = parser._parseItemList [[3, 'plank'], [3, 'wool']] + (i.name for i in list).sort().should.eql ['plank', 'wool'] + + describe '_parseItem', -> + + it 'requires the array to have at least one element', -> + parser._errorLocation = 'boat' + options = index:1, field:'output' + expect(-> parser._parseItem([], options)).to.throw Error, + "output element 1 for boat must have at least one element" + + it 'can fill in a missing number', -> + item = parser._parseItem 'boat' + item.name.should.equal 'boat' + item.quantity.should.equal 1 + + item2 = parser._parseItem ['boat'] + item2.name.should.equal 'boat' + item2.quantity.should.equal 1 + + it 'requires the data to start with a number', -> + parser._errorLocation = 'boat' + options = index:1, field:'output' + expect(-> parser._parseItem(['2', 'book'], options)).to.throw Error, + "output element 1 for boat must start with a number" + + it 'can parse a basic item', -> + item = parser._parseItem [2, 'book'] + item.constructor.name.should.equal 'Item' diff --git a/test/test.coffee b/test/test.coffee new file mode 100644 index 000000000..2d3b01ed3 --- /dev/null +++ b/test/test.coffee @@ -0,0 +1,27 @@ +### +# Crafting Guide - test.coffee +# +# Copyright (c) 2014 by Redwood Labs +# All rights reserved. +### + +# Test Set-up ########################################################################################################## + +chai.use require 'sinon-chai' +chai.config.includeStack = true + +if typeof(global) is 'undefined' + window.global = window + +global.assert = chai.assert +global.expect = chai.expect +global.should = chai.should() + +# Test Registry ######################################################################################################## + +mocha.setup 'bdd' + +require './parser_versions/v1.test' + +mocha.checkLeaks() +mocha.run()