├── .editorconfig
├── .gitignore
├── LICENSE.md
├── README.md
├── homework
├── 00-intro-hw.md
├── 01-node-hw.md
├── 02-heroku-hw.md
├── 03-mongo-hw.md
├── 04-raspberry-hw.md
├── 05-midterm-hw.md
├── 07-audio-hw.md
├── 08-video-hw.md
├── 09-language-hw.md
├── 10-learning-hw.md
├── final.md
└── midterm.md
├── lessons
├── 00-intro
│ ├── 00-intro.md
│ └── img
│ │ ├── LICENSE.md
│ │ ├── atm.jpg
│ │ ├── bank-teller.jpg
│ │ ├── container.jpg
│ │ ├── harmonic_table.png
│ │ ├── notes.png
│ │ ├── spectrogram.png
│ │ └── waveform_visual.png
├── 01-node
│ ├── 01-node.md
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ └── style.css
│ ├── server.js
│ ├── src
│ │ ├── namer.js
│ │ └── os-info.js
│ └── templates
│ │ ├── changename.html
│ │ ├── identity.html
│ │ ├── index.html
│ │ └── nameset.html
├── 02-heroku
│ ├── .babelrc
│ ├── .gitignore
│ ├── 02-heroku.md
│ ├── img
│ │ ├── 01-template.png
│ │ ├── 02-clone-mode.png
│ │ ├── 03-hello.png
│ │ └── 04-oopsie.png
│ ├── package-lock.json
│ ├── package.json
│ ├── server
│ │ └── index.js
│ └── src
│ │ ├── App.jsx
│ │ ├── ServerInfo.jsx
│ │ └── Welcome.jsx
├── 03-persistence
│ ├── 03-persistence.md
│ ├── Procfile
│ ├── img
│ │ ├── mlab-01.png
│ │ ├── mlab-02.png
│ │ ├── postman-json-body.png
│ │ ├── postman-json-headers.png
│ │ ├── smocking.jpg
│ │ ├── webapp-diagram.ai
│ │ └── webapp-diagram.png
│ ├── package-lock.json
│ ├── package.json
│ └── src
│ │ ├── json
│ │ ├── app.js
│ │ └── data.json
│ │ ├── mongo-basic
│ │ └── app.js
│ │ └── trivial
│ │ └── server.js
├── 04-raspberry
│ ├── 04-raspberry.md
│ ├── code
│ │ ├── .gitignore
│ │ ├── index.js
│ │ ├── logging-test.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── yarn-error.log
│ ├── hw
│ │ ├── get_temp_range.js
│ │ ├── make_test_data.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ └── test.log
│ └── img
│ │ ├── circuit.jpg
│ │ ├── hostname-config.png
│ │ └── installing-os-part1.png
├── 05-midterm
│ └── 05-midterm.md
├── 06-osc
│ ├── 06-osc.md
│ ├── img
│ │ ├── appkettle.png
│ │ ├── basic-envelope.png
│ │ ├── osc-controlling-sequencer.png
│ │ ├── osc-multiple-parameters.png
│ │ ├── osc-trigger-env.png
│ │ ├── oscillator.png
│ │ ├── processing-osc.png
│ │ ├── sharks.jpg
│ │ ├── squares.png
│ │ └── unimpressive.png
│ ├── patcher
│ │ ├── silly-dumb-node-thing
│ │ │ ├── .gitignore
│ │ │ ├── code
│ │ │ │ └── silly-dumb.js
│ │ │ ├── patchers
│ │ │ │ └── silly-dumb-node-thing.maxpat
│ │ │ └── silly-dumb-node-thing.maxproj
│ │ └── simple-beap.maxpat
│ ├── processing
│ │ └── patatap_osc
│ │ │ └── patatap_osc.pde
│ └── server
│ │ ├── index.js
│ │ ├── package-lock.json
│ │ └── package.json
├── 07-audio
│ ├── 07-audio.md
│ ├── img
│ │ ├── attribution.txt
│ │ ├── audio-context-warning.png
│ │ └── spectrogram_of_violin.png
│ ├── meyda-app
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ │ ├── app.js
│ │ │ └── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
│ ├── meyda-demo
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ │ ├── app.jsx
│ │ │ ├── components
│ │ │ │ ├── ClockFace.jsx
│ │ │ │ └── RootComponent.jsx
│ │ │ └── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
│ └── tonetest
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ ├── app.jsx
│ │ ├── components
│ │ │ ├── ClockFace.jsx
│ │ │ └── RootComponent.jsx
│ │ └── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
├── 08-video
│ ├── 08-video.md
│ ├── flow-app
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ │ ├── app.js
│ │ │ ├── flow.js
│ │ │ └── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
│ ├── img
│ │ ├── attribution.txt
│ │ ├── illusion.jpg
│ │ ├── kyle-files.png
│ │ ├── smile.png
│ │ └── wave.png
│ └── ml5-app
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ ├── app.js
│ │ └── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
├── 09-language
│ ├── 09-language.md
│ └── poem-docu
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ ├── app.jsx
│ │ ├── components
│ │ │ ├── ClockFace.jsx
│ │ │ ├── PoemDisplay.jsx
│ │ │ └── RootComponent.jsx
│ │ └── index.html
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── poem
│ │ └── poem.js
│ │ ├── public
│ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
├── 10-learning
│ ├── 10-learning.md
│ ├── commander-test
│ │ ├── myscript.js
│ │ ├── package-lock.json
│ │ └── package.json
│ ├── img
│ │ └── learning
│ │ │ ├── learning.001.jpeg
│ │ │ ├── learning.002.jpeg
│ │ │ ├── learning.003.jpeg
│ │ │ ├── learning.004.jpeg
│ │ │ └── learning.005.jpeg
│ └── teachable-machine-app
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── README.md
│ │ ├── app
│ │ ├── app.js
│ │ ├── drawDetector
│ │ │ └── drawDetectorApp.js
│ │ ├── heartHands
│ │ │ ├── heart.js
│ │ │ └── heartHandsApp.js
│ │ ├── imageDetector
│ │ │ └── imageDetectorApp.js
│ │ ├── index.html
│ │ └── soundDetector
│ │ │ └── soundDetectorApp.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ └── style.css
│ │ ├── scripts
│ │ └── imageDownloader.js
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
├── 11-advanced
│ ├── 11-advanced.md
│ └── game-app
│ │ ├── .gitignore
│ │ ├── LICENSE.md
│ │ ├── Procfile
│ │ ├── README.md
│ │ ├── app
│ │ ├── app.js
│ │ ├── game.js
│ │ ├── gameClient.js
│ │ ├── index.html
│ │ └── util.js
│ │ ├── package-lock.json
│ │ ├── package.json
│ │ ├── public
│ │ └── style.css
│ │ ├── server.js
│ │ ├── webpack.config.js
│ │ └── webpack.dev.config.js
├── 13-gesture
│ └── 13-gesture.md
├── 14-back4app-experiment
│ ├── .gitignore
│ ├── LICENSE.md
│ ├── Procfile
│ ├── README.md
│ ├── app
│ │ ├── app.jsx
│ │ ├── components
│ │ │ ├── ClockFace.jsx
│ │ │ ├── DumbTwitter.jsx
│ │ │ ├── DumbTwitterForm.jsx
│ │ │ ├── DumbTwitterList.jsx
│ │ │ └── RootComponent.jsx
│ │ └── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── bundle.js.LICENSE.txt
│ │ └── style.css
│ ├── server.js
│ ├── webpack.config.js
│ └── webpack.dev.config.js
└── TEMPLATE.md
├── links.md
├── makeup
└── 00-intro.md
├── package.json
├── reading_list.md
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = tab
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 |
9 | [package.json]
10 | indent_style = space
11 | tab_width = 2
12 |
13 | [*.yaml]
14 | indent_style = space
15 | tab_width = 2
16 |
17 | [*.md]
18 | indent_style = space
19 | tab_width = 2
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | *.pdf
3 |
--------------------------------------------------------------------------------
/homework/00-intro-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 00
2 |
3 | ## Due Date
4 | This assignment follows the first lesson, [00-intro](../lessons/00-intro/00-intro.md). There is a written portion! It must be turned in by midnight the day before class. You can turn in the assignment by sending it to me in an email attachment, or by sending me a link to a github repository.
5 |
6 | ## Assignment
7 | ### Reading
8 | - Aron Z. Lewis, _Inside the Digital Sensorium_, https://aaronzlewis.com/blog/2021/01/17/inside-the-digital-sensorium/
9 |
10 | The very first thing we do in the second class will be to discuss this reading. The article isn't long, and I recommend reading it twice if you can, once after class and once again before we meet the second time. Some things that you might want to think about:
11 |
12 | - Which of the eight short stories do you identify with most?
13 | - Do you think a website is like a physical place? How do you feel about comparing a website to a sense organ?
14 | - What are the parts of this article that make you feel hopeful? What parts make you uncomfortable?
15 | - What is Instagram? An app? A product? A company? A collection of images and videos? All of these? None of them?
16 |
17 | If you want to make sure you're prepared for discussion, a nice technique is QCQ - Quote, Comment, Question. Make sure that you write down one quote from the reading, that you have some comment on it, and that you have a question about it.
18 |
19 | ### Writing
20 | In addition to the reading assignment this week, there will be a brief writing assignment. I want you to choose a piece of networked art, and to tell me how it works. Your interpretation of networked art can be as broad as you like, but it should be a piece that has multiple, distributed, coordinated parts. Similar to the breakdown we did in class, you should be able to answer:
21 |
22 | - What are the major parts of the system? What are their responsibilities?
23 | - How does the behavior of the system change if one of the parts is non-responsive?
24 | - What are the hardware and software components of each part? Can you make any specific guesses?
25 | - How do the parts communicate? What protocols do they use?
26 |
27 | Here's a list of some networked art pieces you can use:
28 | - David Bowen: https://www.dwbowen.com/telepresentwater — Tele-present water
29 | - Collective Of Two: https://vimeo.com/386776425 — Invisible Hand
30 | - eCLOUD: http://www.ecloudproject.com/
31 | - The Living: http://cheraudesir.com/the-living-twin-mirror-2017/ - Twin Mirror
32 | - Ronin Tool: https://100r.co/site/ronin.html
33 | - The Living: https://architizer.com/projects/living-light/ - Living Light
34 | - Matt Roberts: https://vimeo.com/20500963 - Waves
35 | - Matt Kenyon: https://www.swamp.nu/projects/spore - Spore 1.1
36 | - Lots more here https://www.postscapes.com/networked-art/
37 |
38 | ### Extra Reading
39 |
40 | If you're relatively unfamiliar with Node, Git, or JavaScript itself, I *highly* recommend brushing up before coming to class on Wednesday.
41 |
42 | #### Git
43 | - http://marklodato.github.io/visual-git-guide/index-en.html
44 | - https://rogerdudler.github.io/git-guide/
45 |
46 | #### Node
47 | - https://medium.com/@jesterxl/introduction-bde654b5670e (don't worry so much about all the specific libraries, but _do_ think about they do)
48 |
49 | #### JavaScript
50 | - https://javascript.info/
51 |
52 |
53 | ## Handing it in
54 | The only part of this assignment that must be handed in is the writing assignment. Again, about 500 words should be enough. For this assignment, you can either (1) create a git repository and check the writing in as a .txt or a .md file, or you can (2) email me the assignment at st2774@nyu.edu.
55 |
--------------------------------------------------------------------------------
/homework/01-node-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 01
2 |
3 | ## Due Date
4 |
5 | This assignment follows the second lesson, [01-node](../lessons/01-node/01-node.md).
6 |
7 | ## Reading
8 |
9 | - Baker, Kevin T. _Model Metropolis_ https://logicmag.io/play/model-metropolis/
10 |
11 | ## Assignment - Text Adventure
12 |
13 | Check out this site
14 | http://silly-suggestion.herokuapp.com/
15 |
16 | This is a text adventure realized entirely as a Node Express app. Your assignment is to make your own text adventure, realized in the same way.
17 |
18 | ### Description
19 |
20 | A text adventure is a kind of video game or interactive novel. Typically (though not always) the player navigates through a dungeon, exploring a series of rooms. The player can perform various actions in each room. The simplest text adventure lets the player choose from a list of options. More advanced games might take in a string of text, and then parse the text in some way to determine what happens next. Complex games might record other statistics for a player, like their standing with various factions, their age, health, height, and so on. These and other factors might determine what options are available to the player at any given point.
21 |
22 | ### Requirements
23 | Overall, I encourage you to push your skills. The base requirements for this assignment are small, but if Express and Node are very familiar to you, then try to add something that flexes a new skill you haven't built up yet. There are some hard requirements for this text adventure though:
24 |
25 | - All of the state of the game must be stored on the server. That means no javascript on the client side.
26 | - The server must be implemented using Express, similar to what we saw in class.
27 | - You're not required to use .html template files, but it's strongly encouraged.
28 | - Don't forget to .gitignore your `node_modules` folder.
29 | - Don't forget to include a README.md.
30 | - The page must be styled using a .css file. That file can be very simple, but it must exist. You can use just one .css file for the whole game.
31 | - The player must be able to collect items and place those items in an inventory. It must be possible to check the inventory at any time (unless maybe the player has gone blind, or is injured, or for some lore-related reason cannot check their inventory).
32 | - The game must have at least one "bad" ending and one "good" ending. The precise meaning of "bad" and "good" are up to you, though in one example, falling into a pit could be the "bad" ending, while escaping the dungeon is a "good" ending.
33 | - A fantasy theme is by no means required. The player doesn't have to navigate a literal labyrinth either. Figuring out which classes to take, for example, is its own kind of labyrinth, and would be an excellent theme for an adventure game.
34 |
35 | In addition, you must take on at least one of these optional requirements. If you're feeling punchy, try and push yourself to take on more than one.
36 | - Using CSS classes, change the appearance of the page depending on the state of the game. For example, if the player is in a garden, the background could be green.
37 | - Implementing an online game with state stored on the server has an issue: there's only one "inventory" that all players share. Use the Express cookie-parser middleware, and use this create several "inventories", one for each player.
38 | - Games are more replayable if the experience varies from one play-through to the next. Add some random elements to your game, so that the exact gameplay experience is different each time you play.
39 | - In class we saw how to use forms to submit text to the server. Using a form, accept text or some other input from the player. Maybe they can set their name, or they have to pronounce a magic spell, or give a password.
40 | - Add multimedia elements to your page. This could include background music, images, or maybe even something fancier. (Don't go too crazy with animations, this is about server-side programming after all.)
41 | - What happens if you have a very clever user, who tries to access a page by typing directly in the address bar? Suppose they type the name of a room that doesn't exist? Can your server handle that? What does its 404 page look like?
42 |
43 | ### Grading
44 | This largely a creative assignment, but creativity is not part of your grade (at least for this assigment). I'm grading this assignment entirely on completeness, so provided (1) your game works and (2) you meet all the requirements, you should be in perfect shape.
45 |
46 | ## Handing it in
47 | Please send me a link to a github repository where your text adventure can be found. I should be able to pull your repository, run `npm install`, and then start up a server and run your text adventure. Please don't forget to create a README.md, even if it only contains a single sentence. If there's anything special I should know about running your game, please add it to the README.
48 |
--------------------------------------------------------------------------------
/homework/02-heroku-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 2 - React + Heroku
2 |
3 | ## Reading
4 |
5 | Brain, Tega. _Hack the Planet: Tega Brain on Leaks, Glitches, and Preposterous Futures_ Logic Magazine. Retrieved https://logicmag.io/nature/hack-the-planet-tega-brain-on-leaks-glitches-and-preposterous-futures/
6 |
7 | ## Tic Tac Toe
8 |
9 | Start by forking the starter template I made for you at https://github.com/starakaj/react-express-starter. Next, implement tic-tac-toe.
10 |
11 | ```
12 | a b c
13 | | |
14 | 1 - | - | -
15 | _____|_____|_____
16 | | |
17 | 2 - | - | -
18 | _____|_____|_____
19 | | |
20 | 3 - | - | -
21 | | |
22 | ```
23 |
24 | In case you need a reminder, the way tic tac toe works, two players take turns putting an X or an O in each square. If either player gets three in a row, including diagonals, that player wins.
25 |
26 | ### Requirements
27 | - The game must display which player, X or O, has the current turn.
28 | - There must be an indication when one player or the other wins.
29 | - Use a different React component for the game container and for the squares.
30 | - Put it up on Heroku
31 | - Choose at least one of the optional requirements.
32 |
33 | ### Optional
34 | - There must be a way to reset the game (refreshing the page doesn't count).
35 | - Let the players set their names at the start of the game.
36 | - Color the squares differently for X and O using CSS classes.
37 | - Make it possible to undo a move.
38 | - Set the number of rows or columns at the start of the game.
39 |
40 | ### Considerations
41 | - The trickiest part of this assignment is handling clicks on the squares. The individual squares are dumb—they can't know anything about the state of the game. Rather, each square should have an `onClick` prop, similar to a button.
42 | - You don't need to pass a different function down to each of the boxes. Rather, each box can call its `onClick` function with some information (for example the row and column) that identifies that box.
43 | - If you chose to let the players set their names, you probably don't want to use a `post` Express handler. Remember, React has the state, not Express.
44 |
45 | ### Handing it in
46 |
47 | Please email me a github repo, along with a link to your deployed Heroku app.
48 |
--------------------------------------------------------------------------------
/homework/03-mongo-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 3 - React + Heroku + Mongo
2 |
3 | ## Reading
4 |
5 | Let me think about it, I'll get it to you soon
6 |
7 | ## Dumb Twitter with filters
8 |
9 | In class we made Dumb Twitter (If you weren't in class, be sure to follow the notes so that you too can build something like dumb-twitter.herokuapp.com). It's like Twitter, but dumb. It's especially dumb in that there's only one big, fat feed. There's no way to look just at tweets made by a particular person, for example. There's also no way to delete a tweet, which as we all know is _critically_ important.
10 |
11 | ### Requirements
12 | - Take the version of Dumb Twitter that we made in class. Make it possible to view only the tweets from a particular person.
13 | - This will require adding a server endpoint that lets you filter over your list of tweets.
14 | - You might find Express request params to be very helpful here:
15 |
16 | ```js
17 | // See https://expressjs.com/en/api.html#path-examples
18 | app.get('/user/:id', function (req, res) {
19 | res.send('user ' + req.params.id);
20 | });
21 | ```
22 |
23 | - Make it possible to delete a Tweet. You might consider using the DELETE HTTP verb, in conjunction with https://expressjs.com/en/api.html#app.delete.method
24 | - Remember, you'll have to set `method: "DELETE"` in your fetch.
25 | - Use MongoDB to store your data
26 | - Put it up on Heroku
27 | - You must complete NONE of the optional parts. But if you're feeling eager, you should go for it.
28 |
29 | ### Optional
30 | - Add test search to your Dumb Twitter. Make it possible to search for hashtags
31 | - Rather than forcing people to type their name with every tweet, have them log in to an account
32 | - Add a date to each tweet as it's created, making it possible to search over tweets by date
33 | - Style your page a bit so it doesn't look crappy
34 |
35 | ### Handing it in
36 |
37 | Please email me a github repo, along with a link to your deployed Heroku app.
38 |
--------------------------------------------------------------------------------
/homework/04-raspberry-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 4 - Raspberry Weather Station
2 |
3 | ## Reading
4 |
5 | Look in 05-midterm-hw
6 |
7 | ## Weather Station
8 |
9 | Compared to some of the other homework that you've had previously, this one is going to seem very simple. All you need to do is modify the existing sensor reading code to record temperature and humidity readings. Then you need to write a quick script to scan a log file and report min + max values.
10 |
11 | ### Requirements
12 | - Modify the existing code on the Raspberry Pi so that it records temperature to a log.
13 | - Log that high and low somewhere using `bunyan`.
14 | - Write a Node script that will take a calendar date and a log file as input, returning the temperature high and low for that day.
15 | - You might need to read "https://nodejs.org/en/knowledge/command-line/how-to-parse-command-line-arguments/" for help on processing command line input.
16 |
17 | ### Handing it in
18 | - Please email me a github repo containing the source code. Please include with it a sample log file recorded from the Raspberry Pi.
19 | - You might need to use `scp` to copy a file from your Raspberry Pi to your desktop.
20 |
--------------------------------------------------------------------------------
/homework/05-midterm-hw.md:
--------------------------------------------------------------------------------
1 | # Midterm Preparation
2 |
3 | ## Reading
4 | We're preparing for a group project next week, so the reading should get you in the mindset of group software work.
5 |
6 | - "The Scrum Guide" which you can download here https://www.scrumguides.org/index.html.
7 | - "Why 'Agile' and especially Scrum are terrible" https://michaelochurch.wordpress.com/2015/06/06/why-agile-and-especially-scrum-are-terrible/
8 | - Watch "Connected Worlds" https://nysci.org/home/exhibits/connected-worlds/
9 |
10 | ## Miderm Assignment
11 |
12 | This isn't a full description of the assignment, but rather it's just a bit of prep work to get you ready for the assignment. We're going to be using the midterm to put together all the knowledge that we've accumulated so far. The project will:
13 |
14 | - Take readings from a Raspberry Pi.
15 | - Push that data server and store it in MongoDB.
16 | - Present that data through a client-facing API.
17 | - Display the data in a client-side, React powered web app.
18 |
19 | It's a bit of a funny way to work, in that I'm telling you what pieces you have to use but not what you should use them for. But this basic backbone is extremely flexible and can drive a huge number of different projects. So prepare for the next class by answering the following questions:
20 |
21 | - What kind of story can you tell with data gathered from a Raspberry Pi?
22 | - What kind of sensor data do you want to work with?
23 | - How can you analyze that data once its in a database?
24 | - What might someone on the client side want to do with that data?
25 | - How does that data become meaningful for someone?
26 |
--------------------------------------------------------------------------------
/homework/07-audio-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 07
2 |
3 | ## Due Date
4 |
5 | This assignment follows the audio analysis lesson, [07-audio](../lessons/07-audio/07-audio.md). It must be turned in by midnight, March 31.
6 |
7 | ## Reading
8 |
9 | Optionally, watch this very fun interview with Tarik Barri - https://www.youtube.com/watch?v=xtKnF_9XM_o
10 |
11 | ## Assignment - Audio Visualizer
12 |
13 | Take a look at this
14 | https://willianjusten.com.br/audio-experiments/triangles/
15 |
16 | This is a very simple, yet effective audio visualizer. A number of triangles rotates around a center point. The size of each triangle is proportional to the energy in a particular part of the audio spectrum. You could use the "loudness" feature of the Meyda analyzer, which contains a property called "specific". Each element of this array contains the apparent loudness of a different portion of the audio spectrum. So, you could use this feature to scale the radius of each triangle.
17 |
18 | ### Description
19 |
20 | An audio visualizer creates an evolving and dynamic visual scene, parametrized in some way to reflect the salient features of an audio source. In the case above, the radius of each triangle is proportional to the energy in the spectrum. A visualizer could also draw on the chroma, or the spectral centroid, or any number of other features. For this assignment, make an audio visualizer, using either a microphone or sound file as an audio source.
21 |
22 | ### Requirements
23 | One word of advice: try not to spend too much time on getting a specific piece of data out of the audio. There are problems like accurately detecting beat, or determining the exact point in time at which a new note begins, that can be very difficult and time consuming. Try to work with the data that you have available.
24 |
25 | Requirements:
26 | - You may use any graphics library that you like. If you're familiar with WebGL or another drawing technology, then feel free to use that instead of p5 in instance mode. However, you should write your own visualizer code. It's fine to be inspired by something that you find on shadertoy, but it's not acceptible to copy something that you found online for the visual portion of the assignment.
27 | - You must use at least two of the analysis parameters exposed by Meyda.js.
28 |
29 | You must also complete one of these optional requirements:
30 | - Control the parameters of your audio visualization with dat.gui
31 | - Add a way to switch between different audio tracks.
32 | - Add a way to switch between different video "scenes." For example, you might have a p5 draw function that works in a completely different way, depending on the value of a toggle.
33 |
34 | ### Grading
35 | Again, this is a creative assignment, but creativity is not part of the grade. I'm excited to see what you come up with, but it's most important to me that you complete the requirements. If it's clear that you spent a bit of time with the assignment, and that you worked with Meyda enough to come up with a visualization that you're happy with, then you have nothing to worry about.
36 |
37 | ## Handing it in
38 | Please send me a link to a github repository where your visualizer can be found. I should be able to pull your repository, run `npm install`, and then start up a server and run your visualizer. Please don't forget to create a README.md, even if it only contains a single sentence. If there's anything special I should know about running your visualizer, please add it to the README. The README is also a great place to talk about any problems that you ran into, or to highlight any particular things that you're especially proud of. If your visualizer works best with a particular piece of audio, please include a link where I can find it, but don't add the audio file to your repository.
39 |
--------------------------------------------------------------------------------
/homework/08-video-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 08
2 |
3 | ## Due Date
4 |
5 | This assignment follows the video analysis lesson, [08-video](../lessons/08-video/08-video.md). It must be turned in by midnight, April 7.
6 |
7 | ## Reading
8 |
9 | None, just relax.
10 |
11 | ## Assignment - Video into sound, or video into drawing
12 | In class we looked at two example of how to process video, one generating sound and the other creating a visualization. For this assignment, develop one of those processes further. If you've worked with Tone before, or you're more interested in sound, you can pursue that path. Otherwise you can do more drawing based on video data.
13 |
14 | ### Description
15 | If you choose to do some drawing based on video analysis, you might start from the optical flow example that we looked at in class. You're also free to take another one of the Computer Vision examples from Kyle's page and to start from there. If you'd rather work from face data instead, start from the face tracking example. Rather than sending out particles from the points of optical flow, do something else. Things you might experiment with:
16 |
17 | #### Video
18 | - Drawing text based on movement
19 | - Distorting a shape using video movement
20 | - Directing a swarm of particles using the edges in the video
21 | - Giving the video an animated color depending on movement
22 | - Making an "instagram filter" by drawing shapes or images on top of the face
23 |
24 | #### Audio
25 | - Add an audio effect to the processing chain, like reverb, filter or distortion. Control this with the face or with movement.
26 | - Control the playback of an audio file using the video, perhaps adjusting its speed using the position of your face.
27 | - Play a chord of multiple different notes. Maybe one note is controlled by each eye, and a third with the mouth.
28 |
29 | ### Requirements
30 | There are no hard requirements for this assignment, except that it must use Computer Vision in some way. So, it could be based on one of the CV examples from Kyle's page, or it could use the face tracking data from the ml5 example. You should also try to go beyond simply tweaking what we did in class.
31 |
32 | ### Grading
33 | Again, this is a creative assignment, but creativity is not part of the grade. I'm excited to see what you come up with, but it's most important to me that you complete the requirements. If it's clear that you spent a bit of time with the assignment, and you experimented with something new, then you have nothing to worry about.
34 |
35 | ## Handing it in
36 | Please send me a link to a github repository where your project can be found. I should be able to pull your repository, run `npm install`, and then start up a server and run the example. Please don't forget to create a README.md, even if it only contains a single sentence. The README is also a great place to talk about any problems that you ran into, or to highlight any particular things that you're especially proud of. If you're doing some kind of complex audio mapping, please describe what you were trying to achieve in the README.
37 |
--------------------------------------------------------------------------------
/homework/09-language-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 09
2 |
3 | ## Due Date
4 |
5 | This assignment follows the natural language processing lesson, [09-language](../lessons/09-language/09-language.md). It must be turned in by midnight, April 14.
6 |
7 | ## Assignment - Automatically generated poem
8 | In class we looked at how to draw text from a website, and how to rearrange that text into something like a poem. We looked at how to count syllables, how to register parts of speech, and how to figure out (kind of) when words rhymed. For homework I want you to build on what we talked about in class. Using the poem starter at https://github.com/starakaj/poem-starter, modify the contents of `poem/poem.js` to read in a page from the Internet, do something with its contents, and then return some text to the user that has a poetic form.
9 |
10 | ### Description
11 | After copying the starter, open up the file at `poem/poem.js`. Using the techniques we talked about in class, pull down a webpage and try to do something interesting with its contents. The file should export a `makePoem` function, so that the server (at `server.js` ) can return a poem at the `/poem` endpoint. You have many options open to you, the only requirement is that the function must return an array of text, each element of which is one line of something poetic.
12 |
13 | ### Requirements
14 | When I say that the text returned by `makePoem` must be poetic, it's not entirely clear what that means. A poem is simply a creative arrangement of text, so that certainly leaves you a lot of leeway. Some things that you might try include:
15 |
16 | - Pulling blocks of text containing a common word (look into stemming!)
17 | - Listing only words that have a "negative" or "positive" sentiment (you can use sentiment analysis for this)
18 | - Writing your own new sentences, using vocabulary drawn from the text
19 | - Writing lines with the same number of syllables
20 | - Writing a limerick
21 | - Cutting sentences in half, and then mixing them up and sticking them back together
22 |
23 | If you want, you're strongly encouraged to make the result into a single-page web application. You can use a React form (see [the lesson where we made dumb twitter](../lessons/03-persistence/03-persistence.md) for a refresher) to submit a page to the server, which then returns a poem for rendering. If you like, you can get creative with how the text is displayed. You might try:
24 |
25 | - Size words larger or smaller depending on some criteria
26 | - Arrange words to draw a picture
27 | - Analyze links from the starting page, and use this to draw a map of how pages are connected
28 |
29 | ### Grading
30 | Like other recent assignments, this is a creative assignment, but creativity is not part of the grade. I'm excited to see what you come up with, but it's most important to me that you complete the requirements. If it's clear that you spent a bit of time with the assignment, and you experimented with something new, then you have nothing to worry about.
31 |
32 | ## Handing it in
33 | Please send me a link to a github repository where your project can be found. I should be able to pull your repository, run `npm install`, and then run `npm run poem` to generate a poem. If you had the time, I should also be able to run `npm run watch` to see the poem in the browser. Please don't forget to create a README.md, even if it only contains a single sentence. The README is also a great place to talk about any problems that you ran into, or to highlight any particular things that you're especially proud of. If you're doing some kind of complex audio mapping, please describe what you were trying to achieve in the README.
34 |
--------------------------------------------------------------------------------
/homework/10-learning-hw.md:
--------------------------------------------------------------------------------
1 | # Homework 10
2 |
3 | ## Due Date
4 |
5 | This assignment follows the Teachable Machine lesson, [10-learning](../lessons/10-learning/10-learning.md). It must be turned in by midnight, April 21.
6 |
7 | ## Assignment - Teachable interface
8 | Go ahead into `lessons/10-learning/teachable-machine-app` and run `npm install`. Then go into `app.js` and make sure that `heartHands/heartHandsApp` is the source of the `setup` function. Now `npm run watch` and navigate to `localhost:3000`. Hopefully, when you make a heart with your hands, you'll see a flurry of pink hearts. What I'd like you to do in this assignment is to think about how Teachable Machine can be used as an interface.
9 |
10 | ### Description
11 | Simply put, make something with Teachable Machine. Check out this https://experiments.withgoogle.com/interplay-mode/view/
12 |
13 | Here, we basically have something not significantly more complicated than what we already made in class. The UI is a lot prettier, and it's playing with a nice video, but we already saw how to make something like this just the other day. What else can you imagine that might make use of some of what we saw how to do in class?
14 |
15 | - A drawing canvas, where the things that you draw emerge from the page when they are recognized
16 | - An adventure game, where you make hand signs to determine what action you take
17 | - Something like Berghain Trainer https://berghaintrainer.com/
18 | - A "conversation" with an animated character that can recognize certain words
19 | - An instagram filter (would combine nicely with the head tracker from two lessons ago)
20 | - A sonifier that analyzes your face and tries to play music that matches your mood
21 |
22 | ### Requirements
23 | You must use an original model, not one of the ones that we used in class. You may either upload the model to Google, or include it as part of your repo. You don't have to use p5, you don't even have to do any drawing at all. The important part is that you use an original model in your own code. Other than that, you have a lot of freedom on this assignment.
24 |
25 | ### Grading
26 | Like other recent assignments, this is a creative assignment, but creativity is not part of the grade. I'm excited to see what you come up with, but it's most important to me that you complete the requirements. If it's clear that you spent a bit of time with the assignment, and you experimented with something new, then you have nothing to worry about.
27 |
28 | ## Handing it in
29 | Please send me a link to a github repository where your project can be found. I should be able to pull your repository, run `npm install`, and then run `npm run watch` or `npm run start` to see your code in action. Please don't forget to create a README.md, even if it only contains a single sentence. The README is also a great place to talk about any problems that you ran into, or to highlight any particular things that you're especially proud of. If you're doing some kind of complex audio mapping, please describe what you were trying to achieve in the README.
30 |
--------------------------------------------------------------------------------
/lessons/00-intro/img/LICENSE.md:
--------------------------------------------------------------------------------
1 | #### container.jpg
2 | By Mr Snrub at the English language Wikipedia, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=7005472
3 |
--------------------------------------------------------------------------------
/lessons/00-intro/img/atm.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/atm.jpg
--------------------------------------------------------------------------------
/lessons/00-intro/img/bank-teller.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/bank-teller.jpg
--------------------------------------------------------------------------------
/lessons/00-intro/img/container.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/container.jpg
--------------------------------------------------------------------------------
/lessons/00-intro/img/harmonic_table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/harmonic_table.png
--------------------------------------------------------------------------------
/lessons/00-intro/img/notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/notes.png
--------------------------------------------------------------------------------
/lessons/00-intro/img/spectrogram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/spectrogram.png
--------------------------------------------------------------------------------
/lessons/00-intro/img/waveform_visual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/00-intro/img/waveform_visual.png
--------------------------------------------------------------------------------
/lessons/01-node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "01-node",
3 | "version": "1.0.0",
4 | "description": "Lesson 01: An introduction to Node",
5 | "main": "src/server.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "serve": "node src/server.js",
9 | "info": "node src/os-info.js"
10 | },
11 | "author": "Sam Tarakajian",
12 | "license": " CC-BY-SA-4.0",
13 | "dependencies": {
14 | "chance": "^1.1.4",
15 | "cookie-parser": "^1.4.4",
16 | "express": "^4.17.1",
17 | "express-useragent": "^1.0.13"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/lessons/01-node/public/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: aqua;
3 | }
--------------------------------------------------------------------------------
/lessons/01-node/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const { randomName, randomPlace } = require("./src/namer");
3 | const port = process.env.PORT || 3000;
4 | const fs = require("fs");
5 |
6 | // Create an instance of the express application
7 | const app = express();
8 |
9 | // Serve the public directory as static
10 | app.use(express.static("public"));
11 |
12 | let counter = 0;
13 | let name = null;
14 |
15 | app.get("/", (req, res) => {
16 | counter++;
17 | let htmldoc = fs.readFileSync("./templates/index.html", "utf8");
18 | htmldoc = htmldoc.replace("%%%VIEWS%%%", counter);
19 | res.send(
20 | htmldoc
21 | );
22 | });
23 |
24 | // You can use replace to pretend like you're using React
25 | app.get("/identity", (req, res) => {
26 | const newName = randomName();
27 | const newAddress = randomPlace();
28 | let htmldoc = fs.readFileSync("./templates/index.html", "utf8");
29 | htmldoc = htmldoc.replace("%%%NAME%%%", newName);
30 | htmldoc = htmldoc.replace("%%%PLACE%%%", newAddress);
31 | res.send(
32 | htmldoc
33 | );
34 | });
35 |
36 |
37 | app.listen(port, () => {
38 | console.log(`Express is listening on port ${port}`);
39 | });
40 |
--------------------------------------------------------------------------------
/lessons/01-node/src/namer.js:
--------------------------------------------------------------------------------
1 | const chance = require("chance"); // load the chance module
2 | const c = new chance(); // Create an actual chance instace. See the docs.
3 |
4 | // Only run these lines if you're running the file as a script
5 | if (require.main === module) {
6 | console.log(`Your new random name is ${c.name()}`);
7 | console.log(`You live on ${c.street()} in ${c.state()}`);
8 | }
9 |
10 | module.exports = {
11 | randomName: () => c.name(),
12 | randomPlace: () => `${c.street()}, ${c.state()}`
13 | }
14 |
--------------------------------------------------------------------------------
/lessons/01-node/src/os-info.js:
--------------------------------------------------------------------------------
1 | const os = require("os");
2 |
3 | console.log(`Running on platform ${os.platform()}`);
4 | console.log(`Running on architecture ${os.arch()}`);
5 |
--------------------------------------------------------------------------------
/lessons/01-node/templates/changename.html:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lessons/09-language/poem-docu/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starter-react",
3 | "version": "0.0.1",
4 | "description": "A small scaffold to get you started using React with Webpack",
5 | "main": "server.js",
6 | "scripts": {
7 | "build": "webpack",
8 | "poem": "node poem/poem.js",
9 | "start": "webpack && node server.js",
10 | "watch": "NODE_ENV=development node server.js"
11 | },
12 | "dependencies": {
13 | "express": "^4.16.4",
14 | "jsx-loader": "^0.13.2",
15 | "osmosis": "^1.1.10",
16 | "pos": "^0.4.2",
17 | "react": "^16.8.6",
18 | "react-dom": "^16.8.6",
19 | "rhyme": "0.0.3",
20 | "sbd": "^1.0.17",
21 | "syllable": "^4.0.1",
22 | "webpack": "^4.30.0",
23 | "webpack-cli": "^3.3.0",
24 | "webpack-dev-middleware": "^3.7.2",
25 | "webpack-dev-server": "^3.10.3"
26 | },
27 | "engines": {
28 | "node": "12.x"
29 | },
30 | "repository": {
31 | "url": "https://glitch.com/edit/#!/starter-react"
32 | },
33 | "license": "MIT",
34 | "keywords": [
35 | "node",
36 | "glitch",
37 | "express"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/lessons/09-language/poem-docu/public/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Futura;
3 | }
--------------------------------------------------------------------------------
/lessons/09-language/poem-docu/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // init project
4 | const express = require('express');
5 | const { makePoem } = require("./poem/poem");
6 | const app = express();
7 | const port = process.env.PORT || 3000;
8 |
9 | // Special piece for running with webpack dev server
10 | if (process.env.NODE_ENV === "development") {
11 | const webpack = require('webpack');
12 | const webpackDevMiddleware = require('webpack-dev-middleware');
13 | const config = require('./webpack.dev.config.js');
14 | const compiler = webpack(config);
15 |
16 | // Tell express to use the webpack-dev-middleware and use the webpack.config.js
17 | // configuration file as a base.
18 | app.use(webpackDevMiddleware(compiler, {
19 | publicPath: config.output.publicPath,
20 | }));
21 | }
22 |
23 | // http://expressjs.com/en/starter/static-files.html
24 | app.use(express.static('public'));
25 |
26 | // http://expressjs.com/en/starter/basic-routing.html
27 | app.get("/", function(request, response) {
28 | response.sendFile(__dirname + '/app/index.html');
29 | });
30 |
31 | app.get("/poem", async function(_, response) {
32 | const lines = await makePoem();
33 | response.json(lines);
34 | });
35 |
36 | // listen for requests :)
37 | const listener = app.listen(port, function () {
38 | console.log('Your app is listening on port ' + port);
39 | });
40 |
--------------------------------------------------------------------------------
/lessons/09-language/poem-docu/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'production',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.jsx',
7 | output: {
8 | path: path.join(__dirname, 'public'),
9 | filename: 'bundle.js',
10 | },
11 | resolve: {
12 | extensions: ['.js', '.jsx'],
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.jsx?$/,
18 | loader: 'jsx-loader',
19 | exclude: /node_modules/,
20 | include: path.join(__dirname, 'app'),
21 | },
22 | ],
23 | },
24 | };
--------------------------------------------------------------------------------
/lessons/09-language/poem-docu/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'development',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.jsx',
7 | devtool: 'inline-source-map',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'bundle.js',
11 | publicPath: '/',
12 | },
13 | resolve: {
14 | extensions: ['.js', '.jsx'],
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.jsx?$/,
20 | loader: 'jsx-loader',
21 | exclude: /node_modules/,
22 | include: path.join(__dirname, 'app'),
23 | },
24 | ],
25 | },
26 | devServer: {
27 | contentBase: path.join(__dirname, 'public'),
28 | port: 3000
29 | }
30 | };
--------------------------------------------------------------------------------
/lessons/10-learning/commander-test/myscript.js:
--------------------------------------------------------------------------------
1 | const { program } = require("commander");
2 |
3 | program
4 | .option("-r", "Raw pasta", false)
5 | .option("-p, --pasta ", "What kind of pasta you want", "spaghetti")
6 | .option("-s, ", "What kind of sauce you want", "tomato")
7 | .parse(process.argv);
8 |
9 | console.log(program.R);
10 | console.log(program.pasta);
11 | console.log(program.S);
12 |
--------------------------------------------------------------------------------
/lessons/10-learning/commander-test/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "commander-test",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "commander": {
8 | "version": "5.0.0",
9 | "resolved": "https://registry.npmjs.org/commander/-/commander-5.0.0.tgz",
10 | "integrity": "sha512-JrDGPAKjMGSP1G0DUoaceEJ3DZgAfr/q6X7FVk4+U5KxUSKviYGM2k6zWkfyyBHy5rAtzgYJFa1ro2O9PtoxwQ=="
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/lessons/10-learning/commander-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "commander-test",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "commander": "^5.0.0"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lessons/10-learning/img/learning/learning.001.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/10-learning/img/learning/learning.001.jpeg
--------------------------------------------------------------------------------
/lessons/10-learning/img/learning/learning.002.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/10-learning/img/learning/learning.002.jpeg
--------------------------------------------------------------------------------
/lessons/10-learning/img/learning/learning.003.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/10-learning/img/learning/learning.003.jpeg
--------------------------------------------------------------------------------
/lessons/10-learning/img/learning/learning.004.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/10-learning/img/learning/learning.004.jpeg
--------------------------------------------------------------------------------
/lessons/10-learning/img/learning/learning.005.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/starakaj/programming-is-possible/a489eac142b49b6c9054d59e5c2502a9e976956f/lessons/10-learning/img/learning/learning.005.jpeg
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/.gitignore:
--------------------------------------------------------------------------------
1 | public/bundle.js
2 | node_modules
3 | data
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright 2017 Jenn Schiffer
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/README.md:
--------------------------------------------------------------------------------
1 | Teachable Machine Scaffold
2 | ===========================
3 |
4 | This app is a very small scaffold to get you started using Teachable Machine. It will require an internet connection to work, since it loads ml5 as well as TensorFlow from a CDN.
5 |
6 | ## Basic Usage
7 |
8 | ```
9 | npm run watch
10 | ```
11 |
12 | will start a webpack server at localhost:3000. From the browser you'll be able to see a simple example that recognizes "heart hands," or when you make your hands look like this 
13 |
14 | If you want to see the sound recognition or drawing recognition examples, you'll need to comment out the appropriate line in `app/app.js` to change which `setup` function is loaded.
15 |
16 | ## Running the downloader
17 |
18 | This starter includes a script that you can use to download images off of Image Net. To download 100 random images to a directory called `data/random` you could run
19 |
20 | ```sh
21 | npm run images -- -o data/random
22 | ```
23 |
24 | If you wanted instead to get 100 images with a particular wnid, then you'd execute something like this:
25 |
26 | ```sh
27 | npm run images -- -o data/red-panda --wnid n02509815 --randomize
28 | ```
29 |
30 | Which will download 100 images of a red panda. The `--randomize` flag tells the downloader whether to download the first 100 images, or to scramble the list of images first. You can also use the `--count` flag to limit or increase the number of images downloaded. Note that many links in Image Net are broken, and you may see errors in the console while downloading.
31 |
32 | ## Attribution
33 | A long time ago this was a starter on Glitch using React and Webpack. It was copied by @starakaj, and then React has been removed You can find the original at https://glitch.com/~starter-react.
34 |
35 | This project relates to video 2 of 5 in the [React Starter Kit](https://glitch.com/react-starter-kit) video series.
36 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/app.js:
--------------------------------------------------------------------------------
1 | // Require different files to change behavior
2 | // const setup = require("./imageDetector/imageDetectorApp");
3 | // const setup = require("./soundDetector/soundDetectorApp");
4 | // const setup = require("./drawDetector/drawDetectorApp");
5 | const setup = require("./heartHands/heartHandsApp");
6 |
7 | // Calls the setup function when the page is loaded
8 | window.addEventListener("DOMContentLoaded", setup);
9 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/drawDetector/drawDetectorApp.js:
--------------------------------------------------------------------------------
1 | const p5 = require("p5");
2 |
3 | // Model URL
4 | // If you make your own model, this is where you'd link to it. This is a model
5 | // that I trained on drawings of circles and squares. It should be able to distinguish
6 | // those two at least
7 | const imageModelURL = 'https://teachablemachine.withgoogle.com/models/_W_IEN88s/';
8 |
9 | // Whether or not you want to flip the video horizontally. If you trained your model
10 | // using your webcam, then you'll want to enable this
11 | const flipVideo = true;
12 | const width = 320;
13 | const height = 260;
14 |
15 | const p5draw = (p) => {
16 |
17 | let classifier;
18 | let drawingCanvas;
19 | let label = "";
20 |
21 | p.setup = () => {
22 | p.createCanvas(width, height);
23 | p.background(255);
24 |
25 | // We want the drawing to persist between calls to draw,
26 | // so we make a graphics context into which we can draw
27 | drawingCanvas = p.createGraphics(width, height);
28 | drawingCanvas.background(235);
29 |
30 | classifier = ml5.imageClassifier(imageModelURL + 'model.json', classifyImage);
31 | };
32 |
33 | p.draw = () => {
34 | // Draw a small black circle under the mouse
35 | if (p.mouseIsPressed) {
36 | drawingCanvas.strokeWeight(0);
37 | drawingCanvas.fill(0);
38 | drawingCanvas.ellipse(p.mouseX, p.mouseY, 5, 5);
39 | }
40 |
41 | // To draw what we see, first erase
42 | p.background(235);
43 |
44 | // Draw the drawing canvas
45 | p.image(drawingCanvas, 0, 0, width, height);
46 |
47 | // Draw the label
48 | let textToDraw = label === "" ? "Draw! Space to clear, s to save." : label;
49 | p.fill(0);
50 | p.textSize(16);
51 | p.textAlign(p.CENTER);
52 | p.text(textToDraw, width / 2, height - 4);
53 | };
54 |
55 | p.keyPressed = () => {
56 | if (p.key === " ") {
57 | label = "";
58 | drawingCanvas.background(235);
59 | } else if (p.key === "s") {
60 | p.saveCanvas(drawingCanvas);
61 | }
62 | }
63 |
64 | // Get a prediction for the current video frame
65 | function classifyImage() {
66 | classifier.classify(drawingCanvas, gotResult);
67 | }
68 |
69 | function gotResult(error, results) {
70 | if (error) {
71 | console.error(error);
72 | return;
73 | }
74 |
75 | // results is an array, sorted by confidence. Each
76 | // result will look like { label: "category label" confidence: 0.453 }
77 | // or something like this
78 | if (results[0].confidence > 0.75)
79 | label = results[0].label;
80 | classifyImage();
81 | }
82 | }
83 |
84 | module.exports = function setup() {
85 | const myp5 = new p5(p5draw, "main");
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/heartHands/heart.js:
--------------------------------------------------------------------------------
1 | module.exports = class Heart {
2 | constructor(x, y, vx, vy, a, va) {
3 | this.x = x;
4 | this.y = y;
5 | this.vx = vx;
6 | this.vy = vy;
7 | this.a = a;
8 | this.va = va;
9 | this._scale = 1.0;
10 | }
11 |
12 | set scale(s) {
13 | this._scale = s;
14 | }
15 |
16 | update() {
17 | this.x += this.vx;
18 | this.y += this.vy;
19 | this.a += this.va;
20 | this.vy += 1.0;
21 | }
22 |
23 | draw(p) {
24 | p.push();
25 | p.noFill();
26 | p.stroke(255, 135, 231);
27 |
28 | const n = 11;
29 | const u1 = 5;
30 | const v1 = -6;
31 | const u2 = 14;
32 | const v2 = 5;
33 | const v3 = 11;
34 |
35 | p.translate(this.x, this.y);
36 | p.rotate(this.a);
37 | p.scale(this._scale);
38 | p.strokeWeight(3 / this._scale);
39 | p.bezier(0, 0, 0 + u1/n, 0 + v1/n, 0 + u2/n, 0 + v2/n, 0, 0 + v3/n);
40 | p.bezier(0, 0, 0 - u1/n, 0 + v1/n, 0 - u2/n, 0 + v2/n, 0, 0 + v3/n);
41 |
42 | p.pop();
43 | }
44 |
45 | isOffscreen(p) {
46 | return this.x < 0 - this._scale ||
47 | this.x > p.width + this._scale ||
48 | this.y < 0 - this._scale ||
49 | this.y > p.height + this._scale;
50 | }
51 | }
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/heartHands/heartHandsApp.js:
--------------------------------------------------------------------------------
1 | const p5 = require("p5");
2 | const Heart = require("./heart");
3 |
4 | // Model URL
5 | // If you make your own model, this is where you'd link to it. This is a model
6 | // that I trained on making "heart hands", like this
7 | // https://image.shutterstock.com/image-photo/woman-making-heart-her-hands-600w-1211985307.jpg
8 | const imageModelURL = 'https://teachablemachine.withgoogle.com/models/sltRChS8U/';
9 |
10 | // Whether or not you want to flip the video horizontally. If you trained your model
11 | // using your webcam, then you'll want to enable this
12 | const flipVideo = true;
13 | const width = 320;
14 | const height = 260;
15 |
16 | const p5draw = (p) => {
17 |
18 | let p5video;
19 | let offscreenGraphics;
20 | let classifier;
21 | let label = "";
22 | let hearts = [];
23 |
24 | p.setup = () => {
25 | p.createCanvas(width, height);
26 | p.background(255);
27 |
28 | p5video = p.createCapture(p.VIDEO);
29 | p5video.size(width, height);
30 | p5video.hide();
31 |
32 | // We'll use this offscreen canvas to store the video, in case we
33 | // want to transform it before classifying it
34 | offscreenGraphics = p.createGraphics(width, height);
35 |
36 | classifier = ml5.imageClassifier(imageModelURL + "model.json", classifyVideo);
37 | }
38 |
39 | p.draw = () => {
40 | // This draws the video with X and Y flipped
41 | offscreenGraphics.push();
42 | if (flipVideo) {
43 | offscreenGraphics.translate(width, 0);
44 | offscreenGraphics.scale(-1, 1);
45 | }
46 | offscreenGraphics.image(p5video, 0, 0, width, height);
47 | offscreenGraphics.pop();
48 |
49 | p.image(offscreenGraphics, 0, 0, p.width, p.height);
50 |
51 | // Draw the label
52 | p.fill(255);
53 | p.textSize(16);
54 | p.textAlign(p.CENTER);
55 | p.text(label, p.width / 2, p.height - 4);
56 |
57 | if (label.toLowerCase().startsWith("heart")) {
58 | const h = new Heart(
59 | p.width / 2.0,
60 | p.height / 2.0,
61 | p.map(Math.random(), 0, 1, -1, 1) * 10,
62 | p.map(Math.random(), 0, 1, -1, 1) * 10,
63 | p.map(Math.random(), 0, 1, 0, 2) * Math.PI,
64 | p.map(Math.random(), 0, 1, -1, 1) * Math.PI * 0.05
65 | );
66 | h.scale = p.map(Math.random(), 0, 1, 10, 50);
67 | hearts.push(h);
68 | }
69 |
70 | hearts.forEach(heart => heart.draw(p));
71 | hearts.forEach(heart => heart.update());
72 | hearts = hearts.filter(heart => !heart.isOffscreen(p));
73 | }
74 |
75 | // Get a prediction for the current video frame
76 | function classifyVideo() {
77 | classifier.classify(offscreenGraphics, gotResult);
78 | }
79 |
80 | function gotResult(error, results) {
81 | if (error) {
82 | console.error(error);
83 | return;
84 | }
85 |
86 | // results is an array, sorted by confidence. Each
87 | // result will look like { label: "category label" confidence: 0.453 }
88 | // or something like this
89 | label = results[0].label;
90 | classifyVideo();
91 | }
92 | }
93 |
94 | module.exports = function setup() {
95 | const myp5 = new p5(p5draw, "main");
96 | }
97 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/imageDetector/imageDetectorApp.js:
--------------------------------------------------------------------------------
1 | const p5 = require("p5");
2 |
3 | // Model URL
4 | // If you make your own model, this is where you'd link to it. This is a model
5 | // that I trained on making "heart hands", like this
6 | // https://image.shutterstock.com/image-photo/woman-making-heart-her-hands-600w-1211985307.jpg
7 | const imageModelURL = 'https://teachablemachine.withgoogle.com/models/sltRChS8U/';
8 |
9 | // Whether or not you want to flip the video horizontally. If you trained your model
10 | // using your webcam, then you'll want to enable this
11 | const flipVideo = true;
12 | const width = 320;
13 | const height = 260;
14 |
15 | const p5draw = (p) => {
16 |
17 | let classifier;
18 | let p5video;
19 | let offscreenGraphics;
20 | let label = "";
21 |
22 | p.setup = () => {
23 | p.createCanvas(width, height);
24 | p.background(255);
25 |
26 | p5video = p.createCapture(p.VIDEO);
27 | p5video.size(width, height);
28 | p5video.hide();
29 |
30 | // We'll use this offscreen canvas to store the video, in case we
31 | // want to transform it before classifying it
32 | offscreenGraphics = p.createGraphics(width, height);
33 |
34 | classifier = ml5.imageClassifier(imageModelURL + 'model.json', classifyVideo);
35 | }
36 |
37 | p.draw = () => {
38 | // This draws the video with X and Y flipped
39 | offscreenGraphics.push();
40 | if (flipVideo) {
41 | offscreenGraphics.translate(width, 0);
42 | offscreenGraphics.scale(-1, 1);
43 | }
44 | offscreenGraphics.image(p5video, 0, 0, width, height);
45 | offscreenGraphics.pop();
46 |
47 | p.image(offscreenGraphics, 0, 0, p.width, p.height);
48 |
49 | // Draw the label
50 | p.fill(255);
51 | p.textSize(16);
52 | p.textAlign(p.CENTER);
53 | p.text(label, width / 2, height - 4);
54 | }
55 |
56 | // Get a prediction for the current video frame
57 | function classifyVideo() {
58 | classifier.classify(offscreenGraphics, gotResult);
59 | }
60 |
61 | function gotResult(error, results) {
62 | if (error) {
63 | console.error(error);
64 | return;
65 | }
66 |
67 | // results is an array, sorted by confidence. Each
68 | // result will look like { label: "category label" confidence: 0.453 }
69 | // or something like this
70 | label = results[0].label;
71 | classifyVideo();
72 | }
73 | }
74 |
75 | module.exports = function setup() {
76 | const myp5 = new p5(p5draw, "main");
77 | }
78 |
79 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Teachable Machine Starter
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/app/soundDetector/soundDetectorApp.js:
--------------------------------------------------------------------------------
1 | const p5 = require("p5"); // Just so it's easy to draw
2 |
3 | // Model URL
4 | // If you make your own model, this is where you'd link to it. This is a model
5 | // that I trained on making on saying the word "beep". Hopefully
6 | // if you say the word "beep" in isolation it will detect it. Unfortunately
7 | // it's only trained on my voice.
8 | const soundModelURL = 'https://teachablemachine.withgoogle.com/models/Q-n8u5SXp/';
9 |
10 | // These are the options that you can pass to your sound classifier when creating
11 | // it. Unless you pass "invokeCallbackOnNoiseAndUnknown: true", the callback
12 | // will only trigger when one of the non-noise categories is recognized.
13 | const soundClassifierOptions = {
14 | includeSpectrogram: true, // in case listen should return result.spectrogram
15 | probabilityThreshold: 0.75,
16 | invokeCallbackOnNoiseAndUnknown: true,
17 | overlapFactor: 0.50 // probably want between 0.5 and 0.75.
18 | }
19 |
20 | const width = 320;
21 | const height = 260;
22 |
23 | const p5draw = (p) => {
24 |
25 | let classifier;
26 | let label = "listening...";
27 |
28 | p.setup = () => {
29 | p.createCanvas(width, height);
30 | p.background(255);
31 |
32 | classifier = ml5.soundClassifier(soundModelURL + 'model.json', soundClassifierOptions, audioClassifierReady);
33 | }
34 |
35 | p.draw = () => {
36 | p.background(0);
37 |
38 | // Draw the label
39 | p.fill(255);
40 | p.textSize(16);
41 | p.textAlign(p.CENTER);
42 | p.text(label, width / 2, height - 4);
43 | }
44 |
45 | // Unlike the video classifier, this classifier will run continuously,
46 | // calling gotResult again and again
47 | function audioClassifierReady() {
48 | classifier.classify(gotResult);
49 | }
50 |
51 | function gotResult(error, results) {
52 | if (error) {
53 | console.error(error);
54 | return;
55 | }
56 |
57 | // results is an array, sorted by confidence. Each
58 | // result will look like { label: "category label" confidence: 0.453 }
59 | // or something like this
60 | label = results[0].label;
61 | }
62 | }
63 |
64 | module.exports = function setup() {
65 | const myp5 = new p5(p5draw, "main");
66 | }
67 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starter-react",
3 | "version": "0.0.1",
4 | "description": "A small scaffold to get you started using React with Webpack",
5 | "main": "server.js",
6 | "scripts": {
7 | "build": "webpack",
8 | "images": "node scripts/imageDownloader.js",
9 | "start": "webpack && node server.js",
10 | "watch": "NODE_ENV=development node server.js"
11 | },
12 | "dependencies": {
13 | "commander": "^5.0.0",
14 | "express": "^4.16.4",
15 | "jsx-loader": "^0.13.2",
16 | "mkdirp": "^1.0.4",
17 | "node-fetch": "^2.6.0",
18 | "osmosis": "^1.1.10",
19 | "p5": "^1.0.0",
20 | "react": "^16.8.6",
21 | "react-dom": "^16.8.6",
22 | "webpack": "^4.30.0",
23 | "webpack-cli": "^3.3.0",
24 | "webpack-dev-middleware": "^3.7.2",
25 | "webpack-dev-server": "^3.10.3"
26 | },
27 | "engines": {
28 | "node": "12.x"
29 | },
30 | "repository": {
31 | "url": "https://glitch.com/edit/#!/starter-react"
32 | },
33 | "license": "MIT",
34 | "keywords": [
35 | "node",
36 | "glitch",
37 | "express"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/public/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Futura;
3 | }
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/scripts/imageDownloader.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const fs = require("fs");
4 | const path = require("path");
5 | const osmosis = require("osmosis");
6 | const fetch = require("node-fetch");
7 | const mkdirp = require("mkdirp");
8 | const { program } = require("commander");
9 |
10 | program
11 | .option("-d, --dry", "Dry run--print what would happen but don't do it")
12 | .option('-r, --randomize', 'Randomize the order of downloaded images')
13 | .option('--count ', 'number of images to download', 100)
14 | .option('-o, --output ', 'Directory to write to', process.cwd())
15 | .option("--wnid ", "Source Word Net ID. Leave blank for random images")
16 | .parse(process.argv);
17 |
18 | const stopAt = program.count;
19 | const randomize = program.randomize;
20 | const wnid = program.wnid;
21 | const destPath = path.normalize(program.output);
22 |
23 | const sysnetListUrl = "http://www.image-net.org/api/text/imagenet.synset.obtain_synset_list";
24 | const imagenetRoot = "http://image-net.org/api/text/imagenet.synset.geturls?wnid=";
25 |
26 | if (!!wnid) {
27 | const sourceUrl = imagenetRoot + wnid;
28 | console.log(`Downloading up to ${stopAt} images from ${sourceUrl} to ${destPath} in ${randomize ? "random order" : "nonrandom order"}`);
29 | } else {
30 | console.log(`Downloading up to ${stopAt} Image Net images at random to ${destPath}`);
31 | }
32 |
33 | if (program.dry) process.exit(0);
34 |
35 | // Try to make the output directory
36 | mkdirp.sync(destPath);
37 |
38 | if (!!wnid) {
39 | // download images from a particular wnid link
40 | (async function() {
41 | const pageUrl = imagenetRoot + wnid;
42 | const pageLinks = await getLinksFromImageNetPage(pageUrl, stopAt, randomize);
43 | await Promise.all(pageLinks.map(async link => {
44 | const pathname = (new URL(link)).pathname;
45 | const basename = path.basename(pathname);
46 | const filename = path.join(destPath, basename);
47 | try {
48 | await download(link, filename);
49 | } catch (e) {
50 | console.log("Could not download image from " + link);
51 | }
52 | }))
53 | })();
54 | } else {
55 | // download images at random
56 | (async function() {
57 | const randomWNIDs = await getRandomImageNetLinks(stopAt);
58 | const randomLinks = randomWNIDs.map(wnid => imagenetRoot + wnid);
59 | await Promise.all(randomLinks.map(async link => {
60 | const pageLinks = await getLinksFromImageNetPage(link, 1, true);
61 | const pathname = (new URL(pageLinks[0])).pathname;
62 | const basename = path.basename(pathname);
63 | const filename = path.join(destPath, basename);
64 | try {
65 | await download(pageLinks[0], filename);
66 | } catch (e) {
67 | console.log("Could not download image from " + pageLinks[0]);
68 | }
69 | }));
70 | })();
71 | }
72 |
73 | // Shuffle an array in place
74 | function scramble(array) {
75 | for (let i = 0; i < array.length; i++) {
76 | const randomIndex = Math.floor(Math.random() * array.length);
77 | const tmp = array[randomIndex];
78 | array[randomIndex] = array[i];
79 | array[i] = tmp;
80 | }
81 | }
82 |
83 | // Return an array of random Image Net links
84 | async function getRandomImageNetLinks(count) {
85 | return getLinksFromImageNetPage(sysnetListUrl, count, true);
86 | }
87 |
88 | // Return an array of Image Net links from a page
89 | async function getLinksFromImageNetPage(pageUrl, count, doScramble) {
90 | return new Promise((resolve, reject) => {
91 | let nidsText;
92 | osmosis.get(pageUrl)
93 | .find("body")
94 | .set("nids")
95 | .data(item => nidsText = item.nids)
96 | .done(() => {
97 | if (nidsText) {
98 | let links = nidsText.split("\n");
99 | if (doScramble) scramble(links);
100 | links = links.slice(0, count);
101 | links = links.map(link => link.trim());
102 | resolve(links);
103 | }
104 | })
105 | .error((e) => reject(e));
106 | });
107 | }
108 |
109 | // Download the file at a uri to a location
110 | async function download(uri, filename) {
111 | return new Promise((resolve) => {
112 | fetch(uri).then(res => {
113 | if (res.ok) {
114 | const dest = fs.createWriteStream(filename);
115 | res.body.pipe(dest).on("close", resolve);
116 | }
117 | });
118 | });
119 | };
120 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // init project
4 | const express = require('express');
5 | const app = express();
6 | const port = process.env.PORT || 3000;
7 |
8 | // Special piece for running with webpack dev server
9 | if (process.env.NODE_ENV === "development") {
10 | const webpack = require('webpack');
11 | const webpackDevMiddleware = require('webpack-dev-middleware');
12 | const config = require('./webpack.dev.config.js');
13 | const compiler = webpack(config);
14 |
15 | // Tell express to use the webpack-dev-middleware and use the webpack.config.js
16 | // configuration file as a base.
17 | app.use(webpackDevMiddleware(compiler, {
18 | publicPath: config.output.publicPath,
19 | }));
20 | }
21 |
22 | // http://expressjs.com/en/starter/static-files.html
23 | app.use(express.static('public'));
24 |
25 | // http://expressjs.com/en/starter/basic-routing.html
26 | app.get("/", function(request, response) {
27 | response.sendFile(__dirname + '/app/index.html');
28 | });
29 |
30 | // listen for requests :)
31 | const listener = app.listen(port, function () {
32 | console.log('Your app is listening on port ' + port);
33 | });
34 |
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'production',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.js',
7 | output: {
8 | path: path.join(__dirname, 'public'),
9 | filename: 'bundle.js',
10 | },
11 | resolve: {
12 | extensions: ['.js', '.jsx'],
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.jsx?$/,
18 | loader: 'jsx-loader',
19 | exclude: /node_modules/,
20 | include: path.join(__dirname, 'app'),
21 | },
22 | ],
23 | },
24 | };
--------------------------------------------------------------------------------
/lessons/10-learning/teachable-machine-app/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'development',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.js',
7 | devtool: 'inline-source-map',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'bundle.js',
11 | publicPath: '/',
12 | },
13 | resolve: {
14 | extensions: ['.js', '.jsx'],
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.jsx?$/,
20 | loader: 'jsx-loader',
21 | exclude: /node_modules/,
22 | include: path.join(__dirname, 'app'),
23 | },
24 | ],
25 | },
26 | devServer: {
27 | contentBase: path.join(__dirname, 'public'),
28 | port: 3000
29 | }
30 | };
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/.gitignore:
--------------------------------------------------------------------------------
1 | public/bundle.js
2 | node_modules
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright 2017 Jenn Schiffer
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/Procfile:
--------------------------------------------------------------------------------
1 | web: npm start
2 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/README.md:
--------------------------------------------------------------------------------
1 | Express Game Starter
2 | ===========================
3 |
4 | This app is a very small scaffold to get started making a multiplayer game using p5, express and websockets.
5 |
6 | It's been copied by @starakaj for your enjoyment, and then React has been removed You can find the original at https://glitch.com/~starter-react.
7 |
8 | This project relates to video 2 of 5 in the [React Starter Kit](https://glitch.com/react-starter-kit) video series.
9 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/app/app.js:
--------------------------------------------------------------------------------
1 | const p5 = require("p5");
2 | const Game = require("./game");
3 | const GameClient = require("./gameClient");
4 |
5 | const width = 400;
6 | const height = 400;
7 | const columns = 10;
8 | const rows = 10;
9 | const cellWidth = width / columns;
10 | const cellHeight = height / rows;
11 |
12 | const sketch = (p) => {
13 |
14 | let game = new Game(columns, rows);
15 | let gameClient = new GameClient();
16 | game.on("playerMoved", (player) => gameClient.sendPlayer(player));
17 | gameClient.on("playersUpdate", (players) => game.updatePlayers(players));
18 | gameClient.on("connected", () => gameClient.sendPlayer(game.ownedPlayer));
19 |
20 | p.setup = () => {
21 | p.createCanvas(400, 400);
22 | }
23 |
24 | p.draw = () => {
25 | // Make the background almost white
26 | p.background(240);
27 |
28 | // Draw a nice grid for the background
29 | p.strokeWeight(0.5);
30 | p.stroke(15);
31 | for (let x = 1; x < columns; x++) {
32 | p.line(x * cellWidth, 0, x * cellWidth, height);
33 | }
34 | for (let y = 1; y < rows; y++) {
35 | p.line(0, y * cellHeight, width, y * cellHeight);
36 | }
37 |
38 | // Draw the game
39 | game.draw(p, cellWidth, cellHeight);
40 | }
41 |
42 | p.keyPressed = () => {
43 | game.handleInput(p.key);
44 | }
45 | }
46 |
47 | const myp5 = new p5(sketch, "main");
48 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/app/game.js:
--------------------------------------------------------------------------------
1 | const { EventEmitter } = require("events");
2 | const { clamp } = require("./util");
3 | const { v4: uuidv4 } = require("uuid");
4 |
5 | module.exports = class Game extends EventEmitter {
6 | constructor(columns, rows) {
7 | super();
8 | this._columns = columns;
9 | this._rows = rows;
10 |
11 | // Position the player in the center of the board
12 | this._player = this._makePlayer(
13 | Math.floor(this._columns / 2),
14 | Math.floor(this._rows / 2),
15 | this._makeRandomHue()
16 | )
17 |
18 | this._players = {
19 | [this._player.id]: this._player
20 | };
21 | }
22 |
23 | // Return an HSBA color (Hue, Saturation, Brighness, Alpha)
24 | // with a random hue
25 | _makeRandomHue() {
26 | return [
27 | Math.random() * 255,
28 | 255,
29 | 255,
30 | 255
31 | ];
32 | }
33 |
34 | // Make a new player object out of a position and a color
35 | _makePlayer(px, py, color) {
36 | return {
37 | id: uuidv4(),
38 | x: px,
39 | y: py,
40 | color
41 | };
42 | }
43 |
44 | // Accessor for the player that this game owns, accessed like "game.ownedPlayer"
45 | get ownedPlayer() {
46 | return this._player;
47 | }
48 |
49 | // Draw each player as a square at the appropriate position
50 | draw(p, cellWidth, cellHeight) {
51 | p.push();
52 | p.strokeWeight(0);
53 | p.colorMode(p.HSB);
54 | Object.values(this._players).forEach(player => {
55 | p.fill(player.color);
56 | p.rect(
57 | player.x * cellWidth,
58 | player.y * cellHeight,
59 | cellWidth,
60 | cellHeight
61 | );
62 | });
63 | p.pop();
64 | }
65 |
66 | _movePlayer(dx, dy) {
67 | this._player.x = clamp(this._player.x + dx, 0, this._columns - 1);
68 | this._player.y = clamp(this._player.y + dy, 0, this._rows - 1);
69 |
70 | this.emit("playerMoved", this._player);
71 | }
72 |
73 | handleInput(key) {
74 | if (key === "ArrowLeft") {
75 | this._movePlayer(-1, 0);
76 | } else if (key === "ArrowRight") {
77 | this._movePlayer(1, 0);
78 | } else if (key === "ArrowUp") {
79 | this._movePlayer(0, -1);
80 | } else if (key === "ArrowDown") {
81 | this._movePlayer(0, 1);
82 | }
83 | }
84 |
85 | updatePlayers(players) {
86 | const ourPlayer = {
87 | [this._player.id]: this._player
88 | };
89 |
90 | // Make sure that our player stays in there, no matter what
91 | this._players = Object.assign(players, ourPlayer);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/app/gameClient.js:
--------------------------------------------------------------------------------
1 | const { EventEmitter } = require("events");
2 |
3 | module.exports = class GameClient extends EventEmitter {
4 | constructor() {
5 | super();
6 | const pageUrl = new URL(window.location);
7 | pageUrl.protocol = "ws";
8 | this._websocket = new WebSocket(pageUrl.toString());
9 |
10 | this._websocket.onopen = () => {
11 | this.emit("connected");
12 | };
13 |
14 | this._websocket.onmessage = (event) => {
15 | const players = JSON.parse(event.data);
16 | this.emit("playersUpdate", players);
17 | };
18 | }
19 |
20 | sendPlayer(player) {
21 | this._websocket.send(
22 | JSON.stringify(player)
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MMORPG Starter
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/app/util.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | clamp: (x, min, max) => {
3 | if (x < min) return min;
4 | if (x > max) return max;
5 | return x;
6 | }
7 | }
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starter-react",
3 | "version": "0.0.1",
4 | "description": "A small scaffold to get you started using React with Webpack",
5 | "main": "server.js",
6 | "scripts": {
7 | "build": "webpack",
8 | "start": "webpack && node server.js",
9 | "watch": "NODE_ENV=development node server.js"
10 | },
11 | "dependencies": {
12 | "express": "^4.16.4",
13 | "jsx-loader": "^0.13.2",
14 | "p5": "^1.0.0",
15 | "react": "^16.8.6",
16 | "react-dom": "^16.8.6",
17 | "uuid": "^7.0.3",
18 | "webpack": "^4.30.0",
19 | "webpack-cli": "^3.3.0",
20 | "webpack-dev-middleware": "^3.7.2",
21 | "webpack-dev-server": "^3.10.3",
22 | "ws": "^7.2.3"
23 | },
24 | "engines": {
25 | "node": "12.x"
26 | },
27 | "repository": {
28 | "url": "https://glitch.com/edit/#!/starter-react"
29 | },
30 | "license": "MIT",
31 | "keywords": [
32 | "node",
33 | "glitch",
34 | "express"
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/public/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Futura;
3 | }
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // init project
4 | const express = require('express');
5 | const app = express();
6 | const port = process.env.PORT || 3000;
7 | const WebSocket = require("ws");
8 | const { v4: uuidv4 } = require("uuid");
9 |
10 | // Special piece for running with webpack dev server
11 | if (process.env.NODE_ENV === "development") {
12 | const webpack = require('webpack');
13 | const webpackDevMiddleware = require('webpack-dev-middleware');
14 | const config = require('./webpack.dev.config.js');
15 | const compiler = webpack(config);
16 |
17 | // Tell express to use the webpack-dev-middleware and use the webpack.config.js
18 | // configuration file as a base.
19 | app.use(webpackDevMiddleware(compiler, {
20 | publicPath: config.output.publicPath,
21 | }));
22 | }
23 |
24 | // http://expressjs.com/en/starter/static-files.html
25 | app.use(express.static('public'));
26 |
27 | // http://expressjs.com/en/starter/basic-routing.html
28 | app.get("/", function(request, response) {
29 | response.sendFile(__dirname + '/app/index.html');
30 | });
31 |
32 | // listen for requests :)
33 | const listener = app.listen(port, function () {
34 | console.log('Your app is listening on port ' + port);
35 | });
36 |
37 | // Space to store players, by player id
38 | const players = {};
39 |
40 | // Map from a connection id, to the player id that the connection owns
41 | const playersByConnectionId = {};
42 |
43 | // Start a web socket server
44 | const wsServer = new WebSocket.Server({ server: listener });
45 |
46 | function broadcastPlayers() {
47 | wsServer.clients.forEach(client => {
48 | client.send(
49 | JSON.stringify(players)
50 | );
51 | });
52 | }
53 |
54 | class Game {
55 | constructor(leftPlayer, rightPlayer) {
56 | this._leftPlayer = leftPlayer;
57 | this._rightPlayer = rightPlayer;
58 | }
59 | }
60 |
61 | // map from WSUID -> Game
62 | const activeGames = {};
63 |
64 | const waitingPlayer = null;
65 |
66 | // Handle new connections
67 | wsServer.on("connection", (ws) => {
68 |
69 | // Generate a new UID for this websocket
70 | const wsid = uuidv4();
71 |
72 | if (waitingPlayer === null) {
73 | waitingPlayer = wsid;
74 | ws.send("staus", {message: "Waiting for another player to join"});
75 | } else {
76 | const game = new Game(waitingPlayer, wsid);
77 | activeGames[waitingPlayer] = game;
78 | activeGames[wsid] = game;
79 | }
80 |
81 | // Update players whenever a new move gets made
82 | ws.on("message", (data) => {
83 | const game = activeGames[wsid];
84 | const updateObject = JSON.parse(data);
85 |
86 | if (updateObject.type === "move") {
87 | game.setMove(wsid, updateObject.move);
88 | }
89 |
90 | if (game.leftMove !== null && game.rightMove !== null) {
91 | // broadcast the new state of the game to each player
92 | }
93 | });
94 |
95 | // Clean up when the player disconnects
96 | ws.on("close", () => {
97 | const playerid = playersByConnectionId[wsid];
98 | if (playerid) delete players[playerid];
99 | delete playersByConnectionId[wsid];
100 | broadcastPlayers();
101 | });
102 | });
103 |
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'production',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.js',
7 | output: {
8 | path: path.join(__dirname, 'public'),
9 | filename: 'bundle.js',
10 | },
11 | resolve: {
12 | extensions: ['.js', '.jsx'],
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.jsx?$/,
18 | loader: 'jsx-loader',
19 | exclude: /node_modules/,
20 | include: path.join(__dirname, 'app'),
21 | },
22 | ],
23 | },
24 | };
--------------------------------------------------------------------------------
/lessons/11-advanced/game-app/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'development',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.js',
7 | devtool: 'inline-source-map',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'bundle.js',
11 | publicPath: '/',
12 | },
13 | resolve: {
14 | extensions: ['.js', '.jsx'],
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.jsx?$/,
20 | loader: 'jsx-loader',
21 | exclude: /node_modules/,
22 | include: path.join(__dirname, 'app'),
23 | },
24 | ],
25 | },
26 | devServer: {
27 | contentBase: path.join(__dirname, 'public'),
28 | port: 3000
29 | }
30 | };
--------------------------------------------------------------------------------
/lessons/13-gesture/13-gesture.md:
--------------------------------------------------------------------------------
1 | # Gesture Recognition
2 |
3 | ## Authors
4 | Sam Tarakajian for NYU IDM
5 |
6 | DM-GY 6063
7 |
8 | @starakaj
9 |
10 | ## Essential Questions
11 | - What are the different ways of encoding gestural information for a computer?
12 | - How can we extract useful data from that information?
13 | - What kinds of systems can we drive with that data?
14 |
15 | ## Introduction
16 | In addition to verbal communication, people also have a highly developed language of gestural communication. These gestures can be deliberate forms of person-to-person communication, like waving to say hello, or pointing to indicate a specific object in the distance. They can also communicate between people and objects, for example the gestures by which a violinist communicates with their instuments. Finally, human gestures might communicate something about their environment, in the sense that the swaying of subway passengers tells us something about the motion of the subway car.
17 |
18 | Many computer libraries are designed for working with gestural information. In order to drive computer systems with a gesture, it must first be captured, and then analyzed to retrieve useful information. Cameras, depth sensors, accelerometers and position trackers are all used for gesture capture. Finally, there are several statistical and machine-learning tools that can pull useful information from captured gesture data.
19 |
20 | In this class, we'll look at systems for data capture including webcam, depth camera, and Leap Motion. Next, we'll see how to use Wekinator to analyze captured data, and we'll map that data to some useful output.
21 |
22 | ### Target Audience / Prerequisite & Pre-Assessment
23 | This module is part of DM-GY 6063, _Programming is the Art of the Possible_. This is a second semester creative coding course, designed for students who have a strong JavaScript foundation.
24 |
25 | ### Outcomes & Goals
26 | - In this class we will use webcams, depth cameras, and motion trackers to capture gesture data.
27 | - We will analyze that data and map it to some other process.
28 | - Students will walk away with a deeper understanding of the technologies available for gestural analysis, as well as the challenges inherit in using that data.
29 |
30 | ### Pacing / Duration
31 | TBD
32 |
33 | ## Materials Needed
34 | To be decided, but as a point of departure:
35 | - Hardware
36 | - Webcam
37 | - Depth Camera (Kinect)
38 | - Trackpad
39 | - Leap Motion
40 | - Drawing pad + pen
41 | - Bela.io
42 | - Software
43 | - Max/MSP
44 | - Processing
45 | - Wekinator
46 |
47 | ### Exercises To Do Before Class
48 | TBD, maybe there can be some reading on statistical gestural analysis? HMMs?
49 |
50 | ### Vocabulary
51 | * Gesture - Semiotic dynamic posture. Reconfiguration of a body, relative to its own reference frame or to the world around it, in a way that deliberately or incidentally conveys meaning. (provisional definition to be revisited).
52 | * Features - Parameters of a model that best-explains a given data set. Please revisit this definiton as it's garbage.
53 |
54 | ## Exercise Descriptions
55 | TBD
56 |
57 | ## Student Reflections, Takeaways & Next Steps
58 | TBD
59 |
60 | ## Post Session
61 | TBD
62 |
63 | ### References
64 | TBD
65 |
66 | ### Implementation Guidance & Teaching Reflection
67 | TBD
68 |
69 | ***With thanks and acknowledgement, this is based on the template provided by [Eyebeam](https://github.com/eyebeam/curriculum/blob/master/TEMPLATE.md)***
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/.gitignore:
--------------------------------------------------------------------------------
1 | public/bundle.js
2 | node_modules
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright 2017 Jenn Schiffer
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/Procfile:
--------------------------------------------------------------------------------
1 | web: npm start
2 |
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/README.md:
--------------------------------------------------------------------------------
1 | Starter React App on Glitch
2 | ===========================
3 |
4 | This app is a very small scaffold to get you started using React and Webpack.
5 |
6 | It's been copied by @starakaj for your enjoyment. You can find the original at https://glitch.com/~starter-react.
7 |
8 | This project relates to video 2 of 5 in the [React Starter Kit](https://glitch.com/react-starter-kit) video series.
9 |
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/app/app.jsx:
--------------------------------------------------------------------------------
1 | const React = require("react");
2 | const ReactDOM = require("react-dom");
3 |
4 | /* Import Components */
5 | const RootComponent = require("./components/RootComponent");
6 |
7 | ReactDOM.render(, document.getElementById("main"));
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/app/components/ClockFace.jsx:
--------------------------------------------------------------------------------
1 | const React = require("react");
2 |
3 | function ClockFace(props) {
4 |
5 | const [date, setDate] = React.useState(new Date());
6 |
7 | // This will be called whenever the component renders, but because we pass an empty
8 | // array as the second argument, it will only be called once, when the component
9 | // first renders.
10 | React.useEffect(() => {
11 |
12 | const timerId = setInterval(() => {
13 | setDate(new Date);
14 | }, 1000);
15 |
16 | // By returning a function from useEffect, we tell React that we'd like this
17 | // function called when the component is unmounted
18 | return () => { clearInterval(timerId) };
19 |
20 | }, []);
21 |
22 | let prefix = "";
23 | let postfix = ""
24 | if (props.language === "en") {
25 | prefix = "It is";
26 | postfix = "o'clock";
27 | } else if (props.language === "fr") {
28 | prefix = "Il est";
29 | postfix = "heures";
30 | }
31 |
32 | return (
33 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "back4app-tester",
3 | "version": "0.0.1",
4 | "description": "A small scaffold to get you started using React with Webpack",
5 | "main": "server.js",
6 | "scripts": {
7 | "build": "webpack",
8 | "start": "webpack && node server.js",
9 | "watch": "NODE_ENV=development node server.js"
10 | },
11 | "dependencies": {
12 | "body-parser": "^1.19.0",
13 | "express": "^4.16.4",
14 | "jsx-loader": "^0.13.2",
15 | "parse": "^2.19.0",
16 | "react": "^16.8.6",
17 | "react-dom": "^16.8.6",
18 | "webpack": "^5.14.0",
19 | "webpack-cli": "^3.3.0",
20 | "webpack-dev-middleware": "^3.7.2",
21 | "webpack-dev-server": "^3.11.2"
22 | },
23 | "engines": {
24 | "node": "12.x"
25 | },
26 | "repository": {
27 | "url": "https://glitch.com/edit/#!/starter-react"
28 | },
29 | "license": "MIT",
30 | "keywords": [
31 | "node",
32 | "glitch",
33 | "express"
34 | ],
35 | "author": ""
36 | }
37 |
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/public/bundle.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | object-assign
3 | (c) Sindre Sorhus
4 | @license MIT
5 | */
6 |
7 | /** @license React v0.18.0
8 | * scheduler.production.min.js
9 | *
10 | * Copyright (c) Facebook, Inc. and its affiliates.
11 | *
12 | * This source code is licensed under the MIT license found in the
13 | * LICENSE file in the root directory of this source tree.
14 | */
15 |
16 | /** @license React v16.12.0
17 | * react-dom.production.min.js
18 | *
19 | * Copyright (c) Facebook, Inc. and its affiliates.
20 | *
21 | * This source code is licensed under the MIT license found in the
22 | * LICENSE file in the root directory of this source tree.
23 | */
24 |
25 | /** @license React v16.12.0
26 | * react.production.min.js
27 | *
28 | * Copyright (c) Facebook, Inc. and its affiliates.
29 | *
30 | * This source code is licensed under the MIT license found in the
31 | * LICENSE file in the root directory of this source tree.
32 | */
33 |
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/public/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Futura;
3 | }
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // init project
4 | const express = require('express');
5 | const app = express();
6 | const port = process.env.PORT || 3000;
7 |
8 | // Add the body parser middleware
9 | const bodyParser = require('body-parser');
10 | app.use(bodyParser.json());
11 |
12 | // Initialize your connection to Back4App
13 | const Parse = require('parse/node');
14 | const { json } = require('body-parser');
15 |
16 | Parse.serverURL = 'https://parseapi.back4app.com'; // This is your Server URL
17 | Parse.initialize(
18 | 'woTcOnHZSKrWRhQucRxAkrs4fPZWFmxBdnOH4yFS', // This is your Application ID
19 | 'TPkEzQBaiTVWdpBXqAK6jHLeaUjvvwsPcOybmehO', // This is your Javascript key
20 | 'cbdbjPOsdj7S8cNsmnFTOyYgyJrksQhVu3KjuRHm' // This is your Master key (never use it in the frontend)
21 | );
22 |
23 | // Special piece for running with webpack dev server
24 | if (process.env.NODE_ENV === "development") {
25 | const webpack = require('webpack');
26 | const webpackDevMiddleware = require('webpack-dev-middleware');
27 | const config = require('./webpack.dev.config.js');
28 | const compiler = webpack(config);
29 |
30 | // Tell express to use the webpack-dev-middleware and use the webpack.config.js
31 | // configuration file as a base.
32 | app.use(webpackDevMiddleware(compiler, {
33 | publicPath: config.output.publicPath,
34 | }));
35 | }
36 |
37 | // http://expressjs.com/en/starter/static-files.html
38 | app.use(express.static('public'));
39 |
40 | // http://expressjs.com/en/starter/basic-routing.html
41 | app.get("/", function(request, response) {
42 | response.sendFile(__dirname + '/app/index.html');
43 | });
44 |
45 | const dummyData = [
46 | {user: "Tom", message: "Hi I'm Tom"},
47 | {user: "Alex", message: "Hi I'm Alex"},
48 | {user: "Tom", message: "Hi Alex, nice to meet you"}
49 | ];
50 |
51 | // Fetch tweets from the database. For now, just fetch the first 100
52 | app.get("/api/tweets", (_, res, next) => {
53 | let tweetClass = Parse.Object.extend("tweet");
54 | let query = new Parse.Query(tweetClass);
55 |
56 | // Sort by their creation date
57 | query.descending("createdAt");
58 |
59 | query.find().then(results => {
60 | res.json(results);
61 | }).catch(err => {
62 | next(err);
63 | });
64 | });
65 |
66 | // Post a new tweet
67 | app.post("/api/tweet", (req, res) => {
68 | const body = req.body;
69 | const user = body.user;
70 | const message = body.message;
71 | if (!user || !message) {
72 | res.status(400).send("Missing user or message");
73 | } else {
74 |
75 | let tweetClass = Parse.Object.extend("tweet");
76 | let tweet = new tweetClass();
77 | tweet.set("user", user);
78 | tweet.set("message", message);
79 |
80 | tweet.save().then(result => {
81 | res.json(result);
82 | }).catch(err => {
83 | next(err);
84 | });
85 | }
86 | });
87 |
88 | // listen for requests
89 | const listener = app.listen(port, function () {
90 | console.log('Your app is listening on port ' + port);
91 | });
92 |
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'production',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.jsx',
7 | output: {
8 | path: path.join(__dirname, 'public'),
9 | filename: 'bundle.js',
10 | },
11 | resolve: {
12 | extensions: ['.js', '.jsx'],
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.jsx?$/,
18 | loader: 'jsx-loader',
19 | exclude: /node_modules/,
20 | include: path.join(__dirname, 'app'),
21 | },
22 | ],
23 | },
24 | };
--------------------------------------------------------------------------------
/lessons/14-back4app-experiment/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | mode: 'development',
5 | context: path.join(__dirname, './'),
6 | entry: './app/app.jsx',
7 | devtool: 'inline-source-map',
8 | output: {
9 | path: path.join(__dirname, 'public'),
10 | filename: 'bundle.js',
11 | publicPath: '/',
12 | },
13 | resolve: {
14 | extensions: ['.js', '.jsx'],
15 | },
16 | module: {
17 | rules: [
18 | {
19 | test: /\.jsx?$/,
20 | loader: 'jsx-loader',
21 | exclude: /node_modules/,
22 | include: path.join(__dirname, 'app'),
23 | },
24 | ],
25 | },
26 | devServer: {
27 | contentBase: path.join(__dirname, 'public'),
28 | port: 3000
29 | }
30 | };
--------------------------------------------------------------------------------
/lessons/TEMPLATE.md:
--------------------------------------------------------------------------------
1 | # About Our Template
2 |
3 | Eyebeam's educational focus is to promote artist-led, STEAM based education. This template is intended for our teaching artists to document their lessons with a larger goal for their curriculum to be referenced or used more easily in classrooms, libraries, after school programs or anywhere STEAM programming can be offered.
4 |
5 | This template is based off of NYC Department of Education's CS4All Blueprint to teach creative computing. For more information on the core components they advise teachers and classes focus on, and to give the students the competency to be better prepared to engage with more difficult STEM lessons, I highly encourage you to read about [their approach here](https://blueprint.cs4all.nyc/what-is-cs/).
6 |
7 | # TEMPLATE BELOW
8 |
9 | ## Class Title
10 |
11 | ## Authors
12 | Your name (please include collaborators or funding institutions that have supported this work) and links to your site or Github.
13 |
14 | ## Essential Questions
15 | Questions that lead to meaningful exploration of CS concepts and practices. Examples:
16 | - How can programming represent your ideas and beliefs?
17 | - How might we use math to express ourselves creatively?
18 | - How might we use computing to impact our community?
19 | - What information is my computer sharing about me or my online activity?
20 |
21 | ## Introduction
22 | Please provide a narrative of what the unit is about, and why we should learn it that is simple enough that a student could read and understand. Example: "In this workship we will be using ... to explore ... so that you have a better understanding of how ..."
23 |
24 | ### Target Audience / Prerequisite & Pre-Assessment
25 | What age range is this exercise designed for and what do students and teachers need to know or be able to do to be successful in the workshop? Any coding languages they should already be comfortable with, any frameworks or tools they should have installed before class.
26 |
27 | ### Outcomes & Goals
28 | This can be easily answered by completing these example sentences:
29 | * In this workshop we will be… (soldering, setting up a RPi home network, making a wearable that communicates with….)
30 | * Students will walk away with a deeper understanding of…
31 |
32 | ### Pacing / Duration
33 | Number of total hours the unit will take in a typical workshop session(s). Please try to take into account transition time between instruction and hands on exercises if any prep is necessary.
34 |
35 | - Break down of the class schedule example:
36 | - :15 Overview, context, examples and vocabulary
37 | - :20 Instruction & hands on exercise
38 | - :15 Wrap-up discussion & sharing, reflection or journal and next steps
39 |
40 | ## Materials Needed
41 | What hardware, software, or other materials will students or teachers need for lessons.
42 |
43 | ### Exercises To Do Before Class
44 | What materials (readings, tasks, exercises) should students complete before class to be prepared for the lesson.
45 |
46 | ### Vocabulary (example)
47 | * Program: A procedure, or set of instructions, that performs a specific task when executed by a computer.
48 | * Programming Language: The human-readable commands and syntax (or grammar rules) used to write programs.
49 |
50 | ## Exercise Descriptions
51 | Descriptions of each exercise or phase of class. Similar to pacing but with more description of steps.
52 |
53 | ## Student Reflections, Takeaways & Next Steps
54 | Additional materials for the students to leave with that can help them dig deeper into the subject or additional exercises and challenges to help students progress their knowledge to the next level and gain mastery of the subject through independent study.
55 |
56 | * Multiple Project Exit Points: an idea of high-medium-low projects so students are locked into one end product.
57 | * First Steps - a simple exercise
58 | * Next Steps - medium exercise
59 | * Big Steps - a challenge or open ended study
60 | * Presentation: how might students share their work? With peers, outside world? What media or platforms could/should be referenced to students to encourage sharing (Instagram, Tumblr...)?
61 | * Reflection: reflection questions that ask students to think about CS concepts and practices. How can students express what they’ve learned in some creative way?
62 |
63 | ## Post Session
64 |
65 | ### References
66 | Include any sources cited, but not directly linked in the unit.
67 |
68 | ### Implementation Guidance & Teaching Reflection
69 | e.g. Please provide some guidance based on experience delivering the unit and potential modifications might you are considering making for future iterations of this unit. This is an opportunity for you as the unit author to give teachers practical guidance.
70 |
71 | ***With thanks and acknowledgement, this is based on the template provided by [Eyebeam](https://github.com/eyebeam/curriculum/blob/master/TEMPLATE.md)***
--------------------------------------------------------------------------------
/links.md:
--------------------------------------------------------------------------------
1 | - https://www.shield.ai/
2 | - https://criticalengineering.org/
3 |
--------------------------------------------------------------------------------
/makeup/00-intro.md:
--------------------------------------------------------------------------------
1 | # Making up for 00-intro
2 |
3 | You only need to complete this assingment if you missed the first class, 00-intro.
4 |
5 | ## Questions
6 |
7 | Please write an answer to the following questions. There isn't necessarily a "correct" answer, but you should think about the question and try to provide a thoughtful response.
8 |
9 | ### 1. What makes a program good? (100 words)
10 |
11 | ### 2. Please define the following terms in your own words
12 | - Protocol:
13 | - Interface:
14 | - Encoding:
15 |
16 | ### 3. What is the difference between these two interfaces? (200 words)
17 |
18 | 
19 | 
20 |
21 | ## Handing it in
22 | Please email your responses to me at st2774@nyu.edu.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "programming-is-possible",
3 | "private": true,
4 | "version": "1.0.0",
5 | "description": "Course materials for the programming is the art of the possible class",
6 | "main": "index.js",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/starakaj/programming-is-possible.git"
13 | },
14 | "author": "Sam Tarakajian",
15 | "license": "MIT",
16 | "bugs": {
17 | "url": "https://github.com/starakaj/programming-is-possible/issues"
18 | },
19 | "homepage": "https://github.com/starakaj/programming-is-possible#readme",
20 | "workspaces": [
21 | "lessons/*"
22 | ],
23 | "engines": {
24 | "node": "12.x",
25 | "yarn": "1.21.x"
26 | },
27 | "dependencies": {}
28 | }
29 |
--------------------------------------------------------------------------------
/reading_list.md:
--------------------------------------------------------------------------------
1 | # Reading List
2 |
3 | ## Fun Reading
4 | - http://www.media-arts-uts.com/aes1/wp-content/uploads/2012/01/BasicAnimationAesthetics.pdf
5 | - https://www.mnn.com/earth-matters/climate-weather/stories/pigeons-write-a-smog-blog
6 | - https://mutamorphosis.wordpress.com/2008/10/03/pigeonblog/
7 | - https://github.com/fpereiro/backendlore
8 | - https://www.sametab.com/blog/frameworks-for-remote-working
9 | - Graeber, David. _The Utopia of Rules on Technology, Stupidity, and the Secret Joys of Bureaucracy._
10 | - Shaw, Donald L. "Blue Tigers" _Borges: Ficciones._ Grant & Cutler, 1993.
11 | - https://aaronzlewis.com/blog/2021/01/17/inside-the-digital-sensorium/ "A website is not a place but a new sensorium" (NO)
12 | - Has the nice quotation about interfaces, and some fun stories as well
13 | - https://urcad.es/writing/new-american-interfaces/ "New American Interfaces"
14 | - Good questions about interfaces, doesn't have that sensorium thing I'm looking for.
15 | - https://thecreativeindependent.com/people/a-charming-conversation-between-you-a-computer-and-me/
16 | - "design interfaces with the qualities of memorable conversations in mind"
17 | - "You should feel like your input matters and that you’re more than just a consumer being sold a product or idea"
18 | - https://thecreativeindependent.com/people/lucy-siyao-liu-on-drawing-instructions/
19 | - Relationship between instructions and creativity, representations, relations.
20 | - "How can instructions relay various techniques and skills, while simultaneously leaving space to accommodate evolution and interpretation?"
21 | - Related drawings: https://www.are.na/the-creative-independent-1522276020/drawing-instructions
22 | - https://thecreativeindependent.com/people/toni-dove-on-technology-as-subject-matter/
23 | - Toni Dove, large installations, interactive installations, relationship between art world and artists.
24 | - Balkanization of the art-technology space
25 | - https://www.ucl.ac.uk/bartlett/public-purpose/sites/public-purpose/files/final_why_the_ethics_of_quantification_is_needed_now_saltelli_et_al_20_jan.pdf
26 | - Ethics of quantification. Seems cool but isn't necessarily 1000% percent relevant. Could talk about it at some point of course.
27 | - https://theconvivialsociety.substack.com/p/the-insurrection-will-be-live-streamed
28 | - Take on the blend between real and digital
29 | - Interfaces and interpermeability
30 | - https://link.springer.com/article/10.1007/s00146-020-01140-6
31 | - Wow check out this well documented IoT project
32 | - Kind of fun actually. Ethical implications?
33 |
34 | ## Fun Watching
35 | - https://www.youtube.com/watch?v=-0vrrTQFCjA (esp 21:13 - 24:09)
36 | - https://www.youtube.com/watch?v=Jkupc48RBRw (Daito - Drones)
37 | - https://www.youtube.com/watch?v=2jIlLHfSEfs (Leafcutter light thing)
38 | - https://www.dwbowen.com/telepresentwater (Tele-Present Water David Bowen)
39 | - https://vimeo.com/386776425 (Invisible Hand, https://collectiveoftwo.com/)
40 |
--------------------------------------------------------------------------------