Lab 2: Going Viral
Tuesday, September 16, 11:59pm EST
Before you begin...
One of the most dangerous ways to run this class would be to teach design concepts but then have all the assignments only be written design analyses of existing systems, like asking students to analyze the design of an existing community and suggest improvements. I say "dangerous" because design analyses alone can instill a false sense of confidence in our ability to do design well ourselves and in how simple it would be to fix complex socio-technical systems. By doing it ourselves, we learn how challenging and unpredictable social computing design really is, and develop skills for being effective at it.
So, assignments in this class will be challenging you to synthesize the lessons in the course into creating and populating social spaces. This means that you'll be interacting with and recruiting friends, family, and colleagues online throughout the semester for assignments and projects.
Furthermore, it is important to take seriously the responsibility that we have as social computing designers to mitigate harms and risks to people who use our systems. We have designed our assignments with the goal of maximizing pedagogical value and minimizing risks. We are trusting you to act in good faith to create positive outcomes. That's the Social Computing Fundamental Standard: use reasonable judgment to (1) create joy and meaning in peoples' lives, and (2) mitigate risks and harms.
We do this because the last two decades in tech have proven to me that it's critical that we learn to do this design well, and in order to learn to do this design well, we need spaces for deliberate practice.
Learning Goals
In this lab, you will gain practice making contnt go viral online. Then, you will create an interactive website using JavaScript to showcase your content and reflect on the experience.
The learning goals are:
- JavaScript: Become more familiar with Javascript and how to use it to manipulate the DOM.
- HTML/CSS: Understand how HTML and CSS interact with JavaScript to create interactive web pages.
- Social Computing: Understand what it takes to design content that spreads online, and the challenges of doing so.
1. In-Lab Walkthrough: JavaScript, Events, and the DOM
1.1 Selecting Elements
The Document method querySelector()
returns the first Element object within the document that matches the specified CSS selector, or group of CSS selectors. If no matches are found, null is returned.
Consider the following HTML snippet:
<div id="parent">
<p class="class" id="para1">First paragraph</p>
<p class="class" id="para2">Second paragraph</p>
</div>
Examples:
- Finding the first element by tag name (will select the first
<p>
element):const el = document.querySelector("p");
- Finding an element by ID (will select the element with id="parent"):
const el = document.querySelector("#parent");
- Finding the first element matching a class (will select the first element with class="myclass"):
const el = document.querySelector(".myclass");
- There are also more complex selectors, which will not be covered here.
The matching is done using depth-first pre-order traversal of the document's nodes starting with the first element in the document's markup and iterating through sequential nodes by order of the number of child nodes.
If the specified selector matches an ID that is incorrectly used more than once in the document, the first element with that ID is returned.
For the example code, print out the first paragraph Element using console.log()
. What do you notice?
If you want to print out the text content of the paragraph, you can use the textContent property:
console.log(selected_obj.textContent);
innerHTML
is similar to textContent
, but it is advised against using innerHTML to get or set text inside an element because it deals with raw HTML rather than plain text and can be susceptible to XSS attacks. Even if you are sure that the text never contains HTML syntax, it is still less semantic and slower because it needs to invoke the HTML parser. Additionally, innerText
is similar to textContent
, but it is aware of the rendered appearance of text, while textContent
is not. This means that innerText
will not return the text of hidden elements, and will also trigger a reflow to ensure up-to-date computed styles.
What if we want to select all <p>
elements? We can use querySelectorAll()
instead, which returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
The list is static, meaning that it is not updated when the document changes. If no matches are found, an empty NodeList is returned. NodeList is not an array, but it is iterable using a for()
loop or forEach()
:
const elements = document.querySelectorAll("p");
// using forEach
elements.forEach((el) => console.log(el));
// or using a for loop
for (let i = 0; i < elements.length; i++) {
console.log(elements[i]);
}
For the same example code, print out the IDs of all the paragraph Elements.
1.2 Listening for Events
Events are things that happen in the system you are programming, which the system tells you about so your code can react to them. For example, if the user clicks a button on a webpage, you might want to react to that action by displaying an information box.
Events are fired inside the browser window, and tend to be attached to a specific item that resides in it. This might be a single element, a set of elements, the HTML document loaded in the current tab, or the entire browser window.
To react to an event, you attach an event listener to it. This is a code feature that listens out for the event firing. When the event fires, an event handler function (referenced by, or contained inside the event listener) is called to respond to the event firing. When such a block of code is set up to run in response to an event, we say we are registering an event handler.
Consider the following button:
<button>Change color</button>
We can add an event listener to the button that listens for a click
event and changes the background color of the button when it is clicked:
const btn = document.querySelector("button"); // select the button element
function random(number) {
return Math.floor(Math.random() * (number + 1));
}
function changeBackground() {
const rndCol = `rgb(${random(255)} ${random(255)} ${random(255)})`;
document.body.style.backgroundColor = rndCol;
}
btn.addEventListener("click", changeBackground);
You can try this out on the same CodePen. Click the button to see the background color change.
There are many different events that can be fired by a button element. Change the click
event to one of the following events to see how the button reacts differently:
dblclick
: Fired when the button is double-clicked.mouseover
: Fired when the mouse pointer is moved onto the button.mouseout
: Fired when the mouse pointer is moved out of the button.focus
: Fired when the button gains focus (e.g., when tabbing to it - press thetab
button).blur
: Fired when the button loses focus.
You can even add multiple event listeners to the same element. For example, you can add another event listener to the button that listens for a different event and performs a different action.
Now, add a second event listener to the button that listens for a dblclick
event and changes the background color of the button (background-color
) to brat green (#8ACE00) when it is double-clicked.
To remove an event listener, you can use the removeEventListener()
method. This method takes the same parameters as addEventListener()
, so you need to provide the event type and the event handler function that you want to remove.
const btn = document.querySelector("button"); // select the button element
btn.removeEventListener("click", changeBackground);
1.3 Manipulating Attributes
Elements in HTML have attributes; these are additional values that configure the elements or adjust their behavior in various ways to meet the criteria the users want. Examples include class
, src
, href
, alt
, and many more.
Roughly every attribute on an HTML element is a property on its respective DOM object:
<img src="cat.png" />
const element = document.querySelector('img');
element.src = 'dog.png';
You can control classes applied to an HTML element via
classList.add()
and classList.remove()
:
const image = document.querySelector('img');
// Adds a CSS class called "active".
image.classList.add('active');
// Removes a CSS class called "hidden".
image.classList.remove('hidden');
Consider the code below that toggles the visibility of an image when a button is clicked. It does so by changing the src
attribute of the <img>
element:
<h1>Click for a present:</h1>
<img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/1083533/gift-icon.png" />
function openPresent() {
const image = document.querySelector('img');
image.src ='https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExOWRjaDlwYzQzMG9kMHp0NWJkdThydTE2c2tlMjFrNTMyb2Z5Y3FrOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/hMsapn0UNCGvi3Lu3R/giphy.gif';
image.removeEventListener('click', openPresent);
}
const image = document.querySelector('img');
image.addEventListener('click', openPresent);
In a new CodePen, adjust the textContent
attribute of the <h1>
element to say "Hooray! You got a present!" when the image is clicked.
Like in the previous example (TiO #4), you'll notice we are finding the element twice: once to add the event listener, and once inside the event handler function. This is inefficient, especially if the DOM query is complex. Instead, we can use Event.currentTarget
to refer to the element that the event listener is attached to.
An Event element is passed to the listener as a parameter. The event's currentTarget
property is a reference to the object that we attached to the event, in this case the
<img>
's Element to which we added the event listener.
function openPresent() {
const image = event.currentTarget; // changed!
image.src ='https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExOWRjaDlwYzQzMG9kMHp0NWJkdThydTE2c2tlMjFrNTMyb2Z5Y3FrOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/hMsapn0UNCGvi3Lu3R/giphy.gif';
image.removeEventListener('click', openPresent);
}
const image = document.querySelector('img');
image.addEventListener('click', openPresent);
Note that Event.currentTarget
is different from Event.target
. The target
property the element that was clicked / "dispatched the event" (might be a child of the target). Whereas currentTarget
the element that the original event handler was attached to.
1.4 Manipulating Elements
In addition to manipulating attributes of existing elements, you can also create new elements and add them to the DOM dynamically using createElement()
and appendChild()
.
const newHeader = document.createElement('h1'); // create a new h1 element
newHeader.textContent = 'Hooray! You got a present!'; // set the text content of the h1 element
const newImage = document.createElement('img'); // create a new img element
newImage.src = 'https://media1.giphy.com/media/v1.Y2lkPTc5MGI3NjExOWRjaDlwYzQzMG9kMHp0NWJkdThydTE2c2tlMjFrNTMyb2Z5Y3FrOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/hMsapn0UNCGvi3Lu3R/giphy.gif'; // set the src attribute of the img element
const container = document.querySelector('#container'); // select the parent container element
container.appendChild(newHeader);
container.appendChild(newImage);
We can also remove elements from the DOM by calling the remove()
method on the DOM object.
oldHeader = document.querySelector("h1");
oldImg = document.querySelector("img");
oldHeader.remove();
oldImg.remove();
Alternatively, we can call removeChild()
on the parent element to remove a child element.
const container = document.querySelector('#container'); // select the parent container element
const oldHeader = document.querySelector("h1");
const oldImg = document.querySelector("img");
container.removeChild(oldHeader); // selectively removes h1 header if it is a child of #container
container.removeChild(oldImg); // selectively removes img if it is a child of #container
A third way is to set the innerHTML
property of an element to an empty string, which removes all child elements of that element:
const container = document.querySelector('#container');
container.innerHTML = ''; // removes all child elements of #container
This is a new CodePen.
After the user opens their present, we would like them to be able to leave a thank you message. To the comments
div (line 6), dynamically add a <textarea></textarea>
and a <button>Submit</button>
that asks the user to input a thank you message. When the button is clicked, create a new <p>
element with the thank you message that the user entered in the textarea and append it the <div id="comments"></div>
container. Then, remove the textarea from the page.
Hint: To get the text entered into the textarea, you can use the value
property of the textarea element. For buttons it is innerText
.
1.5 Linking External JavaScript and CSS Files to HTML
Thus far, we've been using CodePen to try out the examples. However, for this assignment, you will be creating your own repository and working locally on your computer. To add a JavaScript file to your HTML file, you can use the <script>
tag in the <head>
or <body>
section of your HTML file. The defer property is useful for when you want JavaScript to run only once the entire document has been parsed. You can also add external CSS files to your HTML file using the <link>
tag in the <head>
section of your HTML file.
This will load the script.js
file and execute the JavaScript code contained in it, and will also load the styles.css
file and apply the CSS styles contained in it to the HTML document.
<!DOCTYPE html>
<html>
<head>
<script src="script.js" defer></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>This is a heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
2. Lab Assignment
2.1 Requirements
By the deadline, you should have created at least 4 memes, two of which have been posted on a social media platform of your choice. See rules below.
And your repository should contain:
-
A directory with the following structure:
- A directory called
memes
that contains the images/videos of your 4 memes (screen recordings or screenshots are fine if you can't share the original file).- At least one meme must be an image with text overlay (a "classic" meme).
memes.html
: An HTML file that showcases your memes and contains your reflection on the experience of creating and posting them.memes.css
: A CSS file that styles the memes HTML file.memes.js
: A JavaScript file that adds interactivity to the memes HTML file.rating.html
: An HTML file where users can rate memes and see the results.rating.css
: A CSS file that styles the rating HTML file.rating.js
: A JavaScript file that adds interactivity to the rating HTML file.
- A directory called
-
Each HTML file should contain the following:
- An appropriate title
- Relevant heading
- Links to the CSS and JavaScript files
-
The
memes
page should contain:- The two memes that you posted on social media, embedded using an
iframe
or as an image or video with a link to the post. - The number of likes, shares, retweets, upvotes, views, or other relevant metrics for each meme. This should be hidden by default and displayed when a button is clicked (toggle).
- Your definition of "viral" and evidence of virality.
- A link to the original social media post in plain text (no
<a>
tag). - A brief reflection of 300 to 500 words:
- How you iterated on the meme(s) you created
- The rationale for choosing a particular platform
- In what larger context (e.g., current events, online subcultures) was the content created?
- Who was the intended audience?
- Why did the meme go viral (or not)?
- This analysis is important: even if you don’t have a lot of social media presence, you can still analyze your design and performance.
- Specify which meme you want to submit to the class vote. To ensure fairness, only images are allowed.
- A link to the
rating.html
page.
- The two memes that you posted on social media, embedded using an
-
The
rating
page should contain:- A section to display one meme after another (4 memes total).
- These must be the four memes that you created for this assignment.
- A text area to input a score from 1 to 10.
- A button to submit the score.
- Once a user submits their score, the next meme should be displayed.
- After all memes have been rated, display the highest-scoring meme and the average score for all four memes.
- A section to display one meme after another (4 memes total).
If you are not comfortable posting to a social media site publicly, you can post to a private group or page and share a video recording or screenshot with me. You can also post anonymously and/or create "finsta"-type accounts instead of using your "rinsta" account. If you have any concerns about this assignment, please reach out to me.
Different websites have different ways of obtaining iframe or embed links; you'll need to do some research to figure out how to embed content from a specific social media site on your website. If the website doesn't have an iframe option, you can take a screenshot of the post and embed the image in your website along with a link to the post.
2.2 Clone Your Repo
Get your Lab SSH URL from the CS77-S25 GitHub organization. The repository to clone is named Lab2-<userID>-<userID>
.
$ git clone [your lab2-userID-userID url]
$ cd lab2-userID-userId
$ ls
memes.html memes.js memes.css rating.html rating.js rating.css memes/
2.3 Make a Meme
This assignment is an exercise in the challenges of designing something that spreads online. Your challenge is simple: create something that goes viral.
You can create any content you want: memes, videos, opinion essays, collective action activism, photoshops, a collective fiction writing effort, and so on. It needs to be spreadable online. Common platforms might include TikTok, Instagram, Facebook, Reddit, Twitter/X, Mastodon, YouTube, Medium, or blogs/news outlets.
You do not necessarily need to try and go viral across the whole internet. You can target a more focused community that you belong to. Make sure you can explain to the staff in your writeup what that community is, and why the piece is designed to go viral in that community. However, think carefully about the norms of the community you're posting to before submitting. For those of you who are not active on social media, here are a few platforms you can join without using your real identity: Reddit, TikTok, and Instagram.
2.3.1 Iterate
Do not expect that your first attempt will go viral or gain much traction. Reflect on what's working and what's not — lecture concepts may help diagnose here — and try something else. Your written reflection will tell us about what you learned through this iteration process. While I won't grade you down if you iterate and nothing goes viral, we will consider whether your meme is a fit for the communities where you post it, and whether it can reasonably spread there: for example, don't push your meme to a WhatsApp group that has only seven people. Remember, a requirement is that you create at least four memes.
Upworthy recommends that you try writing out 25 different versions of the main text or headline before posting — that the first ones will feel awkward and ridiculous, but you need to push through the awkwardness and keep going to find the best way to phrase your idea.
2.3.2 The Rules
- No negativity: create joy, not pain. Follow the Social Computing Fundamental Standard, and use reasonable judgment as to what content is off-limits for a course, including targeting groups that other community members belong to, personal attacks, libel, slander, harassment, pornography, and bullying; check your idea with the staff if you're not sure.
- No CS77 meta-memes. This means no memes about the course or the department, and specifically, memes that say "my professor wants me to go viral, help me go viral.” Seriously. Don't do it. 50% points off if you do.
- You must create the content, not share someone else's content. However, you may remix someone else's content (with attribution/permission as appropriate) to create yours if desired.
- This meme must be new content created for this class: you cannot reuse something that you previously created or shared.
- Collect evidence of your meme's virality. In some cases this is easy, such as retweet, view, or upvote counts; in other cases it might require more creativity, such as analytics trackers (e.g., Google Analytics) if you created a web page or asking around to find out where your emails got forwarded to.
Helpful hints based on what worked (and didn't work) for students in the past
- Be mindful of the platform you are posting in. If you are posting on a Swarthmore meme forum, for example, make sure it’s relevant and particularly resonant for those at Swarthmore. Some of the most viral submissions from last year were in non-Swarthmore communities. Create several pieces of content and iterate on failed viral attempts, even trying similar things on different platforms. (Something could bomb on Facebook but see success on Reddit).
- The best write-ups showed an attention to learning from failure and iterating, despite initial attempts that did not go viral.
- Timing matters. People are less likely to share or upvote something that becomes less original as a type of joke becomes saturated. So get creative!
2.4 Submission Instructions
Submit your assignment by committing and pushing your changes to your GitHub repository:
$ git add <changed file1> <changed file2> ...
$ git commit -m "Lab 2 completed. We're influencers now!"
$ git push
Make sure you have the appropriate files and images in the correct folders as described in the requirements above.
3. Grading
3.1 Grading Rubric
Category | Insufficiency | Adequacy | Proficiency | Mastery |
---|---|---|---|---|
HTML/CSS Content (5 points) | Missing most required content, e.g., title, headings, CSS styling, URLs; content is not relevant to the assignment; and content is not well-structured | Missing many required elements OR content is not well-structured | Missing minor required elements but is well-structured | Includes all required elements and is well-structured |
JavaScript Functionality (5 points) | Missing most required functionality, e.g., event listeners, DOM manipulation; code is not well-organized or commented | Missing many required functionalities OR code is not well-organized or commented | Missing minor required functionalities but is relatively well-organized and commented | Includes all required functionalities and is well-organized and commented |
Meme submission (5 points) | Meme is a repost of your own or others' content; meme not submitted to web portal | Meme is missing required content, e.g., alt text, or alt text is unintelligible | Meme is created de novo for the course and was submitted to the web portal for voting, but may have minor issues (e.g., missing alt text) | Meme created de novo for course, includes alt text, and was submitted for voting |
Execution (5 points) | A single attempt that neither went viral nor was iterated on, or was a poor fit for the target community; unclear message | Limited viral success or limited iteration, limited fit for the target community; limited clarity and creativity | Had some viral success or iterated moderately; relatively good fit for the community; meme is relatively clear and creative | Meme communicates a clear message in a creative and effective way; meme went viral or demonstrated repeated iterations, learning and improving each time. |
Reflection (5 points) | Missing content on decisionmaking and/or evaluation of virality; ineffective reflection of why the content was successful or not; missing or misusing course concepts | Surface-level reflection of why the content was successful or superficial engagement with course concepts | Appropriate reflection of why the content was successful or not and some engagement with course concepts. | Strong evaluation of why the content was successful or not and engages with course concepts. |
3.2 Extra Credit
A small number of submissions may earn extra credit in three ways:
- Class Vote (+5%): The class voted yours as their favorite meme.
- Win the Internet (+10%): You demonstrate that your meme went especially viral.
- Pairwise Comparison (+30%): Your
ranking
page ranks memes using pairwise comparison instead of a simple rating scale. For N items, this requires N*(N-1)/2 comparisons. The meme that wins the most pairwise comparisons is the highest ranked.
Go for it!
FAQ
- Does it matter how viral my meme actually went?
You are not graded directly on how viral your content went, but instead on your reflections on the experience. (Actual virality will be extra credit.)
- Can I pay for popularity?
No. Just no. Don't pay for post boosting.
- Not fair, my friend knows an influencer!
It's OK. You're not graded on actual popularity. They will probably have a different sort of reflection than you, but it doesn't make your experience trying to make something go viral any less valid.
- Do you have examples of memes?
Example Memes
Resources
- Javscript The Definitive Guide
- Mozilla Developer Network Web Docs
- W3Schools HTML Tutorial
- W3Schools CSS Tutorial
- W3Schools JavaScript Tutorial
Acknowledgements
Parts of this assignment are adapted from Michael Bernstein's Social Computing course at Stanford University and: (1) an online tutorial and (2) MDN Web Docs.