├── .gitignore ├── README.md ├── project.clj ├── resources ├── code │ └── 1.cljs └── public │ ├── css │ ├── basscss.css │ ├── codemirror.css │ ├── monokai.css │ ├── sourceserifpro-regular-webfont.eot │ ├── sourceserifpro-regular-webfont.svg │ ├── sourceserifpro-regular-webfont.ttf │ ├── sourceserifpro-regular-webfont.woff │ ├── sourceserifpro-regular-webfont.woff2 │ └── style.css │ ├── img │ └── editme.svg │ ├── index.html │ ├── introclojure.html │ └── js │ └── oneline.js ├── src └── clojure_cup_2015 │ ├── common.cljs │ ├── content.cljs │ ├── core.cljs │ ├── editor.cljs │ ├── macro.clj │ ├── quil_symbols.cljs │ ├── quiltest.cljs │ └── server.clj └── util └── deploy /.gitignore: -------------------------------------------------------------------------------- 1 | /resources/public/js/compiled/** 2 | figwheel_server.log 3 | pom.xml 4 | *jar 5 | /lib/ 6 | /classes/ 7 | /out/ 8 | /target/ 9 | .lein-deps-sum 10 | .lein-repl-history 11 | .lein-plugins/ 12 | .repl 13 | .nrepl-port 14 | .envrc 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clojure Cup 2015 2 | 3 | Submission by: Berlin Bang Bang 4 | 5 | To support the amazing ClojureBridge initiative, we came up with the idea of an 6 | interactive ClojureScript/Quil tutorial for beginners. As organisers of the 7 | Berlin chapter of ClojureBridge, we think that this tutorial takes away some of 8 | the initial hurdles, like editors, build tools and alien operating systems. It 9 | needs some more love content-wise and we have some plans to make it even more 10 | friendly, but technically it's already in a state where it can be used for our 11 | next workshop in January. 12 | 13 | Some of our features: 14 | 15 | * direct feedback/live coding in the browser 16 | * inline Quil documentation (hover over fns) 17 | * inline evaluation/results (Light Table like) 18 | * amazing error heads-up display 19 | * lazy loading of examples 20 | 21 | Made with bootstrapped ClojureScript, CodeMirror, reagent and figwheel. No backend. 22 | 23 | A next step would be to make it work really well on phone, as well as making a 24 | gallery where users can post their sketches. 25 | 26 | Takes inspiration from: Light Table, Bret Victor's talks, Quil examples on Quil.info 27 | 28 | ## Attribution 29 | 30 | The tutorial content is based on the 31 | [ClojureBridge curriculum](https://github.com/ClojureBridge/curriculum). 32 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject clojure-cup-2015 "0.1.0-SNAPSHOT" 2 | :description "FIXME: write this!" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | 7 | :dependencies [[org.clojure/clojure "1.7.0"] 8 | [org.clojure/clojurescript "1.7.170"] 9 | [org.clojure/core.async "0.2.374"] 10 | 11 | [prismatic/dommy "1.1.0"] 12 | 13 | [quil "2.3.0"] 14 | [cljsjs/codemirror "5.8.0-0"] 15 | [reagent "0.5.0"] 16 | 17 | [ring "1.4.0"] 18 | [ring/ring-defaults "0.1.5"] 19 | [compojure "1.4.0"] 20 | [environ "1.0.1"]] 21 | 22 | :plugins [[lein-cljsbuild "1.1.1"] 23 | [lein-figwheel "0.5.0-1"]] 24 | 25 | :source-paths ["src"] 26 | 27 | :main clojure-cup-2015.server 28 | 29 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"] 30 | 31 | :cljsbuild {:builds 32 | [{:id "dev" 33 | :source-paths ["src"] 34 | 35 | :figwheel {:on-jsload "clojure-cup-2015.core/on-js-reload"} 36 | 37 | :compiler {:main clojure-cup-2015.core 38 | :asset-path "js/compiled/out" 39 | :output-to "resources/public/js/compiled/clojure_cup_2015.js" 40 | :output-dir "resources/public/js/compiled/out" 41 | :source-map-timestamp true 42 | 43 | :optimizations :none 44 | :pretty-print false 45 | :static-fns true 46 | :optimize-constants true 47 | :verbose true}} 48 | 49 | ;; This next build is an compressed minified build for 50 | ;; production. You can build this with: 51 | ;; lein cljsbuild once min 52 | {:id "min" 53 | :source-paths ["src"] 54 | :compiler {:output-to "resources/public/js/compiled/clojure_cup_2015.js" 55 | :main clojure-cup-2015.core 56 | 57 | :optimizations :none 58 | :pretty-print false 59 | :static-fns true 60 | :optimize-constants true 61 | :verbose true}}]} 62 | 63 | 64 | :profiles {:uberjar {:hooks [leiningen.cljsbuild] 65 | :env {:production true} 66 | :omit-source true 67 | :aot :all 68 | :main clojure-cup-2015.server 69 | :cljsbuild {:builds 70 | [{:id "app" 71 | :source-paths ["src"] 72 | :compiler {:output-to "resources/public/js/compiled/clojure_cup_2015.js" 73 | :main clojure-cup-2015.core 74 | :jar true 75 | :optimizations :none 76 | :pretty-print false 77 | :static-fns true 78 | :optimize-constants true 79 | :verbose true}}]}}} 80 | 81 | :figwheel {;; :http-server-root "public" ;; default and assumes "resources" 82 | ;; :server-port 3449 ;; default 83 | ;; :server-ip "127.0.0.1" 84 | 85 | :css-dirs ["resources/public/css"] ;; watch and update CSS 86 | 87 | ;; Start an nREPL server into the running figwheel process 88 | :nrepl-port 7888 89 | 90 | ;; Server Ring Handler (optional) 91 | ;; if you want to embed a ring handler into the figwheel http-kit 92 | ;; server, this is for simple ring servers, if this 93 | ;; doesn't work for you just run your own server :) 94 | ;; :ring-handler hello_world.server/handler 95 | 96 | ;; To be able to open files in your editor from the heads up display 97 | ;; you will need to put a script on your path. 98 | ;; that script will have to take a file path and a line number 99 | ;; ie. in ~/bin/myfile-opener 100 | ;; #! /bin/sh 101 | ;; emacsclient -n +$2 $1 102 | ;; 103 | ;; :open-file-command "myfile-opener" 104 | 105 | ;; if you want to disable the REPL 106 | ;; :repl false 107 | 108 | ;; to configure a different figwheel logfile path 109 | ;; :server-logfile "tmp/logs/figwheel-logfile.log" 110 | }) 111 | -------------------------------------------------------------------------------- /resources/code/1.cljs: -------------------------------------------------------------------------------- 1 | (defn draw-pink-triangles [] 2 | ;; First we set the stage: a background color, and no borders around shapes 3 | (background 20 200 151) 4 | (no-stroke) 5 | 6 | ;; Set a fill color for shapes. The numbers correspond with 7 | ;; red - green - blue, and go up to 255 8 | (fill 34 95 215) 9 | 10 | ;; Fill the width and height of the canvas with triangles 11 | (doseq [x (range 0 (width) 50) 12 | y (range 0 (height) 50)] 13 | (triangle (+ x 25) y 14 | x (+ y 50) 15 | (+ x 50) (+ y 50)))) 16 | -------------------------------------------------------------------------------- /resources/public/css/basscss.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Basscss v7.0.4 4 | Low-level CSS toolkit 5 | http://basscss.com 6 | 7 | 14.88 kB 8 | 3.38 kB Gzipped 9 | 286 Rules 10 | 328 Selectors 11 | 441 Declarations 12 | 95 Properties 13 | 14 | */ 15 | 16 | 17 | 18 | body { margin: 0 } 19 | img { max-width: 100% } 20 | svg { max-height: 100% } 21 | 22 | input, 23 | select, 24 | textarea, 25 | fieldset { 26 | font-family: inherit; 27 | font-size: 1rem; 28 | box-sizing: border-box; 29 | margin-top: 0; 30 | margin-bottom: 0; 31 | } 32 | 33 | label { 34 | vertical-align: middle; 35 | } 36 | 37 | input[type=text], 38 | input[type=date], 39 | input[type=datetime], 40 | input[type=datetime-local], 41 | input[type=email], 42 | input[type=month], 43 | input[type=number], 44 | input[type=password], 45 | input[type=search], 46 | input[type=tel], 47 | input[type=time], 48 | input[type=url], 49 | input[type=week] { 50 | height: 2.25rem; 51 | padding: .5rem .5rem; 52 | vertical-align: middle; 53 | -webkit-appearance: none; 54 | } 55 | 56 | select { 57 | line-height: 1.75; 58 | padding: .5rem .5rem; 59 | } 60 | 61 | select:not([multiple]) { 62 | height: 2.25rem; 63 | vertical-align: middle; 64 | } 65 | 66 | textarea { 67 | line-height: 1.75; 68 | padding: .5rem .5rem; 69 | } 70 | 71 | table { 72 | border-collapse: separate; 73 | border-spacing: 0; 74 | max-width: 100%; 75 | width: 100%; 76 | } 77 | 78 | th { 79 | text-align: left; 80 | font-weight: bold; 81 | } 82 | 83 | th, 84 | td { 85 | padding: .25rem 1rem; 86 | line-height: inherit; 87 | } 88 | 89 | th { vertical-align: bottom } 90 | td { vertical-align: top } 91 | 92 | body { 93 | line-height: 1.5; 94 | font-size: 100%; 95 | } 96 | 97 | h1, h2, h3, h4, h5, h6 { 98 | font-weight: bold; 99 | line-height: 1.25; 100 | margin-top: 1em; 101 | margin-bottom: .5em; 102 | } 103 | 104 | p { 105 | margin-top: 0; 106 | margin-bottom: 1rem; 107 | } 108 | 109 | dl, ol, ul { 110 | margin-top: 0; 111 | margin-bottom: 1rem; 112 | } 113 | 114 | pre, code, samp { 115 | font-size: inherit; 116 | } 117 | 118 | pre { 119 | margin-top: 0; 120 | margin-bottom: 1rem; 121 | overflow-x: scroll; 122 | } 123 | 124 | h1 { font-size: 2rem } 125 | h2 { font-size: 1.5rem } 126 | h3 { font-size: 1.25rem } 127 | h4 { font-size: 1rem } 128 | h5 { font-size: .875rem } 129 | h6 { font-size: .75rem } 130 | 131 | body { 132 | color: #111; 133 | background-color: #fff; 134 | } 135 | 136 | a { 137 | color: #0074d9; 138 | text-decoration: none; 139 | } 140 | 141 | a:hover { 142 | text-decoration: underline; 143 | } 144 | 145 | pre, code { 146 | background-color: transparent; 147 | border-radius: 3px; 148 | } 149 | 150 | hr { 151 | border: 0; 152 | border-bottom-style: solid; 153 | border-bottom-width: 1px; 154 | border-bottom-color: rgba(0,0,0,.125); 155 | } 156 | 157 | .field { 158 | border-style: solid; 159 | border-width: 1px; 160 | border-color: rgba(0,0,0,.125); 161 | border-radius: 3px; 162 | } 163 | 164 | .field:focus, 165 | .field.is-focused { 166 | outline: none; 167 | border-color: #0074d9; 168 | box-shadow: 0 0 0 2px rgba(0, 116, 217, 0.5); 169 | } 170 | 171 | .field:disabled, 172 | .field.is-disabled { 173 | background-color: rgba(0,0,0,.125); 174 | opacity: .5; 175 | } 176 | 177 | .field:read-only:not(select), 178 | .field.is-read-only { 179 | background-color: rgba(0,0,0,.125); 180 | } 181 | 182 | 183 | .field.is-success { 184 | border-color: #2ecc40; 185 | } 186 | 187 | .field.is-success:focus, 188 | .field.is-success.is-focused { 189 | box-shadow: 0 0 0 2px rgba(46, 204, 64, 0.5); 190 | } 191 | 192 | .field.is-warning { 193 | border-color: #ffdc00; 194 | } 195 | 196 | .field.is-warning:focus, 197 | .field.is-warning.is-focused { 198 | box-shadow: 0 0 0 2px rgba(255, 220, 0, 0.5); 199 | } 200 | 201 | .field:invalid, 202 | .field.is-error { 203 | border-color: #ff4136; 204 | } 205 | 206 | .field:invalid:focus, 207 | .field:invalid.is-focused, 208 | .field.is-error:focus, 209 | .field.is-error.is-focused { 210 | box-shadow: 0 0 0 2px rgba(255, 65, 54, 0.5); 211 | } 212 | 213 | .table-light th, 214 | .table-light td { 215 | border-bottom-width: 1px; 216 | border-bottom-style: solid; 217 | border-bottom-color: rgba(0,0,0,.125); 218 | } 219 | 220 | .table-light tr:last-child td { 221 | border-bottom: 0; 222 | } 223 | 224 | .btn { 225 | font-size: inherit; 226 | text-decoration: none; 227 | cursor: pointer; 228 | display: inline-block; 229 | line-height: 1.125rem; 230 | padding: .5rem 1rem; 231 | margin: 0; 232 | height: auto; 233 | border: 1px solid transparent; 234 | vertical-align: middle; 235 | -webkit-appearance: none; 236 | color: inherit; 237 | background-color: transparent; 238 | } 239 | 240 | .btn:hover { 241 | text-decoration: none; 242 | } 243 | 244 | .btn:focus { 245 | outline: none; 246 | border-color: rgba(0,0,0,.125); 247 | box-shadow: 0 0 0 3px rgba(0,0,0,.25); 248 | } 249 | 250 | ::-moz-focus-inner { 251 | border: 0; 252 | padding: 0; 253 | } 254 | 255 | .btn-primary { 256 | color: #fff; 257 | background-color: #0074d9; 258 | border-radius: 3px; 259 | } 260 | 261 | .btn-primary:hover { 262 | box-shadow: inset 0 0 0 20rem rgba(0,0,0,.0625); 263 | } 264 | 265 | .btn-primary:active { 266 | box-shadow: inset 0 0 0 20rem rgba(0,0,0,.125), 267 | inset 0 3px 4px 0 rgba(0,0,0,.25), 268 | 0 0 1px rgba(0,0,0,.125); 269 | } 270 | 271 | .btn-primary:disabled, 272 | .btn-primary.is-disabled { 273 | opacity: .5; 274 | } 275 | 276 | .btn-outline, 277 | .btn-outline:hover { 278 | border-color: currentcolor; 279 | } 280 | 281 | .btn-outline { 282 | border-radius: 3px; 283 | } 284 | 285 | .btn-outline:hover { 286 | box-shadow: inset 0 0 0 20rem rgba(0,0,0,.0625); 287 | } 288 | 289 | .btn-outline:active { 290 | box-shadow: inset 0 0 0 20rem rgba(0,0,0,.125), 291 | inset 0 3px 4px 0 rgba(0,0,0,.25), 292 | 0 0 1px rgba(0,0,0,.125); 293 | } 294 | 295 | .btn-outline:disabled, 296 | .btn-outline.is-disabled { 297 | opacity: .5; 298 | } 299 | 300 | .h1 { font-size: 2rem } 301 | .h2 { font-size: 1.5rem } 302 | .h3 { font-size: 1.25rem } 303 | .h4 { font-size: 1rem } 304 | .h5 { font-size: .875rem } 305 | .h6 { font-size: .75rem } 306 | 307 | .bold { font-weight: bold } 308 | .regular { font-weight: normal } 309 | .italic { font-style: italic } 310 | .caps { text-transform: uppercase; letter-spacing: .2em; } 311 | 312 | .left-align { text-align: left } 313 | .center { text-align: center } 314 | .right-align { text-align: right } 315 | .justify { text-align: justify } 316 | 317 | .nowrap { white-space: nowrap } 318 | .break-word { word-wrap: break-word } 319 | 320 | .truncate { 321 | max-width: 100%; 322 | overflow: hidden; 323 | text-overflow: ellipsis; 324 | white-space: nowrap; 325 | } 326 | 327 | .list-reset { 328 | list-style: none; 329 | padding-left: 0; 330 | } 331 | 332 | .inline { display: inline } 333 | .block { display: block } 334 | .inline-block { display: inline-block } 335 | .table { display: table } 336 | .table-cell { display: table-cell } 337 | 338 | .overflow-hidden { overflow: hidden } 339 | .overflow-scroll { overflow: scroll } 340 | .overflow-auto { overflow: auto } 341 | 342 | .clearfix:before, 343 | .clearfix:after { 344 | content: " "; 345 | display: table 346 | } 347 | .clearfix:after { clear: both } 348 | 349 | .left { float: left } 350 | .right { float: right } 351 | 352 | .fit { max-width: 100% } 353 | 354 | .border-box { box-sizing: border-box } 355 | 356 | .align-baseline { vertical-align: baseline } 357 | .align-top { vertical-align: top } 358 | .align-middle { vertical-align: middle } 359 | .align-bottom { vertical-align: bottom } 360 | 361 | .m0 { margin: 0 } 362 | .mt0 { margin-top: 0 } 363 | .mr0 { margin-right: 0 } 364 | .mb0 { margin-bottom: 0 } 365 | .ml0 { margin-left: 0 } 366 | 367 | .m1 { margin: .5rem } 368 | .mt1 { margin-top: .5rem } 369 | .mr1 { margin-right: .5rem } 370 | .mb1 { margin-bottom: .5rem } 371 | .ml1 { margin-left: .5rem } 372 | 373 | .m2 { margin: 1rem } 374 | .mt2 { margin-top: 1rem } 375 | .mr2 { margin-right: 1rem } 376 | .mb2 { margin-bottom: 1rem } 377 | .ml2 { margin-left: 1rem } 378 | 379 | .m3 { margin: 2rem } 380 | .mt3 { margin-top: 2rem } 381 | .mr3 { margin-right: 2rem } 382 | .mb3 { margin-bottom: 2rem } 383 | .ml3 { margin-left: 2rem } 384 | 385 | .m4 { margin: 4rem } 386 | .mt4 { margin-top: 4rem } 387 | .mr4 { margin-right: 4rem } 388 | .mb4 { margin-bottom: 4rem } 389 | .ml4 { margin-left: 4rem } 390 | 391 | .mxn1 { margin-left: -.5rem; margin-right: -.5rem; } 392 | .mxn2 { margin-left: -1rem; margin-right: -1rem; } 393 | .mxn3 { margin-left: -2rem; margin-right: -2rem; } 394 | .mxn4 { margin-left: -4rem; margin-right: -4rem; } 395 | 396 | .mx-auto { margin-left: auto; margin-right: auto; } 397 | .p0 { padding: 0 } 398 | 399 | .p1 { padding: .5rem } 400 | .py1 { padding-top: .5rem; padding-bottom: .5rem } 401 | .px1 { padding-left: .5rem; padding-right: .5rem } 402 | 403 | .p2 { padding: 1rem } 404 | .py2 { padding-top: 1rem; padding-bottom: 1rem } 405 | .px2 { padding-left: 1rem; padding-right: 1rem } 406 | 407 | .p3 { padding: 2rem } 408 | .py3 { padding-top: 2rem; padding-bottom: 2rem } 409 | .px3 { padding-left: 2rem; padding-right: 2rem } 410 | 411 | .p4 { padding: 4rem } 412 | .py4 { padding-top: 4rem; padding-bottom: 4rem } 413 | .px4 { padding-left: 4rem; padding-right: 4rem } 414 | 415 | .relative { position: relative } 416 | .absolute { position: absolute } 417 | .fixed { position: fixed } 418 | 419 | .top-0 { top: 0 } 420 | .right-0 { right: 0 } 421 | .bottom-0 { bottom: 0 } 422 | .left-0 { left: 0 } 423 | 424 | .z1 { z-index: 1 } 425 | .z2 { z-index: 2 } 426 | .z3 { z-index: 3 } 427 | .z4 { z-index: 4 } 428 | 429 | .sm-show, .md-show, .lg-show { 430 | display: none !important 431 | } 432 | 433 | @media (min-width: 40em) { 434 | .sm-show { display: block !important } 435 | } 436 | 437 | @media (min-width: 52em) { 438 | .md-show { display: block !important } 439 | } 440 | 441 | @media (min-width: 64em) { 442 | .lg-show { display: block !important } 443 | } 444 | 445 | 446 | @media (min-width: 40em) { 447 | .sm-hide { display: none !important } 448 | } 449 | 450 | @media (min-width: 52em) { 451 | .md-hide { display: none !important } 452 | } 453 | 454 | @media (min-width: 64em) { 455 | .lg-hide { display: none !important } 456 | } 457 | 458 | .display-none { display: none !important } 459 | 460 | .hide { 461 | position: absolute !important; 462 | height: 1px; 463 | width: 1px; 464 | overflow: hidden; 465 | clip: rect(1px, 1px, 1px, 1px); 466 | } 467 | 468 | .container { 469 | max-width: 64em; 470 | margin-left: auto; 471 | margin-right: auto; 472 | } 473 | .col { 474 | float: left; 475 | box-sizing: border-box; 476 | } 477 | 478 | .col-right { 479 | float: right; 480 | box-sizing: border-box; 481 | } 482 | 483 | .col-1 { 484 | width: 8.33333%; 485 | } 486 | 487 | .col-2 { 488 | width: 16.66667%; 489 | } 490 | 491 | .col-3 { 492 | width: 25%; 493 | } 494 | 495 | .col-4 { 496 | width: 33.33333%; 497 | } 498 | 499 | .col-5 { 500 | width: 41.66667%; 501 | } 502 | 503 | .col-6 { 504 | width: 50%; 505 | } 506 | 507 | .col-7 { 508 | width: 58.33333%; 509 | } 510 | 511 | .col-8 { 512 | width: 66.66667%; 513 | } 514 | 515 | .col-9 { 516 | width: 75%; 517 | } 518 | 519 | .col-10 { 520 | width: 83.33333%; 521 | } 522 | 523 | .col-11 { 524 | width: 91.66667%; 525 | } 526 | 527 | .col-12 { 528 | width: 100%; 529 | } 530 | @media (min-width: 40em) { 531 | 532 | .sm-col { 533 | float: left; 534 | box-sizing: border-box; 535 | } 536 | 537 | .sm-col-right { 538 | float: right; 539 | box-sizing: border-box; 540 | } 541 | 542 | .sm-col-1 { 543 | width: 8.33333%; 544 | } 545 | 546 | .sm-col-2 { 547 | width: 16.66667%; 548 | } 549 | 550 | .sm-col-3 { 551 | width: 25%; 552 | } 553 | 554 | .sm-col-4 { 555 | width: 33.33333%; 556 | } 557 | 558 | .sm-col-5 { 559 | width: 41.66667%; 560 | } 561 | 562 | .sm-col-6 { 563 | width: 50%; 564 | } 565 | 566 | .sm-col-7 { 567 | width: 58.33333%; 568 | } 569 | 570 | .sm-col-8 { 571 | width: 66.66667%; 572 | } 573 | 574 | .sm-col-9 { 575 | width: 75%; 576 | } 577 | 578 | .sm-col-10 { 579 | width: 83.33333%; 580 | } 581 | 582 | .sm-col-11 { 583 | width: 91.66667%; 584 | } 585 | 586 | .sm-col-12 { 587 | width: 100%; 588 | } 589 | 590 | } 591 | @media (min-width: 52em) { 592 | 593 | .md-col { 594 | float: left; 595 | box-sizing: border-box; 596 | } 597 | 598 | .md-col-right { 599 | float: right; 600 | box-sizing: border-box; 601 | } 602 | 603 | .md-col-1 { 604 | width: 8.33333%; 605 | } 606 | 607 | .md-col-2 { 608 | width: 16.66667%; 609 | } 610 | 611 | .md-col-3 { 612 | width: 25%; 613 | } 614 | 615 | .md-col-4 { 616 | width: 33.33333%; 617 | } 618 | 619 | .md-col-5 { 620 | width: 41.66667%; 621 | } 622 | 623 | .md-col-6 { 624 | width: 50%; 625 | } 626 | 627 | .md-col-7 { 628 | width: 58.33333%; 629 | } 630 | 631 | .md-col-8 { 632 | width: 66.66667%; 633 | } 634 | 635 | .md-col-9 { 636 | width: 75%; 637 | } 638 | 639 | .md-col-10 { 640 | width: 83.33333%; 641 | } 642 | 643 | .md-col-11 { 644 | width: 91.66667%; 645 | } 646 | 647 | .md-col-12 { 648 | width: 100%; 649 | } 650 | 651 | } 652 | @media (min-width: 64em) { 653 | 654 | .lg-col { 655 | float: left; 656 | box-sizing: border-box; 657 | } 658 | 659 | .lg-col-right { 660 | float: right; 661 | box-sizing: border-box; 662 | } 663 | 664 | .lg-col-1 { 665 | width: 8.33333%; 666 | } 667 | 668 | .lg-col-2 { 669 | width: 16.66667%; 670 | } 671 | 672 | .lg-col-3 { 673 | width: 25%; 674 | } 675 | 676 | .lg-col-4 { 677 | width: 33.33333%; 678 | } 679 | 680 | .lg-col-5 { 681 | width: 41.66667%; 682 | } 683 | 684 | .lg-col-6 { 685 | width: 50%; 686 | } 687 | 688 | .lg-col-7 { 689 | width: 58.33333%; 690 | } 691 | 692 | .lg-col-8 { 693 | width: 66.66667%; 694 | } 695 | 696 | .lg-col-9 { 697 | width: 75%; 698 | } 699 | 700 | .lg-col-10 { 701 | width: 83.33333%; 702 | } 703 | 704 | .lg-col-11 { 705 | width: 91.66667%; 706 | } 707 | 708 | .lg-col-12 { 709 | width: 100%; 710 | } 711 | 712 | } 713 | 714 | .flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex } 715 | 716 | .flex-column { -webkit-box-orient: vertical; -webkit-box-direction: normal; -webkit-flex-direction: column; -ms-flex-direction: column; flex-direction: column } 717 | .flex-wrap { -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap } 718 | 719 | .flex-center { -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center } 720 | .flex-baseline { -webkit-box-align: baseline; -webkit-align-items: baseline; -ms-flex-align: baseline; align-items: baseline } 721 | .flex-stretch { -webkit-box-align: stretch; -webkit-align-items: stretch; -ms-flex-align: stretch; align-items: stretch } 722 | .flex-start { -webkit-box-align: start; -webkit-align-items: flex-start; -ms-flex-align: start; align-items: flex-start } 723 | .flex-end { -webkit-box-align: end; -webkit-align-items: flex-end; -ms-flex-align: end; align-items: flex-end } 724 | 725 | .flex-justify { -webkit-box-pack: justify; -webkit-justify-content: space-between; -ms-flex-pack: justify; justify-content: space-between } 726 | 727 | .flex-auto { 728 | -webkit-box-flex: 1; 729 | -webkit-flex: 1 1 auto; 730 | -ms-flex: 1 1 auto; 731 | flex: 1 1 auto; 732 | min-width: 0; 733 | min-height: 0; 734 | } 735 | .flex-grow { -webkit-box-flex: 1; -webkit-flex: 1 0 auto; -ms-flex: 1 0 auto; flex: 1 0 auto } 736 | .flex-none { -webkit-box-flex: 0; -webkit-flex: none; -ms-flex: none; flex: none } 737 | 738 | .flex-first { -webkit-box-ordinal-group: 0; -webkit-order: -1; -ms-flex-order: -1; order: -1 } 739 | .flex-last { -webkit-box-ordinal-group: 100000; -webkit-order: 99999; -ms-flex-order: 99999; order: 99999 } 740 | @media (min-width: 40em) { 741 | .sm-flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex } 742 | } 743 | @media (min-width: 52em) { 744 | .md-flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex } 745 | } 746 | @media (min-width: 64em) { 747 | .lg-flex { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex } 748 | } 749 | 750 | .border { 751 | border-style: solid; 752 | border-width: 1px; 753 | border-color: rgba(0,0,0,.125); 754 | } 755 | 756 | .border-top { 757 | border-top-style: solid; 758 | border-top-width: 1px; 759 | border-top-color: rgba(0,0,0,.125); 760 | } 761 | 762 | .border-right { 763 | border-right-style: solid; 764 | border-right-width: 1px; 765 | border-right-color: rgba(0,0,0,.125); 766 | } 767 | 768 | .border-bottom { 769 | border-bottom-style: solid; 770 | border-bottom-width: 1px; 771 | border-bottom-color: rgba(0,0,0,.125); 772 | } 773 | 774 | .border-left { 775 | border-left-style: solid; 776 | border-left-width: 1px; 777 | border-left-color: rgba(0,0,0,.125); 778 | } 779 | 780 | .border-none { border: 0 } 781 | 782 | .rounded { border-radius: 3px } 783 | .circle { border-radius: 50% } 784 | 785 | .rounded-top { border-radius: 3px 3px 0 0 } 786 | .rounded-right { border-radius: 0 3px 3px 0 } 787 | .rounded-bottom { border-radius: 0 0 3px 3px } 788 | .rounded-left { border-radius: 3px 0 0 3px } 789 | 790 | .not-rounded { border-radius: 0 } 791 | 792 | .black { color: #111 } 793 | .gray { color: #aaa } 794 | .silver { color: #ddd } 795 | .white { color: #fff } 796 | 797 | .aqua { color: #7fdbff } 798 | .blue { color: #0074d9 } 799 | .navy { color: #001f3f } 800 | .teal { color: #39cccc } 801 | .green { color: #2ecc40 } 802 | .olive { color: #3d9970 } 803 | .lime { color: #01ff70 } 804 | 805 | .yellow { color: #ffdc00 } 806 | .orange { color: #ff851b } 807 | .red { color: #ff4136 } 808 | .fuchsia { color: #f012be } 809 | .purple { color: #b10dc9 } 810 | .maroon { color: #85144b } 811 | 812 | .color-inherit { color: inherit } 813 | .muted { opacity: .5 } 814 | 815 | .bg-black { background-color: #111 } 816 | .bg-gray { background-color: #aaa } 817 | .bg-silver { background-color: #ddd } 818 | .bg-white { background-color: #fff } 819 | 820 | .bg-aqua { background-color: #7fdbff } 821 | .bg-blue { background-color: #0074d9 } 822 | .bg-navy { background-color: #001f3f } 823 | .bg-teal { background-color: #39cccc } 824 | .bg-green { background-color: #2ecc40 } 825 | .bg-olive { background-color: #3d9970 } 826 | .bg-lime { background-color: #01ff70 } 827 | 828 | .bg-yellow { background-color: #ffdc00 } 829 | .bg-orange { background-color: #ff851b } 830 | .bg-red { background-color: #ff4136 } 831 | .bg-fuchsia { background-color: #f012be } 832 | .bg-purple { background-color: #b10dc9 } 833 | .bg-maroon { background-color: #85144b } 834 | 835 | .bg-darken-1 { background-color: rgba(0,0,0,.0625) } 836 | .bg-darken-2 { background-color: rgba(0,0,0,.125) } 837 | .bg-darken-3 { background-color: rgba(0,0,0,.25) } 838 | .bg-darken-4 { background-color: rgba(0,0,0,.5) } 839 | 840 | .bg-lighten-1 { background-color: rgba(255,255,255,.0625) } 841 | .bg-lighten-2 { background-color: rgba(255,255,255,.125) } 842 | .bg-lighten-3 { background-color: rgba(255,255,255,.25) } 843 | .bg-lighten-4 { background-color: rgba(255,255,255,.5) } 844 | 845 | 846 | -------------------------------------------------------------------------------- /resources/public/css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 300px; 7 | color: black; 8 | } 9 | 10 | /* PADDING */ 11 | 12 | .CodeMirror-lines { 13 | padding: 4px 0; /* Vertical padding around content */ 14 | } 15 | .CodeMirror pre { 16 | padding: 0 4px; /* Horizontal padding of content */ 17 | } 18 | 19 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 20 | background-color: white; /* The little square between H and V scrollbars */ 21 | } 22 | 23 | /* GUTTER */ 24 | 25 | .CodeMirror-gutters { 26 | border-right: 1px solid #ddd; 27 | background-color: #f7f7f7; 28 | white-space: nowrap; 29 | } 30 | .CodeMirror-linenumbers {} 31 | .CodeMirror-linenumber { 32 | padding: 0 3px 0 5px; 33 | min-width: 20px; 34 | text-align: right; 35 | color: #999; 36 | white-space: nowrap; 37 | } 38 | 39 | .CodeMirror-guttermarker { color: black; } 40 | .CodeMirror-guttermarker-subtle { color: #999; } 41 | 42 | /* CURSOR */ 43 | 44 | .CodeMirror-cursor { 45 | border-left: 1px solid black; 46 | border-right: none; 47 | width: 0; 48 | } 49 | /* Shown when moving in bi-directional text */ 50 | .CodeMirror div.CodeMirror-secondarycursor { 51 | border-left: 1px solid silver; 52 | } 53 | .cm-fat-cursor .CodeMirror-cursor { 54 | width: auto; 55 | border: 0; 56 | background: #7e7; 57 | } 58 | .cm-fat-cursor div.CodeMirror-cursors { 59 | z-index: 1; 60 | } 61 | 62 | .cm-animate-fat-cursor { 63 | width: auto; 64 | border: 0; 65 | -webkit-animation: blink 1.06s steps(1) infinite; 66 | -moz-animation: blink 1.06s steps(1) infinite; 67 | animation: blink 1.06s steps(1) infinite; 68 | background-color: #7e7; 69 | } 70 | @-moz-keyframes blink { 71 | 0% {} 72 | 50% { background-color: transparent; } 73 | 100% {} 74 | } 75 | @-webkit-keyframes blink { 76 | 0% {} 77 | 50% { background-color: transparent; } 78 | 100% {} 79 | } 80 | @keyframes blink { 81 | 0% {} 82 | 50% { background-color: transparent; } 83 | 100% {} 84 | } 85 | 86 | /* Can style cursor different in overwrite (non-insert) mode */ 87 | .CodeMirror-overwrite .CodeMirror-cursor {} 88 | 89 | .cm-tab { display: inline-block; text-decoration: inherit; } 90 | 91 | .CodeMirror-ruler { 92 | border-left: 1px solid #ccc; 93 | position: absolute; 94 | } 95 | 96 | /* DEFAULT THEME */ 97 | 98 | .cm-s-default .cm-header {color: blue;} 99 | .cm-s-default .cm-quote {color: #090;} 100 | .cm-negative {color: #d44;} 101 | .cm-positive {color: #292;} 102 | .cm-header, .cm-strong {font-weight: bold;} 103 | .cm-em {font-style: italic;} 104 | .cm-link {text-decoration: underline;} 105 | .cm-strikethrough {text-decoration: line-through;} 106 | 107 | .cm-s-default .cm-keyword {color: #708;} 108 | .cm-s-default .cm-atom {color: #219;} 109 | .cm-s-default .cm-number {color: #164;} 110 | .cm-s-default .cm-def {color: #00f;} 111 | .cm-s-default .cm-variable, 112 | .cm-s-default .cm-punctuation, 113 | .cm-s-default .cm-property, 114 | .cm-s-default .cm-operator {} 115 | .cm-s-default .cm-variable-2 {color: #05a;} 116 | .cm-s-default .cm-variable-3 {color: #085;} 117 | .cm-s-default .cm-comment {color: #a50;} 118 | .cm-s-default .cm-string {color: #a11;} 119 | .cm-s-default .cm-string-2 {color: #f50;} 120 | .cm-s-default .cm-meta {color: #555;} 121 | .cm-s-default .cm-qualifier {color: #555;} 122 | .cm-s-default .cm-builtin {color: #30a;} 123 | .cm-s-default .cm-bracket {color: #997;} 124 | .cm-s-default .cm-tag {color: #170;} 125 | .cm-s-default .cm-attribute {color: #00c;} 126 | .cm-s-default .cm-hr {color: #999;} 127 | .cm-s-default .cm-link {color: #00c;} 128 | 129 | .cm-s-default .cm-error {color: #f00;} 130 | .cm-invalidchar {color: #f00;} 131 | 132 | .CodeMirror-composing { border-bottom: 2px solid; } 133 | 134 | /* Default styles for common addons */ 135 | 136 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;} 137 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} 138 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } 139 | .CodeMirror-activeline-background {background: #e8f2ff;} 140 | 141 | /* STOP */ 142 | 143 | /* The rest of this file contains styles related to the mechanics of 144 | the editor. You probably shouldn't touch them. */ 145 | 146 | .CodeMirror { 147 | position: relative; 148 | overflow: hidden; 149 | background: white; 150 | } 151 | 152 | .CodeMirror-scroll { 153 | overflow: scroll !important; /* Things will break if this is overridden */ 154 | /* 30px is the magic margin used to hide the element's real scrollbars */ 155 | /* See overflow: hidden in .CodeMirror */ 156 | margin-bottom: -30px; margin-right: -30px; 157 | padding-bottom: 30px; 158 | height: 100%; 159 | outline: none; /* Prevent dragging from highlighting the element */ 160 | position: relative; 161 | } 162 | .CodeMirror-sizer { 163 | position: relative; 164 | border-right: 30px solid transparent; 165 | } 166 | 167 | /* The fake, visible scrollbars. Used to force redraw during scrolling 168 | before actuall scrolling happens, thus preventing shaking and 169 | flickering artifacts. */ 170 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 171 | position: absolute; 172 | z-index: 6; 173 | display: none; 174 | } 175 | .CodeMirror-vscrollbar { 176 | right: 0; top: 0; 177 | overflow-x: hidden; 178 | overflow-y: scroll; 179 | } 180 | .CodeMirror-hscrollbar { 181 | bottom: 0; left: 0; 182 | overflow-y: hidden; 183 | overflow-x: scroll; 184 | } 185 | .CodeMirror-scrollbar-filler { 186 | right: 0; bottom: 0; 187 | } 188 | .CodeMirror-gutter-filler { 189 | left: 0; bottom: 0; 190 | } 191 | 192 | .CodeMirror-gutters { 193 | position: absolute; left: 0; top: 0; 194 | z-index: 3; 195 | } 196 | .CodeMirror-gutter { 197 | white-space: normal; 198 | height: 100%; 199 | display: inline-block; 200 | margin-bottom: -30px; 201 | /* Hack to make IE7 behave */ 202 | *zoom:1; 203 | *display:inline; 204 | } 205 | .CodeMirror-gutter-wrapper { 206 | position: absolute; 207 | z-index: 4; 208 | background: none !important; 209 | border: none !important; 210 | } 211 | .CodeMirror-gutter-background { 212 | position: absolute; 213 | top: 0; bottom: 0; 214 | z-index: 4; 215 | } 216 | .CodeMirror-gutter-elt { 217 | position: absolute; 218 | cursor: default; 219 | z-index: 4; 220 | } 221 | .CodeMirror-gutter-wrapper { 222 | -webkit-user-select: none; 223 | -moz-user-select: none; 224 | user-select: none; 225 | } 226 | 227 | .CodeMirror-lines { 228 | cursor: text; 229 | min-height: 1px; /* prevents collapsing before first draw */ 230 | } 231 | .CodeMirror pre { 232 | /* Reset some styles that the rest of the page might have set */ 233 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 234 | border-width: 0; 235 | background: transparent; 236 | font-family: inherit; 237 | font-size: inherit; 238 | margin: 0; 239 | white-space: pre; 240 | word-wrap: normal; 241 | line-height: inherit; 242 | color: inherit; 243 | z-index: 2; 244 | position: relative; 245 | overflow: visible; 246 | -webkit-tap-highlight-color: transparent; 247 | } 248 | .CodeMirror-wrap pre { 249 | word-wrap: break-word; 250 | white-space: pre-wrap; 251 | word-break: normal; 252 | } 253 | 254 | .CodeMirror-linebackground { 255 | position: absolute; 256 | left: 0; right: 0; top: 0; bottom: 0; 257 | z-index: 0; 258 | } 259 | 260 | .CodeMirror-linewidget { 261 | position: relative; 262 | z-index: 2; 263 | overflow: auto; 264 | } 265 | 266 | .CodeMirror-widget {} 267 | 268 | .CodeMirror-code { 269 | outline: none; 270 | } 271 | 272 | /* Force content-box sizing for the elements where we expect it */ 273 | .CodeMirror-scroll, 274 | .CodeMirror-sizer, 275 | .CodeMirror-gutter, 276 | .CodeMirror-gutters, 277 | .CodeMirror-linenumber { 278 | -moz-box-sizing: content-box; 279 | box-sizing: content-box; 280 | } 281 | 282 | .CodeMirror-measure { 283 | position: absolute; 284 | width: 100%; 285 | height: 0; 286 | overflow: hidden; 287 | visibility: hidden; 288 | } 289 | 290 | .CodeMirror-cursor { position: absolute; } 291 | .CodeMirror-measure pre { position: static; } 292 | 293 | div.CodeMirror-cursors { 294 | visibility: hidden; 295 | position: relative; 296 | z-index: 3; 297 | } 298 | div.CodeMirror-dragcursors { 299 | visibility: visible; 300 | } 301 | 302 | .CodeMirror-focused div.CodeMirror-cursors { 303 | visibility: visible; 304 | } 305 | 306 | .CodeMirror-selected { background: #d9d9d9; } 307 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 308 | .CodeMirror-crosshair { cursor: crosshair; } 309 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } 310 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } 311 | 312 | .cm-searching { 313 | background: #ffa; 314 | background: rgba(255, 255, 0, .4); 315 | } 316 | 317 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */ 318 | .CodeMirror span { *vertical-align: text-bottom; } 319 | 320 | /* Used to force a border model for a node */ 321 | .cm-force-border { padding-right: .1px; } 322 | 323 | @media print { 324 | /* Hide the cursor when printing */ 325 | .CodeMirror div.CodeMirror-cursors { 326 | visibility: hidden; 327 | } 328 | } 329 | 330 | /* See issue #2901 */ 331 | .cm-tab-wrap-hack:after { content: ''; } 332 | 333 | /* Help users use markselection to safely style text background */ 334 | span.CodeMirror-selectedtext { background: none; } -------------------------------------------------------------------------------- /resources/public/css/monokai.css: -------------------------------------------------------------------------------- 1 | /* Based on Sublime Text's Monokai theme */ 2 | 3 | .cm-s-monokai.CodeMirror { background: #272822; color: #f8f8f2; } 4 | .cm-s-monokai div.CodeMirror-selected { background: #49483E; } 5 | .cm-s-monokai .CodeMirror-line::selection, .cm-s-monokai .CodeMirror-line > span::selection, .cm-s-monokai .CodeMirror-line > span > span::selection { background: rgba(73, 72, 62, .99); } 6 | .cm-s-monokai .CodeMirror-line::-moz-selection, .cm-s-monokai .CodeMirror-line > span::-moz-selection, .cm-s-monokai .CodeMirror-line > span > span::-moz-selection { background: rgba(73, 72, 62, .99); } 7 | .cm-s-monokai .CodeMirror-gutters { background: #272822; border-right: 0px; } 8 | .cm-s-monokai .CodeMirror-guttermarker { color: white; } 9 | .cm-s-monokai .CodeMirror-guttermarker-subtle { color: #d0d0d0; } 10 | .cm-s-monokai .CodeMirror-linenumber { color: #d0d0d0; } 11 | .cm-s-monokai .CodeMirror-cursor { border-left: 1px solid #f8f8f0; } 12 | 13 | .cm-s-monokai span.cm-comment { color: #75715e; } 14 | .cm-s-monokai span.cm-atom { color: #ae81ff; } 15 | .cm-s-monokai span.cm-number { color: #ae81ff; } 16 | 17 | .cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute { color: #a6e22e; } 18 | .cm-s-monokai span.cm-keyword { color: #f92672; } 19 | .cm-s-monokai span.cm-string { color: #e6db74; } 20 | 21 | .cm-s-monokai span.cm-variable { color: #f8f8f2; } 22 | .cm-s-monokai span.cm-variable-2 { color: #9effff; } 23 | .cm-s-monokai span.cm-variable-3 { color: #66d9ef; } 24 | .cm-s-monokai span.cm-def { color: #fd971f; } 25 | .cm-s-monokai span.cm-bracket { color: #f8f8f2; } 26 | .cm-s-monokai span.cm-tag { color: #f92672; } 27 | .cm-s-monokai span.cm-header { color: #ae81ff; } 28 | .cm-s-monokai span.cm-link { color: #ae81ff; } 29 | .cm-s-monokai span.cm-error { background: #f92672; color: #f8f8f0; } 30 | 31 | .cm-s-monokai .CodeMirror-activeline-background { background: #373831; } 32 | .cm-s-monokai .CodeMirror-matchingbracket { 33 | text-decoration: underline; 34 | color: white !important; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /resources/public/css/sourceserifpro-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellea/clojure-cup-2015/3af384fd09af5b55a88a42297b5fcbbf15ddc559/resources/public/css/sourceserifpro-regular-webfont.eot -------------------------------------------------------------------------------- /resources/public/css/sourceserifpro-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellea/clojure-cup-2015/3af384fd09af5b55a88a42297b5fcbbf15ddc559/resources/public/css/sourceserifpro-regular-webfont.ttf -------------------------------------------------------------------------------- /resources/public/css/sourceserifpro-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellea/clojure-cup-2015/3af384fd09af5b55a88a42297b5fcbbf15ddc559/resources/public/css/sourceserifpro-regular-webfont.woff -------------------------------------------------------------------------------- /resources/public/css/sourceserifpro-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jellea/clojure-cup-2015/3af384fd09af5b55a88a42297b5fcbbf15ddc559/resources/public/css/sourceserifpro-regular-webfont.woff2 -------------------------------------------------------------------------------- /resources/public/css/style.css: -------------------------------------------------------------------------------- 1 | /* some style */ 2 | 3 | @font-face { 4 | font-family: 'source_serif_proregular'; 5 | src: url('sourceserifpro-regular-webfont.eot'); 6 | src: url('sourceserifpro-regular-webfont.eot?#iefix') format('embedded-opentype'), 7 | url('sourceserifpro-regular-webfont.woff2') format('woff2'), 8 | url('sourceserifpro-regular-webfont.woff') format('woff'), 9 | url('sourceserifpro-regular-webfont.ttf') format('truetype'), 10 | url('sourceserifpro-regular-webfont.svg#source_serif_proregular') format('svg'); 11 | font-weight: normal; 12 | font-style: normal; 13 | } 14 | 15 | body { 16 | font-family: "source_serif_proregular"; 17 | padding-left: 10px; 18 | -webkit-font-smoothing: antialiased; 19 | padding: 2em; 20 | } 21 | 22 | h1,h2,h4,p,em,i,span { 23 | max-width: 600px; 24 | } 25 | 26 | h2, h3, h4 { 27 | margin-top: 3em; 28 | } 29 | 30 | p { 31 | font-size: 120%; 32 | } 33 | 34 | pre { 35 | font-family: "Cousine", "Menlo", monospace; 36 | margin-bottom: 0em; 37 | } 38 | 39 | .CodeMirror { 40 | font-family: "Cousine", "Menlo", monospace; 41 | font-style: normal; 42 | font-weight: normal; 43 | padding: 15px; 44 | padding-right: 45px; 45 | background-color: #2C2C2C; 46 | color: white; 47 | height: auto; 48 | z-index: 1; 49 | border-radius: 5px; 50 | position: relative; 51 | 52 | margin-bottom: 15px; 53 | } 54 | 55 | .CodeMirror:not(.monoline){ 56 | min-height: 320px; 57 | } 58 | 59 | .CodeMirror-widget { 60 | color: rgb(5, 255, 13); 61 | } 62 | 63 | canvas { 64 | border: 5px #2C2C2C solid; 65 | border-left: none; 66 | width: 300px; 67 | height: 300px; 68 | border-radius: 0 5px 5px 0; 69 | background-color: white; 70 | } 71 | 72 | .holder { 73 | transform-origin: top; 74 | transition: transform 200ms ease-out; 75 | transform: translate(-30px,15px); 76 | z-index: 2; 77 | position: relative; 78 | } 79 | 80 | .error { 81 | font-family: "Cousine", "Menlo", monospace; 82 | font-style: normal; 83 | font-weight: normal; 84 | font-size: 14px; 85 | border-radius: 5px; 86 | padding: 10px; 87 | transform-origin: bottom; 88 | transform: translate(-10px,-61px); 89 | text-overflow: ellipsis; 90 | overflow: hidden; 91 | white-space: nowrap; 92 | box-sizing: border-box; 93 | max-width: 260px; 94 | color: white; 95 | z-index: 3; 96 | position: relative; 97 | background-color: red; 98 | float: right; 99 | animation: fade-in-bottom 0.2s ease-in-out 1; 100 | } 101 | 102 | .error:before { 103 | content: "\2639"; 104 | padding-right: 5px; 105 | font-size: 16px; 106 | } 107 | 108 | @keyframes fade-in-bottom { 109 | from {opacity: 0; 110 | transform: translate(-10px,0px);} 111 | to {opacity: 1; 112 | transform: translate(-10px,-61px);} 113 | } 114 | -------------------------------------------------------------------------------- /resources/public/img/editme.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | editme 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 |
25 |

Into the Land of Quil

26 |

A Great and Valiant Journey of Derring-do

27 |
28 | 29 |
30 | 31 |
32 |

33 | Good day, traveler. Today you embark upon a journey into Quil. May your 34 | vision be keen, for there are sights to behold. 35 |

36 |

37 | If you're new to the realms of Clojure, click here to start from scratch. → 38 |

39 |

40 | This is a tutorial 41 | for Quil, 42 | a visual programming system that combines the powers 43 | of ClojureScript 44 | and Processing.js. 45 |

46 |

47 | A Quil program is called a sketch. A sketch can be a simple drawing, 48 | but it can also be a rich animation or an interactive visualization. 49 |

50 |

51 | You'll find many sketches in this tutorial. All of them are "live" — 52 | change the code and you should immediately see the sketch change. 53 | Hover over a Quil function name to see what it does. 54 |

55 | 56 |

A Taste of Quil

57 |

58 | These first few sketches will give you a taste of things to come. They 59 | are presented without much explanation. We'll dive into the details 60 | later. Play around with them, there's nothing you can break. Should 61 | you happen to make a mess, simply hit the red "revert" button, and 62 | you'll get the original code back. 63 |

64 | 65 |

The Pine Forest

66 | 67 |

68 | The road to Quil starts in the Pine Forest. Try changing some numbers 69 | and see what happens! 70 |

71 | 72 | 73 | 97 | 98 |

99 | That's already a lovely pattern we've got going. Knit it into a 100 | turtleneck and aunt Juliet will envy you forever. But there's more. 101 | How about we get things moving? 102 |

103 | 104 |

The Carousel

105 |

106 | Time to make your head spin! This is an example of an animation. Think 107 | of it like an old fashioned film projector, spinning through a 108 | sequence of images. Quil calls your draw function many times in rapid 109 | succession to draw the individual images, called frames. 110 |

111 |

112 | Quil keeps a count of how many frames have passed. This sketch uses 113 | that frame-count to determine the position of the circle. 114 |

115 | 133 | 134 |

Paint Blotches

135 | 136 |

137 | Quil also lets you make interactive sketches. Move your mouse 138 | over the canvas to smear it with thick blotches of paint that run down 139 | the screen. 140 |

141 | 142 |

143 | This is an example of a sketch that has state. This means 144 | that how it looks depends on its history, in this case, the past 145 | positions of the mouse. 146 |

147 | 148 | 190 | 191 |

Creating a sketch

192 | 193 |

194 | To get Quil to draw something on the screen, you need a :draw 195 | function. You pass this function on to Quil when you call (sketch 196 | ...). Quil accepts other functions as well, like 197 | a :setup function, which is called once when your sketch 198 | starts to run. 199 |

200 |

201 | The :host is the HTML id of the canvas element, 202 | which is where Quil will draw your sketch. In this tutorial, all the 203 | canvases are already set up for you, so no need to worry about that. 204 |

205 | 206 |

The Quil API

207 | 208 |

209 | Inside the :draw function you have access to a long list of functions 210 | provided by Quil. Keep the Quil API 211 | reference close to you at all times. Hang it above your bed, keep 212 | it under your pillow. It's a magical toolbox providing endless 213 | opportunities for your creations. 214 |

215 | 216 |

Drawing shapes

217 | 218 |

219 | When you draw a shape, it stays on the canvas until you draw something 220 | on top of it. You can see this well in the last example, where the new 221 | "paint" is drawn on top of the old.. 222 |

223 | 224 |

225 | With (background ...) you can get it a clean slate, since it 226 | will refill the whole canvas with a solid color. You can use it in 227 | your draw function to clear the canvas before drawing the new frame. 228 |

229 | 230 |

231 | One of the easiest things you can draw is a rectangle. Quil's rect 232 | function takes four parameters, x, y, width 233 | and height. The first two arguments represent the location of the top 234 | left corner of rectangle on the canvas. Remember that in Quil, as in computer 235 | graphics in general, the origin (0, 0) of the coordinate system represents 236 | the top left corner of the drawing surface. In this example, we're drawing a 237 | centered equilateral rectangle or square. 238 |

239 | 240 | 250 | 251 |

252 | By default Quil draws shapes with a light gray fill color, and a thin black 253 | border, on a dark gray background. Unless normcore becomes even more... norm, 254 | this color scheme won't win many prizes. 255 |

256 | 257 |

258 | To spice things up let's add some color! We already talked 259 | about background, which is really a lot like a draw function in its 260 | own right, since it refills the whole canvas. Shapes like rectangles or 261 | triangles on the other hand depend on a fill color, and 262 | a stroke. The stroke has a color and 263 | a stroke-weight, the width of the stroke in pixels. 264 |

265 | 266 |

267 | By default all colors are specified 268 | in the RGB color space, meaning 269 | red - green - blue, with values between 0 and 255. Try and 270 | see how the colors change as you modify the three numbers! 271 |

272 | 273 | 291 | 292 |

293 | Drawing a circle isn't any harder. While Quil does not come with a 294 | special function for drawing circles, it supplies a function for the general 295 | case of drawing ovals (or ellipses). That will work well — after all, a 296 | circle is just an ellipse that is as high as it is wide. 297 |

298 |

299 | The ellipse function takes the same arguments 300 | as rect: x, y, width and height. 301 | However, whereas in the case of rect the point (x,y) 302 | reprents the top-left corner of the figure, in ellipse it represents 303 | its center. This decision of Quil's authors makes sense: an ellipse doesn't 304 | have corners. 305 |

306 | 307 | 320 | 321 |

Animation and State

322 | 323 |

324 |

325 | Don't just draw something, make it move! — Winston Churchill 326 |
327 |

328 | 329 |

Slider

330 | 331 |

332 | There are a few different ways you can create animations in Quil. You already 333 | saw the Carrousel example above, which used the current (frame-count) 334 | and based the rendering of each frame on that. 335 |

336 | 337 |

338 | You can change the frame rate, the number of frames Quil renders per second, with (frame-rate n). This will change the speed of animations based on frame-count. 339 |

340 | 341 |

342 | Another approach is the use the current time in milliseconds, this way we have a way to measure passing time independent of the the current frame rate. Quil provides the handy (millis) function for that. 343 |

344 | 345 |

346 | In this next example we use (millis) to calculate a horizontal position. 347 | With Clojure's mod function (modulo, in other words the remainder after 348 | division), we let the animation wrap around again. 349 |

350 | 368 | 369 |

Hyper

370 | 371 |

372 | This next sketch is an adaptation of a sketch by by Erik Svedäng. 373 |

374 | 375 |

376 | This is an example of a sketch that uses state. The initial state is returned 377 | by setup And update-state continually updates that state, in 378 | this case growing the radius, or changing the color. Draw in turn can then use that state. 379 |

380 | 381 | 419 | 420 | 421 |

Advanced Examples

422 | 423 |

424 | These examples are taken from the Quil site. Can you find out how they work? 425 |

426 | 427 |

Tailspin by Erik Svedäng

428 | 429 |

430 | Tailspin by Erik Svedäng on Quil.info 431 |

432 | 433 | 483 | 484 | 485 |

Dry Paint by Erik Svedäng

486 | 487 |

488 | Dry Paint by Erik Svedäng on Quil.info 489 |

490 | 491 | 559 | 560 |

About Us

561 | 562 |

563 | This interactive tutorial was created in a weekend by BERLIN!! 564 | for ClojureCup 2015. 565 |

566 | 567 |

568 | We are Arne Brasseur, Chelsey Mitchell, Jelle Akkerman, and Paulus Esterhazy. 569 |

570 | 571 |

572 | All code is available under 573 | the Eclipe Public 574 | License and can be 575 | found on 576 | Github. Tutorial text and code samples 577 | are available under Creative 578 | Commons-Attribution-Share Alike 4.0. Quil examples taken from 579 | the Quil site are © their respective authors, and are EPL like 580 | the Quil site. 581 |

582 |
583 | 584 |
585 | 586 | 587 | 588 | 589 | -------------------------------------------------------------------------------- /resources/public/introclojure.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

Intro to Clojure

15 |

A short intro to Clojure, many thanks to Clojure Bridge for most of the material.

16 |
17 |
18 |

19 | Notice the parentheses. Parentheses enclose instructions to the computer 20 | in Clojure. A left parenthesis is the start of the instruction, and a 21 | matching right parenthesis is the end of the enclosing instruction. Clojure code has a lot of nested parentheses. 22 |

23 | 24 | 27 |

28 | Next to the parentheses, we see the instructions to the computer. That instruction is normally what we call a function. The functions do all the hard work in Clojure. print-str, + and forward are all functions. When these functions get run, they return a some type of value. Clojure functions always return a value. 29 |

30 |

31 | Simple Values 32 |

33 |

34 | Strings 35 |

36 |

What is a string? A string is just a piece of text. To make a string, you enclose it in quotation marks. Look at the last example. A backslash is how we put a quotation mark inside a string. Do not try using single quotes to make a string. 37 |

 38 |    "Hello, World!"
 39 |    "Aubrey said, \"I think we should go to the Orange Julius.\""
 40 |         
41 |

42 |

43 | Booleans and nil 44 |

45 |

46 | A boolean is a true or false value, and you type them just like that, true and false. Often in programming, we need to ask a true or false question, like “Is this class in the current semester?” or “Is this person’s birthday today?” When we ask those questions, we get a boolean back. 47 | There is another value nil, which behaves like a boolean in terms of truthiness. But, nil means no value at all and not a boolean 48 |

 49 |    true
 50 |    false
 51 |    nil
 52 |         
53 |

54 |

55 | Keywords 56 |

57 |

58 | Keywords are the strangest of the basic value types. Some computer languages have similar one. However, keywords don’t have a real world analog like numbers, strings, or booleans. You can think of them as a special type of string, one that’s used for labels. They are often used as keys of key-value pair for maps (data structure; will learn later). 59 |

 60 |    :trinity
 61 |    :first
 62 |    :last
 63 |         
64 |

65 |

66 | Numbers 67 |

68 |

69 | Clojure has several different types of numbers. 70 | First up are integers. Integers include zero, the positive whole numbers, and the negative whole numbers, and you write them just like we write them normally. 71 |

72 |
 73 |    0, 12, -42
 74 |       
75 |

Then we have decimal numbers, which are also called floats. They include any numbers that have a decimal point in them. 76 |

77 |
 78 |    0.0000072725, 10.5, -99.9
 79 |       
80 |

Finally, we have fractions, which are also called ratios. Computers cannot perfectly represent all floats, but ratios are always exact. We write them with a slash, like so: 81 | Note that, just like with pen-and-paper math, the denominator of your ratio cannot be equal to 0. 82 |

 83 |    1/2, -7/3
 84 |         
85 |

86 |

87 | Infix vs. prefix notation 88 |

89 |

90 | In Clojure, +, -, * and / appear before two numbers. This is called prefx 91 | notation. What you’re used to seeing is called infx notation, as the arithmetic 92 | operator is in-between the two operands. 93 |

94 | 97 |

98 | Explicit precedence 99 |

100 |

101 | Imagine both are unclear, but notice that in the prefix version, you do not have to ever think about the precedence of operators. Because each expression has the operator before all the operands and the entire expression is wrapped in parentheses, all precendence is explicit. 102 |

103 |

104 | This example uses integers but try changing the numbers to floats, decimals, or fractions and see what happens. 105 |

106 |

107 | See how this infix example is written in Clojure in the editor below.

108 | Infix: 1 + 2 / 3 109 |

110 | 113 |

114 | Less repetitive 115 |

116 |

117 | Another reason prefix notation can be nice is that it can make long expressions less repetitive. With prefix notation, if we plan to use the same operator on many operands, we do not have to repeat the operator between them. 118 |

119 |

120 | See how this infix example is written in Clojure in the editor below

121 | Infix: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 122 |

123 | 126 |

127 | Some basic Clojure functions 128 |

129 |

130 | str this example combines two strings, but try changing one of them to a number. 131 |

132 | 135 |

136 | inc 137 |

138 | 141 |

142 | Data Structures 143 |

144 |

145 | So far, we’ve dealt with discrete pieces of data: one number, one string, one value. When programming, it is more often the case that you want to work with groups of data. 146 |

147 |

148 | Vectors 149 |

150 |

151 | A vector is a sequential collection of values. A vector may be empty. A vector may contain values of different types. Each value in a vector is numbered starting at 0, that number is called its index. The index is used to refer to each value when looking them up. 152 |
153 |
154 | Vectors are written using square brackets with any number of pieces of data inside them, separated by spaces. Here are some examples of vectors: 155 |

156 |

157 | The next two functions are used to make new vectors. The vector function takes any number of items and puts them in a new vector. conj is an interesting function that you’ll see used with all the data structures. With vectors, it takes a vector and an item and returns a new vector with that item added to the end of the vector. Why the name conj? conj is short for conjoin, which means to join or combine. This is what we’re doing: we’re joining the new item to the vector. 158 |

159 | 162 | 165 |

166 | Now, take a look at these four functions. 167 |

168 |

169 | count gives us a count of the number of items in a vector. 170 |

171 | 174 |

175 | nth gives us the nth item in the vector. Note that we start counting at 0, so in the example, calling nth with the number 1 gives us what we’d call the second element when we aren’t programming. 176 |

177 | 180 |

181 | first returns the first item in the collection. 182 |

183 | 186 |

187 | rest returns all except the first item. 188 |

189 | 192 |

193 | concat 194 |

195 | 198 |

199 | Maps 200 |

201 |

202 | Maps hold a set of keys and values associated with them. You can think of it like a dictionary: you look up things using a word (a keyword) and see the definition (its value). If you’ve programmed in another language, you might have seen something like maps–maybe called dictionaries, hashes, or associative arrays. 203 |

204 |

205 | We write maps by enclosing alternating keys and values in curly braces, like so. 206 | {:first "Sally" :last "Brown"} 207 | Maps are useful because they can hold data in a way we normally think about it. 208 | Take our made up example, Sally Brown. A map can hold her first name and last name, her address, her favorite food, 209 | or anything else. It’s a simple way to collect that data and make it easy to look up. 210 |

211 | This is an empty map. Add some key-value pairs! 212 |

213 | 216 |

217 | assoc and dissoc are paired functions: they associate and disassociate items from a map. 218 | See how we add the last name “Mitchell” to the map with assoc, and then we remove it with dissoc. 219 |

220 | 223 | 226 |

227 | merge merges two maps together to make a new map. 228 |

229 | 232 |

233 | count every collection has this function. Why do you think the answer is two? count is returning the number of associations. 234 |

235 | 238 |

239 | Since map is a key-value pair, the key is used to get a value from a map. One of the ways often used in Clojure is the examples below. We can use a keyword like using a function in order to look up values in a map. 240 |

241 | 244 |

245 | Then we have keys and vals, which are pretty simple: they return the keys and values in the map. The order is not guaranteed, so we could have gotten (:first :last) or (:last :first). 246 |

247 | 250 | 253 |

254 | Simple values such as numbers, keywords, and strings are not the only types of things you can put into collections. You can also put other collections into collections, so you can have a vector of maps, or a list of vectors, or whatever combination fits your data. 255 |

256 |

257 | Now you know how to do Clojure lets make some beautiful animation! Go to the Quil tutorial.→ 258 |

259 | At the request of the survivors, the names have been changed. Out of respect for the dead, 260 | the rest has been told exactly as it occurred 261 |
262 | 263 | 264 | 265 | 266 | -------------------------------------------------------------------------------- /resources/public/js/oneline.js: -------------------------------------------------------------------------------- 1 | function oneLineCM(cm){ 2 | cm.getWrapperElement().className += " monoline"; 3 | cm.setSize("70%", cm.defaultTextHeight() + 2 * 4); 4 | cm.on("beforeChange", function(instance, change) { 5 | var newtext = change.text.join("").replace(/\n/g, ""); // remove ALL \n ! 6 | change.update(change.from, change.to, [newtext]); 7 | return true; 8 | }); 9 | }; 10 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/common.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.common 2 | (:require [reagent.core :as reagent])) 3 | 4 | (def config 5 | {:initial-code "(+ 1 4)"}) 6 | 7 | (defonce !tooltip (reagent/atom nil)) 8 | 9 | (defonce !state (reagent/atom {:code (:initial-code config)})) 10 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/content.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.content) 2 | 3 | (def header 4 | [:header 5 | [:h1 "Into the Land of Quil"] 6 | [:h2 "A Great and Valiant Journey of Derring-do"]]) 7 | 8 | (def chapter-1 9 | [:div 10 | [:em "Goodday, traveler. Today you embark upon a journey into Quil. May your eyes be bright, for there are sights to behold."] 11 | [:p "Quil lets you do visual programming. You can make drawings and animations, even interactive ones with keyboard and mouse."] 12 | [:p "A Quil program is called a sketch. We set up a \"draw function\" that creates the actual visuals."] 13 | [:quil-code 14 | "pink-triangles" " 15 | ;; This is the draw function which Quil will run 16 | (defn draw-pink-triangles [] 17 | ;; First we set the stage: a background color, and no borders around shapes 18 | (background 20 200 151) 19 | (no-stroke) 20 | 21 | ;; Set a fill color for shapes. The numbers correspond with 22 | ;; red - green - blue, and go up to 255 23 | (fill 34 95 215) 24 | 25 | ;; Fill the width and height of the canvas with triangles 26 | (doseq [x (range 0 (width) 50) 27 | y (range 0 (height) 50)] 28 | (triangle (+ x 25) y 29 | x (+ y 50) 30 | (+ x 50) (+ y 50)))) 31 | 32 | (sketch 33 | :host \"pink-triangles\" 34 | :size [300 300] 35 | :draw draw-pink-triangles 36 | :setup #(frame-rate 1))"] 37 | 38 | 39 | [:p "That's already a lovely pattern we got going. Knit it into a turtleneck and aunt Juliet will envy you forever. But there's more, how about we get things moving a bit?"] 40 | 41 | [:quil-code "carousel" "(defn draw-carousel [] 42 | (background 255) 43 | (no-stroke) 44 | (fill 252 90 44) 45 | 46 | (let [radians (/ (frame-count) 20) 47 | x (+ 150 (* 100 (cos radians))) 48 | y (+ 150 (* 100 (sin radians))) 49 | width 30 50 | height 30] 51 | (ellipse x y, width height))) 52 | 53 | (sketch 54 | :host \"carousel\" 55 | :size [300 300] 56 | :draw draw-carousel)"] 57 | 58 | [:p] 59 | 60 | [:quil-code "tailspin" " 61 | (defn setup [] 62 | (frame-rate 30) 63 | (let [max-r (/ (width) 2) 64 | n (int (map-range (width) 65 | 200 500 66 | 20 50))] 67 | {:dots (into [] (for [r (map #(* max-r %) 68 | (range 0 1 (/ n)))] 69 | [r 0]))})) 70 | 71 | (def speed 0.0003) 72 | 73 | (defn move [dot] 74 | (let [[r a] dot] 75 | [r (+ a (* r speed))])) 76 | 77 | (defn update-state [state] 78 | (update-in state [:dots] #(map move %))) 79 | 80 | (defn dot->coord [[r a]] 81 | [(+ (/ (width) 2) (* r (cos a))) 82 | (+ (/ (height) 2) (* r (sin a)))]) 83 | 84 | (defn draw-state [state] 85 | (background 255) 86 | (fill 0) 87 | (let [dots (:dots state)] 88 | (loop [curr (first dots) 89 | tail (rest dots) 90 | prev nil] 91 | (let [[x y] (dot->coord curr)] 92 | (ellipse x y 5 5) 93 | (when prev 94 | (let [[x2 y2] (dot->coord prev)] 95 | (line x y x2 y2)))) 96 | (when (seq tail) 97 | (recur (first tail) 98 | (rest tail) 99 | curr))))) 100 | 101 | (sketch 102 | :host \"tailspin\" 103 | :size [500 500] 104 | :setup setup 105 | :update update-state 106 | :draw draw-state 107 | :middleware [m/fun-mode])"]]) 108 | 109 | 110 | (def all 111 | [:div 112 | header 113 | chapter-1]) 114 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/core.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.core 2 | (:require-macros [clojure-cup-2015.macro :refer [read-snippets]]) 3 | (:require [reagent.core :as reagent] 4 | [dommy.core :as d 5 | :refer-macros [sel sel1]] 6 | [clojure-cup-2015.editor :refer [cm-editor mirrors]] 7 | [clojure-cup-2015.common :refer [config !state !tooltip]] 8 | [cljsjs.codemirror] 9 | [cljsjs.codemirror] 10 | [cljsjs.codemirror.mode.clojure] 11 | [cljsjs.codemirror.addon.edit.matchbrackets] 12 | [cljsjs.codemirror.addon.fold.foldgutter] 13 | [cljsjs.codemirror.addon.edit.closebrackets] 14 | [clojure-cup-2015.content :as content] 15 | [quil.core] 16 | [quil.middleware])) 17 | 18 | (def !snippets (atom {})) 19 | 20 | (enable-console-print!) 21 | 22 | (defn q [selector] (.querySelector js/document selector)) 23 | (defn by-id [id] (.getElementById js/document id)) 24 | 25 | (defn error-display [id] 26 | (let [{:keys [error]} @!state 27 | cid (:id error)] 28 | [:div 29 | (when (and error (= id cid)) 30 | [:p.error (:message error)])])) 31 | 32 | (defn revert! [id _] 33 | (when-let [mirror (get @mirrors id)] 34 | (when-let [snippet (get @!snippets id)] 35 | (.setValue mirror snippet)))) 36 | 37 | (defn canvas-editor 38 | "Code mirror + a canvas, so quil can render to it" 39 | [id default-code] 40 | [:div 41 | [:div.right.holder {:id (str id "_holder")} 42 | [:canvas {:id id}] 43 | [error-display id]] 44 | [cm-editor {:default-value default-code :id id} {}] 45 | [:div.right {:style {:margin-right "315px" 46 | :position "relative" 47 | :z-index 400 48 | :transform "translateY(-45px)"}} 49 | [:div.btn.bg-red.rounded.mr1 {:on-click (partial revert! id)} "revert code"] 50 | #_[:div.btn.bg-green.rounded {:on-click (partial restart! id)} "restart sketch"]]]) 51 | 52 | (defn monoline-editor 53 | [id default-code] 54 | [:div [cm-editor {:default-value default-code 55 | :monoline true 56 | :id id} 57 | {:scrollbarStyle "null"}]]) 58 | 59 | (defn tooltip [tt] 60 | (if @tt 61 | (let [{left :left top :top doc :doc name :name} @tt] 62 | [:div.tooltip {:style {:position "absolute" 63 | :left left :top top 64 | :z-index 2000000 65 | :backgroundColor "#d0faf4" 66 | :border "2px solid #c6ddf5" 67 | :maxWidth "40em" 68 | :maxHeight "10000px" 69 | :padding "1em"}} 70 | [:div {:style {:textDecoration "underline" 71 | :fontWeight "bold"}} name] 72 | [:div doc]]) 73 | [:div])) 74 | 75 | (defn on-js-reload []) 76 | 77 | (defn mirrorize-one! [e] 78 | (let [monoline (d/attr e "data-monoline") 79 | cmid (d/attr e "data-cmid") 80 | text (->> e .-text clojure.string/trim) 81 | new (d/create-element :div)] 82 | (d/remove-class! e "editor") ;; only replace once (d/add-class! editor "cm") 83 | ;; (d/add-class! new "cm") 84 | (d/insert-before! new e) 85 | (reagent/render-component [(if monoline monoline-editor canvas-editor) cmid text] new) 86 | (swap! !snippets assoc cmid text))) 87 | 88 | (defn mirrorize! [] 89 | (doseq [e (sel ".editor")] 90 | (mirrorize-one! e))) 91 | 92 | (defn init [] 93 | (mirrorize!) 94 | (reagent/render-component [tooltip !tooltip] (d/sel1 :#tooltip))) 95 | 96 | (init) 97 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/editor.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.editor 2 | (:require [reagent.core :as reagent] 3 | [clojure-cup-2015.common :refer [config !state !tooltip]] 4 | [clojure-cup-2015.quil-symbols :as quil-symbols :refer [quildocs]] 5 | [cljs.js :as cljs] 6 | [cljs.tools.reader] 7 | [dommy.core :as d])) 8 | 9 | (defn debounce 10 | ([f] (debounce f 1000)) 11 | ([f timeout] 12 | (let [id (atom nil)] 13 | (fn [evt] 14 | (js/clearTimeout @id) 15 | (reset! id (js/setTimeout f timeout)))))) 16 | 17 | (def opts {:matchBrackets true 18 | :lineNumbers false 19 | :autoCloseBrackets true 20 | :theme "monokai" 21 | :mode "clojure" 22 | :lineWrapping true}) 23 | 24 | (defn move-canvas 25 | [cm canvas-id] 26 | (when canvas-id 27 | (let [canvas (.getElementById js/document (str canvas-id "_holder")) 28 | cmheight (.heightAtLine cm (+ (.-line (.getCursor cm)) 1) "local") 29 | height (min (max (- cmheight 300) 15))] 30 | (set! (.. canvas -style -transform) (str "translate(-30px," height "px)"))))) 31 | 32 | (defn outer-sexp 33 | "Returns the outer sexp" 34 | [cm] 35 | (if-not (-> cm (.getTokenAt (.getCursor cm)) 36 | .-state 37 | .-indentStack) 38 | (prn "not in from") 39 | 40 | (let [cur-cursor (.getCursor cm)] 41 | (while (-> cm (.getTokenAt (.getCursor cm)) .-state .-indentStack) 42 | (.moveH cm -1 "char")) 43 | (let [start (.getCursor cm)] 44 | (.moveH cm 1 "char") 45 | (while (-> cm (.getTokenAt (.getCursor cm)) .-state .-indentStack) 46 | (.moveH cm 1 "char")) 47 | (let [end (.getCursor cm)] 48 | (.setSelection cm start end) 49 | (let [selection (.getSelection cm)] 50 | (.setCursor cm cur-cursor) 51 | selection)))))) 52 | 53 | (defn add-inline 54 | "Add a inline comment/result/documentation what ever" 55 | [{:keys [line ch text]} editor] 56 | (let [dom-node (.createElement js/document "span")] 57 | (set! (.-innerHTML dom-node) (str " => " text)) 58 | (when-let [b (-> editor .-doc .getAllMarks first)] 59 | (.clear b)) 60 | (.setBookmark (.-doc editor) #js {:line line :ch ch} #js {:widget dom-node}))) 61 | 62 | (defn error! [error] 63 | (swap! !state assoc :error error)) 64 | 65 | (defn dismiss! [] (error! nil)) 66 | 67 | (defonce cljs-compiler-state (cljs/empty-state)) 68 | 69 | (defn warning-hook [& args] 70 | (throw (ex-info "Cljs warning" {:args args}))) 71 | 72 | 73 | (defn find-error [id {:keys [error value]}] 74 | (if error 75 | (do 76 | (error! {:message (->> error .-cause .-message) 77 | :id id}) 78 | (swap! !state assoc :result nil)) 79 | (do 80 | (dismiss!) 81 | (swap! !state assoc :result (str value))))) 82 | 83 | (defn find-value [editor {:keys [value]}] 84 | ;;(js/console.log value) 85 | (if value 86 | (add-inline {:line 0 :ch 100 :text value} editor))) 87 | 88 | (defn eval 89 | ([name-space in-str] 90 | (eval name-space in-str #())) 91 | 92 | ([name-space in-str callback] 93 | (let [st cljs-compiler-state] 94 | (binding [cljs.analyzer/*cljs-warning-handlers* [warning-hook]] 95 | (cljs/eval-str st in-str (symbol name-space) 96 | {:eval cljs/js-eval 97 | :ns (symbol name-space) 98 | ;;:verbose true 99 | 100 | ;; don't ask me why this works. It stops Clojurescript from complaining that 101 | ;; *load-fn* isn't defined 102 | :load (fn [_ cb] (cb {:lang :clj :source ""}))} 103 | callback))))) 104 | 105 | (defn ns-str [ns] 106 | (str "(ns " ns " (:require [quil.core :as q] [quil.middleware :as m]))")) 107 | 108 | 109 | (defn handle-mouse-over [ns editor event] 110 | (let [left (.-pageX event) 111 | top (.-pageY event) 112 | line-char (.coordsChar editor #js {"left" left 113 | "top" top}) 114 | char (.-ch line-char) 115 | line (.-line line-char) 116 | token (.-string (.getTokenAt editor #js {"ch" char "line" line}))] 117 | 118 | (if-let [doc (get quildocs token)] 119 | (reset! !tooltip {:left left :top top :doc doc :name token}) 120 | (reset! !tooltip nil)))) 121 | 122 | (def mirrors (atom {})) 123 | 124 | (defn in-viewport? [cm init !initiated?] 125 | (let [dom-node (.getWrapperElement cm) 126 | rects (.getBoundingClientRect dom-node) 127 | vh (or (.-innerHeight js/window) (aget js/document "documentElement" "clientHeight")) 128 | in-view? (and (< (.-top rects) vh) 129 | (> (.-bottom rects) 0))] 130 | (when (and in-view? (not @!initiated?)) 131 | (reset! !initiated? true) (init)))) ; TODO destroy! 132 | 133 | (defn cm-editor 134 | "CodeMirror reagent component" 135 | [props cm-opts] 136 | (reagent/create-class 137 | {:component-did-mount 138 | (fn [this] 139 | (let [id (:id props) 140 | name-space (str (:id props) ".user") 141 | dom-node (reagent/dom-node this) 142 | opts (clj->js (merge opts cm-opts)) 143 | editor (.fromTextArea js/CodeMirror dom-node opts) 144 | !initiated? (atom false) 145 | init #(eval name-space 146 | (str (ns-str name-space) 147 | (quil-symbols/import-symbols-src) 148 | (.getValue editor)) 149 | (partial find-error id))] 150 | 151 | (swap! mirrors assoc id editor) 152 | 153 | (when (:monoline props) 154 | (js/oneLineCM editor) 155 | (eval name-space 156 | (.getValue editor) 157 | (partial find-value editor)) 158 | 159 | (.on editor "change" (debounce #(eval name-space 160 | (.getValue editor) 161 | (partial find-value editor)) 162 | 200))) 163 | 164 | (.addEventListener js/document "scroll" 165 | (debounce #(in-viewport? editor init !initiated?) 100)) 166 | 167 | (.on editor "change" (debounce #(eval name-space 168 | (.getValue editor) 169 | (partial find-error id)))) 170 | 171 | (d/listen! (.getWrapperElement editor) :mouseover #(handle-mouse-over name-space editor %)) 172 | 173 | (when-not (:monoline props) 174 | (.on editor "cursorActivity" #(move-canvas % (:id props)))) 175 | (reagent/set-state this {:editor editor}))) 176 | 177 | :reagent-render 178 | (fn [_] 179 | [:textarea {:default-value (:default-value props)}])})) 180 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/macro.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.macro) 2 | 3 | (defn read-resource [n] 4 | (some->> (str "code/" n ".cljs") 5 | clojure.java.io/resource 6 | clojure.java.io/file 7 | slurp)) 8 | 9 | (defmacro read-snippets [n] 10 | (->> (range 1 (inc n)) 11 | (map (fn [n] [n (read-resource n)])) 12 | (into {}))) 13 | 14 | (defmacro docstrings [ns vars] 15 | (let [result 16 | (into {} (map (fn [v] 17 | [(str v) (:doc (meta (clojure.core/ns-resolve (find-ns ns) v)))]) 18 | vars))] 19 | result)) 20 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/quil_symbols.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.quil-symbols 2 | (:require-macros [clojure-cup-2015.macro :refer [docstrings]]) 3 | (:require [clojure.string :as s] 4 | [clojure.string :as str])) 5 | 6 | (def quildocs 7 | (docstrings quil.core 8 | [;; COLOR ;; 9 | ;; Creating & Reading 10 | alpha 11 | blend-color 12 | blue 13 | brightness 14 | color 15 | color-mode 16 | current-fill 17 | current-stroke 18 | green 19 | hue 20 | lerp-color 21 | red 22 | saturation 23 | ;; Setting 24 | background 25 | background-float 26 | background-image 27 | background-int 28 | fill 29 | fill-float 30 | fill-int 31 | no-fill 32 | no-stroke 33 | stroke 34 | stroke-float 35 | stroke-int 36 | ;; Utility Macros 37 | ;; with-fill 38 | ;; with-stroke 39 | ;; TYPOGRAPHY ;; 40 | ;; Attributes 41 | text-align 42 | text-leading 43 | text-mode 44 | text-size 45 | text-width 46 | ;; Loading & Displaying 47 | available-fonts 48 | create-font 49 | load-font 50 | text 51 | text-char 52 | text-font 53 | text-num 54 | ;; Metrics 55 | text-ascent 56 | text-descent 57 | ;; IMAGE ;; 58 | create-image 59 | resize 60 | ;; Loading & Displaying 61 | image 62 | image-mode 63 | load-image 64 | no-tint 65 | request-image 66 | tint 67 | tint-float 68 | tint-int 69 | ;; Pixels 70 | blend 71 | copy 72 | display-filter 73 | get-pixel 74 | image-filter 75 | pixels 76 | set-image 77 | set-pixel 78 | update-pixels 79 | ;; Rendering 80 | create-graphics 81 | ;; TRANSFORM ;; 82 | apply-matrix 83 | pop-matrix 84 | print-matrix 85 | push-matrix 86 | reset-matrix 87 | rotate 88 | rotate-x 89 | rotate-y 90 | rotate-z 91 | scale 92 | shear-x 93 | shear-y 94 | translate 95 | ;; Utility Macros 96 | ;; with-rotation 97 | ;; with-translation 98 | ;; RENDERING ;; 99 | hint 100 | ;; with-graphics 101 | ;; Shaders 102 | load-shader 103 | ;; MATH ;; 104 | ;; Calculation 105 | abs 106 | ceil 107 | constrain 108 | dist 109 | exp 110 | floor 111 | lerp 112 | log 113 | mag 114 | map-range 115 | norm 116 | pow 117 | round 118 | sq 119 | sqrt 120 | ;; Random 121 | noise 122 | noise-detail 123 | noise-seed 124 | random 125 | random-gaussian 126 | random-seed 127 | ;; Trigonometry 128 | acos 129 | asin 130 | atan 131 | atan2 132 | cos 133 | degrees 134 | radians 135 | sin 136 | tan 137 | ;; DATA ;; 138 | ;; Conversion 139 | binary 140 | hex 141 | unbinary 142 | unhex 143 | ;; STATE ;; 144 | set-state! 145 | state 146 | state-atom 147 | ;; SHAPE ;; 148 | ;; 2D Primitives 149 | arc 150 | ellipse 151 | line 152 | point 153 | quad 154 | rect 155 | triangle 156 | ;; 3D Primitives 157 | box 158 | sphere 159 | sphere-detail 160 | ;; Attributes 161 | ellipse-mode 162 | no-smooth 163 | rect-mode 164 | smooth 165 | stroke-cap 166 | stroke-join 167 | stroke-weight 168 | ;; Curves 169 | bezier 170 | bezier-detail 171 | bezier-point 172 | bezier-tangent 173 | curve 174 | curve-detail 175 | curve-point 176 | curve-tangent 177 | curve-tightness 178 | ;; Loading & Displaying 179 | load-shape 180 | shape 181 | shape-mode 182 | ;; Vertex 183 | begin-contour 184 | begin-shape 185 | bezier-vertex 186 | curve-vertex 187 | end-contour 188 | end-shape 189 | quadratic-vertex 190 | texture 191 | texture-mode 192 | vertex 193 | ;; LIGHTS, CAMERA ;; 194 | ;; Camera 195 | begin-camera 196 | camera 197 | end-camera 198 | frustum 199 | ortho 200 | perspective 201 | print-camera 202 | print-projection 203 | ;; Coordinates 204 | model-x 205 | model-y 206 | model-z 207 | screen-x 208 | screen-y 209 | screen-z 210 | ;; Lights 211 | ambient-light 212 | directional-light 213 | light-falloff 214 | light-specular 215 | lights 216 | no-lights 217 | normal 218 | point-light 219 | spot-light 220 | ;; Material Properties 221 | ambient 222 | ambient-float 223 | ambient-int 224 | emissive 225 | emissive-float 226 | emissive-int 227 | shininess 228 | specular 229 | ;; ENVIRONMENT ;; 230 | current-frame-rate 231 | current-graphics 232 | cursor 233 | cursor-image 234 | ;;defsketch 235 | focused 236 | frame-count 237 | frame-rate 238 | height 239 | no-cursor 240 | ;;sketch 241 | target-frame-rate 242 | width 243 | ;; INPUT ;; 244 | ;; Keyboard 245 | key-as-keyword 246 | key-code 247 | key-coded? 248 | key-pressed? 249 | raw-key 250 | ;; Mouse 251 | mouse-button 252 | mouse-pressed? 253 | mouse-x 254 | mouse-y 255 | pmouse-x 256 | pmouse-y 257 | ;; Time & Date 258 | day 259 | hour 260 | millis 261 | minute 262 | month 263 | seconds 264 | year 265 | ;; OUTPUT ;; 266 | ;; Files 267 | end-raw 268 | ;; Image 269 | save 270 | save-frame 271 | ;; STRUCTURE ;; 272 | delay-frame 273 | exit 274 | no-loop 275 | pop-style 276 | push-style 277 | redraw 278 | start-loop 279 | ;; MIDDLEWARE ;; 280 | ;; fun-mode 281 | ;; navigation-2d 282 | ;; navigation-3d 283 | ])) 284 | 285 | (def functions (keys quildocs)) 286 | 287 | (def macros '[defsketch with-fill with-stroke with-translation]) 288 | 289 | (def live-sketches (atom {})) 290 | 291 | (defn sketch* 292 | "Start a new sketch and store it with the original options." 293 | [{:keys [host] :as opts}] 294 | (let [new-sketch (apply quil.core/sketch (apply concat opts))] 295 | (swap! live-sketches assoc host {:sketch new-sketch 296 | :opts opts}))) 297 | 298 | (defn sketch-wrapper 299 | "Start a sketch, but idempotent. If an identical sketch is running, leave it 300 | alone, if a sketch with different options but same id (host) is running, stop 301 | the old one and start a new one." 302 | [& {:keys [host] :as opts}] 303 | (if-let [old-sketch (get @live-sketches host)] 304 | (when-not (= (:opts old-sketch) opts) 305 | (.exit (:sketch old-sketch)) 306 | (sketch* opts)) 307 | (sketch* opts))) 308 | 309 | (defn import-symbols-src 310 | "A hack to make quil functions available in the main namespace, generates a 311 | string that looks like (def fill quil.core/fill), which we then eval." 312 | [] 313 | (str 314 | (str/join "\n" (map #(str "(def " % " quil.core/" % ")") functions)) 315 | "(def sketch (.. js/clojure_cup_2015 -quil-symbols -sketch-wrapper))")) 316 | 317 | ;; (defn make-require-str [] 318 | ;; (str 319 | ;; "(:require [quil.core :as q \n :refer [\n" 320 | ;; (s/join " " functions) 321 | ;; "\n]\n" 322 | ;; " :refer-macros [\n" 323 | ;; (s/join " " macros) 324 | ;; "\n]]\n" 325 | ;; "[quil.middleware :as m])") 326 | ;; ) 327 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/quiltest.cljs: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.quiltest 2 | (:require [quil.core :as q 3 | :refer [ 4 | ;;;; COLOR ;;;; 5 | 6 | ;; Creating & Reading 7 | alpha 8 | blend-color 9 | blue 10 | brightness 11 | color 12 | color-mode 13 | current-fill 14 | current-stroke 15 | green 16 | hue 17 | lerp-color 18 | red 19 | saturation 20 | 21 | ;; Setting 22 | background 23 | background-float 24 | background-image 25 | background-int 26 | fill 27 | fill-float 28 | fill-int 29 | no-fill 30 | no-stroke 31 | stroke 32 | stroke-float 33 | stroke-int 34 | 35 | ;; Utility Macros 36 | ;; with-fill 37 | ;; with-stroke 38 | 39 | ;;;; TYPOGRAPHY ;;;; 40 | 41 | ;; Attributes 42 | text-align 43 | text-leading 44 | text-mode 45 | text-size 46 | text-width 47 | 48 | ;; Loading & Displaying 49 | available-fonts 50 | create-font 51 | load-font 52 | text 53 | text-char 54 | text-font 55 | text-num 56 | 57 | ;; Metrics 58 | text-ascent 59 | text-descent 60 | 61 | ;;;; IMAGE ;;;; 62 | create-image 63 | resize 64 | 65 | ;; Loading & Displaying 66 | image 67 | image-mode 68 | load-image 69 | no-tint 70 | request-image 71 | tint 72 | tint-float 73 | tint-int 74 | 75 | ;; Pixels 76 | blend 77 | copy 78 | display-filter 79 | get-pixel 80 | image-filter 81 | pixels 82 | set-image 83 | set-pixel 84 | update-pixels 85 | 86 | ;; Rendering 87 | create-graphics 88 | 89 | ;;;; TRANSFORM ;;;; 90 | apply-matrix 91 | pop-matrix 92 | print-matrix 93 | push-matrix 94 | reset-matrix 95 | rotate 96 | rotate-x 97 | rotate-y 98 | rotate-z 99 | scale 100 | shear-x 101 | shear-y 102 | translate 103 | 104 | ;; Utility Macros 105 | ;; with-rotation 106 | ;; with-translation 107 | 108 | ;;;; RENDERING ;;;; 109 | hint 110 | ;; with-graphics 111 | 112 | ;; Shaders 113 | load-shader 114 | 115 | ;;;; MATH ;;;; 116 | 117 | ;; Calculation 118 | abs 119 | ceil 120 | constrain 121 | dist 122 | exp 123 | floor 124 | lerp 125 | log 126 | mag 127 | map-range 128 | norm 129 | pow 130 | round 131 | sq 132 | sqrt 133 | 134 | ;; Random 135 | noise 136 | noise-detail 137 | noise-seed 138 | random 139 | random-gaussian 140 | random-seed 141 | 142 | ;; Trigonometry 143 | acos 144 | asin 145 | atan 146 | atan2 147 | cos 148 | degrees 149 | radians 150 | sin 151 | tan 152 | 153 | ;;;; DATA ;;;; 154 | 155 | ;; Conversion 156 | binary 157 | hex 158 | unbinary 159 | unhex 160 | 161 | ;;;; STATE ;;;; 162 | set-state! 163 | state 164 | state-atom 165 | 166 | ;;;; SHAPE ;;;; 167 | 168 | ;; 2D Primitives 169 | arc 170 | ellipse 171 | line 172 | point 173 | quad 174 | rect 175 | triangle 176 | 177 | ;; 3D Primitives 178 | box 179 | sphere 180 | sphere-detail 181 | 182 | ;; Attributes 183 | ellipse-mode 184 | no-smooth 185 | rect-mode 186 | smooth 187 | stroke-cap 188 | stroke-join 189 | stroke-weight 190 | 191 | ;; Curves 192 | bezier 193 | bezier-detail 194 | bezier-point 195 | bezier-tangent 196 | curve 197 | curve-detail 198 | curve-point 199 | curve-tangent 200 | curve-tightness 201 | 202 | ;; Loading & Displaying 203 | load-shape 204 | shape 205 | shape-mode 206 | 207 | ;; Vertex 208 | begin-contour 209 | begin-shape 210 | bezier-vertex 211 | curve-vertex 212 | end-contour 213 | end-shape 214 | quadratic-vertex 215 | texture 216 | texture-mode 217 | vertex 218 | 219 | ;;;; LIGHTS, CAMERA ;;;; 220 | 221 | ;; Camera 222 | begin-camera 223 | camera 224 | end-camera 225 | frustum 226 | ortho 227 | perspective 228 | print-camera 229 | print-projection 230 | 231 | ;; Coordinates 232 | model-x 233 | model-y 234 | model-z 235 | screen-x 236 | screen-y 237 | screen-z 238 | 239 | ;; Lights 240 | ambient-light 241 | directional-light 242 | light-falloff 243 | light-specular 244 | lights 245 | no-lights 246 | normal 247 | point-light 248 | spot-light 249 | 250 | ;; Material Properties 251 | ambient 252 | ambient-float 253 | ambient-int 254 | emissive 255 | emissive-float 256 | emissive-int 257 | shininess 258 | specular 259 | 260 | ;;;; ENVIRONMENT ;;;; 261 | current-frame-rate 262 | current-graphics 263 | cursor 264 | cursor-image 265 | ;;defsketch 266 | focused 267 | frame-count 268 | frame-rate 269 | height 270 | no-cursor 271 | sketch 272 | target-frame-rate 273 | width 274 | 275 | ;;;; INPUT ;;;; 276 | 277 | ;; Keyboard 278 | key-as-keyword 279 | key-code 280 | key-coded? 281 | key-pressed? 282 | raw-key 283 | 284 | ;; Mouse 285 | mouse-button 286 | mouse-pressed? 287 | mouse-x 288 | mouse-y 289 | pmouse-x 290 | pmouse-y 291 | 292 | ;; Time & Date 293 | day 294 | hour 295 | millis 296 | minute 297 | month 298 | seconds 299 | year 300 | 301 | ;;;; OUTPUT ;;;; 302 | 303 | ;; Files 304 | end-raw 305 | 306 | ;; Image 307 | save 308 | save-frame 309 | 310 | ;;;; STRUCTURE ;;;; 311 | delay-frame 312 | exit 313 | no-loop 314 | pop-style 315 | push-style 316 | redraw 317 | start-loop 318 | 319 | ;;;; MIDDLEWARE ;;;; 320 | ;; fun-mode 321 | ;; navigation-2d 322 | ;; navigation-3d 323 | ] 324 | :refer-macros [with-translation defsketch]] 325 | [quil.middleware :as m] 326 | 327 | )) 328 | 329 | (enable-console-print!) 330 | 331 | (defn create-canvas [id] 332 | (let [el (.createElement js/document "canvas")] 333 | (aset el "id" (str id)) 334 | (aset el "style" "clear: both;") 335 | (.appendChild (.-body js/document) el))) 336 | 337 | 338 | ; define function which draws spiral 339 | (defn draw [] 340 | ; make background white 341 | (background 255) 342 | 343 | ; move origin point to centre of the sketch 344 | ; by default origin is in the left top corner 345 | (with-translation [(/ (q/width) 2) (/ (q/height) 2)] 346 | ; parameter t goes 0, 0.01, 0.02, ..., 99.99, 100 347 | (doseq [t (range 0 100 0.01)] 348 | ; draw a point with x = t * sin(t) and y = t * cos(t) 349 | (point (* t (q/sin t)) 350 | (* t (q/cos t)))))) 351 | 352 | (create-canvas "trigonometry") 353 | (defsketch trigonometry 354 | :host "trigonometry" 355 | :size [300 300] 356 | :draw draw) 357 | 358 | 359 | 360 | (create-canvas "shapes") 361 | (defsketch shapes 362 | :host "shapes" 363 | :size [300 300] 364 | :draw (fn [] 365 | ;; x1 y1 x2 y2 366 | (q/rect 50 50 100 100) 367 | 368 | ;; x y width height 369 | (q/ellipse 90 250 90 70) 370 | 371 | ;; x1 y1 x2 y2 x3 y3 372 | (q/triangle 200 20 175 75 250 75) 373 | 374 | ;; x1 y1 x2 y2 375 | (q/line 230 150 290 220) 376 | (q/line 230 220 290 150) 377 | )) 378 | 379 | (defn fill-orange [] 380 | (q/fill 252 90 44)) 381 | 382 | (defn fill-pink [] 383 | (q/fill 241 104 176)) 384 | 385 | (defn fill-blue [] 386 | (q/fill 45 119 242)) 387 | 388 | (defn black-stroke [] 389 | (q/stroke 0 0 0)) 390 | 391 | (defn draw-color-and-shape [] 392 | (fill-orange) 393 | ;; x1 y1 x2 y2 394 | (q/rect 50 50 100 100) 395 | 396 | (fill-blue) 397 | (q/no-stroke) 398 | ;; x y width height 399 | (q/ellipse 90 250 90 70) 400 | 401 | (fill-pink) 402 | (black-stroke) 403 | ;; x1 y1 x2 y2 x3 y3 404 | (q/triangle 200 20 175 75 250 75) 405 | 406 | ;; x1 y1 x2 y2 407 | (q/line 230 150 290 220) 408 | (q/line 230 220 290 150)) 409 | 410 | (create-canvas "color-and-shape") 411 | (defsketch color-and-shape 412 | :host "color-and-shape" 413 | :size [300 300] 414 | :draw draw-color-and-shape) 415 | 416 | 417 | 418 | (create-canvas "pink-triangles") 419 | (defn draw-pink-triangles [] 420 | (no-stroke) 421 | 422 | (fill 244 213 221) ;; #f4d5dd 423 | (triangle 20 20, 60 90, 15 60) 424 | 425 | (fill 249 202 216) ;; #f9cad8 426 | (triangle 220 210, 280 260, 215 240) 427 | 428 | (fill 232 181 188) ;; #e8b5bc 429 | (triangle 150 40, 227 50, 90 170)) 430 | 431 | (defsketch pink-triangles 432 | :host "pink-triangles" 433 | :size [300 300] 434 | :draw draw-pink-triangles) 435 | -------------------------------------------------------------------------------- /src/clojure_cup_2015/server.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-cup-2015.server 2 | (:require [clojure.java.io :as io] 3 | [compojure.core :refer [GET defroutes]] 4 | [compojure.route :refer [resources]] 5 | [ring.middleware.reload :as reload] 6 | [ring.middleware.defaults :refer [wrap-defaults api-defaults]] 7 | [environ.core :refer [env]] 8 | [ring.adapter.jetty :refer [run-jetty]]) 9 | (:gen-class)) 10 | 11 | (defroutes routes 12 | (GET "/" _ (slurp (io/resource "public/index.html"))) 13 | (resources "/")) 14 | 15 | (def http-handler 16 | (wrap-defaults routes api-defaults)) 17 | 18 | (defn run-web-server [& [port]] 19 | (let [port (Integer. (or port (env :port) 10555))] 20 | (println (format "Starting web server on port %d." port)) 21 | (run-jetty http-handler {:port port :join? false}))) 22 | 23 | (defn -main [& [port]] 24 | (run-web-server port)) 25 | -------------------------------------------------------------------------------- /util/deploy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | lein clean 4 | lein uberjar 5 | 6 | aws s3 --region eu-central-1 sync --delete resources/public/ s3://landofquil.we-do-fp.berlin/ 7 | --------------------------------------------------------------------------------