├── .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 |
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 |
--------------------------------------------------------------------------------