PageSourceSearch

https://roll20.net/

html roll20.net collected 2026-09-24 08:29:16 UTC 75,679 bytes, 1,910 lines download raw bytes

1
2<!DOCTYPE html>
3<html lang="en" data-navbar-cached="1">
4<head>
5	<meta name=“facebook-domain-verification” content=“lb07chyng6etwkpmjwu29mkje960mx” />
6	<!-- Google Tag Manager -->
7  
7<script id="gtmScript" nonce=''>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
8  new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
9  j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
10  'https://www.googletagmanager.com/gtm.js?id='+i+dl+ '&gtm_auth=RyNPjkDTh-LgK4oo5gJi6A&gtm_preview=env-1&gtm_cookies_win=x';
11  var n=d.querySelector('[nonce]');n&&j.setAttribute('nonce',n.nonce||n.getAttribute('nonce'));f.parentNode.insertBefore(j,f);
12  })(window,document,'script','dataLayer','GTM-MKL9HM6');</script>
12
13<!-- End Google Tag Manager -->
14	<meta charset="utf-8">
15	<meta name="viewport" content="width=device-width, initial-scale=1" />
16
17	<meta charset="utf-8">
18	
19	<title>Roll20: Online virtual tabletop for pen and paper RPGs and board games </title>
20	
21
22	
23
24	
25		<meta property="og:title" content="Roll20 - Virtual Tabletop for Playing D&amp;D, Pathfinder, Call of Cthulhu, TTRPGs" /><meta property='og:type' content='website' />
26<meta property='og:url' content='https://roll20.net' />
27<meta property='og:image' content='images/roll20-home-og.jpg' />
28<meta property="og:description" content="Easily create characters, organize games, purchase content, find players, and customize your story for your group - all in your browser." /><meta property='og:locale' content='en_US' />
29<meta property='og:locale:alternate' content='af_ZA' />
30<meta property='og:locale:alternate' content='ca_CA' />
31<meta property='og:locale:alternate' content='zh_Hant_TW' />
32<meta property='og:locale:alternate' content='cs_CZ' />
33<meta property='og:locale:alternate' content='da_DK' />
34<meta property='og:locale:alternate' content='nl_NL' />
35<meta property='og:locale:alternate' content='fr_FR' />
36<meta property='og:locale:alternate' content='de_DE' />
37<meta property='og:locale:alternate' content='el_GR' />
38<meta property='og:locale:alternate' content='he_IL' />
39<meta property='og:locale:alternate' content='hu_HU' />
40<meta property='og:locale:alternate' content='it_IT' />
41<meta property='og:locale:alternate' content='ja_JP' />
42<meta property='og:locale:alternate' content='ko_KR' />
43<meta property='og:locale:alternate' content='pl_PL' />
44<meta property='og:locale:alternate' content='pt_PT' />
45<meta property='og:locale:alternate' content='ru_RU' />
46<meta property='og:locale:alternate' content='es_ES' />
47<meta property='og:locale:alternate' content='sv_SE' />
48<meta property='og:locale:alternate' content='tr_TR' />
49<meta property='og:locale:alternate' content='uk_UK' />
50
51		<meta property="og:site_name" content="Roll20" />
52		<meta property="og:logo" content="https://roll20.net/images/logo-die-large.png?1790172625" />
53		<meta property="og:image:alt" content='Roll20 logo, a pink and purple 20-sided die with the number twenty featured on its face. The die sits on top of the name "Roll20" in black font.' />
54		<meta name="twitter:card" content="summary"/>
55		<meta name="twitter:site" content="@roll20app"/>
56		
57	
58
59	<meta name="description" content="Play games anywhere. Share them with anyone. With Roll20® as your virtual tabletop, your adventures are limitless.">
60
61	
62		<link rel="stylesheet" href="/v3/assets/css/marketplace-v3.css?1790172626" type="text/css" />
63	
64	<link rel="stylesheet" href="/v3/assets/js/libs/@fortawesome/fontawesome-free/css/all.min.css?1790172626" type="text/css" />
65	<link rel="stylesheet" href="/v2/css/stripe.css?1790172626" type="text/css" />
66	<link rel="stylesheet" href="/css/fonts.css?1790172625" type="text/css" />
67	<link rel="stylesheet" href="/v2/css/colors.css?1790172626" type="text/css" />
68	<link rel="stylesheet" href="/v3/assets/css/homepage-v3.css?1790172626" type="text/css" />
69
70	
71		
71<script type="text/javascript" src="/assets/v3.js?1790172626"></script>
71
72	
73
74	
75	
75<script src="https://js.stripe.com/v3/"></script>
75
76	
76<script type="text/javascript">
77		const stripe = Stripe("pk_live_1vH03GH31ZvT2lI7yU8bcClq9jDHOPU4OlnsWqZKu2s4Vs014SXpmjsjnRv37wD8PhLLkYj1YcLSxVDbdzba2HZiQ00qGgUFDqB");
78		const elements = stripe.elements();
79	</script>
79
80
81	
82
83	
83<script type="text/javascript">
84		
85			$('html').attr('data-theme', 'light');
86		
87	</script>
87
88
89	
90	
90<script type="text/javascript">
91		const url = new URL(window.location.href);
92		url.pathname = url.pathname.split('/').slice(0, 3).join('/'); // get the first one or two parts of the url path i.e. '/campaigns/search' or '/login'
93		var _conv_page_type = url.toString();
94		var _conv_category_id = ""; // unused
95		var _conv_category_name = ""; // only used in V2 marketplace
96		var _conv_product_sku = ""; // only used in V2 marketplace
97		var _conv_product_name = ""; // only used in V2 marketplace & characters
98		var _conv_product_price = ""; // only used in V2 marketplace
99		var _conv_customer_id = 'visitor';
100		var _conv_custom_v1 = 'loggedout';
101		var _conv_custom_v2 = ""; // unused
102		var _conv_custom_v3 = ""; // unused
103		var _conv_custom_v4 = ""; // unused
104	</script>
104
105	
106	
107		
107<script type="text/javascript" src="//cdn-4.convertexperiments.com/v1/js/10042023-10042444.js" integrity="sha384-gSDcZjQNbDoXzGah4K3Gb02Y6qVZNgNiMUn6LdQ5FCsldO6ne//TUKkgKabzB65Z"></script>
107
108	
109
110	
111	
112		
113			<link rel="stylesheet" href="/static-fallback/nav-bar/master/assets/main-DLmYOJ5a.css" />
114		
115	
116</head>
117
118<body>
119	<a href="mainContent" class="skip-link">Skip to Main Content</a>
120	<!-- Google Tag Manager (noscript) -->
121  <noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-MKL9HM6&gtm_auth=RyNPjkDTh-LgK4oo5gJi6A&gtm_preview=env-1&gtm_cookies_win=x"
122  height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
123<!-- End Google Tag Manager (noscript) -->
124	<style>
125	.bottom-banner {
126		background-color: #fff;
127		position: fixed;
128		bottom: 40px;
129		z-index: 9999;
130		width: calc(100% - 30px);
131		margin-left: 15px;
132		box-shadow: 0px 0px 16px #888888;
133		display: flex;
134		align-items:center;
135		justify-content: space-around;
136	}
137
138	.bottom-banner-css-version-v2{
139		border-left: 15px solid #ec008c;
140	}
141	.bottom-banner-css-version-v3{
142		border-left: 15px solid #35c8f5;
143	}
144	.bottom-banner-css-version-v2 .bottom-banner__button{
145		background-color: #35c8f5;
146	}
147	.bottom-banner-css-version-v3 .bottom-banner__button{
148		background-color: #ec008c;
149	}
150
151	.bottom-banner--hidden {
152		display:none;
153	}
154
155	.bottom-banner__message {
156		padding: 1em;
157		float: left;
158		font-size: 12px;
159		line-height: 1.4;
160	}
161
162	.bottom-banner__dismiss-icon {
163		float: right;
164		padding:10px;
165		color: #d1d1d1;
166		cursor: pointer;
167		align-self: flex-start;
168	}
169	.bottom-banner__dismiss-icon:hover {
170		color: #333333;
171	}
172
173	.bottom-banner__button, .bottom-banner__button:hover, .bottom-banner__button:visited, .bottom-banner__button:active {
174		float:right;
175		font-size: 16px;
176		line-height: 1.6;
177		border-radius: 4px;
178		padding: 7px 15px 7px 15px;
179		color: #fff !important;
180		transition: all .25s linear;
181		text-decoration: none;
182	}
183	.bottom-banner__button:hover {
184		color: #fff;
185	}
186
187	.cookie-modal--hidden {
188		display: none;
189		position: fixed;
190		z-index: 10001;
191		left: 0;
192		top: 0;
193		width: 100%;
194		height: 100%;
195		overflow: auto;
196	}
197
198	.cookie-modal-content {
199		background-color: var(--color-surface1);
200		margin: 20% auto;
201		padding: 20px;
202		width: 40%;
203		box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.6), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
204	}
205
206    .cookie-modal-content h3 {
207        display: inline-block;
208	}
209
210	.cookie-modal-css-version-v3 {
211		padding-top: 16px;
212	}
213
214	.cookie-modal_switch .switch{
215        display: inline-block;
216        float: right;
217        margin-top: 30px;
218		width: 60px;
219	}
220	.switch {
221		position: relative;
222		display: inline-block;
223		width: 60px;
224		height: 26px;
225	}
226
227	.switch input {
228		opacity: 0;
229		width: 0;
230		height: 0;
231	}
232
233	.slider {
234		position: absolute;
235		cursor: pointer;
236		top: 0;
237		left: 0;
238		right: 0;
239		bottom: 0;
240		background-color: #8492A6;
241		-webkit-transition: .3s;
242		transition: .3s;
243	}
244
245	.slider:after {
246		content: "Off";
247		position: absolute;
248		top: 50%;
249		right: 11px;
250		transform: translateY(-50%);
251		color: #fff;
252		font-family: helvetica;
253		font-weight: bold;
254		font-size: 13px;
255	}
256
257	.slider:before {
258		position: absolute;
259		content: "";
260		height: 20px;
261		width: 20px;
262		left: 3px;
263		bottom: 3px;
264		background-color: white;
265		-webkit-transition: .3s;
266		transition: .3s;
267	}
268
269	input:checked + .slider {
270		background-color: #00853C;
271	}
272
273	input:disabled + .slider {
274		cursor: no-drop;
275		background-color: #C2C7D1;
276	}
277
278	input:disabled + .slider:before {
279		background-color: #DFE2E7;
280	}
281
282	input:focus + .slider {
283		box-shadow: 0 0 5px #2196F3;
284	}
285
286	input:checked + .slider:before {
287		-webkit-transform: translateX(33px);
288		-ms-transform: translateX(33px);
289		transform: translateX(33px);
290	}
291
292	input:checked + .slider:after {
293		content: "On";
294		right: auto;
295		left: 11px;
296	}
297
298	/* Rounded sliders */
299	.slider.round {
300		border-radius: 26px;
301		width: 60px;
302	}
303
304	.slider.round:before {
305		border-radius: 50%;
306	}
307	.close {
308		float: right;
309		font-size: 20px;
310		font-weight: bold;
311		line-height: 18px;
312		color: var(--color-grayscale1);
313		text-shadow: 0 1px 0 #ffffff;
314		opacity: 0.2;
315		filter: alpha(opacity=20);
316	}
317	.close:hover {
318		color: var(--color-grayscale1);
319		text-decoration: none;
320		opacity: 0.4;
321		filter: alpha(opacity=40);
322		cursor: pointer;
323	}
324</style>
325
326<!--googleoff: all-->
327<div id="gdpr-notification" class="bottom-banner bottom-banner--hidden bottom-banner-css-version-v3">
328	<div class="bottom-banner__message">
329		Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences <a href='#' id='banner-link-preferences'>here</a>.
330	</div>
331	<span class="bottom-banner__dismiss-icon" id="gdpr-notification-dismiss-button" aria-label="Close Cookie Toast" role="button" tabindex="0">&times;</span>
332</div>
333
334<div id="cookie-modal" class="cookie-modal--hidden">
335
336  <!-- Modal content -->
337  <div class="cookie-modal-content cookie-modal-css-version-v3">
338    <span class="close" id="cookie-modal-dismiss">&times;</span>
339	<h3>Cookie Preferences</h3>
340	<span class="cookie-modal_switch">
341		<label class="switch">
342		<span class="sr-only">Accept cookies</span>
343		<input class="feature_toggle" id="cookie-modal-input" type="checkbox">
344		<span class="slider round"></span>
345	</span>
346	<hr>
347
348    We use Cookies to help personalize and improve Roll20. For more information on our use of non-essential Cookies, visit our Privacy Policy <a href=https://roll20.zendesk.com/hc/articles/360037770793-Terms-of-Service-and-Privacy-Policy target='_blank'>here.</a>
349  </div>
350
351</div>
352<!--googleon: all-->
353
354<script src="https://www.datadoghq-browser-agent.com/datadog-rum.js" type="text/javascript">
355</script>
vendor: 64 bytes, lines 355-356
355
356<script async src="https://www.googletagmanager.com/gtag/js?id=
356UA-31040388-1
vendor: 12 bytes, line 356
356"></script>
357<script type="text/javascript" nonce="">
358	// Google analytics function to send events via analytics.js
359	// Remove after everything has been switched to gtag
360	(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
361	(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
362	m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
363	})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
364
365	// Google analytics function to send events via gtag.js
366	function gtag(){dataLayer.push(arguments);}
367
368	initializeOldGoogleAnalytics();
369	initializeNewGoogleAnalytics();
370
371	window['ga-disable-UA-31040388-1'] = true;
372
373	var gdprCookie = getCookie("gdpr_accepts_cookies");
374
375	if (gdprCookie != undefined) {
376		gdprCookie == "true" ? gdprCookie = true : gdprCookie = false;
377	};
378
379	var gdprBanner = document.getElementById("gdpr-notification");
380	var gdprBannerDissmissButton = document.getElementById("gdpr-notification-dismiss-button");
381	var gdprLoggedIn = false;
382	var gdprAccountAcceptsCookies = null;
383
384	var cookieModal = document.getElementById("cookie-modal");
385	var cookieModalClose = document.getElementById("cookie-modal-dismiss");
386	var cookieModalSwitch = document.getElementById("cookie-modal-input");
387
388	var bannerLinkPreferences = document.getElementById("banner-link-preferences");
389
390	bannerLinkPreferences.onclick = function () {
391 		cookieModal.style.display = 'block';
392		hideGDPRBanner();
393 	}
394
395	function setGDPRCookie(value, expirationInDays) {
396		var date = new Date();
397		date.setTime(date.getTime() + expirationInDays * 24 * 60 * 60 * 1000); //convert to milleseconds
398		var expires = "expires="+ date.toUTCString();
399		document.cookie = "gdpr_accepts_cookies=" + value + ";" + expires + ";path=/"+ ";domain=.roll20.net";
400	}
401
402	function getCookie(cname) {
403		var name = cname + "=";
404		var ca = document.cookie.split(';');
405		for(var i = 0; i < ca.length; i++) {
406			var c = ca[i];
407			while (c.charAt(0) == ' ') {
408				c = c.substring(1);
409			}
410			if (c.indexOf(name) == 0) {
411				return c.substring(name.length, c.length);
412			}
413		}
414		return undefined;
415	}
416
417	function checkGdprStatus() {
418		if (gdprLoggedIn == true) {
419			checkAccountGdprCookieSettings();
420		} else {
421			checkPublicGdprCookieSettings();
422		}
423	}
424
425	function checkAccountGdprCookieSettings() {
426		var cookieExists = getCookie("gdpr_accepts_cookies");
427
428		switch(cookieExists){
429			case "true":
430				acceptCookies();
431				break
432			case "false":
433				denyCookies();
434				break
435			case undefined:
436				showGDPRBanner();
437				acceptCookies();
438				break
439		}
440	}
441
442	function checkPublicGdprCookieSettings() {
443		console.log('Not logged in - checking cookie GDPR status');
444		const in_discord = false;
445		if (gdprCookie == undefined) {
446			console.log("No GPDR Cookie Detected");
447			// If a user is logging in from the discord activity, we want to deny our cookies by default so we don't show the cookie banner. Later, we can figure out a better way to handle instead of denying out of the gate (so we have analytics, for example), but for MVP, this works
448			if(in_discord){
449				denyCookies();
450			}else{
451				showGDPRBanner();
452				acceptCookies();
453			}
454
455		} else if (gdprCookie == true){
456			console.log("GDPR Cookie Detected");
457			acceptCookies();
458		}
459	}
460
461	// Options object for google analytics based on the current account
462	function getAnalyticsConfigOptions() {
463		
464			return {'cookieDomain': 'auto'}
465		
466	}
467
468	// Not impacted by GDPR - just connects our account
469	// Remove after everything has been switched to gtag
470	function initializeOldGoogleAnalytics() {
471		ga('create', 'UA-31040388-1', getAnalyticsConfigOptions());
472	}
473
474	// Not impacted by GDPR - just connects our account
475	function initializeNewGoogleAnalytics() {
476		window.dataLayer = window.dataLayer || [];
477
478		gtag('js', new Date());
479
480		// Universal analytics
481		gtag('config', 'UA-31040388-1', { ...getAnalyticsConfigOptions(), send_page_view: false });
482		// Google Analytics 4
483		gtag('config', 'G-SZLSVQPSWG', { ...getAnalyticsConfigOptions(), send_page_view: false });
484	}
485
486	function turnOnGoogleAnalytics() {
487		window['ga-disable-UA-31040388-1'] = false;
488		ga('send', 'pageview');
489		if(window.dataLayer) {
490			dataLayer.push({'event': 'optedIn'});
491		}
492	}
493
494	var showGDPRBanner = function () {
495		gdprBanner.classList.remove("bottom-banner--hidden");
496	}
497
498	var hideGDPRBanner = function () {
499		gdprBanner.classList.add("bottom-banner--hidden");
500	}
501
502	var updateUserAccount = function(account_id, value) {
503		var xhr = new XMLHttpRequest();
504		// need to get the below working for marketplace, compendium, landing (only works for app)
505		xhr.open("PATCH", '/accounts/'+account_id, true);
506		xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
507		var cookieValue = "account[gdpr_accepts_cookies]=" + value;
508		xhr.send(cookieValue);
509	}
510
511	var acceptCookies = function () {
512		setGDPRCookie(true, 365);
513		
514
515		turnOnGoogleAnalytics();
516		turnOnDataDogRUM();
517		// hideGDPRBanner();
518		document.getElementById("cookie-modal-input").checked = true;
519	}
520
521	var denyCookies = function () {
522		setGDPRCookie(false, 365);
523		
524	}
525
526	var toggleCookie = function () {
527		var switchChecked = document.getElementById("cookie-modal-input").checked;
528		setGDPRCookie(switchChecked, 365);
529
530		
531	}
532
533	var showCookieModal = function (){
534		cookieModal.style.display = "block";
535	}
536	var closeCookieModal = function (){
537		cookieModal.style.display = "none";
538	}
539
540	if (gdprCookie == true || gdprAccountAcceptsCookies == true){
541		document.getElementById("cookie-modal-input").checked = true;
542	}
543
544	gdprBannerDissmissButton.addEventListener("click", hideGDPRBanner);
545	cookieModalClose.addEventListener("click", closeCookieModal);
546	cookieModalSwitch.addEventListener("click", toggleCookie);
547
548	checkGdprStatus();
549
550	function vttSampleRate() {
551		const sampleRate = 0;
552		if (sampleRate > 5) return sampleRate;
553		return 5;
554	}
555
556	function experiment({ chatTech }) {
557		const experimentsEnabled =false;
558		return experimentsEnabled && chatTech === 'simple-peer';
559	}
560
561	function staging({ hostName }) {
562		return hostName === 'roll20staging.net';
563	}
564
565	function ddSampleRate(opts) {
566		if (experiment(opts)) return 100;
567		return staging(opts) ? 100 : vttSampleRate();
568	}
569
570	function turnOnDataDogRUM () {
571		var tmplMeta = {
572			chatTech: '',
573			hostName: 'roll20.net',
574			version: '26.9.23',
575		};
576		var sampleRate = ddSampleRate(tmplMeta);
577		window.DD_RUM && window.DD_RUM.init({
578			applicationId: '95ddf222-5b92-4a62-803a-185cdd723c8b',
579			clientToken: 'pub3fb1f7cf273c5d345be974e50be0dfda',
580			site: 'datadoghq.com',
581			service:'d20app',
582			sampleRate,
583			trackInteractions: true,
584			version: tmplMeta.version,
585		});
586	}
587</script>
587
588
589
590	
590<script type="text/javascript">
591    // Sets a browser cookie, but only allows true or false flags
592    function setCookie(name, value, expirationInDays) {
593        let date = new Date();
594        date.setTime(date.getTime() + expirationInDays * 24 * 60 * 60 * 1000); //convert to milleseconds
595        const expires = `expires=${date.toUTCString()}`;
596        if (value == true || value == false) {  
597            document.cookie = `${name}=${value};${expires};path=/;domain=.roll20.net`;
598        } else if (name == "subscriptionGiftPurchaseInfo"){
599            // it is a gift subscription and we need some actual values
600            let amount = value.substring(
601                value.indexOf("=") + 1,
602                value.lastIndexOf("|")
603            )
604            let giftToId = value.split('|giftToId=')[1];
605            document.cookie = `subscriptionGiftPurchaseInfo=true|amount=${amount*100}|giftToId=${giftToId};${expires};path=/;domain=.roll20.net`;
606        }else {
607            return undefined;
608        }
609    }
610
611    // Gets a browser cookie value
612    function getCookie(cname) {
613        let name = cname + '=';
614        let ca = document.cookie.split(';');
615        for(let i = 0; i < ca.length; i++) {
616            let c = ca[i];
617            while (c.charAt(0) == ' ') {
618                c = c.substring(1);
619            }
620            if (c.indexOf(name) == 0) {
621                return c.substring(name.length, c.length);
622            }
623        }
624        return undefined;
625    }
626
627    function checkCookieFlag(name) {
628        let flag = getCookie(name);
629        if (flag != undefined) {
630            flag == 'true' ? flag = true : flag = false;
631        }
632        return flag;
633    }
634</script>
634
635
636
637	<!-- some pages use the full width of the page (i.e. Characters) but others are more constrained (i.e. v2 pages), so setting width as "full" or "reg" we can make the navbar span the full width or 1440px based on which page the user is on -->
638<style>
639.reg{
640  display: flex;
641  justify-content: center;
642}
643.reg .navbar-placeholder{
644  max-width: 1440px;
645}
646.full .navbar-placeholder{
647  width: 100%;
648}
649.navbar-placeholder{
650  background-color: var(--color-navbar-background);
651  height: 60px;
652  width: 100%;
653  display: flex;
654  align-items: center;
655  justify-content: space-between;
656  padding: 0 20px;
657  box-sizing: border-box;
658  box-shadow: 0 4px 2px -2px rgba(31, 41, 55, 0.1)
659}
660.left-side-placeholder{
661  display: flex;
662  gap: 2rem;
663  align-items: center;
664  flex-direction: row;
665}
666.right-side-placeholder {
667  display: flex;
668  gap: 1rem;
669  align-items: center;
670  flex-direction: row;
671}
672.left-side-placeholder p{
673  text-decoration: none;
674  display: flex;
675  flex-direction: row;
676  font-size: 18px;
677  position: unset;
678  font-weight: 700;
679  margin-left: 0;
680  color: var(--color-item);
681}
682.left-side-placeholder p {
683  display: flex;
684  align-items: center;
685  padding-top: 20px;
686}
687.arrow-svg {
688  height: 24px;
689}
690.placeholder-subscribe-light{
691  background: linear-gradient(to left, #CC8900 40%, #664400);
692  border: none !important;
693  text-transform: none;
694  color: var(--color-filled-button-text);
695  border-radius: 8px;
696}
697.placeholder-subscribe-dark{
698  background: linear-gradient(to left, #CC8900 40%, #664400);
699  border: none !important;
700  text-transform: none;
701  color: var(--color-filled-button-text);
702  border-radius: 8px;
703}
704.navbar-mobile-placeholder{
705  display: none;
706}
707@media (max-width: 991px) {
708  .navbar-placeholder{
709    display: none;
710  }
711  .navbar-mobile-placeholder{
712    display: flex;
713    justify-content: space-between;
714    align-items: center;
715    background-color: var(--color-navbar-background);
716    height: 60px;
717    width: 100%;
718    padding: 0 20px;
719    box-sizing: border-box;
720    box-shadow: 0 4px 2px -2px rgba(31, 41, 55, 0.1)
721  }
722}
723@media (max-width: 1325px){
724  .left-side-placeholder{
725    gap: 1rem;
726  }
727}
728@media (max-width: 1255px){
729  .left-side-placeholder p, .left-side-placeholder .btn{
730    font-size: 14px;
731  }
732}
733</style>
734
735
736<div id="new-navbar" class="full" data-dark-mode="false" data-subscriber="false" data-role="" data-app-url="https://app.roll20.net" data-marketplace-url="https://marketplace.roll20.net" data-landing-url="https://roll20.net" data-display-name="" data-account-notifications-count="" data-site-notifications-count="0" data-logged-in="false" data-pub-id="false" data-compendium-tools="false" data-env="production" style="width: 100%; position: relative; z-index: 2000;">
737<!-- The navbar Vue app will mount here. To prevent a flashing of no navbar, a static navbar with no functionality exists in this div and will be replaced upon mount (about a second in, so hopefully the user doesn't notice anything) -->
738  
739    <div class="navbar-placeholder">
740      <div class="left-side-placeholder">
741        <img src="/images/roll20-logo-light.svg" alt="Roll20 Logo" height="30">
742        <p>Play Now<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
743        <p>Join a Game<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
744        <p>Characters<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
745        <p>Shop<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
746        <p>Tools<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
747        <p>Compendium<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
748        <p>Community<img src="/images/arrow-light.svg" alt="Arrow" height="30" class="arrow-svg"></p>
749        <button class="btn placeholder-subscribe-light">Subscribe</button>
750      </div>
751      <div class="right-side-placeholder">
752        <img src="/images/bell-light.svg" alt="Search" class="arrow-svg">
753        <p>Sign In<img src="/images/arrow-grey-light.svg" alt="Arrow" class="arrow-svg"></p>
754      </div>
755    </div>
756  
757  <div class="navbar-mobile-placeholder">
758    <img src="/images/roll20-logo-light.svg" alt="Roll20 Logo" height="30">
759    <img src="/images/hamburger-light.svg" alt="Hamburger Menu" height="30">
760
761  </div>
762
763</div>
764
765
766
767<script type='text/javascript'>
768	Object.defineProperty(window, "LANGUAGE", { value: "" , writable: false });
769</script>
769
770
771
772	
773
774	<div id="mainContent" class="sr-only"></div>
775
776	<section class="hero-section" role="banner" aria-label="#1 Choice for D&D Online Section">
777    <div class="hero-content">
778        <div class="hero-text">
779            <h2 class="header-text">The #1 Choice</h2>
780            <h2 class="header-text">For D&D Online.</h2>
781            <button class="homepage-primary-button" onclick="window.location.href='https://app.roll20.net/create-account'">Create Free Account</button>
782            <div class="hero-list">
783                <p>Join 15+ million players</p>
784                <ul>
785                    <li>Play D&D and 1,200+ other game systems — <b>free</b></li>
786                    <li>Biggest library of licensed adventures</li>
787                    <li><b>No downloads. No hosting.</b> Just open your browser and play</li>
788                </ul>
789            </div>
790        </div>
791        <div class="hero-image">
792            <img src="/v3/assets/img/homepage/hero.png" alt="Hero Image" />
793        </div>
794    </div>
795    <div class="hero-footer">
796        <div class="footer-logos">
797            <img src="/v3/assets/img/logos/dungeons-dragons.png" alt="D&D Logo" />
798            <img src="/v3/assets/img/logos/pathfinder2.png" alt="Pathfinder 2 Logo" />
799            <img src="/v3/assets/img/logos/call-of-cthulhu.png" alt="Call of Cthulhu Logo" />
800            <img src="/v3/assets/img/logos/MARRPGP_logo.png" alt="Marvel Multiverse Logo" />
801            <img src="/v3/assets/img/logos/daggerheart.png" alt="Daggerheart Logo" />
802            <img src="/v3/assets/img/logos/cyberpunk-logo.png" alt="Cyberpunk Logo" />
803            <img src="/v3/assets/img/logos/fallout.png" alt="Fallout Logo" />
804        </div>
805        <div class="footer-text">
806            <span><b>The most flexible tabletop platform on the web.</b></span>
807            <span>Supporting D&D, Pathfinder, and 1,200+ game systems. 15+ million players worldwide.</span>
808        </div>
809    </div>
810    
811</section>
812<div class="hero-wave-bottom zindex-100" data-shape-position="bottom" aria-hidden="true">
813    <svg viewBox="0 159.693 1440 115" preserveAspectRatio="xMidYMin slice" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
814        <path class="hero-wave-fill"d="M0 274.693h1440v-90c-312.847-25-582.257-20-808.23 35-226.2 55-436.12 50-631.77-10v60z" fill="currentColor" />
815    </svg>
816</div>
817<div class="mobile-spacer-div"></div>
818<div class="multi-section-div">
819    <img class="party-group" src="/v3/assets/img/homepage/party-group.png" alt="Party Around Fire Image" />
820    <section class="adventures-section" role="region" aria-labelledby="adventures-title">
821        <div class="adventures-text-wrapper">
822            <h2 id="adventures-title" class="header-text">Start with Ready-to-Play Adventures</h2>
823            <p>Roll20® is the most complete solution for digital play. Access character sheets, tokens, rulebooks, dice, and more - with powerful tools to automate the tedious stuff.</p>
824            <button class="homepage-secondary-button" onclick="window.location.href='https://app.roll20.net/create-account'">Create Free Account</button>
825        </div>
826    </section>
827
828    <section class="vtt-image" role="region" aria-label="VTT Playground Interface with various tools and features">
829        <div class="hotspot__container">
830            <div class="hotspot__row row justify-content-between d-none d-lg-flex">
831                <div id="hotspot__card-one" class="hotspot-card">
832                    <b> Roll Dice & Track Characters</b>
833                    <span> Integrated dice, character sheets, and automation </span>
834                </div>
835                <div id="hotspot__card-two" class="hotspot-card">
836                    <b> Organize Your Campaign</b>
837                    <span> Pages, folders, and asset management built in </span>
838                </div>
839            </div>
840            <div id="homepage-hotspot__svg-container" class="hotspot__svg-container">
841                <svg id="hotspot__svg" width="0" height="0" class="d-none d-lg-inline">
842                    <path id="hotspot__path1" d="M0 0" stroke="var(--color-primary4)" fill="none" stroke-width="2px" />
843                    <path id="hotspot__path2" d="M0 0" stroke="var(--color-primary4)" fill="none" stroke-width="2px" />
844                    <path id="hotspot__path3" d="M0 0" stroke="var(--color-primary4)" fill="none" stroke-width="2px" />
845                    <path id="hotspot__path4" d="M0 0" stroke="var(--color-primary4)" fill="none" stroke-width="2px" />
846                    <path id="hotspot__path5" d="M0 0" stroke="var(--color-primary4)" fill="none" stroke-width="2px" />
847                </svg>
848            </div>
849            <div class="hotspot__dots-wrapper mt-5">
850                <span id="dot-one" class="homepage-hotspot__dot dot-one"><span class="d-block d-lg-none">1</span></span>
851                <span id="dot-two" class="homepage-hotspot__dot dot-two"><span class="d-block d-lg-none">2</span></span>
852                <span id="dot-three" class="homepage-hotspot__dot dot-three"><span class="d-block d-lg-none">2</span></span>
853                <span id="dot-four" class="homepage-hotspot__dot dot-four"><span class="d-block d-lg-none">3</span></span>
854                <span id="dot-five" class="homepage-hotspot__dot dot-five"><span class="d-block d-lg-none">4</span></span>
855                <div class="hotspot__image shadow-lg">
856                    <img sizes="100vw" src="/v3/assets/img/homepage/vtt-playground.png" alt="VTT Playground Image" class="img-fluid" />
857                </div>
858            </div>
859            <div class="hotspot__row row mt-5 justify-content-between d-none d-lg-flex">
860                <div id="hotspot__card-three" class="hotspot-card">
861                    <b> Dynamic Lighting & Fog of War</b>
862                    <span> Reveal maps as players explore (immersion advantage) </span>
863                </div>
864                 <div id="hotspot__card-four" class="hotspot-card">
865                    <b> Free Mapmaking with Dungeon Scrawl</b>
866                    <span> Create maps in seconds with integrated tools </span>
867                </div>
868            </div>
869            <div class="hotspot__mobile-row row d-flex d-lg-none mt-5">
870                <div class="col">
871                    <ul class="list-group">
872                        <li class="list-group-item d-flex justify-content-between align-items-center">
873                            <div class="d-flex align-items-center">
874                                <span><b> Roll Dice & Track Characters</b> - Integrated dice, character sheets, and automation </span>
875                            </div>
876                            <span class="badge badge-primary badge-circle">1</span>
877                        </li>
878                        <li class="list-group-item d-flex justify-content-between align-items-center">
879                            <div class="d-flex align-items-center">
880                                <span><b> Organize Your Campaign</b> - Pages, folders, and asset management built in </span>
881                            </div>
882                            <span class="badge badge-primary badge-circle">2</span>
883                        </li>
884                        <li class="list-group-item d-flex justify-content-between align-items-center">
885                            <div class="d-flex align-items-center">
886                                <span><b> Dynamic Lighting & Fog of War</b> - Reveal maps as players explore (immersion advantage) </span>
887                            </div>
888                            <span class="badge badge-primary badge-circle">3</span>
889                        </li>
890                        <li class="list-group-item d-flex justify-content-between align-items-center">
891                            <div class="d-flex align-items-center">
892                                <span><b> Free Mapmaking with Dungeon Scrawl</b> - Create maps in seconds with integrated tools </span>
893                            </div>
894                            <span class="badge badge-primary badge-circle">4</span>
895                        </li>
896                    </ul>
897                </div>
898            </div>
899        </div>
900    </section>
901
902    <section class="steps-section" role="region" aria-label="Steps to Get Started">
903        <div class="steps-box-wrapper">
904            <div class="steps-box-div">
905                <img src="/v3/assets/img/homepage/daggerheart-turtle.png" alt="Daggerheart Character 1" class="steps-daggerheart-1-image" aria-hidden="true"/>
906                
907                <img src="/v3/assets/img/homepage/roll20-logo.png" alt="Roll20 Logo" class="steps-icon"/>
908                <h3><b>Sign Up Free</b></h3>
909                <p>Start today, no credit card. Free tier available forever, whether you're a GM or player.</p>
910            </div>
911            <div class="steps-box-div">
912                <img src="/v3/assets/img/homepage/choose-game-icon.png" alt="Choose Game Icon" class="steps-icon"/>
913                <h3><b>Pick your Game</b></h3>
914                <p>D&D, Pathfinder, Call of Cthulhu, or 1,200+ others. Hundreds of free adventures available.</p>
915            </div>
916            <div class="steps-box-div">
917                <img src="/v3/assets/img/homepage/invite-friends-icon.png" alt="Invites Friends Icon" class="steps-icon"/>
918                <h3><b>Find your Party</b></h3>
919                <p>Invite friends with a link, or find a group on our LFG tool and Discord. Solo? We've got options for you too.</p>
920            </div>
921            <div class="steps-box-div">
922                <img src="/v3/assets/img/homepage/play-icon.png" alt="Play Icon" class="steps-icon"/>
923                <h3><b>Play</b></h3>
924                <p>That's it. No downloads, no hosting, no setup. Just click and play. New to TTRPGs? Check out our tutorials.</p>
925
926                <img src="/v3/assets/img/homepage/daggerheart-wolf-parent.png" alt="Daggerheart Character 2" class="steps-daggerheart-2-image" aria-hidden="true"/>
927            </div>
928        </div>
929        <button class="homepage-primary-button steps-button" onclick="window.location.href='https://app.roll20.net/create-account'">Create Free Account</button>
930    </section>
931
932    <section class="testimonials-section" role="region" aria-labelledby="testimonials-title">
933        <div class="testimonials-wrapper">
934            <h2 id="testimonials-title" class="header-text">User Testimonials</h2>
935                <div class="owl-carousel owl-theme">
936                    <div class="item">
937                        <div class="carousel-img-wrapper">
938                            <img src="/v3/assets/img/homepage/testimonial-1.jpeg" alt="User Testimonial 1" />
939                        </div>
940                        <img src="/v3/assets/img/homepage/testimonial-avatar-1.png" alt="User Testimonial Avatar 1" class="testimonial-avatar avatar-right"/>
941                        <p class="testimonial-text">"I met most of my friends online. Roll20 keeps our friendships going and keeps us connected in good times and bad."</p>
942                        <p class="testimonial-name"><b>James R.</b></p>
943                    </div>
944                    <div class="item">
945                        <div class="carousel-img-wrapper">
946                            <img src="/v3/assets/img/homepage/testimonial-2.jpeg" alt="User Testimonial 2" />
947                        </div>
948                        <img src="/v3/assets/img/homepage/testimonial-avatar-2.png" alt="User Testimonial Avatar 2" class="testimonial-avatar avatar-left"/>
949                        <p class="testimonial-text">"Roll20 is the easiest and most accessible way to get started in the VTT space, and you won't regret it."</p>
950                        <p class="testimonial-name"><b>Calbeb P.</b></p>
951                    </div>
952                    <div class="item">
953                        <div class="carousel-img-wrapper">
954                            <img src="/v3/assets/img/homepage/testimonial-3.jpeg" alt="User Testimonial 3" />
955                        </div>
956                        <img src="/v3/assets/img/homepage/testimonial-avatar-3.png" alt="User Testimonial Avatar 3" class="testimonial-avatar avatar-right"/>
957                        <p class="testimonial-text">"Roll20 helps break down all the stuff that seems complicated about TTRPGs."</p>
958                        <p class="testimonial-name"><b>Mário R.</b></p>
959                    </div>
960                    <div class="item">
961                        <div class="carousel-img-wrapper">
962                            <img src="/v3/assets/img/homepage/testimonial-4.jpeg" alt="User Testimonial 4" />
963                        </div>
964                        <img src="/v3/assets/img/homepage/testimonial-avatar-4.png" alt="User Testimonial Avatar 4" class="testimonial-avatar avatar-left"/>
965                        <p class="testimonial-text">"I love the ability to create stories and memories and laughs with my friends from all around the world!"</p>
966                        <p class="testimonial-name"><b>Allison M.</b></p>
967                    </div>
968                    <div class="item">
969                        <div class="carousel-img-wrapper">
970                            <img src="/v3/assets/img/homepage/testimonial-5.jpeg" alt="User Testimonial 5" />
971                        </div>
972                        <img src="/v3/assets/img/homepage/testimonial-avatar-5.png" alt="User Testimonial Avatar 5" class="testimonial-avatar avatar-right"/>
973                        <p class="testimonial-text">"I love the freedom to create and play however and whatever I want while turning it into a great time with my party."</p>
974                        <p class="testimonial-name"><b>Maya O.</b></p>
975                    </div>
976                </div>
977        </div>
978    </section>
979</div>
980
981<section class="customize-section" role="region" aria-labelledby="customize-title">
982    <img src="/v3/assets/img/homepage/battle-box.png" alt="Battle Box Image" class="customize-battle-box-image" aria-hidden="true"/>
983    
984    <div class="customize-content-wrapper">
985        <h3 id="customize-title" class="header-text">Customize Your Game</h3>
986        <div class="customize-text-img-wrapper">
987            <img src="/v3/assets/img/homepage/Macro_Customize.webp" alt="Customize Illustration Image" class="customize-illustration-image" aria-hidden="true"/>
988            <div class="customize-text-wrapper">
989                <div class="customize-cards-wrapper">
990                    <div class="customize-card">
991                        <div class="customize-card-header">
992                            <img src="/v3/assets/img/homepage/dice-icon.png" alt="Dice Icon Image" class="customize-icon" aria-hidden="true"/>
993                            <h4 class="header-text"><b>Automate Rolls & Actions</b></h4>
994                        </div>
995                        <p>Save time with macros. One click for complex rolls, spell effects, and character actions. Works for any game system.</p>
996                    </div>
997                    <div class="customize-card">
998                        <div class="customize-card-header">
999                            <img src="/v3/assets/img/homepage/sheet-icon.png" alt="Sheet Icon Image" class="customize-icon" aria-hidden="true"/>
1000                            <h4 class="header-text"><b>
1000Character Sheets for Every System</b></h4>
1001                        </div>
1002                        <p>Built-in sheets for 250+ game systems including D&D, Pathfinder, and more. Or design your own.</p>
1003                    </div>
1004                    <div class="customize-card">
1005                        <div class="customize-card-header">
1006                            <img src="/v3/assets/img/homepage/api-icon.png" alt="API Icon Image" class="customize-icon" aria-hidden="true"/>
1007
1008                            <h4 class="header-text"><b>Advanced Customization (Optional)</b></h4>
1009                        </div>
1010                        <p>For power users: Full API to extend Roll20. Add new features, automate campaigns, and more. Pro subscription required.</p>
1011                    </div>
1012                    <div class="customize-card">
1013                        <div class="customize-card-header">
1014                            <img src="/v3/assets/img/homepage/ds-icon.png" alt="Battle Box Image" class="customize-icon" aria-hidden="true"/>
1015                            <h4 class="header-text"><b>Dungeon Scrawl Free Map Creation with Dungeon Scrawl</b></h4>
1016                        </div>
1017                        <p>Create gorgeous maps in minutes with our integrated Dungeon Scrawl tool. No art skills needed.</p>
1018                    </div>
1019                </div>
1020            </div>
1021        </div>
1022        <button class="homepage-secondary-button customize-button" onclick="window.location.href='https://app.roll20.net/create-account'">Create Free Account</button>
1023
1024    </div>
1025</section>
1026
1027<section class="community-section" role="region" aria-labelledby="community-title">
1028    <div class="community-content-div">
1029        <h2 id="community-title-mobile" class="header-text">Join the Community</h2>
1030        <div class="community-illustration-wrapper">
1031            <img src="/v3/assets/img/homepage/community.png" alt="Community Illustration Image" class="community-illustration-image" aria-hidden="true"/>
1032        </div>
1033        <div class="community-content-wrapper">
1034            <div class="community-text-wrapper">
1035                <h2 id="community-title" class="header-text">Join the Community</h2>
1036                <p class="community-subtitle"><b>Connect with 15+ million players worldwide.</b></p>
1037                <p class="community-text">Find groups on our LFG tool, join the official Discord with 100K+ members, or explore forums and subreddits. New players welcome.</p>
1038            </div>
1039
1040            <div class="community-action-items-wrapper">
1041                <button class="community-visit external" data-url="https://discord.com/invite/roll20" aria-label="Visit Roll20 Discord">
1042                    <img src="/v3/assets/img/homepage/discord-icon.png" aria-hidden="true" />
1043                    Join Roll20 Discord
1044                    <img src="/v3/assets/img/homepage/arrow-shape.png" aria-hidden="true" />
1045                </button>
1046                <button class="community-visit" onclick="window.location.href='https://app.roll20.net/lfg/search/'" aria-label="Visit Roll20 Looking For Group">
1047                    <img src="/v3/assets/img/homepage/friends-icon.png" aria-hidden="true" />
1048                    Find a Group
1049                    <img src="/v3/assets/img/homepage/arrow-shape.png" aria-hidden="true" />
1050                </button>
1051                <button class="community-visit" onclick="window.location.href='https://app.roll20.net/forum'" aria-label="Visit Roll20 Forums">
1052                    <img src="/v3/assets/img/homepage/roll20-icon.png" aria-hidden="true" />
1053                    Browse Forums
1054                    <img src="/v3/assets/img/homepage/arrow-shape.png" aria-hidden="true" />
1055                </button>
1056                <button class="community-visit external" data-url="https://www.reddit.com/r/Roll20" aria-label="Visit Roll20 Reddit">
1057                    <img src="/v3/assets/img/homepage/reddit-icon.png" aria-hidden="true" />
1058                    Visit r/Roll20
1059                    <img src="/v3/assets/img/homepage/arrow-shape.png" aria-hidden="true" />
1060                </button>
1061            </div>
1062        </div>
1063    </div>
1064</section>
1065
1066
1067<section class="articles-section" role="region" aria-label="start-here-articles">
1068    <h2 id="articles-title" class="header-text">New to Tabletop Roleplaying Games? Start Here</h2>
1069    <div class="articles-wrapper">
1070        <div class="article-card" data-url="https://pages.roll20.net/-dnd-starter-sets-complete-guide">
1071            <h3 class="header-text"><b>Is D&D For Me?</b></h3>
1072            <img src="/v3/assets/img/homepage/article-1.webp" alt="Article 1 Image" class="article-image" />
1073            <div class="article-content">
1074                <p>This article demonstrates that D&D is for everyone, dispels myths about time commitment myths, and offers guidance on how to start.</p>
1075                <a class="external-article" href="https://pages.roll20.net/-dnd-starter-sets-complete-guide" target="_blank" rel="noopener noreferrer">Read more</a>
1076            </div>
1077        </div>
1078        <div class="article-card" data-url="https://help.roll20.net/hc/en-us/articles/360037774473-Using-Our-Looking-for-Group-Tool">
1079            <h3 class="header-text"><b>How to Find Your First Group</b></h3>
1080
1081            <img src="/v3/assets/img/homepage/FindaGroup.png" alt="Article 2 Image" class="article-image" />
1082            <div class="article-content">
1083                <p>Explore the guide to using LFG tool, Discord, forums, what to look for in beginner-friendly groups.</p>
1084                <a class="external-article" href="https://help.roll20.net/hc/en-us/articles/360037774473-Using-Our-Looking-for-Group-Tool" target="_blank" rel="noopener noreferrer">Read more</a>
1085            </div>
1086        </div>
1087        <div class="article-card" data-url="https://pages.roll20.net/roll20-101">
1088            <h3 class="header-text"><b>Roll20 Masterclass Series</b></h3>
1089            <img src="/v3/assets/img/homepage/article-3.webp" alt="Article 3 Image" class="article-image" />
1090            <div class="article-content">
1091                <p>Discover GM tips, player tips and feature tutorials.</p>
1092                <a class="external-article" href="https://pages.roll20.net/roll20-101" target="_blank" rel="noopener noreferrer">View Series</a>
1093            </div>
1094        </div>
1095    </div>
1096</section>
1097
1098<section class="blog-section" role="region" aria-labelledby="latest-news-title">
1099    <h2 id="latest-news-title" class="header-text">Latest News</h2>
1100    <div class="blog-articles-wrapper">
1101        
1102        <div class="blog-article-0 blog-article-card">
1103            <img src="/v3/assets/img/backgrounds/signup-bg.svg" alt="Blog Article 1 Image" class="blog-article-0-image" />
1104            <div class="blog-article-0-content">
1105                <h3 class="blog-article-0-title">What's New...</h3>
1106                <p class="blog-article-0-date">- - -</p>
1107            </div> 
1108        </div>
1109        <div class="blog-article-1 blog-article-card">
1110            <img src="/v3/assets/img/backgrounds/signup-bg.svg" alt="Blog Article 2 Image" class="blog-article-1-image" />
1111            <div class="blog-article-1-content">
1112                <h3 class="blog-article-1-title">Checking...</h3>
1113                <p class="blog-article-1-date">- - -</p>
1114            </div> 
1115        </div>
1116        <div class="blog-article-2 blog-article-card">
1117            <img src="/v3/assets/img/backgrounds/signup-bg.svg" alt="Blog Article 3 Image" class="blog-article-2-image" />
1118            <div class="blog-article-2-content">
1119                <h3 class="blog-article-2-title">Taking a look...</h3>
1120                <p class="blog-article-2-date">- - -</p>
1121            </div> 
1122        </div>
1123    </div>
1124    <div class="blog-footer">
1125        <button class="homepage-secondary-button blog-button" data-url="https://blog.roll20.net/">Roll20 Blog</button>
1126        <h3><b>Ready to start your adventure?</b></h3>
1127        <button class="homepage-primary-button" onclick="window.location.href='https://app.roll20.net/create-account'">Sign Up Free</button>
1128        <p>No Credit Card Required</p>
1129        <p class="special-thanks-text"><span>Special thanks to our featured Partner:</span> <a href="https://marketplace.roll20.net/browse/publisher/1634" target="_blank">Ori the Cartographer</a></p>
1130    </div>
1131</section>
1132
1133<script type="text/javascript">
1134// Below JS controls the drawing of elbowed lines from dots to hotspot cards
1135
1136// Each hotspot object defines how to connect a dot to a box
1137    // dotId is the id of the dot element
1138    // boxId is the id of the box element
1139    // elbowDistance controls how far away from the dot the elbow bend occurs
1140    // elbowDirection controls whether the elbow goes out horizontally first, or vertically first
1141    // boxSide controls which side of the box the line connects to
1142    // dotSide controls which side of the dot the line starts from
1143const hotspots = [
1144  { dotId: '#dot-one', boxId: '#hotspot__card-one', elbowDistance: 50, elbowDirection: 'horizontal', boxSide: 'bottom', dotSide: 'right'},
1145  { dotId: '#dot-two', boxId: '#hotspot__card-two', elbowDistance: 100, elbowDirection: 'vertical', boxSide: 'left', dotSide: 'top' },
1146  { dotId: '#dot-three', boxId: '#hotspot__card-two', elbowDistance: 125, elbowDirection: 'horizontal', boxSide: 'bottom', dotSide: 'right' },
1147  { dotId: '#dot-four', boxId: '#hotspot__card-three', elbowDistance: 40, elbowDirection: 'horizontal', boxSide: 'top', dotSide: 'right' },
1148  { dotId: '#dot-five', boxId: '#hotspot__card-four', elbowDistance: 150, elbowDirection: 'vertical', boxSide: 'left', dotSide: 'bottom' },
1149];
1150
1151function drawElbowPath(svg, path, startX, startY, endX, endY, hotspot) {
1152    // Ensure SVG is big enough
1153    const stroke = parseFloat(path.attr("stroke-width") || 2);
1154    svg.attr("width", Math.max(svg.attr("width") || 0, startX, endX));
1155    svg.attr("height", Math.max(svg.attr("height") || 0, startY, endY));
1156
1157    let cornerX = startX;
1158    let cornerY = startY;
1159
1160    // Determine elbow point using direction and distance
1161    if (hotspot.elbowDirection === "horizontal") {
1162        cornerX += (endX >= startX ? 1 : -1) * hotspot.elbowDistance;
1163    } else if (hotspot.elbowDirection === "vertical") {
1164        cornerY += Math.sign(endY - startY) * hotspot.elbowDistance;
1165    }
1166
1167    // Draw path: start → corner → end
1168    if (hotspot.elbowDirection === "horizontal") {
1169        path.attr("d", `M${startX} ${startY} L${cornerX} ${cornerY} L${cornerX} ${endY}`);
1170    } else {
1171        path.attr("d", `M${startX} ${startY} L${cornerX} ${cornerY} L${endX} ${cornerY}`);
1172    }
1173}
1174
1175function connectHotspot(svg, path, hotspot) {
1176    const startElem = $(hotspot.dotId);
1177    const endElem   = $(hotspot.boxId);
1178
1179    if (!startElem.length || !endElem.length) return;
1180
1181    const svgContainer = $("#homepage-hotspot__svg-container");
1182    const svgTop  = svgContainer.offset().top;
1183    const svgLeft = svgContainer.offset().left;
1184
1185    const startCoord = startElem.offset();
1186    const endCoord   = endElem.offset();
1187
1188    // Determine startX/startY based on dotSide
1189    let startX, startY;
1190    switch (hotspot.dotSide) {
1191        // NOTE: "left" does not work if it goes off the left of the image, if the dot is on the left of the image. It will work if the dot is further right.
1192        case 'left':
1193            startX = startCoord.left - svgLeft;
1194            startY = startCoord.top + startElem.outerHeight() / 2 - svgTop;
1195            break;
1196        case 'right':
1197            startX = startCoord.left + startElem.outerWidth() - svgLeft; // right edge
1198            startY = startCoord.top + startElem.outerHeight() / 2 - svgTop;
1199            break;
1200        case 'top':
1201            startX = startCoord.left + startElem.outerWidth() / 2 - svgLeft;
1202            startY = startCoord.top - svgTop;
1203            break;
1204        case 'bottom':
1205            startX = startCoord.left + startElem.outerWidth() / 2 - svgLeft;
1206            startY = startCoord.top + startElem.outerHeight() - svgTop;
1207            break;
1208        default:
1209            startX = startCoord.left + startElem.outerWidth() / 2 - svgLeft;
1210            startY = startCoord.top + startElem.outerHeight() / 2 - svgTop;
1211    }
1212
1213
1214    // Determine endX/endY of the text box based on boxSide
1215    let endX, endY;
1216    switch (hotspot.boxSide) {
1217        case 'left':
1218            endX = endCoord.left - svgLeft;
1219            endY = endCoord.top + endElem.outerHeight() / 2 - svgTop;
1220            break;
1221        case 'right':
1222            endX = endCoord.left + endElem.outerWidth() - svgLeft;
1223            endY = endCoord.top + endElem.outerHeight() / 2 - svgTop;
1224            break;
1225        case 'top':
1226            endX = endCoord.left + endElem.outerWidth() / 2 - svgLeft;
1227            endY = endCoord.top - svgTop;
1228            break;
1229        case 'bottom':
1230            endX = endCoord.left + endElem.outerWidth() / 2 - svgLeft;
1231            endY = endCoord.top + endElem.outerHeight() - svgTop;
1232            break;
1233        default:
1234            endX = endCoord.left + endElem.outerWidth() / 2 - svgLeft;
1235            endY = endCoord.top + endElem.outerHeight() / 2 - svgTop;
1236    }
1237
1238    drawElbowPath(svg, path, startX, startY, endX, endY, hotspot);
1239}
1240
1241function connectAllHotspots() {
1242    const svg = $("#hotspot__svg");
1243    svg.attr("width", 0).attr("height", 0);
1244    hotspots.forEach((hotspot, i) => {
1245        const pathId = `#hotspot__path${i + 1}`;
1246        const path = $(pathId);
1247        connectHotspot(svg, path, hotspot);
1248    });
1249}
1250
1251function resetAndConnect() {
1252    const svg = $("#hotspot__svg");
1253    svg.attr("height", "0");
1254    svg.attr("width", "0");
1255    connectAllHotspots();
1256}
1257
1258// This will wait until all images are loaded to ensure correct positions
1259$(window).on('load', resetAndConnect);
1260$(window).resize(resetAndConnect);
1261
1262$('.owl-carousel').owlCarousel({
1263    loop: true,
1264    nav: true,
1265    dots: false,
1266    items: 1,
1267    margin: 0,
1268    navText: ['<span class="custom-prev"><img src="/v3/assets/img/homepage/chevron.svg" alt="Previous"></span>', '<span class="custom-next"><img src="/v3/assets/img/homepage/chevron.svg" alt="Next"></span>'],
1269    responsive: {
1270        1220: {
1271            items: 2
1272        }
1273    }
1274});
1275
1276$('.community-visit.external, .article-card, .blog-button, .blog-article-card').on('click', function() {
1277    const url = $(this).data('url');
1278    window.open(url, '_blank');
1279});
1280
1281async function getBlogData() {
1282  const url = "https://blog.roll20.net/wp-json/wp/v2/posts?status=publish&per_page=3";
1283  try {
1284    const response = await fetch(url, 
1285    );
1286    if (!response.ok) {
1287      throw new Error(`Response status: ${response.status}`);
1288    }
1289    const result = await response.json();
1290    if (result){
1291        result.forEach((post, i) => {
1292            console.log(post)
1293            const postLink = post.link;
1294            const imageSrc = post.jetpack_featured_media_url;
1295            const postTitle = post.title.rendered;
1296            const postDate = new Date(post.date);
1297            const formattedDate = postDate.toLocaleDateString('en-US', {
1298                year: 'numeric',
1299                month: 'short'
1300            });
1301            $(`.blog-article-${i}`).attr('data-url', postLink);
1302            $(`.blog-article-${i}-image`).attr('src', imageSrc);
1303            $(`.blog-article-${i}-title`).html(postTitle);
1304            $(`.blog-article-${i}-date`).html(formattedDate);
1305            
1306        });
1307    }
1308  } catch (error) {
1309    console.error(error.message);
1310  }
1311}
1312$(document).ready(function() {
1313  getBlogData();
1314});
1315
1316</script>
1316
1317
1318	<footer id="footer" class="container globalfooter">
1319	<div class="footer-terms">
1320        
1321	        <a href="https://roll20.net/" target="_blank"><img src="/v3/assets/img/logos/roll20-logo-new-light.svg" alt="Go to Roll20 Homepage"/></a>
1322        
1323        <span>&copy; Roll20, LLC | <a href="https://help.roll20.net/hc/articles/360037770793-Terms-of-Service-and-Privacy-Policy#Notification_of_Copyright_Infringement_.28DMCA_Policy.29" target="_blank">Terms of Service & Privacy Policy</a> | <a href="https://help.roll20.net/hc/articles/360037770833-DMCA" target="_blank">DMCA</a> | <a href="https://roll20.zendesk.com/hc/requests/new " target="_blank">Contact Us</a> | <a href="https://roll20.net/help" target="_blank">Help Center</a> | All rights reserved. All product and company names are trademarks<sup>&trade;</sup> or registered<sup>&reg;</sup> trademarks of their respective holders.</span>
1324        
1325            <div class="socials">
1326                <a href="http://discord.gg/roll20" target="_blank"><img src="/v2/images/Discord-LightMode.png" alt="Join the Roll20 Discord Server" /></a>
1327                <a href="https://www.facebook.com/roll20app/" target="_blank"><img src="/v2/images/Icon-Facebook.png" alt="Go to Roll20 on Facebook" /></a>
1328                <a href="https://x.com/roll20app" target="_blank"><img src="/v2/images/Icon-X.png" alt="Go to Roll20 on Twitter" /></a>
1329                <a href="https://bsky.app/profile/roll20.net" target="_blank"><img src="/v2/images/Icon-Bluesky.png" alt="Go to Roll20 on Bluesky" /></a>
1330                <a href="https://www.instagram.com/roll20app/" target="_blank"><img src="/v2/images/Icon-Instagram.png" alt="Go to Roll20 on Instagram" /></a>
1331                <a href=" https://www.tiktok.com/@roll20app?lang=en" target="_blank"><img src="/v2/images/Icon-TikTok.png" alt="Go to Roll20 on TikTok"  style="max-height: 41px;"/></a>
1332                <a href="https://www.youtube.com/roll20app" target="_blank"><img src="/v2/images/Icon-YouTube.png" alt="Go to Roll20 on YouTube" /></a>
1333                <a href="https://www.twitch.tv/roll20app " target="_blank"><img src="/v2/images/Icon-Twitch.png" alt="Go to Roll20 on Twitch" /></a>
1334                <a href="https://www.linkedin.com/company/roll20/" target="_blank"><img src="/v2/images/Icon-LinkedIn.png" alt="Go to Roll20 on LinkedIn" /></a>
1335            </div>
1336        
1337	</div>
1338	<div class="footer-content">
1339        <span class="powered-by">Powered by Roll20</span>
1340
1341        <div class="grid-container">
1342            <div class="footer-column">
1343                <div class="section">
1344                    <a class="section-title" href="https://roll20.net" target="_blank">Roll20 <br> The #1 Tabletop for Playing RPGs Online</a>
1345                    
1346                    <p class="collapsed-section-title">Roll20 <br> <i>The #1 Tabletop for Playing RPGs Online</i></p>
1347                    <div class="section-content">
1348                        <a href="https://roll20.net" target="_blank">Roll20 Tabletop</a>
1349                        <a href="https://app.roll20.net/characters" target="_blank">Roll20 Characters</a>
1350                        <a href="https://marketplace.roll20.net" target="_blank">Roll20 Marketplace</a>
1351                        <a href="https://roll20.net/compendium" target="_blank">Roll20 Compendium</a>
1352                    </div>
1353                </div>
1354                <div class="section">
1355                    <a class="section-title" href="https://drivethrurpg.com/" target="_blank" aria-label="Go to DriveThru Homepage">DriveThru <br> The Largest RPG Marketplace</a>
1356                    <p class="collapsed-section-title">DriveThru <br> <i>The Largest RPG Marketplace</i></p>
1357
1358                    <div class="section-content">
1359                        
1360                        <a class="homepage-link" href="https://drivethrurpg.com/" target="_blank">DriveThru</a>
1361                        <a href="https://www.drivethrucomics.com/" target="_blank">DriveThruComics</a>
1362                        <a href="https://www.drivethrufiction.com/index.php" target="_blank">DriveThruFiction</a>
1363                        <a href="https://www.drivethrucards.com/" target="_blank">DriveThruCards</a>
1364                        <a href="https://www.wargamevault.com/" target="_blank">Wargame Vault</a>
1365                    </div>
1366                </div>
1367            </div>
1368
1369            <div class="footer-column">
1370                <div class="section">
1371                    <a class="section-title" href="https://app.demiplane.com/home" target="_blank" aria-label="Go to Demiplane Homepage">Demiplane <br> Official Character Creation and Game Companion</a>
1372                    <p class="collapsed-section-title">Demiplane <br> <i>Official Character Creation and Game Companion</i></p>
1373                    <div class="section-content">
1374                        <a class="homepage-link" href="https://app.demiplane.com/home" target="_blank">Demiplane</a>
1375                        <a href="https://app.demiplane.com/nexus/pathfinder2e" target="_blank">Pathfinder Nexus</a>
1376                        <a href="https://app.demiplane.com/nexus/daggerheart" target="_blank">Daggerheart Nexus</a>
1377                        <a href="https://app.demiplane.com/nexus/vampire" target="_blank">Vampire: The Masquerade Nexus</a>
1378                        <a href="https://app.demiplane.com/nexus/marvelrpg" target="_blank">Marvel Multiverse RPG Nexus</a>
1379                        <a href="https://app.demiplane.com/nexus/cosmererpg" target="_blank">Cosmere RPG Nexus</a>
1380                        <a href="https://cyberpunkrednexus.com" target="_blank">Cyberpunk RED Nexus</a>
1381                        <a href="https://app.demiplane.com/nexus/starfinder2e" target="_blank">Starfinder 2e Nexus</a>
1382                        <a href="https://app.demiplane.com/nexus/traveller" target="_blank">Traveller Nexus</a>
1383                        <a href="https://app.demiplane.com/nexus/alienrpg" target="_blank">ALIEN RPG Nexus</a>
1384                        <a href="https://app.demiplane.com/nexus/dc20" target="_blank">DC20 Nexus</a>
1385                        <a href="https://app.demiplane.com/nexus/falloutrpg" target="_blank">Fallout RPG Nexus</a>
1386                        <a href="https://app.demiplane.com/nexus/candelaobscura" target="_blank">Candela Obscura Nexus</a>
1387                        <a href="https://app.demiplane.com/nexus/hunter" target="_blank">Hunter: The Reckoning Nexus</a>
1388                        <a href="https://app.demiplane.com/nexus/mutantyearzero" target="_blank">Mutant: Year Zero Nexus</a>
1389                        <a href="https://app.demiplane.com/nexus/scion" target="_blank">Scion Nexus</a>
1390                    </div>
1391                </div>
1392            </div>
1393
1394            <div class="footer-column">
1395                <div class="section">
1396                    <a class="section-title" href="https://www.dungeonscrawl.com/" target="_blank" aria-label="Go to Dungeon Scrawl Homepage">Dungeon Scrawl <br> Create RPG Maps in Minutes</a>
1397                    <p class="collapsed-section-title">Dungeon Scrawl <br> <i>Create RPG Maps in Minutes</i></p>
1398
1399                    <div class="section-content">
1400                        <a class="homepage-link" href="https://www.dungeonscrawl.com/" target="_blank">Dungeon Scrawl</a>
1401                        <a href="https://www.dungeonscrawl.com/" target="_blank">Create a Map</a>
1402                    </div>
1403                </div>
1404                <div class="section">
1405                    <span class="section-title community-content">Community Content</span>
1406                    <p class="collapsed-section-title">Community Content <br> <i>Adventure by Fans Everywhere</i></p>
1407
1408                    <div class="section-content">
1409                        <a href="https://www.dmsguild.com/" target="_blank">Dungeon Masters Guild (D&D)</a>
1410                        <a href="https://www.pathfinderinfinite.com/" target="_blank">Pathfinder Infinite</a>
1411                        <a href="https://www.starfinderinfinite.com/" target="_blank">Starfinder Infinite</a>
1412                        <a href="https://www.drivethrurpg.com/cc/16/Miskatonic " target="_blank">Miskatonic Repository</a>
1413                        <a href="https://www.storytellersvault.com/" target="_blank">Storytellers Vault</a>
1414                    </div>
1415                </div>
1416            </div>
1417        </div>
1418
1419    </div>
1420	<div class="footer-bottom">
1421        <div class="dice">
1422            <img src="/v2/images/Icon-Dice.svg" alt="Dice Icon"/>
1423        </div>
1424        <div class="roll20-logos">
1425            <div class="roll20-logo-text">
1426                
1427                    <img src="/v2/images/roll20-logo.png" alt="Pink Roll20 Logo"/>
1428                
1429                <p class="bottom-text">Everything for <br> your adventures</p>
1430            </div>
1431            <div class="all-logos">
1432                
1433                    <img src="/v3/assets/img/logos/roll20-logo-new-light.svg" alt="Pink Roll20 Logo"/>
1434                
1435                <img src="/v2/images/DriveThruRPG-LG.png" alt="DriveThru RPG Logo"/>
1436                
1437                    <img src="/v2/images/Demiplane-LG.png" alt="Demiplane Logo"/>
1438                
1439                <img src="/v2/images/DMG-LG.png" alt="Dungeon Masters Guild Logo"/>
1440                
1441                    <img src="/v2/images/DungeonScrawl-LG.png" alt="Dungeown Scrawl"/>
1442                
1443            </div>
1444        </div>
1445	</div>
1446</footer>
1447
1448<style>
1449#footer {
1450    padding-top: 3rem;
1451}
1452.footer-terms{
1453	display: flex;
1454	justify-content: space-around;
1455    align-items: center;
1456    font-weight: 300;
1457    font-size: 1.3rem;
1458    line-height: 1.5rem;
1459}
1460.footer-terms span{
1461    width: 60%;
1462    padding-left: 1rem;
1463    font-size: 1rem;
1464}
1465#footer sup {
1466/* necessary to override stylings */
1467    top: 0;
1468    font-size: 100%;
1469}
1470
1471.powered-by {
1472    display: flex;
1473    align-items: center;
1474    text-align: center;
1475    padding: 2rem 3.5rem;
1476}
1477.powered-by::before,
1478.powered-by::after {
1479    content: "";
1480    flex: 1;
1481    border-bottom: 1px solid rgba(98, 91, 101, 1);
1482    margin: 0 10px;
1483}
1484
1485.section-content{
1486    display: flex;
1487    flex-direction: column;
1488
1489}
1490.section-content a{
1491    color: var(--color-grayscale1);
1492}
1493.homepage-link{
1494    display: none;
1495}
1496.community-content{
1497    color: var(--color-primary-text) !important;
1498}
1499/* Large screens - 3 columns layout (2, 1, 2) */
1500.grid-container {
1501    display: grid;
1502    grid-template-columns: 1fr 1fr 1fr; /* Three columns */
1503    gap: 10px;
1504    align-items: start; /* Ensures items align to the top of the grid */
1505    padding-left: 3.5rem;
1506}
1507
1508.footer-column {
1509    display: flex;
1510    flex-direction: column;
1511    gap: 16px;
1512}
1513
1514.collapsed-section-title{
1515    display: none;
1516}
1517
1518.dice{
1519    display: flex;
1520    align-items: center;
1521    text-align: center;
1522    justify-content: center;
1523    padding: 0 7.5rem;
1524}
1525.dice::before,
1526.dice::after {
1527    content: "";
1528    flex: 1;
1529    border-bottom: 1px solid rgba(98, 91, 101, 1);
1530    margin: 0 10px;
1531}
1532.roll20-logo-text{
1533    display: flex;
1534    flex-direction: column;
1535    align-items: center;
1536    justify-content: center;
1537    text-align: center;
1538}
1539.roll20-logo-text img{
1540    height: 5rem;
1541}
1542.bottom-text{
1543    color: var(--color-grayscale1);
1544    text-transform: uppercase;
1545    font-weight: 600;
1546}
1547.footer-bottom{
1548    padding-bottom: 30px;
1549}
1550.roll20-logos{
1551    padding: 2rem 0 2rem 3rem;
1552    display: flex;
1553    justify-content: space-between;
1554}
1555.all-logos{
1556    text-align: center;
1557    width: 73%;
1558    max-width: 50rem;
1559}
1560.all-logos img{
1561    padding-right: 1rem;
1562}
1563
1564/* There is a higher-level page break in a different CSS file, so I need to handle a specific width here when that happens */
1565@media (max-width: 1200px) {
1566    .all-logos {
1567        width: 70%;
1568    }
1569    .all-logos img{
1570        padding-right: 1rem;
1571    }
1572}
1573/* There is a higher-level page break in a different CSS file, so I need to handle a specific width here when that happens */
1574@media (max-width: 991px) {
1575    .footer-terms span {
1576        width: 48%;
1577        padding-left: 10px;
1578    }
1579}
1580
1581/* Medium screens - 2 columns layout (2, 3) */
1582@media (max-width: 1024px) {
1583    .grid-container {
1584        grid-template-columns: 1fr 1fr; /* Two equal columns */
1585    }
1586
1587    .footer-column:nth-child(1) {
1588        grid-column: 1;
1589        grid-row: 1;
1590    }
1591    .footer-column:nth-child(2) {
1592        grid-column: 2;
1593        grid-row: 1;
1594    }
1595    .footer-column:nth-child(3) {
1596        grid-column: 2;
1597        grid-row: 2;
1598    }
1599    .footer-bottom{
1600        padding-top: 30px;
1601    }
1602    .all-logos{
1603        display: none;
1604    }
1605    .roll20-logos{
1606        justify-content: center;
1607    }
1608    .dice {
1609        padding: 0;
1610    }
1611}
1612
1613/* Small screens - 1 column, collapsible sections */
1614@media (max-width: 768px) {
1615    .section-title {
1616        display: none;
1617    }
1618
1619    .socials{
1620        display: flex;
1621        gap: 1rem;
1622        padding-top: 1rem;
1623    }
1624    .collapsed-section-title{
1625        display: unset;
1626        width: 100%;
1627        font-weight: 600;
1628    }
1629    .footer-terms{
1630        flex-direction: column;
1631
1632    }
1633    .footer-terms span{
1634        display: none;
1635    }
1636    .footer-content{
1637        display: flex;
1638        flex-direction: column;
1639    }
1640    .grid-container {
1641        display: flex;
1642        flex-direction: column;
1643        align-self: center;
1644        width: 85%;
1645        padding-left: 0;
1646        position: relative;
1647        left: -16px;
1648    }
1649
1650    .homepage-link{
1651        display: unset;
1652    }
1653    .globalfooter p{
1654        color: var(--color-grayscale1);
1655    }
1656
1657    .section{
1658        display: flex;
1659        align-items: center;
1660        justify-content: space-between;
1661        width: 100%;
1662        flex-direction: column;
1663        border-bottom: 1px solid rgba(98, 91, 101, 1);
1664        width: 110%;
1665    }
1666
1667    .section-content a{
1668        color: var(--color-primary-text);
1669        font-size: 1rem;
1670    }
1671
1672    .footer-column {
1673        display: contents;
1674    }
1675
1676    i {
1677        font-weight: 400;
1678    }
1679    .section-content {
1680        display: none; /* Hidden by default */
1681    }
1682
1683    .section.active .section-content {
1684        display: flex; /* Show content when active */
1685        flex-direction: column;
1686        align-items: flex-start;
1687        width: 98%;
1688        font-size: 1.5rem;
1689        padding: 0 0 10px 5px;
1690
1691    }
1692
1693    .collapsed-section-title::after {
1694        content: '+';
1695        float: right;
1696    }
1697
1698    .collapsed-section-title.active::after {
1699        content: '-';
1700        transform: scaleX(1.8);
1701    }
1702    .footer-bottom{
1703        padding-top: 20px;
1704    }
1705
1706    .powered-by {
1707        display: flex;
1708        align-items: center;
1709        text-align: center;
1710        padding: 2rem 0;
1711    }
1712    .roll20-logos{
1713        padding: 2rem 0;
1714    }
1715}
1716
1717
1718
1719</style>
1720
1721<script>
1722    // Toggle collapsible sections on small screens
1723    document.querySelectorAll('.collapsed-section-title').forEach(section => {
1724        section.addEventListener('click', function() {
1725            this.classList.toggle('active');
1726            this.parentElement.classList.toggle('active');
1727        });
1728    });
1729</script>
1729
1730
1731
1732
1733
1734	
1734<script type="text/javascript">
1735		$(function() {
1736			var cookieName = 'roll20tempauth';
1737			var cookieValue = Math.floor(Math.random()*100);
1738			var myDate = new Date();
1739			myDate.setMonth(myDate.getMonth() + 1);
1740			var cookieinfo = cookieName +"=" + cookieValue + ";expires=" + myDate + ";domain=.roll20.net;path=/";
1741			document.cookie = cookieinfo;
1742		});
1743	</script>
1743
1744
1745	
1745<script type="text/javascript">
1746
1747	function navtumblrload(payload) {
1748		if(payload.meta.status === 200) {
1749			for(var i=0; i < payload.response.posts.length; i++) {
1750				var post = payload.response.posts[i];
1751				var snippet = (post.body + "").split("</p>").slice(0,2).join(" ");
1752				snippet = strip_tags(snippet, "<a><br><br /><p><strong><em><b><i>");
1753				$(".community").find(".listing").eq(i).find(".snippet").html(snippet);
1754				$(".community").find(".listing").eq(i).find("h3").text(post.title);
1755				$(".community").find(".listing").eq(i).find("a.readmore").attr('href', post.post_url);
1756			}
1757		}
1758	}
1759
1760	function strip_tags(input, allowed) {
1761		allowed = (((allowed || '') + '')
1762			.toLowerCase()
1763			.match(/<[a-z][a-z0-9]*>/g) || [])
1764			.join(''); // making sure the allowed arg is a string containing only tags in lowercase (<a><b><c>)
1765		var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi,
1766			commentsAndPhpTags = /<!--[\s\S]*?-->|<\?(?:php)?[\s\S]*?\?>/gi;
1767		return input.replace(commentsAndPhpTags, '')
1768			.replace(tags, function($0, $1) {
1769			return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : '';
1770		});
1771	}
1772	$(".join-newsletter button[type=submit]").on("click", function() {
1773		var $this = $(this);
1774		$this.addClass("disabled");
1775		$.get("/subscribe_newsletter?email=" + escape($(this).prev("input").val()), function(data) {
1776			if (data === "success") {
1777				$this.parents(".join-newsletter").find(".sub-error").hide();
1778				$this.text("Subscribed!");
1779			}
1780			else {
1781				$this.parents(".join-newsletter").find(".sub-error").text(data).show();
1782				$this.removeClass("disabled");
1783			}
1784		});
1785	})
1786
1787	</script>
1787
1788
1789	
1789<script type="text/javascript">
1790	$(function() {
1791		setTimeout(function(){
1792			if($(".obs_container").length > 0) {
1793				// GA Event Tracking
1794				ga('send', {
1795					'hitType': 'event',
1796					'eventCategory': 'obsAdvert',
1797					'eventAction': 'topbar',
1798					'eventLabel': ''
1799				});
1800			}
1801		}, 0);
1802
1803		$(".localtimeme-short").each(function() {
1804			let time = parseInt($.trim($(this).text()), 10);
1805			let d = new Date(time*1000);
1806			$(this).attr("data-timestamp", d.getTime());
1807
1808			let mytimezone = "";
1809			if(d.toLocaleString) {
1810				mytimezone = d.toLocaleString('en', {timeZoneName: 'short'}).split(' ').pop();
1811			}
1812			const options = { month: 'long', hour:'numeric', minute:'numeric', day: 'numeric', timeZoneName: 'short' };
1813			$(this).text(d.toLocaleDateString('en-EN', options));
1814		});
1815	});
1816
1817	$("#roll20-top .loginform button").on("click", function() {
1818		console.log("click");
1819		var $form = $(this).parents("form");
1820		$form.attr("action", $form.attr("action") + "?backto=" + escape(window.location));
1821		$form.submit();
1822		return false;
1823	});
1824
1825	$(".topbarnotifications .notification button").on("click", function() {
1826		var notid = $(this).attr("data-notification-id");
1827		var othis = this;
1828
1829		$.getJSON("https://app.roll20.net/notifications/dismiss/" + notid + "/?callback=?", function(data) {
1830			if(notid == "all") {
1831				$(othis).parents(".notifications").fadeOut();
1832				$(".alertcount").html("");
1833				$(".topbarnotifications .dropdown-menu").remove();
1834				$(".topbarnotifications.nav-item-messages").html("<a href='https://app.roll20.net/private_message/inbox/' class='nav-link'><i class='fas fa-envelope'></i></a>");
1835				return;
1836			}
1837			if($(othis).attr("href")) {
1838				window.location = "https://app.roll20.net" + $(othis).attr("href");
1839			}
1840			else {
1841				$(othis).parents(".notification").fadeOut();
1842				var $count = $(othis).parents(".notifications").find("a .count");
1843				var current = parseInt($.trim($count.text()), 10);
1844				current = current - 1;
1845				if(current < 0) current = 0;
1846				$count.text(current);
1847				countdown = parseInt($(".alertcount").html(), 10)
1848				$(".alertcount").html(countdown - 1);
1849				if(countdown < 2) {
1850					$(othis).parents(".notifications").fadeOut();
1851					$(".alertcount").html("");
1852					$(".topbarnotifications .dropdown-menu").remove();
1853					$(".topbarnotifications.nav-item-messages").html("<a href='https://app.roll20.net/private_message/inbox/' class='nav-link'><i class='fas fa-envelope'></i></a>");
1854					return;
1855				}
1856			}
1857		});
1858		return false;
1859	});
1860
1861	$(".topbarsitenotifications .newalerts").on("click", function() {
1862		
1863	});
1864
1865	$("#navbar-notifications__see-more-btn").on("click", function() {
1866		window.location = "https://app.roll20.net/sitenotifications";
1867	});
1868
1869	$("#menu-mobile-site-alerts").on("click", function(e) {
1870		e.preventDefault();
1871		window.location = "https://app.roll20.net/sitenotifications";
1872	});
1873
1874	$("#remove-admin-menu").on("click", function() {
1875		$("#menu-adminhalla").remove();
1876		$("ul.dropdown-menu[aria-labelledby='menu-adminhalla']").remove();
1877		$(".logo img").prop("style", "");
1878	});
1879
1880	
1881		if(window.dataLayer) {
1882			dataLayer.push({ 'event': 'start_pw'});
1883		}
1884	
1885</script>
1885
1886
1887	
1887<script type="text/javascript">
1888function getS3Endpoint(
1889	url,
1890) {
1891	if (!url || typeof url !== 'string') return '';
1892
1893	return url
1894		.replace('s3.amazonaws.com/files.d20.io', 'files.d20.io')
1895		.replace('s3.amazonaws.com/files.staging.d20.io', 'files.staging.d20.io')
1896		.replace('s3.amazonaws.com/files-d20-io', 'files.d20.io')
1897		.replace('s3.amazonaws.com/files-staging-d20-io', 'files.staging.d20.io');
1898}
1899
1900window.d20ext = window.d20ext || {};
1901window.d20ext.utils = window.d20ext.utils || {};
1902window.d20ext.utils.getS3Endpoint = getS3Endpoint;
1903</script>
1903
1904	
1904<script type="text/javascript" src="https://cdn.roll20.net/production/blog_preview.latest.bundle.js"></script>
1904
1905
1906	
1907		
1907<script type="module" src="/static-fallback/nav-bar/master/assets/main-f-yrV3eN.js"></script>
1907
1908	
1909</body>
1910</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.