├── test └── .eslintrc ├── .bowerrc ├── shared ├── fonts │ ├── gdqpixel │ │ ├── import.html │ │ ├── gdqpixel.woff2 │ │ └── stylesheet.css │ ├── montserrat │ │ ├── import.html │ │ ├── Montserrat-Black.woff │ │ ├── Montserrat-ExtraBold.woff │ │ ├── Montserrat-Regular.woff │ │ ├── Montserrat-SemiBold.woff │ │ ├── Montserrat-Bold-Tabular.woff │ │ └── stylesheet.css │ ├── letter-gothic-std │ │ ├── import.html │ │ ├── Letter Gothic Std Medium.woff2 │ │ └── stylesheet.css │ └── source-code-pro │ │ ├── import.html │ │ ├── SourceCodePro-It.ttf.woff2 │ │ ├── SourceCodePro-Black.ttf.woff2 │ │ ├── SourceCodePro-Bold.ttf.woff2 │ │ ├── SourceCodePro-BoldIt.ttf.woff2 │ │ ├── SourceCodePro-Light.ttf.woff2 │ │ ├── SourceCodePro-Medium.ttf.woff2 │ │ ├── SourceCodePro-BlackIt.ttf.woff2 │ │ ├── SourceCodePro-LightIt.ttf.woff2 │ │ ├── SourceCodePro-MediumIt.ttf.woff2 │ │ ├── SourceCodePro-Regular.ttf.woff2 │ │ ├── SourceCodePro-Semibold.ttf.woff2 │ │ ├── SourceCodePro-ExtraLight.ttf.woff2 │ │ ├── SourceCodePro-SemiboldIt.ttf.woff2 │ │ └── SourceCodePro-ExtraLightIt.ttf.woff2 ├── imports │ ├── d3-random.html │ ├── moment.html │ ├── random.html │ ├── svgjs.html │ ├── textFit.html │ ├── gsap-CustomEase.html │ ├── gsap-DrawSVG.html │ ├── gsap-SplitText.html │ ├── gsap.html │ ├── MaybeRandom.html │ ├── TypeAnims.html │ ├── gsap-ModifiersPlugin.html │ ├── easeljs.html │ └── dragula.html ├── elements │ ├── .eslintrc │ └── interfaces │ │ └── ui-timeago │ │ ├── ui-timeago.html │ │ └── ui-timeago.js ├── style │ ├── gdq-fui-styles.html │ ├── gdq-text-styles.html │ ├── gdq-checkbox-style.html │ └── gdq-input-style.html └── lib │ └── vendor │ └── d3-random.v1.min.js ├── .eslintignore ├── graphics ├── elements │ ├── molecules │ │ ├── gdq-break │ │ │ ├── gdq-break-loop.html │ │ │ ├── img │ │ │ │ ├── lines_bg.png │ │ │ │ ├── top_bg.png │ │ │ │ ├── bottom_bg.png │ │ │ │ ├── prize-fallback.png │ │ │ │ ├── bottom-bar-gdq-logo.png │ │ │ │ ├── bottom-bar-pcf-logo.png │ │ │ │ └── run-bottom-greeble.svg │ │ │ ├── gdq-break-header.js │ │ │ ├── gdq-break.js │ │ │ ├── gdq-break-bid-many.html │ │ │ ├── gdq-break-header.html │ │ │ ├── gdq-break-schedule.html │ │ │ ├── gdq-break-bid-many-option.js │ │ │ ├── gdq-break-bottom-frame.html │ │ │ ├── gdq-break-top-frame.html │ │ │ ├── gdq-break-bid-binary.html │ │ │ └── gdq-break-bid-many.js │ │ ├── gdq-lttp-tracker │ │ │ └── img │ │ │ │ ├── bow.png │ │ │ │ ├── net.png │ │ │ │ ├── bombos.png │ │ │ │ ├── book.png │ │ │ │ ├── boots.png │ │ │ │ ├── boss0.png │ │ │ │ ├── boss1.png │ │ │ │ ├── boss10.png │ │ │ │ ├── boss2.png │ │ │ │ ├── boss3.png │ │ │ │ ├── boss4.png │ │ │ │ ├── boss5.png │ │ │ │ ├── boss6.png │ │ │ │ ├── boss7.png │ │ │ │ ├── boss8.png │ │ │ │ ├── boss9.png │ │ │ │ ├── byrna.png │ │ │ │ ├── cape.png │ │ │ │ ├── ether.png │ │ │ │ ├── flute.png │ │ │ │ ├── glove0.png │ │ │ │ ├── glove1.png │ │ │ │ ├── glove2.png │ │ │ │ ├── hammer.png │ │ │ │ ├── icerod.png │ │ │ │ ├── mirror.png │ │ │ │ ├── powder.png │ │ │ │ ├── quake.png │ │ │ │ ├── shovel.png │ │ │ │ ├── sword0.png │ │ │ │ ├── sword1.png │ │ │ │ ├── sword2.png │ │ │ │ ├── sword3.png │ │ │ │ ├── sword4.png │ │ │ │ ├── tunic1.png │ │ │ │ ├── tunic2.png │ │ │ │ ├── tunic3.png │ │ │ │ ├── bottle0.png │ │ │ │ ├── bottle1.png │ │ │ │ ├── bottle2.png │ │ │ │ ├── bottle3.png │ │ │ │ ├── bottle4.png │ │ │ │ ├── dungeon0.png │ │ │ │ ├── dungeon1.png │ │ │ │ ├── dungeon2.png │ │ │ │ ├── dungeon3.png │ │ │ │ ├── dungeon4.png │ │ │ │ ├── firerod.png │ │ │ │ ├── flippers.png │ │ │ │ ├── hookshot.png │ │ │ │ ├── lantern.png │ │ │ │ ├── mushroom.png │ │ │ │ ├── shield0.png │ │ │ │ ├── shield1.png │ │ │ │ ├── shield2.png │ │ │ │ ├── shield3.png │ │ │ │ ├── silvers.png │ │ │ │ ├── somaria.png │ │ │ │ ├── blank-pixel.png │ │ │ │ ├── boomerang0.png │ │ │ │ ├── boomerang1.png │ │ │ │ ├── boomerang2.png │ │ │ │ ├── boomerang3.png │ │ │ │ ├── medallion0.png │ │ │ │ ├── medallion1.png │ │ │ │ ├── medallion2.png │ │ │ │ ├── medallion3.png │ │ │ │ ├── moonpearl.png │ │ │ │ ├── mpupgrade0.png │ │ │ │ ├── mpupgrade1.png │ │ │ │ └── mpupgrade2.png │ │ ├── gdq-omnibar │ │ │ ├── img │ │ │ │ ├── logo-gdq.png │ │ │ │ └── logo-charity.png │ │ │ ├── gdq-omnibar-left-divider.js │ │ │ ├── gdq-omnibar-prize.html │ │ │ ├── gdq-omnibar-run.html │ │ │ ├── gdq-omnibar-prize.js │ │ │ ├── gdq-omnibar-list.html │ │ │ ├── gdq-omnibar-left-divider.html │ │ │ ├── gdq-omnibar-total.js │ │ │ ├── gdq-omnibar-run.js │ │ │ ├── gdq-omnibar-milestone-alert.html │ │ │ ├── gdq-omnibar-bidwars.html │ │ │ ├── gdq-omnibar-challenges.html │ │ │ ├── gdq-omnibar-milestone-tracker-point.html │ │ │ ├── gdq-omnibar-milestone-tracker-point.js │ │ │ ├── gdq-omnibar-challenges.js │ │ │ └── gdq-omnibar-list-item.js │ │ ├── gdq-countdown │ │ │ └── img │ │ │ │ └── gdqlogo.png │ │ ├── gdq-sponsors │ │ │ ├── img │ │ │ │ └── blank-pixel.png │ │ │ └── gdq-sponsors.html │ │ ├── gdq-nameplate │ │ │ ├── gdq-nameplate-twitch-logo.js │ │ │ └── gdq-nameplate-twitch-logo.html │ │ ├── gdq-runinfo │ │ │ ├── gdq-runinfo-category.js │ │ │ └── gdq-runinfo-misc.js │ │ ├── gdq-interview-question │ │ │ └── gdq-interview-question.html │ │ ├── gdq-runner-nameplate │ │ │ ├── gdq-runner-nameplate-audio-indicator.html │ │ │ ├── gdq-runner-nameplate.html │ │ │ └── gdq-runner-nameplate-result.js │ │ └── gdq-lowerthird │ │ │ └── gdq-lowerthird.html │ ├── atoms │ │ ├── atom-refresh-indicator │ │ │ ├── img │ │ │ │ └── progress_load.png │ │ │ └── atom-refresh-indicator.js │ │ ├── atom-tweening-number │ │ │ └── atom-tweening-number.html │ │ ├── atom-gridlines │ │ │ ├── atom-gridlines.js │ │ │ └── atom-gridlines.html │ │ ├── atom-inner-glow-text │ │ │ ├── atom-inner-glow-text.js │ │ │ └── atom-inner-glow-text.html │ │ ├── atom-text-greeble │ │ │ ├── atom-text-greeble.html │ │ │ └── atom-text-greeble.js │ │ ├── atom-greeble │ │ │ ├── atom-greeble.js │ │ │ └── atom-greeble.html │ │ ├── atom-gradient-text │ │ │ ├── atom-gradient-text.js │ │ │ └── atom-gradient-text.html │ │ ├── atom-chevron │ │ │ └── atom-chevron.html │ │ ├── atom-tronlines │ │ │ └── atom-tronlines.html │ │ └── atom-arrow-block │ │ │ └── atom-arrow-block.html │ └── interfaces │ │ ├── dash-host │ │ ├── dash-host-prize.js │ │ ├── dash-host-totals.html │ │ ├── dash-host-name.js │ │ ├── dash-host-totals.js │ │ ├── dash-host.js │ │ ├── dash-host-bid-option.js │ │ ├── dash-host-styles.html │ │ ├── dash-host-prizes.js │ │ ├── dash-host-prize.html │ │ ├── dash-host-adbreak.js │ │ ├── dash-host-bid.js │ │ ├── dash-host-bid-option.html │ │ └── dash-host-currentrun.js │ │ ├── dash-interview-monitor │ │ ├── dash-interview-monitor-tweet.js │ │ ├── dash-interview-monitor-prizes.html │ │ ├── dash-interview-monitor-tweets.html │ │ ├── dash-interview-monitor-tweet.html │ │ └── dash-interview-monitor-prize.js │ │ ├── dash-interview-tablet │ │ ├── dash-interview-tablet-scrollbar-styles.html │ │ ├── dash-interview-tablet-lowerthird-refill-option.js │ │ ├── dash-lowerthird-name-input.js │ │ ├── dash-interview-tablet-lowerthird-refill-option.html │ │ └── dash-interview-tablet-lowerthird.html │ │ ├── dash-producer │ │ ├── dash-producer.js │ │ └── dash-producer-checklist.js │ │ ├── ui-tweet │ │ └── ui-tweet.js │ │ ├── ui-dragula-element │ │ └── ui-dragula-element.html │ │ └── ui-element-tester │ │ └── ui-element-tester.html ├── style │ ├── base.css │ ├── advertisements.css │ └── layout.css ├── .eslintrc ├── audio_dashboard.html ├── break.html ├── host.html ├── countdown.html ├── omnibar.html ├── lttp_tracker.html ├── producer_dashboard.html ├── interview.html ├── interview_monitor.html ├── mixins │ └── CSSReflectionMixin.html ├── interview_tablet.html └── test_tronlines.html ├── scripts ├── .eslintrc └── test_donation_server.js ├── util ├── .eslintrc ├── index.js └── format-dollars.js ├── .win_folder_icon ├── foldericon.ico ├── desktop.ini └── apply_folder_icon.bat ├── schemas ├── nextRun.json ├── currentRun.json ├── autoCycleRecordings.json ├── autoUpdateTotal.json ├── canSeekSchedule.json ├── caspar%3Aconnected.json ├── checklistComplete.json ├── currentHost.json ├── gdq%3AcurrentLayout.json ├── autoUploadRecordings.json ├── recordTrackerEnabled.json ├── interview%3AthrowIncoming.json ├── interview%3AquestionShowing.json ├── interview%3AshowPrizesOnMonitor.json ├── bits%3Atotal.json ├── tweets.json ├── interview%3AquestionTweets.json ├── interview%3AquestionSortMap.json ├── interview%3AprizePlaylistSortMap.json ├── twitch%3AcanPlayAd.json ├── total.json ├── interview%3Astopwatch.json ├── interview%3AprizePlaylist.json ├── currentIntermission.json ├── caspar%3Afiles.json ├── types │ ├── interview.json │ ├── timeStruct.json │ ├── adBreak.json │ └── ad.json └── stopwatch.json ├── desktop.ini ├── dashboard ├── .eslintrc ├── elements │ ├── time-validator │ │ ├── time-validator.html │ │ └── time-validator.js │ ├── gdq-totals │ │ ├── gdq-totals-total.js │ │ ├── gdq-totals-total.html │ │ └── gdq-totals.js │ ├── time-input │ │ ├── time-input.js │ │ └── time-input.html │ ├── gdq-timekeeper │ │ ├── img │ │ │ └── flag-checkered.svg │ │ └── gdq-timekeeper-runner.js │ ├── gdq-throw │ │ ├── gdq-throw.js │ │ └── gdq-throw.html │ ├── gdq-twitter-controls │ │ ├── tweet-item.js │ │ └── gdq-twitter-controls.js │ ├── gdq-recordings │ │ ├── gdq-recordings.html │ │ └── gdq-recordings.js │ ├── gdq-checklist │ │ └── gdq-checklist.js │ ├── gdq-schedule │ │ └── gdq-schedule-runinfo.js │ └── gdq-countdown │ │ └── gdq-countdown.js ├── record-tracker.js ├── obs.html └── record-tracker.html ├── .idea ├── watcherTasks.xml ├── codeStyles │ └── codeStyleConfig.xml ├── misc.xml ├── vcs.xml ├── jsLibraryMappings.xml ├── modules.xml ├── codeStyleSettings.xml ├── agdq18-layouts.iml ├── inspectionProfiles │ └── Project_Default.xml └── runConfigurations │ └── NodeCG_v0_9.xml ├── extension ├── util │ └── nodecg-api-context.js ├── twitch-title-updater.js ├── countdown.js ├── twitch-bits.js └── nowplaying.js ├── polymer.json ├── .editorconfig ├── .gitignore ├── .eslintrc ├── LICENSE ├── .gitattributes └── appveyor.yml /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "resolvers": [ 3 | "bower-npm-resolver" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /shared/fonts/gdqpixel/import.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | coverage 4 | /shared/lib/vendor 5 | -------------------------------------------------------------------------------- /shared/fonts/montserrat/import.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/fonts/letter-gothic-std/import.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/import.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/imports/d3-random.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/imports/moment.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/imports/random.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/imports/svgjs.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/imports/textFit.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-loop.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /scripts/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "require-jsdoc": "off", 4 | "valid-jsdoc": ["error"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /util/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "func-names": [ 4 | "error", 5 | "as-needed" 6 | ] 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /util/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | formatDollars: require('./format-dollars') 5 | }; 6 | -------------------------------------------------------------------------------- /.win_folder_icon/foldericon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/.win_folder_icon/foldericon.ico -------------------------------------------------------------------------------- /schemas/nextRun.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "default": {} 5 | } 6 | -------------------------------------------------------------------------------- /schemas/currentRun.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "default": {} 5 | } 6 | -------------------------------------------------------------------------------- /shared/fonts/gdqpixel/gdqpixel.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/gdqpixel/gdqpixel.woff2 -------------------------------------------------------------------------------- /shared/imports/gsap-CustomEase.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /shared/imports/gsap-DrawSVG.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /shared/imports/gsap-SplitText.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /desktop.ini: -------------------------------------------------------------------------------- 1 | [.ShellClassInfo] 2 | IconResource="./.win_folder_icon/foldericon.ico",0 3 | [ViewState] 4 | Mode= 5 | Vid= 6 | FolderType=Documents 7 | -------------------------------------------------------------------------------- /schemas/autoCycleRecordings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": true 5 | } 6 | -------------------------------------------------------------------------------- /schemas/autoUpdateTotal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": true 5 | } 6 | -------------------------------------------------------------------------------- /schemas/canSeekSchedule.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": true 5 | } 6 | -------------------------------------------------------------------------------- /schemas/caspar%3Aconnected.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": false 5 | } 6 | -------------------------------------------------------------------------------- /schemas/checklistComplete.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": false 5 | } 6 | -------------------------------------------------------------------------------- /schemas/currentHost.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "string", 4 | "default": "Edobean" 5 | } 6 | -------------------------------------------------------------------------------- /schemas/gdq%3AcurrentLayout.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "string", 4 | "default": "" 5 | } 6 | -------------------------------------------------------------------------------- /schemas/autoUploadRecordings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": true 5 | } 6 | -------------------------------------------------------------------------------- /schemas/recordTrackerEnabled.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": false 5 | } 6 | -------------------------------------------------------------------------------- /shared/imports/gsap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /dashboard/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "globals": { 6 | "nodecg": true, 7 | "Polymer": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /schemas/interview%3AthrowIncoming.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "boolean", 4 | "default": false 5 | } 6 | -------------------------------------------------------------------------------- /shared/fonts/montserrat/Montserrat-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/montserrat/Montserrat-Black.woff -------------------------------------------------------------------------------- /schemas/interview%3AquestionShowing.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "boolean", 5 | "default": false 6 | } 7 | -------------------------------------------------------------------------------- /shared/elements/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "globals": { 6 | "nodecg": true, 7 | "Polymer": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /shared/fonts/montserrat/Montserrat-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/montserrat/Montserrat-ExtraBold.woff -------------------------------------------------------------------------------- /shared/fonts/montserrat/Montserrat-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/montserrat/Montserrat-Regular.woff -------------------------------------------------------------------------------- /shared/fonts/montserrat/Montserrat-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/montserrat/Montserrat-SemiBold.woff -------------------------------------------------------------------------------- /.win_folder_icon/desktop.ini: -------------------------------------------------------------------------------- 1 | [.ShellClassInfo] 2 | IconResource="./.win_folder_icon/foldericon.ico",0 3 | [ViewState] 4 | Mode= 5 | Vid= 6 | FolderType=Documents 7 | -------------------------------------------------------------------------------- /schemas/interview%3AshowPrizesOnMonitor.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "boolean", 5 | "default": false 6 | } 7 | -------------------------------------------------------------------------------- /shared/imports/MaybeRandom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/watcherTasks.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/lines_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-break/img/lines_bg.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/top_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-break/img/top_bg.png -------------------------------------------------------------------------------- /shared/fonts/montserrat/Montserrat-Bold-Tabular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/montserrat/Montserrat-Bold-Tabular.woff -------------------------------------------------------------------------------- /shared/imports/TypeAnims.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/bottom_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-break/img/bottom_bg.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bow.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/net.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/net.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/img/logo-gdq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-omnibar/img/logo-gdq.png -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-It.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-It.ttf.woff2 -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-countdown/img/gdqlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-countdown/img/gdqlogo.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bombos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bombos.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/book.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/book.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boots.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss10.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss4.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss5.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss6.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss7.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss8.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boss9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boss9.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/byrna.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/byrna.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/cape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/cape.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/ether.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/ether.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/flute.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/flute.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/glove0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/glove0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/glove1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/glove1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/glove2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/glove2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/hammer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/hammer.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/icerod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/icerod.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/mirror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/mirror.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/powder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/powder.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/quake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/quake.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/shovel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/shovel.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/sword0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/sword0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/sword1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/sword1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/sword2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/sword2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/sword3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/sword3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/sword4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/sword4.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/tunic1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/tunic1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/tunic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/tunic2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/tunic3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/tunic3.png -------------------------------------------------------------------------------- /schemas/bits%3Atotal.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "number", 4 | "minimum": 0, 5 | "multipleOf": 1.0, 6 | "default": 0 7 | } 8 | -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-Black.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-Black.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-Bold.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-Bold.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-BoldIt.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-BoldIt.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-Light.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-Light.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-Medium.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-Medium.ttf.woff2 -------------------------------------------------------------------------------- /shared/imports/gsap-ModifiersPlugin.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/prize-fallback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-break/img/prize-fallback.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bottle0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bottle0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bottle1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bottle1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bottle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bottle2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bottle3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bottle3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/bottle4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/bottle4.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/dungeon0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/dungeon0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/dungeon1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/dungeon1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/dungeon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/dungeon2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/dungeon3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/dungeon3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/dungeon4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/dungeon4.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/firerod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/firerod.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/flippers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/flippers.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/hookshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/hookshot.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/lantern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/lantern.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/mushroom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/mushroom.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/shield0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/shield0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/shield1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/shield1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/shield2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/shield2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/shield3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/shield3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/silvers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/silvers.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/somaria.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/somaria.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/img/logo-charity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-omnibar/img/logo-charity.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-sponsors/img/blank-pixel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-sponsors/img/blank-pixel.png -------------------------------------------------------------------------------- /shared/fonts/letter-gothic-std/Letter Gothic Std Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/letter-gothic-std/Letter Gothic Std Medium.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-BlackIt.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-BlackIt.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-LightIt.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-LightIt.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-MediumIt.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-MediumIt.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-Regular.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-Regular.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-Semibold.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-Semibold.ttf.woff2 -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/blank-pixel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/blank-pixel.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boomerang0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boomerang0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boomerang1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boomerang1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boomerang2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boomerang2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/boomerang3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/boomerang3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/medallion0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/medallion0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/medallion1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/medallion1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/medallion2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/medallion2.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/medallion3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/medallion3.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/moonpearl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/moonpearl.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/mpupgrade0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/mpupgrade0.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/mpupgrade1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/mpupgrade1.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lttp-tracker/img/mpupgrade2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-lttp-tracker/img/mpupgrade2.png -------------------------------------------------------------------------------- /schemas/tweets.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "array", 5 | "items": { 6 | "type": "object" 7 | }, 8 | "default": [] 9 | } 10 | -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-ExtraLight.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-ExtraLight.ttf.woff2 -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-SemiboldIt.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-SemiboldIt.ttf.woff2 -------------------------------------------------------------------------------- /shared/imports/easeljs.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/bottom-bar-gdq-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-break/img/bottom-bar-gdq-logo.png -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/bottom-bar-pcf-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/molecules/gdq-break/img/bottom-bar-pcf-logo.png -------------------------------------------------------------------------------- /shared/fonts/source-code-pro/SourceCodePro-ExtraLightIt.ttf.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/shared/fonts/source-code-pro/SourceCodePro-ExtraLightIt.ttf.woff2 -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-refresh-indicator/img/progress_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GamesDoneQuick/agdq18-layouts/HEAD/graphics/elements/atoms/atom-refresh-indicator/img/progress_load.png -------------------------------------------------------------------------------- /shared/fonts/gdqpixel/stylesheet.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'gdqpixel'; 3 | src: url('gdqpixel.woff2') format('woff2'); 4 | font-weight: normal; 5 | font-style: normal; 6 | } 7 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /extension/util/nodecg-api-context.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let context; 4 | module.exports = { 5 | get() { 6 | return context; 7 | }, 8 | set(ctx) { 9 | context = ctx; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /schemas/interview%3AquestionTweets.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "array", 5 | "items": { 6 | "type": "object" 7 | }, 8 | "default": [] 9 | } 10 | -------------------------------------------------------------------------------- /schemas/interview%3AquestionSortMap.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "array", 5 | "items": { 6 | "type": "string" 7 | }, 8 | "default": [] 9 | } 10 | -------------------------------------------------------------------------------- /schemas/interview%3AprizePlaylistSortMap.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "array", 5 | "items": { 6 | "type": "number" 7 | }, 8 | "default": [] 9 | } 10 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-tweening-number/atom-tweening-number.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dashboard/elements/time-validator/time-validator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /graphics/style/base.css: -------------------------------------------------------------------------------- 1 | @import '../../shared/fonts/montserrat/stylesheet.css'; 2 | @import '../../shared/fonts/gdqpixel/stylesheet.css'; 3 | 4 | body { 5 | margin: 0; 6 | opacity: 0; 7 | } 8 | 9 | #container { 10 | position: absolute; 11 | overflow: hidden; 12 | } 13 | -------------------------------------------------------------------------------- /polymer.json: -------------------------------------------------------------------------------- 1 | { 2 | "lint": { 3 | "rules": ["polymer-2"], 4 | "ignoreWarnings": [ 5 | "unknown-superclass", 6 | "unknown-polymer-behavior" 7 | ] 8 | }, 9 | "sources": [ 10 | "graphics/**/*", 11 | "dashboard/**/*", 12 | "shared/**/*", 13 | "bower.json" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-gridlines/atom-gridlines.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class AtomGridlines extends Polymer.Element { 6 | static get is() { 7 | return 'atom-gridlines'; 8 | } 9 | } 10 | 11 | customElements.define(AtomGridlines.is, AtomGridlines); 12 | -------------------------------------------------------------------------------- /schemas/twitch%3AcanPlayAd.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "default": { 5 | "canPlay": { 6 | "type": "boolean", 7 | "default": true 8 | }, 9 | "reason": { 10 | "type": "string", 11 | "default": "" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /shared/elements/interfaces/ui-timeago/ui-timeago.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dashboard/elements/time-validator/time-validator.js: -------------------------------------------------------------------------------- 1 | Polymer({ 2 | is: 'time-validator', 3 | 4 | behaviors: [ 5 | Polymer.IronValidatorBehavior 6 | ], 7 | 8 | validate(value) { 9 | // This regex validates incomplete times (by design) 10 | return !value || value.match(/^[0-9]{0,2}:[0-9]{0,2}$/); 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /.idea/codeStyleSettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 9 | -------------------------------------------------------------------------------- /schemas/total.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "properties": { 5 | "raw": { 6 | "type": "number", 7 | "minimum": 0 8 | }, 9 | "formatted": { 10 | "type": "string" 11 | } 12 | }, 13 | "default": { 14 | "raw": 0, 15 | "formatted": "$0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /schemas/interview%3Astopwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "object", 5 | "additionalProperties": false, 6 | "properties": { 7 | "running": { 8 | "type": "boolean", 9 | "default": false 10 | }, 11 | "time": { 12 | "$ref": "types/timeStruct.json" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /shared/fonts/letter-gothic-std/stylesheet.css: -------------------------------------------------------------------------------- 1 | /* Generated by Fontie */ 2 | 3 | @font-face { 4 | font-family: 'Letter Gothic Std'; 5 | src: url('Letter Gothic Std Medium.woff2') format('woff2'); 6 | font-weight: 400; 7 | font-style: normal; 8 | font-stretch: normal; 9 | unicode-range: U+0020-FB02; 10 | } 11 | -------------------------------------------------------------------------------- /shared/style/gdq-fui-styles.html: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-prize.js: -------------------------------------------------------------------------------- 1 | class DashHostPrize extends Polymer.MutableData(Polymer.Element) { 2 | static get is() { 3 | return 'dash-host-prize'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | prize: { 9 | type: Object 10 | } 11 | }; 12 | } 13 | } 14 | 15 | customElements.define(DashHostPrize.is, DashHostPrize); 16 | -------------------------------------------------------------------------------- /graphics/style/advertisements.css: -------------------------------------------------------------------------------- 1 | #imageAdContainer { 2 | z-index: 11; 3 | background-color: black; 4 | transform: translateX(-1280px); 5 | } 6 | 7 | #imageAdContainer img { 8 | position: absolute; 9 | left: 640px; 10 | top: 360px; 11 | max-width: 1280px; 12 | height: 720px; 13 | transform: translate(-50%, -50%); 14 | } 15 | 16 | #videoPlayer { 17 | z-index: 11; 18 | } 19 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqBreakHeader extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-break-header'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | text: String 13 | }; 14 | } 15 | } 16 | 17 | customElements.define(GdqBreakHeader.is, GdqBreakHeader); 18 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-left-divider.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqOmnibarLeftDivider extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-omnibar-left-divider'; 8 | } 9 | 10 | static get properties() { 11 | return {}; 12 | } 13 | } 14 | 15 | customElements.define(GdqOmnibarLeftDivider.is, GdqOmnibarLeftDivider); 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | charset = utf-8 4 | 5 | [*] 6 | indent_style = tab 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | indent_size = 4 12 | 13 | [{package.json,*.yml}] 14 | indent_style = space 15 | indent_size = 2 16 | 17 | # Don't remove trailing whitespace from Markdown 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-nameplate/gdq-nameplate-twitch-logo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqNameplateTwitchLogo extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-nameplate-twitch-logo'; 8 | } 9 | 10 | static get properties() { 11 | return {}; 12 | } 13 | } 14 | 15 | customElements.define(GdqNameplateTwitchLogo.is, GdqNameplateTwitchLogo); 16 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-inner-glow-text/atom-inner-glow-text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class AtomInnerGlowText extends Polymer.Element { 6 | static get is() { 7 | return 'atom-inner-glow-text'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | text: String 13 | }; 14 | } 15 | } 16 | 17 | customElements.define(AtomInnerGlowText.is, AtomInnerGlowText); 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | 4 | coverage 5 | .nyc_output 6 | 7 | /graphics/img/boxart/* 8 | !/graphics/img/boxart/default.png 9 | !.empty_directory 10 | 11 | # JetBrains IDEs (IntelliJ/WebStorm) 12 | /.idea/compiler.xml 13 | /.idea/encodings.xml 14 | /.idea/copyright/profiles_settings.xml 15 | /.idea/workspace.xml 16 | /.idea/shelf/ 17 | 18 | firebase-credentials.json 19 | 20 | npm-debug.log 21 | -------------------------------------------------------------------------------- /dashboard/record-tracker.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const $toggle = document.getElementById('toggle'); 5 | const recordTrackerEnabled = nodecg.Replicant('recordTrackerEnabled'); 6 | 7 | recordTrackerEnabled.on('change', newVal => { 8 | $toggle.checked = newVal; 9 | }); 10 | 11 | $toggle.addEventListener('change', e => { 12 | recordTrackerEnabled.value = e.target.checked; 13 | }); 14 | })(); 15 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-text-greeble/atom-text-greeble.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqBreak extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-break'; 8 | } 9 | 10 | static get properties() { 11 | return {}; 12 | } 13 | 14 | ready() { 15 | super.ready(); 16 | this.$.tweet.companionElement = this.$.prizes; 17 | } 18 | } 19 | 20 | customElements.define(GdqBreak.is, GdqBreak); 21 | -------------------------------------------------------------------------------- /dashboard/obs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /schemas/interview%3AprizePlaylist.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "array", 5 | "items": { 6 | "type": "object", 7 | "additionalProperties": false, 8 | "properties": { 9 | "id": { 10 | "type": "number", 11 | "required": true 12 | }, 13 | "complete": { 14 | "type": "boolean", 15 | "required": true 16 | } 17 | } 18 | }, 19 | 20 | "default": [] 21 | } 22 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "xo/esnext", 3 | "rules": { 4 | "new-cap": [2, { 5 | "capIsNewExceptions": [ 6 | "Polymer", 7 | "Polymer.GestureEventListeners", 8 | "Polymer.MutableData", 9 | "nodecg.Replicant", 10 | "CSSReflectionMixin", 11 | "MapSortMixin", 12 | "SVG" 13 | ] 14 | }], 15 | "valid-jsdoc": ["error"], 16 | "capitalized-comments": [0] 17 | }, 18 | "plugins": [ 19 | "html" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-runinfo/gdq-runinfo-category.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqRuninfoCategory extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-runinfo-category'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | maxTextWidth: Number, 13 | category: String 14 | }; 15 | } 16 | } 17 | 18 | customElements.define(GdqRuninfoCategory.is, GdqRuninfoCategory); 19 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-greeble/atom-greeble.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class AtomGreeble extends Polymer.Element { 6 | static get is() { 7 | return 'atom-greeble'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | align: { 13 | type: String, 14 | value: 'left', 15 | reflectToAttribute: true 16 | } 17 | }; 18 | } 19 | } 20 | 21 | customElements.define(AtomGreeble.is, AtomGreeble); 22 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-runinfo/gdq-runinfo-misc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqRuninfoMisc extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-runinfo-misc'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | maxTextWidth: Number, 13 | console: String, 14 | releaseYear: String, 15 | estimate: String 16 | }; 17 | } 18 | } 19 | 20 | customElements.define(GdqRuninfoMisc.is, GdqRuninfoMisc); 21 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-gradient-text/atom-gradient-text.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class AtromGradientText extends Polymer.Element { 6 | static get is() { 7 | return 'atom-gradient-text'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | text: String, 13 | align: { 14 | type: String, 15 | reflectToAttribute: true 16 | }, 17 | maxWidth: Number 18 | }; 19 | } 20 | } 21 | 22 | customElements.define(AtromGradientText.is, AtromGradientText); 23 | -------------------------------------------------------------------------------- /.idea/agdq18-layouts.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-prize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /schemas/currentIntermission.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "properties": { 6 | "preOrPost": { 7 | "type": "string", 8 | "enum": ["pre", "post"] 9 | }, 10 | "content": { 11 | "type": "array", 12 | "items": { 13 | "oneOf": [ 14 | { "$ref": "types/adBreak.json" }, 15 | { "$ref": "types/interview.json" } 16 | ] 17 | } 18 | } 19 | }, 20 | "default": { 21 | "preOrPost": "post", 22 | "content": [] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /shared/style/gdq-text-styles.html: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 | -------------------------------------------------------------------------------- /graphics/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true 4 | }, 5 | "globals": { 6 | "nodecg": true, 7 | "Polymer": true, 8 | "TimelineMax": true, 9 | "TimelineLite": true, 10 | "TweenLite": true, 11 | "TweenMax": true, 12 | "Linear": true, 13 | "Power1": true, 14 | "Power2": true, 15 | "Power3": true, 16 | "Power4": true, 17 | "Elastic": true, 18 | "Back": true, 19 | "Sine": true, 20 | "SlowMo": true, 21 | "CustomEase": true, 22 | "textFit": true, 23 | "createjs": true, 24 | "SVG": true, 25 | "MaybeRandom": true, 26 | "TypeAnims": true 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-monitor/dash-interview-monitor-tweet.js: -------------------------------------------------------------------------------- 1 | class DashInterviewMonitorTweet extends Polymer.Element { 2 | static get is() { 3 | return 'dash-interview-monitor-tweet'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | tweet: { 9 | type: Object, 10 | observer: 'populateBody' 11 | } 12 | }; 13 | } 14 | 15 | populateBody() { 16 | if (!this.tweet) { 17 | return; 18 | } 19 | 20 | this.$.body.innerHTML = this.tweet.text; 21 | } 22 | } 23 | 24 | customElements.define(DashInterviewMonitorTweet.is, DashInterviewMonitorTweet); 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Games Done Quick 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-tablet/dash-interview-tablet-scrollbar-styles.html: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | -------------------------------------------------------------------------------- /graphics/audio_dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Audio Dashboard 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /util/format-dollars.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Formats an amount as USD, cents optional. 5 | * @param {Number} amount - The amount to format. 6 | * @param {Boolean} cents - Whether or not to include cents in the formatted string. 7 | * @returns {string} - The formatted string. 8 | */ 9 | module.exports = function formatDollars(amount, {cents = true} = {}) { 10 | const fractionDigits = cents ? 2 : 0; 11 | return parseFloat(amount).toLocaleString('en-US', { 12 | style: 'currency', 13 | currency: 'USD', 14 | maximumFractionDigits: fractionDigits, 15 | minimumFractionDigits: fractionDigits 16 | }); 17 | }; 18 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-totals/gdq-totals-total.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | class GdqTotalsTotal extends Polymer.Element { 5 | static get is() { 6 | return 'gdq-totals-total'; 7 | } 8 | 9 | static get properties() { 10 | return { 11 | value: { 12 | type: String, 13 | value: '?' 14 | }, 15 | currency: { 16 | type: String 17 | } 18 | }; 19 | } 20 | 21 | edit() { 22 | this.dispatchEvent(new CustomEvent('edit', {bubbles: true, composed: true})); 23 | } 24 | 25 | equal(a, b) { 26 | return a === b; 27 | } 28 | } 29 | 30 | customElements.define(GdqTotalsTotal.is, GdqTotalsTotal); 31 | })(); 32 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-totals.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-run.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-prize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqOmnibarPrize extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-omnibar-prize'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | prize: Object 13 | }; 14 | } 15 | 16 | enter() { 17 | return this.$.listItem.enter(); 18 | } 19 | 20 | exit() { 21 | return this.$.listItem.exit(); 22 | } 23 | 24 | calcBidAmountText(prize) { 25 | return prize.sumdonations ? 26 | `${prize.minimumbid} in Total Donations` : 27 | `${prize.minimumbid} Single Donation`; 28 | } 29 | } 30 | 31 | customElements.define(GdqOmnibarPrize.is, GdqOmnibarPrize); 32 | -------------------------------------------------------------------------------- /graphics/break.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Break 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /schemas/caspar%3Afiles.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "array", 4 | "items": { 5 | "type": "object", 6 | "properties": { 7 | "name": { 8 | "type": "string" 9 | }, 10 | "nameWithExt": { 11 | "type": "string" 12 | }, 13 | "type": { 14 | "type": "string" 15 | }, 16 | "size": { 17 | "type": "number" 18 | }, 19 | "changed": { 20 | "type": "number" 21 | }, 22 | "frames": { 23 | "type": "number" 24 | }, 25 | "frameTime": { 26 | "type": "string" 27 | }, 28 | "frameRate": { 29 | "type": "number" 30 | }, 31 | "duration": { 32 | "type": "number" 33 | } 34 | } 35 | }, 36 | "default": [] 37 | } 38 | -------------------------------------------------------------------------------- /scripts/test_donation_server.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable new-cap */ 2 | 'use strict'; 3 | 4 | const io = require('socket.io')(22341); 5 | let totalInCents = 0; 6 | 7 | generateAndEmitDonation(); 8 | 9 | function generateAndEmitDonation() { 10 | const rawAmountInCents = randomInt(100, 60000); 11 | totalInCents += rawAmountInCents; 12 | 13 | const data = { 14 | rawAmount: String(rawAmountInCents / 100), 15 | newTotal: String(totalInCents / 100) 16 | }; 17 | 18 | io.emit('donation', data); 19 | console.log('Emitted donation:', data); 20 | 21 | setTimeout(generateAndEmitDonation, randomInt(100, 3000)); 22 | } 23 | 24 | function randomInt(min, max) { 25 | return Math.floor(Math.random() * (max - min)) + min; 26 | } 27 | -------------------------------------------------------------------------------- /graphics/host.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host Dashboard 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /graphics/countdown.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Countdown 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-tablet/dash-interview-tablet-lowerthird-refill-option.js: -------------------------------------------------------------------------------- 1 | class DashInterviewTabletLowerthirdRefillOption extends Polymer.Element { 2 | static get is() { 3 | return 'dash-interview-tablet-lowerthird-refill-option'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | type: { 9 | type: String, 10 | reflectToAttribute: true 11 | }, 12 | names: Array 13 | }; 14 | } 15 | 16 | accept() { 17 | this.dispatchEvent(new CustomEvent('accepted', { 18 | detail: { 19 | names: this.names.filter(name => name !== '(none)') 20 | } 21 | })); 22 | } 23 | } 24 | 25 | customElements.define(DashInterviewTabletLowerthirdRefillOption.is, DashInterviewTabletLowerthirdRefillOption); 26 | -------------------------------------------------------------------------------- /graphics/omnibar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Omnibar 6 | 7 | 8 | 9 | 15 | 16 | 17 |
18 | 19 |
20 | 21 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /schemas/types/interview.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "properties": { 6 | "id": { 7 | "type": "number" 8 | }, 9 | "interviewees": { 10 | "type": "array", 11 | "items": { 12 | "type": "string" 13 | } 14 | }, 15 | "interviewers": { 16 | "type": "array", 17 | "items": { 18 | "type": "string" 19 | } 20 | }, 21 | "duration": { 22 | "type": "string" 23 | }, 24 | "order": { 25 | "type": "number" 26 | }, 27 | "subject": { 28 | "type": "string" 29 | }, 30 | "suborder": { 31 | "type": "number" 32 | }, 33 | "type": { 34 | "type": "string", 35 | "enum": ["interview"] 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-list.html: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files you want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.css text eol=lf 7 | *.html text eol=lf 8 | *.js text eol=lf 9 | *.js text eol=lf 10 | *.json text eol=lf 11 | *.md text eol=lf 12 | 13 | # Force images/fonts to be handled as binaries 14 | *.jpg binary 15 | *.jpeg binary 16 | *.gif binary 17 | *.png binary 18 | *.t3x binary 19 | *.t3d binary 20 | *.exe binary 21 | *.data binary 22 | *.ttf binary 23 | *.eof binary 24 | *.eot binary 25 | *.woff binary 26 | *.swf binary 27 | *.mov binary 28 | *.mp4 binary 29 | *.mp3 binary 30 | *.ogg binary 31 | *.flv binary 32 | *.webm binary 33 | -------------------------------------------------------------------------------- /graphics/lttp_tracker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LttP Tracker 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /graphics/producer_dashboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Producer Dashboard 6 | 7 | 8 | 9 | 10 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /schemas/types/timeStruct.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "properties": { 6 | "days": { 7 | "type": "number", 8 | "default": 0 9 | }, 10 | "hours": { 11 | "type": "number", 12 | "default": 0 13 | }, 14 | "minutes": { 15 | "type": "number", 16 | "default": 0 17 | }, 18 | "seconds": { 19 | "type": "number", 20 | "default": 0 21 | }, 22 | "milliseconds": { 23 | "type": "number", 24 | "default": 0 25 | }, 26 | "formatted": { 27 | "type": "string", 28 | "default": "00:00" 29 | }, 30 | "raw": { 31 | "type": "number", 32 | "default": 0 33 | }, 34 | "timestamp": { 35 | "type": "number", 36 | "default": 0 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-sponsors/gdq-sponsors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /graphics/interview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Interview 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 |
16 | 17 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-bid-many.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /dashboard/elements/time-input/time-input.js: -------------------------------------------------------------------------------- 1 | Polymer({ 2 | is: 'time-input', 3 | 4 | properties: { 5 | invalid: { 6 | reflectToAttribute: true, 7 | type: Boolean, 8 | value: false 9 | }, 10 | 11 | value: { 12 | notify: true, 13 | type: String 14 | }, 15 | 16 | _minutes: { 17 | type: Number 18 | }, 19 | 20 | _seconds: { 21 | type: Number 22 | }, 23 | 24 | validator: { 25 | type: String, 26 | value: 'time-validator' 27 | } 28 | }, 29 | 30 | behaviors: [ 31 | Polymer.IronValidatableBehavior 32 | ], 33 | 34 | observers: [ 35 | '_computeValue(_minutes,_seconds)' 36 | ], 37 | 38 | setMS(m, s) { 39 | this._minutes = m < 10 ? `0${m}` : m; 40 | this._seconds = s < 10 ? `0${s}` : s; 41 | }, 42 | 43 | _computeValue(minutes, seconds) { 44 | this.value = `${minutes}:${seconds}`; 45 | } 46 | }); 47 | -------------------------------------------------------------------------------- /graphics/interview_monitor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Interview Monitor 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-name.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const currentHost = nodecg.Replicant('currentHost'); 3 | 4 | /** 5 | * @customElement 6 | * @polymer 7 | */ 8 | class DashHostName extends Polymer.Element { 9 | static get is() { 10 | return 'dash-host-name'; 11 | } 12 | 13 | static get properties() { 14 | return { 15 | currentHost: String, 16 | _enteredName: { 17 | type: String, 18 | value: '' 19 | } 20 | }; 21 | } 22 | 23 | ready() { 24 | super.ready(); 25 | currentHost.on('change', newVal => { 26 | this.currentHost = newVal; 27 | }); 28 | } 29 | 30 | take() { 31 | currentHost.value = this._enteredName; 32 | this._enteredName = ''; 33 | } 34 | 35 | _falsey(value) { 36 | return !value; 37 | } 38 | } 39 | 40 | customElements.define(DashHostName.is, DashHostName); 41 | })(); 42 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-totals.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const cashTotal = nodecg.Replicant('total'); 5 | const bitsTotal = nodecg.Replicant('bits:total'); 6 | 7 | class DashHostTotals extends Polymer.Element { 8 | static get is() { 9 | return 'dash-host-totals'; 10 | } 11 | 12 | static get properties() { 13 | return { 14 | cashTotal: { 15 | type: String 16 | }, 17 | bitsTotal: { 18 | type: String 19 | } 20 | }; 21 | } 22 | 23 | connectedCallback() { 24 | super.connectedCallback(); 25 | cashTotal.on('change', newVal => { 26 | this.cashTotal = newVal.formatted; 27 | }); 28 | bitsTotal.on('change', newVal => { 29 | this.bitsTotal = newVal.toLocaleString('en-US'); 30 | }); 31 | } 32 | } 33 | 34 | customElements.define(DashHostTotals.is, DashHostTotals); 35 | })(); 36 | -------------------------------------------------------------------------------- /shared/fonts/montserrat/stylesheet.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'montserrat'; 3 | src: url('Montserrat-Regular.woff') format('woff'); 4 | font-weight: 400; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'montserrat'; 10 | src: url('Montserrat-SemiBold.woff') format('woff'); 11 | font-weight: 600; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'montserrat'; 17 | src: url('Montserrat-Bold-Tabular.woff') format('woff'); 18 | font-weight: 700; 19 | font-style: normal; 20 | } 21 | 22 | @font-face { 23 | font-family: 'montserrat'; 24 | src: url('Montserrat-ExtraBold.woff') format('woff'); 25 | font-weight: 800; 26 | font-style: normal; 27 | } 28 | 29 | @font-face { 30 | font-family: 'montserrat'; 31 | src: url('Montserrat-Black.woff') format('woff'); 32 | font-weight: 900; 33 | font-style: normal; 34 | } 35 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | class DashHost extends Polymer.MutableData(Polymer.Element) { 5 | static get is() { 6 | return 'dash-host'; 7 | } 8 | 9 | static get properties() { 10 | return { 11 | currentTime: { 12 | type: String 13 | }, 14 | selectedBidsAndPrizesTab: { 15 | type: Number, 16 | value: 0 17 | } 18 | }; 19 | } 20 | 21 | connectedCallback() { 22 | super.connectedCallback(); 23 | this.updateCurrentTime = this.updateCurrentTime.bind(this); 24 | this.updateCurrentTime(); 25 | setInterval(this.updateCurrentTime, 1000); 26 | } 27 | 28 | updateCurrentTime() { 29 | const date = new Date(); 30 | this.currentTime = date.toLocaleTimeString('en-US', {hour12: true}); 31 | } 32 | } 33 | 34 | customElements.define(DashHost.is, DashHost); 35 | })(); 36 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-timekeeper/img/flag-checkered.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-bid-option.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class DashHostBidOption extends Polymer.Element { 6 | static get is() { 7 | return 'dash-host-bid-option'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | bid: Object, 13 | option: Object, 14 | index: { 15 | type: Number, 16 | reflectToAttribute: true 17 | } 18 | }; 19 | } 20 | 21 | calcOptionMeterFillStyle(bid, option) { 22 | if (!bid || !option || !bid.options || bid.options.length <= 0) { 23 | return ''; 24 | } 25 | 26 | let percent = option.rawTotal / bid.options[0].rawTotal; 27 | percent = Math.max(percent, 0); // Clamp to min 0 28 | percent = Math.min(percent, 1); // Clamp to max 1 29 | if (Number.isNaN(percent)) { 30 | percent = 0; 31 | } 32 | return `transform: scaleX(${percent});`; 33 | } 34 | } 35 | 36 | customElements.define(DashHostBidOption.is, DashHostBidOption); 37 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-left-divider.html: -------------------------------------------------------------------------------- 1 | 2 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /shared/imports/dragula.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 30 | 31 | -------------------------------------------------------------------------------- /schemas/types/adBreak.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "properties": { 6 | "type": { 7 | "type": "string", 8 | "enum": ["adBreak"] 9 | }, 10 | "ads": { 11 | "type": "array", 12 | "items": { 13 | "$ref": "ad.json" 14 | } 15 | }, 16 | "id": { 17 | "type": "number" 18 | }, 19 | "state": { 20 | "type": "object", 21 | "additionalProperties": false, 22 | "properties": { 23 | "canStart": { 24 | "type": "boolean", 25 | "default": false 26 | }, 27 | "cantStartReason": { 28 | "type": "string", 29 | "default": "" 30 | }, 31 | "started": { 32 | "type": "boolean", 33 | "default": false 34 | }, 35 | "canComplete": { 36 | "type": "boolean", 37 | "default": false 38 | }, 39 | "completed": { 40 | "type": "boolean", 41 | "default": false 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-producer/dash-producer.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | class DashProducer extends Polymer.MutableData(Polymer.Element) { 5 | static get is() { 6 | return 'dash-producer'; 7 | } 8 | 9 | static get properties() { 10 | return { 11 | currentTime: { 12 | type: String 13 | }, 14 | selectedContentTab: { 15 | type: Number, 16 | value: 0 17 | }, 18 | selectedBidsAndPrizesTab: { 19 | type: Number, 20 | value: 0 21 | } 22 | }; 23 | } 24 | 25 | connectedCallback() { 26 | super.connectedCallback(); 27 | this.updateCurrentTime = this.updateCurrentTime.bind(this); 28 | this.updateCurrentTime(); 29 | setInterval(this.updateCurrentTime, 1000); 30 | } 31 | 32 | updateCurrentTime() { 33 | const date = new Date(); 34 | this.currentTime = date.toLocaleTimeString('en-US', {hour12: true}); 35 | } 36 | } 37 | 38 | customElements.define(DashProducer.is, DashProducer); 39 | })(); 40 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-interview-question/gdq-interview-question.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-chevron/atom-chevron.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /schemas/stopwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | 4 | "type": "object", 5 | "additionalProperties": false, 6 | "properties": { 7 | "state": { 8 | "type": "string", 9 | "enum": ["not_started", "running", "paused", "finished"], 10 | "default": "not_started" 11 | }, 12 | "time": { 13 | "$ref": "types/timeStruct.json" 14 | }, 15 | "results": { 16 | "type": "array", 17 | "minItems": 4, 18 | "maxItems": 4, 19 | "items": { 20 | "type": ["object", "null"], 21 | "additionalProperties": false, 22 | "properties": { 23 | "time": { 24 | "$ref": "types/timeStruct.json" 25 | }, 26 | "place": { 27 | "type": "number", 28 | "minimum": 0, 29 | "maximum": 4, 30 | "multipleOf": 1.0 31 | }, 32 | "forfeit": { 33 | "type": "boolean", 34 | "default": false 35 | } 36 | } 37 | }, 38 | "default": [null, null, null, null], 39 | "required": ["time", "place", "forfeit"] 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-throw/gdq-throw.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const throwIncoming = nodecg.Replicant('interview:throwIncoming'); 3 | const currentLayout = nodecg.Replicant('gdq:currentLayout'); 4 | 5 | class GdqThrow extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-throw'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | throwIncoming: { 13 | type: Boolean, 14 | value: false 15 | }, 16 | disabled: { 17 | type: Boolean, 18 | value: false, 19 | reflectToAttribute: true 20 | } 21 | }; 22 | } 23 | 24 | ready() { 25 | super.ready(); 26 | throwIncoming.on('change', newVal => { 27 | this.throwIncoming = newVal; 28 | }); 29 | currentLayout.on('change', newVal => { 30 | this.disabled = newVal === 'interview'; 31 | }); 32 | } 33 | 34 | arm() { 35 | throwIncoming.value = true; 36 | } 37 | 38 | disarm() { 39 | throwIncoming.value = false; 40 | } 41 | } 42 | 43 | customElements.define(GdqThrow.is, GdqThrow); 44 | })(); 45 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-total.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const total = nodecg.Replicant('total'); 5 | 6 | class GdqOmnibarTotal extends Polymer.Element { 7 | static get is() { 8 | return 'gdq-omnibar-total'; 9 | } 10 | 11 | ready() { 12 | super.ready(); 13 | this.$.totalTextAmount.displayValueTransform = this._totalDisplayValueTransform.bind(this); 14 | total.on('change', newVal => { 15 | this.$.totalTextAmount.value = newVal.raw; 16 | }); 17 | } 18 | 19 | _totalDisplayValueTransform(displayValue) { 20 | const formatted = displayValue.toLocaleString('en-US', { 21 | maximumFractionDigits: 0, 22 | minimumFractionDigits: 0 23 | }).replace(/1/ig, '\u00C0'); 24 | 25 | // Part of the workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=67029 26 | this.$.totalTextAmountPlaceholder.textContent = formatted; 27 | 28 | return formatted; 29 | } 30 | } 31 | 32 | customElements.define(GdqOmnibarTotal.is, GdqOmnibarTotal); 33 | })(); 34 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-tablet/dash-lowerthird-name-input.js: -------------------------------------------------------------------------------- 1 | class DashLowerthirdNameInput extends Polymer.Element { 2 | static get is() { 3 | return 'dash-lowerthird-name-input'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | selectedItem: { 9 | type: String, 10 | notify: true 11 | }, 12 | value: { 13 | type: String, 14 | notify: true 15 | }, 16 | disabled: Boolean, 17 | items: Array 18 | }; 19 | } 20 | 21 | ready() { 22 | super.ready(); 23 | this.$.input.$.input.style.fontSize = '32px'; 24 | this.$.input.$.toggleIcon.style.width = '44px'; 25 | this.$.input.$.toggleIcon.style.height = '100%'; 26 | this.$.input.$.toggleIcon.style.padding = '0'; 27 | this.$.input.$.clearIcon.style.width = '44px'; 28 | this.$.input.$.clearIcon.style.height = '100%'; 29 | this.$.input.$.clearIcon.style.padding = '0'; 30 | } 31 | 32 | clear() { 33 | this.$.input.value = ''; 34 | } 35 | } 36 | 37 | customElements.define(DashLowerthirdNameInput.is, DashLowerthirdNameInput); 38 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/ui-tweet/ui-tweet.js: -------------------------------------------------------------------------------- 1 | class UiTweet extends Polymer.Element { 2 | static get is() { 3 | return 'ui-tweet'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | tweet: { 9 | type: Object, 10 | observer: 'populateBody' 11 | }, 12 | profileUrl: { 13 | type: String, 14 | computed: 'computeProfileUrl(tweet)' 15 | }, 16 | tweetUrl: { 17 | type: String, 18 | computed: 'computeTweetUrl(profileUrl, tweet)' 19 | } 20 | }; 21 | } 22 | 23 | computeProfileUrl(tweet) { 24 | if (!tweet || !tweet.user) { 25 | return; 26 | } 27 | 28 | return `https://twitter.com/${tweet.user.screen_name}`; 29 | } 30 | 31 | computeTweetUrl(profileUrl, tweet) { 32 | if (!profileUrl || !tweet) { 33 | return; 34 | } 35 | 36 | return `${profileUrl}/status/${tweet.id_str}`; 37 | } 38 | 39 | populateBody() { 40 | if (!this.tweet) { 41 | return; 42 | } 43 | 44 | this.$.body.innerHTML = this.tweet.text; 45 | } 46 | } 47 | 48 | customElements.define(UiTweet.is, UiTweet); 49 | -------------------------------------------------------------------------------- /graphics/mixins/CSSReflectionMixin.html: -------------------------------------------------------------------------------- 1 | 2 | 34 | -------------------------------------------------------------------------------- /graphics/style/layout.css: -------------------------------------------------------------------------------- 1 | @import 'base.css'; 2 | 3 | body { 4 | font-family: 'Source Code Pro'; 5 | } 6 | 7 | #container { 8 | position: relative; 9 | width: 1600px; 10 | height: 845px; 11 | } 12 | 13 | #container > #background, 14 | #container > #foreground, 15 | #container > #addon { 16 | position: absolute; 17 | top: 0; 18 | left: 0; 19 | } 20 | 21 | #container > #background { 22 | z-index: -10; 23 | } 24 | 25 | #container > #foreground { 26 | pointer-events: none; 27 | z-index: 10; 28 | } 29 | 30 | #container > #addon { 31 | pointer-events: none; 32 | z-index: -11; 33 | } 34 | 35 | /* 36 | For use in gathering viewport metrics. 37 | Dump this javascript into your console to make the measuring div appear: 38 | 39 | const measuringDiv = document.createElement('div'); 40 | measuringDiv.id = 'measuring'; 41 | measuringDiv.style.left = '0px'; 42 | measuringDiv.style.top = '0px'; 43 | document.body.appendChild(measuringDiv); 44 | */ 45 | #measuring { 46 | position: absolute; 47 | width: 200px; 48 | height: 150px; 49 | background-color: #464646; 50 | z-index: -100; 51 | } 52 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-throw/gdq-throw.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-producer/dash-producer-checklist.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const checklist = nodecg.Replicant('checklist'); 5 | 6 | /** 7 | * @customElement 8 | * @polymer 9 | */ 10 | class DashProducerChecklist extends Polymer.MutableData(Polymer.Element) { 11 | static get is() { 12 | return 'dash-producer-checklist'; 13 | } 14 | 15 | static get properties() { 16 | return { 17 | stageTechDuties: Array, 18 | extraContent: Array, 19 | audioReady: Boolean, 20 | techStationDuties: Array, 21 | audioEngineerDuties: Array 22 | }; 23 | } 24 | 25 | ready() { 26 | super.ready(); 27 | checklist.on('change', newVal => { 28 | this.extraContent = newVal.extraContent; 29 | this.techStationDuties = newVal.techStationDuties; 30 | this.stageTechDuties = newVal.stageTechDuties; 31 | this.audioEngineerDuties = newVal.audioEngineerDuties; 32 | }); 33 | } 34 | 35 | _calcItemName(item) { 36 | return item ? (item.shortName || item.name) : ''; 37 | } 38 | } 39 | 40 | customElements.define(DashProducerChecklist.is, DashProducerChecklist); 41 | })(); 42 | -------------------------------------------------------------------------------- /shared/elements/interfaces/ui-timeago/ui-timeago.js: -------------------------------------------------------------------------------- 1 | /* global moment */ 2 | (function () { 3 | moment.updateLocale('en', { 4 | relativeTime: { 5 | future: 'in %s', 6 | past: '%s', 7 | s: 'just now', 8 | m: '1m', 9 | mm: '%dm', 10 | h: '1h', 11 | hh: '%dh', 12 | d: '1d', 13 | dd: '%dd', 14 | M: '1mo', 15 | MM: '%dmo', 16 | y: '1y', 17 | yy: '%dy' 18 | } 19 | }); 20 | 21 | Polymer({ 22 | is: 'ui-timeago', 23 | 24 | properties: { 25 | timeago: { 26 | type: String, 27 | value: '', 28 | notify: true 29 | }, 30 | datetime: { 31 | type: String, 32 | value: '0000-00-00T00:00:00.000Z', 33 | observer: '_datetimeChanged' 34 | } 35 | }, 36 | 37 | ready() { 38 | this.restartInterval(); 39 | }, 40 | 41 | restartInterval() { 42 | this.recalculate(); 43 | clearInterval(this.interval); 44 | this.interval = setInterval(this.recalculate.bind(this), 60000); 45 | }, 46 | 47 | recalculate() { 48 | this.timeago = moment(new Date(this.datetime)).fromNow(); 49 | }, 50 | 51 | _datetimeChanged() { 52 | this.restartInterval(); 53 | } 54 | }); 55 | })(); 56 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-monitor/dash-interview-monitor-prizes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-monitor/dash-interview-monitor-tweets.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /shared/style/gdq-checkbox-style.html: -------------------------------------------------------------------------------- 1 | 2 | 43 | 44 | -------------------------------------------------------------------------------- /graphics/interview_tablet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Interview Tablet Controller 6 | 7 | 8 | 9 | 10 | 11 | 12 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /.win_folder_icon/apply_folder_icon.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | goto check_permissions 4 | 5 | :check_permissions 6 | echo Administrative permissions required. Detecting permissions... 7 | 8 | net session >nul 2>&1 9 | if %errorLevel% == 0 ( 10 | echo Success: Administrative permissions confirmed. 11 | goto script 12 | ) else ( 13 | echo Failure: Current permissions inadequate. 14 | echo Run this script as Administrator and try again. 15 | goto end 16 | ) 17 | 18 | :script 19 | echo Applying custom folder icon... 20 | cd %~dp0 21 | cd .. 22 | 23 | :: Delete any existing desktop.ini, otherwise the copy step will fail. 24 | del /A S /F desktop.ini 25 | 26 | :: Copy our desktop.ini and set the required "system" and "hidden" attributes on it. 27 | copy /V ".win_folder_icon\desktop.ini" "desktop.ini" 28 | attrib +s +h -a desktop.ini 29 | 30 | :: Strangely, the folder also has to be set to read-only for its icon to show up. 31 | attrib +r . 32 | 33 | echo Success! 34 | echo You may need to restart Explorer from your Task Manager to see the new icon. 35 | goto end 36 | 37 | :end 38 | pause 39 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-greeble/atom-greeble.html: -------------------------------------------------------------------------------- 1 | 2 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/ui-dragula-element/ui-dragula-element.html: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 20 | 21 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-styles.html: -------------------------------------------------------------------------------- 1 | 2 | 50 | 51 | -------------------------------------------------------------------------------- /dashboard/record-tracker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-twitter-controls/tweet-item.js: -------------------------------------------------------------------------------- 1 | class TweetItem extends Polymer.Element { 2 | static get is() { 3 | return 'tweet-item'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | value: { 9 | type: Object, 10 | observer: '_valueChanged' 11 | }, 12 | profileUrl: { 13 | type: String, 14 | computed: 'computeProfileUrl(value)' 15 | }, 16 | tweetUrl: { 17 | type: String, 18 | computed: 'computeTweetUrl(profileUrl, value)' 19 | } 20 | }; 21 | } 22 | 23 | _valueChanged(newValue) { 24 | Polymer.dom(this.$.body).innerHTML = newValue.text; 25 | } 26 | 27 | computeProfileUrl(value) { 28 | return `https://twitter.com/${value.user.screen_name}`; 29 | } 30 | 31 | computeTweetUrl(profileUrl, value) { 32 | return `${profileUrl}/status/${value.id_str}`; 33 | } 34 | 35 | computePhotoOrPhotos(numPhotos) { 36 | return numPhotos > 1 ? 'photos' : 'photo'; 37 | } 38 | 39 | computeIndexPlusOne(index) { 40 | return index + 1; 41 | } 42 | 43 | accept() { 44 | nodecg.sendMessage('acceptTweet', this.value); 45 | } 46 | 47 | reject() { 48 | nodecg.sendMessage('rejectTweet', this.value.id_str); 49 | } 50 | } 51 | 52 | customElements.define(TweetItem.is, TweetItem); 53 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-twitter-controls/gdq-twitter-controls.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const currentLayout = nodecg.Replicant('gdq:currentLayout'); 5 | const tweets = nodecg.Replicant('tweets'); 6 | 7 | class GdqTwitterControls extends Polymer.MutableData(Polymer.Element) { 8 | static get is() { 9 | return 'gdq-twitter-controls'; 10 | } 11 | 12 | static get properties() { 13 | return { 14 | tweets: Array 15 | }; 16 | } 17 | 18 | ready() { 19 | super.ready(); 20 | 21 | currentLayout.on('change', newVal => { 22 | switch (newVal) { 23 | case 'countdown': 24 | case 'interview': 25 | case 'standard_4': 26 | case 'widescreen_4': 27 | case 'gameboy_4': 28 | case 'ds': 29 | this.$.cover.style.display = 'flex'; 30 | break; 31 | default: 32 | this.$.cover.style.display = 'none'; 33 | } 34 | }); 35 | 36 | tweets.on('change', newVal => { 37 | this.$.empty.style.display = newVal.length > 0 ? 'none' : 'flex'; 38 | this.tweets = newVal; 39 | }); 40 | } 41 | 42 | _sortTweets(a, b) { 43 | return new Date(b.created_at) - new Date(a.created_at); 44 | } 45 | } 46 | 47 | customElements.define(GdqTwitterControls.is, GdqTwitterControls); 48 | })(); 49 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-recordings/gdq-recordings.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-prizes.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const currentPrizes = nodecg.Replicant('currentPrizes'); 3 | 4 | class DashHostPrizes extends Polymer.MutableData(Polymer.Element) { 5 | static get is() { 6 | return 'dash-host-prizes'; 7 | } 8 | 9 | static get properties() { 10 | return { 11 | prizes: { 12 | type: Array 13 | }, 14 | prizeFilterString: { 15 | type: String, 16 | notify: true 17 | } 18 | }; 19 | } 20 | 21 | ready() { 22 | super.ready(); 23 | currentPrizes.on('change', newVal => { 24 | this.prizes = newVal; 25 | }); 26 | 27 | nodecg.listenFor('prizes:updating', () => { 28 | this.$.cooldown.indeterminate = true; 29 | }); 30 | 31 | nodecg.listenFor('prizes:updated', () => { 32 | this.$.cooldown.startCountdown(60); 33 | }); 34 | } 35 | 36 | computePrizesFilter(string) { 37 | if (string) { 38 | // Return a filter function for the current search string. 39 | const regexp = new RegExp(string, 'ig'); 40 | return function (bid) { 41 | return regexp.test(bid.description); 42 | }; 43 | } 44 | 45 | // Set filter to null to disable filtering. 46 | return null; 47 | } 48 | } 49 | 50 | customElements.define(DashHostPrizes.is, DashHostPrizes); 51 | })(); 52 | -------------------------------------------------------------------------------- /shared/lib/vendor/d3-random.v1.min.js: -------------------------------------------------------------------------------- 1 | // https://d3js.org/d3-random/ Version 1.1.0. Copyright 2017 Mike Bostock. 2 | !function(n,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports):"function"==typeof define&&define.amd?define(["exports"],r):r(n.d3=n.d3||{})}(this,function(n){"use strict";var r=function(){return Math.random()},t=function n(r){function t(n,t){return n=null==n?0:+n,t=null==t?1:+t,1===arguments.length?(t=n,n=0):t-=n,function(){return r()*t+n}}return t.source=n,t}(r),u=function n(r){function t(n,t){var u,e;return n=null==n?0:+n,t=null==t?1:+t,function(){var o;if(null!=u)o=u,u=null;else do{u=2*r()-1,o=2*r()-1,e=u*u+o*o}while(!e||e>1);return n+t*o*Math.sqrt(-2*Math.log(e)/e)}}return t.source=n,t}(r),e=function n(r){function t(){var n=u.source(r).apply(this,arguments);return function(){return Math.exp(n())}}return t.source=n,t}(r),o=function n(r){function t(n){return function(){for(var t=0,u=0;u 2 | 3 | 4 | 5 | 6 | 7 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-totals/gdq-totals-total.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-gradient-text/atom-gradient-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-run.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqOmnibarRun extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-omnibar-run'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | run: Object, 13 | first: { 14 | type: Boolean, 15 | reflectToAttribute: true 16 | } 17 | }; 18 | } 19 | 20 | enter() { 21 | return this.$.listItem.enter(); 22 | } 23 | 24 | exit() { 25 | return this.$.listItem.exit(); 26 | } 27 | 28 | formatName(name) { 29 | return name.replace('\\n', ' ').trim(); 30 | } 31 | 32 | concatenateRunners(run) { 33 | if (run.pk === 2640) { 34 | // Pre-Show 35 | return 'SpikeVegeta, feasel, Blechy, Protomagicalgirl & JHobz'; 36 | } 37 | 38 | if (run.pk === 2779) { 39 | // Mega Man 1 - 3 Team Relay Race Any% 40 | return '12 Runners'; 41 | } 42 | 43 | let concatenatedRunners = run.runners[0].name; 44 | if (run.runners.length > 1) { 45 | concatenatedRunners = run.runners.slice(1).reduce((prev, curr, index, array) => { 46 | if (index === array.length - 1) { 47 | return `${prev} & ${curr.name}`; 48 | } 49 | 50 | return `${prev}, ${curr.name}`; 51 | }, concatenatedRunners); 52 | } 53 | return concatenatedRunners; 54 | } 55 | } 56 | 57 | customElements.define(GdqOmnibarRun.is, GdqOmnibarRun); 58 | -------------------------------------------------------------------------------- /extension/twitch-title-updater.js: -------------------------------------------------------------------------------- 1 | // Packages 2 | const request = require('request-promise'); 3 | 4 | // Ours 5 | const nodecg = require('./util/nodecg-api-context').get(); 6 | 7 | const log = new nodecg.Logger(`${nodecg.bundleName}:twitch`); 8 | const currentRun = nodecg.Replicant('currentRun'); 9 | let lastLongName; 10 | 11 | currentRun.on('change', newVal => { 12 | if (newVal.longName === lastLongName) { 13 | return; 14 | } 15 | 16 | log.info('Updating Twitch title and game to', newVal.longName); 17 | lastLongName = newVal.longName; 18 | request({ 19 | method: 'put', 20 | uri: `https://api.twitch.tv/kraken/channels/${nodecg.bundleConfig.twitch.channelId}`, 21 | headers: { 22 | Accept: 'application/vnd.twitchtv.v5+json', 23 | Authorization: `OAuth ${nodecg.bundleConfig.twitch.oauthToken}`, 24 | 'Client-ID': nodecg.bundleConfig.twitch.clientId, 25 | 'Content-Type': 'application/json' 26 | }, 27 | body: { 28 | channel: { 29 | // eslint-disable-next-line no-template-curly-in-string 30 | status: nodecg.bundleConfig.twitch.titleTemplate.replace('${gameName}', newVal.longName), 31 | game: newVal.longName 32 | } 33 | }, 34 | json: true 35 | }).then(() => { 36 | log.info('Successfully updated Twitch title and game to', newVal.longName); 37 | }).catch(err => { 38 | log.error('Failed updating Twitch title and game:\n\t', err); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-milestone-alert.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-prize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-tronlines/atom-tronlines.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-checklist/gdq-checklist.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const checklist = nodecg.Replicant('checklist'); 5 | 6 | class GdqChecklist extends Polymer.MutableData(Polymer.Element) { 7 | static get is() { 8 | return 'gdq-checklist'; 9 | } 10 | 11 | static get properties() { 12 | return { 13 | stageTechDuties: Array, 14 | extraContent: Array, 15 | audioReady: Boolean, 16 | techStationDuties: Array 17 | }; 18 | } 19 | 20 | ready() { 21 | super.ready(); 22 | checklist.on('change', newVal => { 23 | this.extraContent = newVal.extraContent; 24 | this.techStationDuties = newVal.techStationDuties; 25 | this.stageTechDuties = newVal.stageTechDuties; 26 | this.audioReady = newVal.audioEngineerDuties.every(task => task.complete); 27 | }); 28 | 29 | this._checkboxChanged = this._checkboxChanged.bind(this); 30 | this.addEventListener('change', this._checkboxChanged); 31 | } 32 | 33 | _checkboxChanged(e) { 34 | const target = e.path[0]; 35 | const category = target.getAttribute('category'); 36 | const name = target.innerText.trim(); 37 | checklist.value[category].find(task => { 38 | if (task.name === name) { 39 | task.complete = target.checked; 40 | return true; 41 | } 42 | 43 | return false; 44 | }); 45 | } 46 | } 47 | 48 | customElements.define(GdqChecklist.is, GdqChecklist); 49 | })(); 50 | -------------------------------------------------------------------------------- /.idea/runConfigurations/NodeCG_v0_9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 11 | 14 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-inner-glow-text/atom-inner-glow-text.html: -------------------------------------------------------------------------------- 1 | 2 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-bidwars.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-recordings/gdq-recordings.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const autoCycleRecordings = nodecg.Replicant('autoCycleRecordings'); 5 | const autoUploadRecordings = nodecg.Replicant('autoUploadRecordings'); 6 | 7 | class GdqRecordings extends Polymer.Element { 8 | static get is() { 9 | return 'gdq-recordings'; 10 | } 11 | 12 | static get properties() { 13 | return {}; 14 | } 15 | 16 | ready() { 17 | super.ready(); 18 | Polymer.RenderStatus.beforeNextRender(this, () => { 19 | autoCycleRecordings.on('change', newVal => { 20 | this.$.cycleToggle.checked = newVal; 21 | this._checkUploadToggleDisable(); 22 | }); 23 | 24 | autoUploadRecordings.on('change', newVal => { 25 | this.$.uploadToggle.checked = newVal; 26 | }); 27 | 28 | this._checkUploadToggleDisable(); 29 | }); 30 | } 31 | 32 | _checkUploadToggleDisable() { 33 | if (!autoCycleRecordings.value || !nodecg.bundleConfig.youtubeUploadScriptPath) { 34 | this.$.uploadToggle.setAttribute('disabled', 'true'); 35 | } else { 36 | this.$.uploadToggle.removeAttribute('disabled'); 37 | } 38 | } 39 | 40 | _handleCycleToggleChange(e) { 41 | autoCycleRecordings.value = e.target.checked; 42 | } 43 | 44 | _handleUploadToggleChange(e) { 45 | autoUploadRecordings.value = e.target.checked; 46 | } 47 | } 48 | 49 | customElements.define(GdqRecordings.is, GdqRecordings); 50 | })(); 51 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-challenges.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-runner-nameplate/gdq-runner-nameplate-audio-indicator.html: -------------------------------------------------------------------------------- 1 | 2 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-tablet/dash-interview-tablet-lowerthird-refill-option.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /dashboard/elements/time-input/time-input.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /graphics/test_tronlines.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test Tron Lines 6 | 7 | 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 | 39 | 40 | Clear Nodes 41 | 42 | 43 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /shared/style/gdq-input-style.html: -------------------------------------------------------------------------------- 1 | 2 | 57 | 58 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-adbreak.js: -------------------------------------------------------------------------------- 1 | class DashHostAdbreak extends Polymer.MutableData(Polymer.Element) { 2 | static get is() { 3 | return 'dash-host-adbreak'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | adBreak: { 9 | type: Object 10 | } 11 | }; 12 | } 13 | 14 | start() { 15 | this.dispatchEvent(new CustomEvent('start', { 16 | detail: { 17 | adBreakId: this.adBreak.id 18 | }, 19 | bubbles: true, 20 | composed: true 21 | })); 22 | } 23 | 24 | cancel() { 25 | this.dispatchEvent(new CustomEvent('cancel', { 26 | detail: { 27 | adBreakId: this.adBreak.id 28 | }, 29 | bubbles: true, 30 | composed: true 31 | })); 32 | } 33 | 34 | complete() { 35 | this.dispatchEvent(new CustomEvent('complete', { 36 | detail: { 37 | adBreakId: this.adBreak.id 38 | }, 39 | bubbles: true, 40 | composed: true 41 | })); 42 | } 43 | 44 | _calcStartButtonText(adBreakState) { 45 | if (adBreakState.canStart) { 46 | return 'Start Break'; 47 | } 48 | 49 | if (adBreakState.cantStartReason) { 50 | return adBreakState.cantStartReason; 51 | } 52 | 53 | return 'Prequisites unmet'; 54 | } 55 | 56 | _calcCompleteButtonHidden(adBreak) { 57 | const lastAd = adBreak.ads[adBreak.ads.length - 1]; 58 | return lastAd.adType.toLowerCase() !== 'image'; 59 | } 60 | 61 | any(...args) { 62 | return args.find(arg => Boolean(arg)); 63 | } 64 | } 65 | 66 | customElements.define(DashHostAdbreak.is, DashHostAdbreak); 67 | -------------------------------------------------------------------------------- /schemas/types/ad.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "type": "object", 4 | "additionalProperties": false, 5 | "properties": { 6 | "id": { 7 | "type": "number" 8 | }, 9 | "name": { 10 | "type": "string" 11 | }, 12 | "adType": { 13 | "type": "string", 14 | "enum": ["VIDEO", "IMAGE"] 15 | }, 16 | "filename": { 17 | "type": "string" 18 | }, 19 | "duration": { 20 | "type": "string" 21 | }, 22 | "order": { 23 | "type": "number" 24 | }, 25 | "suborder": { 26 | "type": "number" 27 | }, 28 | "sponsorName": { 29 | "type": "string" 30 | }, 31 | "type": { 32 | "type": "string", 33 | "enum": ["ad"] 34 | }, 35 | "state": { 36 | "type": "object", 37 | "additionalProperties": false, 38 | "properties": { 39 | "canStart": { 40 | "type": "boolean", 41 | "default": false 42 | }, 43 | "started": { 44 | "type": "boolean", 45 | "default": false 46 | }, 47 | "canComplete": { 48 | "type": "boolean", 49 | "default": false 50 | }, 51 | "completed": { 52 | "type": "boolean", 53 | "default": false 54 | }, 55 | "durationFrames": { 56 | "type": "number", 57 | "default": 0 58 | }, 59 | "framesLeft": { 60 | "type": "number", 61 | "default": 0 62 | }, 63 | "frameNumber": { 64 | "type": "number", 65 | "default": 0 66 | }, 67 | "fps": { 68 | "type": "number", 69 | "default": 60 70 | } 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-milestone-tracker-point.html: -------------------------------------------------------------------------------- 1 | 2 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /extension/countdown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Ours 4 | const nodecg = require('./util/nodecg-api-context').get(); 5 | const TimeUtils = require('./lib/time'); 6 | 7 | const time = nodecg.Replicant('countdown', {defaultValue: TimeUtils.createTimeStruct(600 * 1000), persistent: false}); 8 | const running = nodecg.Replicant('countdownRunning', {defaultValue: false, persistent: false}); 9 | let countdownTimer; 10 | 11 | nodecg.listenFor('startCountdown', start); 12 | nodecg.listenFor('stopCountdown', stop); 13 | 14 | /** 15 | * Starts the countdown at the specified startTime. 16 | * @param {string} startTime - A formatted time string, such as 1:00 for one hour. 17 | * @returns {undefined} 18 | */ 19 | function start(startTime) { 20 | if (running.value) { 21 | return; 22 | } 23 | 24 | const durationMs = TimeUtils.parseTimeString(startTime); 25 | if (durationMs <= 0) { 26 | return; 27 | } 28 | 29 | running.value = true; 30 | time.value = TimeUtils.createTimeStruct(durationMs); 31 | 32 | if (countdownTimer) { 33 | countdownTimer.stop(); 34 | countdownTimer.removeAllListeners(); 35 | } 36 | 37 | countdownTimer = new TimeUtils.CountdownTimer(Date.now() + durationMs); 38 | countdownTimer.on('tick', remainingTimeStruct => { 39 | time.value = remainingTimeStruct; 40 | }); 41 | } 42 | 43 | /** 44 | * Stops the countdown. 45 | * @returns {undefined} 46 | */ 47 | function stop() { 48 | if (!running.value) { 49 | return; 50 | } 51 | 52 | running.value = false; 53 | if (countdownTimer) { 54 | countdownTimer.stop(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-nameplate/gdq-nameplate-twitch-logo.html: -------------------------------------------------------------------------------- 1 | 47 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-bid-many-option.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqBreakBidManyOption extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-break-bid-many-option'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | bid: Object, 13 | option: Object 14 | }; 15 | } 16 | 17 | ready() { 18 | super.ready(); 19 | this.$.amount.ease = Power2.easeOut; 20 | this.$.amount.displayValueTransform = displayValue => { 21 | return '$' + displayValue.toLocaleString('en-US', { 22 | maximumFractionDigits: 0, 23 | useGrouping: false 24 | }); 25 | }; 26 | } 27 | 28 | enter() { 29 | let meterPercent = this.option.rawTotal / this.bid.options[0].rawTotal; 30 | meterPercent = Math.max(meterPercent, 0); // Clamp to min 0 31 | meterPercent = Math.min(meterPercent, 1); // Clamp to max 1 32 | if (Number.isNaN(meterPercent)) { 33 | meterPercent = 0; 34 | } 35 | 36 | const tl = new TimelineLite(); 37 | const duration = 0.75 * meterPercent; 38 | 39 | tl.fromTo(this.$.meter, duration, { 40 | scaleX: 0 41 | }, { 42 | scaleX: meterPercent, 43 | ease: Power2.easeOut, 44 | callbackScope: this, 45 | onStart() { 46 | this.$.amount.tween(this.option.rawTotal, duration); 47 | } 48 | }); 49 | 50 | return tl; 51 | } 52 | 53 | _calcOptionName(option) { 54 | if (!option) { 55 | return ''; 56 | } 57 | 58 | return option.name || option.description; 59 | } 60 | } 61 | 62 | customElements.define(GdqBreakBidManyOption.is, GdqBreakBidManyOption); 63 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-runner-nameplate/gdq-runner-nameplate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-schedule/gdq-schedule-runinfo.js: -------------------------------------------------------------------------------- 1 | class GdqScheduleRuninfo extends Polymer.Element { 2 | static get is() { 3 | return 'gdq-schedule-runinfo'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | notes: { 9 | type: String, 10 | observer: '_notesChanged' 11 | }, 12 | label: { 13 | type: String, 14 | reflectToAttribute: true 15 | }, 16 | coop: Boolean, 17 | releaseYear: String, 18 | console: String, 19 | estimate: String, 20 | category: String, 21 | name: String, 22 | originalValues: Object, 23 | order: Number 24 | }; 25 | } 26 | 27 | _notesChanged(newVal) { 28 | if (newVal) { 29 | this.$.notes.querySelector('.value').innerHTML = newVal.replace(/\r\n/g, '
').replace(/\n/g, '
'); 30 | } else { 31 | this.$.notes.querySelector('.value').innerHTML = ''; 32 | } 33 | } 34 | 35 | setRun(run) { 36 | this.name = run.name; 37 | this.console = run.console; 38 | this.runners = run.runners; 39 | this.releaseYear = run.releaseYear; 40 | this.estimate = run.estimate; 41 | this.category = run.category; 42 | this.order = run.order; 43 | this.notes = run.notes; 44 | this.coop = run.coop; 45 | this.originalValues = run.originalValues; 46 | } 47 | 48 | calcName(name) { 49 | if (name) { 50 | return name.split('\\n').join(' '); 51 | } 52 | 53 | return name; 54 | } 55 | 56 | calcModified(original) { 57 | return typeof original === 'undefined' || original === null ? '' : 'modified'; 58 | } 59 | } 60 | 61 | customElements.define(GdqScheduleRuninfo.is, GdqScheduleRuninfo); 62 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-bid.js: -------------------------------------------------------------------------------- 1 | class DashHostBid extends Polymer.MutableData(Polymer.Element) { 2 | static get is() { 3 | return 'dash-host-bid'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | type: { 9 | type: String, 10 | reflectToAttribute: true, 11 | computed: '_computeType(bid)' 12 | }, 13 | bid: { 14 | type: Object 15 | }, 16 | failed: { 17 | type: Boolean, 18 | computed: 'computeFailed(closed, bid)', 19 | reflectToAttribute: true 20 | }, 21 | closed: { 22 | type: Boolean, 23 | computed: 'computeClosed(bid)', 24 | reflectToAttribute: true 25 | } 26 | }; 27 | } 28 | 29 | computeFailed(closed, bid) { 30 | return closed && bid.rawTotal < bid.rawGoal; 31 | } 32 | 33 | computeClosed(bid) { 34 | return bid.state.toLowerCase() === 'closed'; 35 | } 36 | 37 | bidIsChallenge(bid) { 38 | return bid.type === 'challenge'; 39 | } 40 | 41 | limitOptions(options) { 42 | if (!options) { 43 | return []; 44 | } 45 | 46 | return options.slice(0, 3); 47 | } 48 | 49 | bidHasMoreThanThreeOptions(bid) { 50 | if (!bid.options) { 51 | return false; 52 | } 53 | 54 | return bid.options.length > 3; 55 | } 56 | 57 | calcNumAdditionalOptions(bid) { 58 | if (!bid.options) { 59 | return 0; 60 | } 61 | 62 | return bid.options.length - 3; 63 | } 64 | 65 | calcBidName(description) { 66 | return description.replace(/\\n/g, ' '); 67 | } 68 | 69 | _computeType(bid) { 70 | return bid ? bid.type : ''; 71 | } 72 | } 73 | 74 | customElements.define(DashHostBid.is, DashHostBid); 75 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-milestone-tracker-point.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const ONE_MILLION = 1000000; 5 | 6 | class GdqOmnibarMilestoneTrackerPoint extends Polymer.Element { 7 | static get is() { 8 | return 'gdq-omnibar-milestone-tracker-point'; 9 | } 10 | 11 | static get properties() { 12 | return { 13 | align: { 14 | type: String, 15 | value: 'left', 16 | reflectToAttribute: true, 17 | observer: '_alignChanged' 18 | }, 19 | amount: Number, 20 | dropTrailingZeroes: { 21 | type: Boolean, 22 | value: false 23 | } 24 | }; 25 | } 26 | 27 | _alignChanged(newVal) { 28 | if (newVal !== 'center') { 29 | this.$.body.style.left = ''; 30 | } 31 | 32 | const bodyRect = this.$.body.getBoundingClientRect(); 33 | this.$.body.style.left = `${(bodyRect.width / -2) + 1.5}px`; 34 | } 35 | 36 | _calcDisplayAmount(amount) { 37 | return `$${this._formatAmount(amount / ONE_MILLION)}M`; 38 | } 39 | 40 | _formatAmount(amount) { 41 | let amountString = String(amount).substr(0, 4); 42 | 43 | if (this.dropTrailingZeroes) { 44 | while ( 45 | (amountString.endsWith('0') || amountString.endsWith('.')) && 46 | amountString.length > 1 47 | ) { 48 | amountString = amountString.slice(0, -1); 49 | } 50 | } 51 | 52 | // Use the monospace version of the "1" character in the gdqpixel font. 53 | return amountString.replace(/1/ig, '\u00C0'); 54 | } 55 | } 56 | 57 | customElements.define(GdqOmnibarMilestoneTrackerPoint.is, GdqOmnibarMilestoneTrackerPoint); 58 | })(); 59 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-monitor/dash-interview-monitor-tweet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-gridlines/atom-gridlines.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /extension/twitch-bits.js: -------------------------------------------------------------------------------- 1 | // Packages 2 | const TwitchPubSub = require('twitchps'); 3 | 4 | // Ours 5 | const nodecg = require('./util/nodecg-api-context').get(); 6 | 7 | const DEBUG = nodecg.bundleConfig.twitch.debug; 8 | const BITS_TOTAL_UPDATE_INTERVAL = 10 * 1000; 9 | const log = new nodecg.Logger(`${nodecg.bundleName}:twitch-bits`); 10 | const autoUpdateTotal = nodecg.Replicant('autoUpdateTotal'); 11 | const bitsTotal = nodecg.Replicant('bits:total'); 12 | 13 | autoUpdateTotal.on('change', newVal => { 14 | if (newVal) { 15 | updateBitsTotal(); 16 | } 17 | }); 18 | 19 | // Optional reconnect, debug options (Defaults: reconnect: true, debug: false) 20 | // var ps = new TwitchPS({init_topics: init_topics}); 21 | const pubsub = new TwitchPubSub({ 22 | init_topics: [{ // eslint-disable-line camelcase 23 | topic: `channel-bits-events-v1.${nodecg.bundleConfig.twitch.channelId}`, 24 | token: nodecg.bundleConfig.twitch.oauthToken 25 | }], 26 | reconnect: true, 27 | debug: DEBUG 28 | }); 29 | 30 | pubsub.on('connected', () => { 31 | log.info('Connected to PubSub.'); 32 | }); 33 | 34 | pubsub.on('disconnected', () => { 35 | log.warn('Disconnected from PubSub.'); 36 | }); 37 | 38 | pubsub.on('reconnect', () => { 39 | log.info('Reconnecting to PubSub...'); 40 | }); 41 | 42 | pubsub.on('bits', cheer => { 43 | if (DEBUG) { 44 | log.info('Received cheer:', cheer); 45 | } else { 46 | log.debug('Received cheer:', cheer); 47 | } 48 | nodecg.sendMessage('cheer', cheer); 49 | }); 50 | 51 | updateBitsTotal(); 52 | setInterval(updateBitsTotal, BITS_TOTAL_UPDATE_INTERVAL); 53 | 54 | function updateBitsTotal() { 55 | bitsTotal.value = 0; 56 | } 57 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-challenges.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqOmnibarChallenges extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-omnibar-challenges'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | challenges: Array 13 | }; 14 | } 15 | 16 | enter(displayDuration, scrollHoldDuration) { 17 | const tl = new TimelineLite(); 18 | 19 | this.challenges.forEach((challenge, index) => { 20 | const challengeElement = document.createElement('gdq-omnibar-challenge'); 21 | challengeElement.classList.add('challenge'); 22 | challengeElement.bid = challenge; 23 | this.$.challenges.appendChild(challengeElement); 24 | 25 | tl.call(() => { 26 | this.$.challenges.select(index); 27 | }, null, null, '+=0.03'); 28 | 29 | if (index === 0) { 30 | tl.add(this.$.label.enter(challenge.description)); 31 | } else { 32 | tl.add(this.$.label.change(challenge.description)); 33 | } 34 | 35 | tl.call(() => { 36 | tl.pause(); 37 | challengeElement.render(); 38 | const tempTl = challengeElement.enter(displayDuration, scrollHoldDuration); 39 | tempTl.call(tl.resume, null, tl); 40 | }); 41 | 42 | tl.call(() => { 43 | tl.pause(); 44 | const tempTl = challengeElement.exit(); 45 | tempTl.call(tl.resume, null, tl); 46 | }, null, null, `+=${displayDuration}`); 47 | }); 48 | 49 | return tl; 50 | } 51 | 52 | exit() { 53 | const tl = new TimelineLite(); 54 | tl.add(this.$.label.exit()); 55 | return tl; 56 | } 57 | } 58 | 59 | customElements.define(GdqOmnibarChallenges.is, GdqOmnibarChallenges); 60 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-tablet/dash-interview-tablet-lowerthird.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-bottom-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | platform: 4 | - x64 5 | 6 | environment: 7 | PKG_CACHE_PATH: '%USERPROFILE%\pkg-cache' 8 | 9 | cache: 10 | - '%APPDATA%\npm' 11 | - '%APPDATA%\npm-cache' 12 | - '%LOCALAPPDATA%\bower' 13 | - '%USERPROFILE%\pkg-cache' 14 | 15 | install: 16 | - ps: Install-Product node 8 x64 17 | - git reset --hard HEAD 18 | - npm install -g bower polymer-cli pkg 19 | - npm install 20 | - bower install 21 | 22 | before_build: 23 | - node --version 24 | - npm --version 25 | - npm test 26 | 27 | build_script: 28 | - cd .. 29 | - git clone https://github.com/nodecg/nodecg.git 30 | - cd nodecg 31 | - git checkout pkg 32 | - npm i && bower install 33 | - 'move %APPVEYOR_BUILD_FOLDER% bundles\%APPVEYOR_PROJECT_SLUG%' 34 | - pkg . --targets node8-win-x64 --public 35 | - if not exist cfg mkdir cfg 36 | - 'echo {"logging": {"console": {"level": "info"},"file": {"enabled": true,"level": "debug"},"replicants": false}} >> cfg/nodecg.json' 37 | - ps: Start-FileDownload 'https://redacted.com/agdq18-layouts-demo-config.json' -FileName 'cfg/agdq18-layouts.json' 38 | 39 | after_build: 40 | - ps: '$env:PKG_ZIP_NAME = "agdq18-layouts-$(-join $env:APPVEYOR_REPO_COMMIT[0..7]).zip"' 41 | - 7z a %PKG_ZIP_NAME% nodecg.exe cfg 42 | - ps: 'Get-ChildItem -Recurse -ErrorAction SilentlyContinue bundles\$env:APPVEYOR_PROJECT_SLUG\node_modules\*.node | % { 7z a $env:PKG_ZIP_NAME $_.FullName }' 43 | - 'if not exist %APPVEYOR_BUILD_FOLDER% mkdir %APPVEYOR_BUILD_FOLDER%' 44 | - 'move %PKG_ZIP_NAME% %APPVEYOR_BUILD_FOLDER%' 45 | 46 | test: off 47 | 48 | artifacts: 49 | - path: '%PKG_ZIP_NAME%' 50 | name: pkg-agdq18-layouts 51 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-lowerthird/gdq-lowerthird.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-top-frame.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-totals/gdq-totals.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const cashTotal = nodecg.Replicant('total'); 5 | const autoUpdateTotal = nodecg.Replicant('autoUpdateTotal'); 6 | const recordTrackerEnabled = nodecg.Replicant('recordTrackerEnabled'); 7 | 8 | class GdqTotals extends Polymer.Element { 9 | static get is() { 10 | return 'gdq-totals'; 11 | } 12 | 13 | static get properties() { 14 | return { 15 | cashTotal: { 16 | type: String, 17 | value: '?' 18 | }, 19 | bitsTotal: { 20 | type: String, 21 | value: '?' 22 | }, 23 | autoUpdateTotal: Boolean, 24 | recordTrackerEnabled: Boolean 25 | }; 26 | } 27 | 28 | ready() { 29 | super.ready(); 30 | cashTotal.on('change', newVal => { 31 | this.cashTotal = newVal.formatted; 32 | }); 33 | autoUpdateTotal.on('change', newVal => { 34 | this.autoUpdateTotal = newVal; 35 | }); 36 | recordTrackerEnabled.on('change', newVal => { 37 | this.recordTrackerEnabled = newVal; 38 | }); 39 | } 40 | 41 | editCashTotal() { 42 | this.$.editTotalInput.value = cashTotal.value.raw; 43 | this._editTarget = 'cash'; 44 | this.$.editDialog.open(); 45 | } 46 | 47 | _handleAutoUpdateToggleChange(e) { 48 | autoUpdateTotal.value = e.target.checked; 49 | } 50 | 51 | _handleMiletoneTrackerToggleChange(e) { 52 | recordTrackerEnabled.value = e.target.checked; 53 | } 54 | 55 | _handleEditDialogConfirmed() { 56 | nodecg.sendMessage('setTotal', { 57 | type: this._editTarget, 58 | newValue: parseFloat(this.$.editTotalInput.value) 59 | }); 60 | } 61 | } 62 | 63 | customElements.define(GdqTotals.is, GdqTotals); 64 | })(); 65 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-bid-binary.html: -------------------------------------------------------------------------------- 1 | 2 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-arrow-block/atom-arrow-block.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-bid-option.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /extension/nowplaying.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Packages 4 | const app = require('express')(); 5 | const bodyParser = require('body-parser'); 6 | const debounce = require('lodash.debounce'); 7 | 8 | // Ours 9 | const nodecg = require('./util/nodecg-api-context').get(); 10 | 11 | const pulsing = nodecg.Replicant('nowPlayingPulsing', {defaultValue: false, persistent: false}); 12 | const nowPlaying = nodecg.Replicant('nowPlaying', {defaultValue: {}, persistent: false}); 13 | let pulseTimeout; 14 | 15 | nodecg.listenFor('pulseNowPlaying', pulse); 16 | 17 | const changeSong = debounce(newSong => { 18 | nowPlaying.value = { 19 | game: newSong.game, 20 | title: newSong.title 21 | }; 22 | 23 | // If the graphic is already showing, end it prematurely and show the new song 24 | if (pulsing.value) { 25 | clearTimeout(pulseTimeout); 26 | pulsing.value = false; 27 | } 28 | 29 | // Show the graphic 30 | pulse(); 31 | }, 2000); 32 | 33 | app.use(bodyParser.json()); 34 | app.post(`/${nodecg.bundleName}/song`, (req, res, next) => { 35 | if (typeof req.body !== 'object') { 36 | res.sendStatus(400); 37 | return next(); 38 | } 39 | 40 | if (nodecg.bundleConfig.nowPlayingKey && req.body.key !== nodecg.bundleConfig.nowPlayingKey) { 41 | return res.sendStatus(401); 42 | } 43 | 44 | changeSong(req.body); 45 | res.sendStatus(200); 46 | }); 47 | 48 | nodecg.mount(app); 49 | 50 | /** 51 | * Shows the nowPlaying graphic for 12 seconds. 52 | * @returns {undefined} 53 | */ 54 | function pulse() { 55 | // Don't stack pulses 56 | if (pulsing.value) { 57 | return; 58 | } 59 | 60 | pulsing.value = true; 61 | 62 | // Hard-coded 12 second duration 63 | pulseTimeout = setTimeout(() => { 64 | pulsing.value = false; 65 | }, 12 * 1000); 66 | } 67 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-omnibar/gdq-omnibar-list-item.js: -------------------------------------------------------------------------------- 1 | /* global MaybeRandom */ 2 | /** 3 | * @customElement 4 | * @polymer 5 | */ 6 | class GdqOmnibarListItem extends Polymer.Element { 7 | static get is() { 8 | return 'gdq-omnibar-list-item'; 9 | } 10 | 11 | static get properties() { 12 | return { 13 | firstLine: String, 14 | secondLine: String 15 | }; 16 | } 17 | 18 | ready() { 19 | super.ready(); 20 | this._$borderBodies = this.shadowRoot.querySelectorAll('.border-body'); 21 | this._$leftBorderCaps = this.shadowRoot.querySelectorAll('.border-cap:first-child'); 22 | this._$rightBorderCaps = this.shadowRoot.querySelectorAll('.border-cap:last-child'); 23 | } 24 | 25 | enter() { 26 | const enterTL = new TimelineLite(); 27 | 28 | enterTL.fromTo(this, 0.234, { 29 | x: 20, 30 | opacity: 0 31 | }, { 32 | x: 0, 33 | opacity: 1, 34 | ease: Sine.easeOut 35 | }); 36 | 37 | return enterTL; 38 | } 39 | 40 | exit() { 41 | const exitTL = new TimelineLite(); 42 | 43 | exitTL.to(this._$borderBodies, 0.465, { 44 | scaleX: 0, 45 | ease: Sine.easeInOut 46 | }, 0); 47 | 48 | exitTL.to(this._$rightBorderCaps, 0.465, { 49 | x: -this.clientWidth + 2, 50 | ease: Sine.easeInOut 51 | }, 0); 52 | 53 | exitTL.add(MaybeRandom.createTween({ 54 | target: this.$.text.style, 55 | propName: 'opacity', 56 | duration: 0.465, 57 | start: {probability: 1, normalValue: 0}, 58 | end: {probability: 0, normalValue: 0} 59 | }), 0); 60 | 61 | exitTL.to([this._$leftBorderCaps, this._$rightBorderCaps], 0.165, { 62 | scaleX: 0, 63 | ease: Sine.easeInOut 64 | }); 65 | 66 | return exitTL; 67 | } 68 | } 69 | 70 | customElements.define(GdqOmnibarListItem.is, GdqOmnibarListItem); 71 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-refresh-indicator/atom-refresh-indicator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class AtomRefreshIndicator extends Polymer.Element { 6 | static get is() { 7 | return 'atom-refresh-indicator'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | indeterminate: { 13 | type: Boolean, 14 | value: true, 15 | reflectToAttribute: true, 16 | observer: '_indeterminateChanged' 17 | }, 18 | timeUntilRefresh: { 19 | type: String, 20 | value: ':??' 21 | } 22 | }; 23 | } 24 | 25 | startCountdown(seconds) { 26 | this.indeterminate = false; 27 | this.stopCountdown(); 28 | this.$['meter-fill'].style.transform = ''; 29 | 30 | const startTimestamp = Date.now(); 31 | this._countdownInterval = setInterval(() => { 32 | const nowTimestamp = Date.now(); 33 | const millisecondsElapsed = nowTimestamp - startTimestamp; 34 | const secondsRemaining = seconds - Math.ceil(millisecondsElapsed / 1000); 35 | const percentElapsed = Math.min(millisecondsElapsed / (seconds * 1000), 1) * 100; 36 | 37 | this.$['meter-fill'].style.transform = `translateX(-${percentElapsed}%)`; 38 | this.timeUntilRefresh = `:${String(secondsRemaining).padStart(2, '0')}`; 39 | 40 | if (secondsRemaining <= 0) { 41 | clearInterval(this._countdownInterval); 42 | this.indeterminate = true; 43 | } 44 | }, 1 / 60); 45 | } 46 | 47 | stopCountdown() { 48 | if (this._countdownInterval) { 49 | clearInterval(this._countdownInterval); 50 | } 51 | } 52 | 53 | _indeterminateChanged(newVal) { 54 | if (newVal) { 55 | this.stopCountdown(); 56 | this.timeUntilRefresh = ':00'; 57 | } 58 | } 59 | } 60 | 61 | customElements.define(AtomRefreshIndicator.is, AtomRefreshIndicator); 62 | -------------------------------------------------------------------------------- /graphics/elements/atoms/atom-text-greeble/atom-text-greeble.js: -------------------------------------------------------------------------------- 1 | /* global Random */ 2 | (function () { 3 | 'use strict'; 4 | 5 | /** 6 | * @customElement 7 | * @polymer 8 | */ 9 | class AtomTextGreeble extends Polymer.Element { 10 | static get is() { 11 | return 'atom-text-greeble'; 12 | } 13 | 14 | static get properties() { 15 | return { 16 | /** 17 | * The number of characters this greeble should be in length. 18 | */ 19 | length: { 20 | type: Number, 21 | value: 15 22 | }, 23 | 24 | /** 25 | * How many times per second to update the text. 26 | */ 27 | tickRate: { 28 | type: Number, 29 | value: 5, 30 | observer: '_tickRateChanged' 31 | }, 32 | 33 | /** 34 | * The set of characters from which to create the random strings. 35 | */ 36 | characters: { 37 | type: String, 38 | value: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 39 | }, 40 | 41 | /** 42 | * The text currently being shown. 43 | */ 44 | text: String, 45 | 46 | _charactersArray: { 47 | type: Array, 48 | computed: '_computeCharactersArray(characters)' 49 | } 50 | }; 51 | } 52 | 53 | update() { 54 | let string = ''; 55 | for (let i = 0; i < this.length; i++) { 56 | string += Random.pick(Random.engines.browserCrypto, this._charactersArray); 57 | } 58 | this.text = string; 59 | } 60 | 61 | _tickRateChanged(newVal) { 62 | if (this._tickInterval) { 63 | clearInterval(this._tickInterval); 64 | } 65 | 66 | this._tickInterval = setInterval(() => { 67 | this.update(); 68 | }, 1000 / newVal); 69 | } 70 | 71 | _computeCharactersArray(characters) { 72 | return characters.split(''); 73 | } 74 | } 75 | 76 | customElements.define(AtomTextGreeble.is, AtomTextGreeble); 77 | })(); 78 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/img/run-bottom-greeble.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/ui-element-tester/ui-element-tester.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-interview-monitor/dash-interview-monitor-prize.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const currentRun = nodecg.Replicant('currentRun'); 5 | 6 | /** 7 | * @customElement 8 | * @polymer 9 | */ 10 | class DashInterviewMonitorPrize extends Polymer.MutableData(Polymer.Element) { 11 | static get is() { 12 | return 'dash-interview-monitor-prize'; 13 | } 14 | 15 | static get properties() { 16 | return { 17 | prize: Object, 18 | currentRun: Object, 19 | bidType: { 20 | type: String, 21 | reflectToAttribute: true, 22 | computed: '_computeBidType(prize)' 23 | }, 24 | closed: { 25 | type: Boolean, 26 | reflectToAttribute: true, 27 | computed: '_computeClosed(prize, currentRun)' 28 | } 29 | }; 30 | } 31 | 32 | ready() { 33 | super.ready(); 34 | 35 | currentRun.on('change', newVal => { 36 | this.currentRun = newVal; 37 | }); 38 | } 39 | 40 | _computeBidType(prize) { 41 | return prize.sumdonations ? 'total' : 'single'; 42 | } 43 | 44 | _computeClosed(prize, currentRun) { 45 | if (!prize || !currentRun) { 46 | return false; 47 | } 48 | 49 | return prize.endrun.order < currentRun.order; 50 | } 51 | 52 | _calcBidTypeChar(bidType) { 53 | if (!bidType) { 54 | return ''; 55 | } 56 | return bidType.charAt(0); 57 | } 58 | 59 | _calcOpening(prize, currentRun) { 60 | if (!prize || !currentRun) { 61 | return '?'; 62 | } 63 | 64 | if (prize.startrun.order <= currentRun.order) { 65 | return 'OPEN'; 66 | } 67 | 68 | return prize.startrun.name; 69 | } 70 | 71 | _calcClosing(prize, currentRun) { 72 | if (!prize || !currentRun) { 73 | return '?'; 74 | } 75 | 76 | if (prize.endrun.order < currentRun.order) { 77 | return 'CLOSED'; 78 | } 79 | 80 | return prize.endrun.name; 81 | } 82 | } 83 | 84 | customElements.define(DashInterviewMonitorPrize.is, DashInterviewMonitorPrize); 85 | })(); 86 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-break/gdq-break-bid-many.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqBreakBidMany extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-break-bid-many'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | bid: Object 13 | }; 14 | } 15 | 16 | enter() { 17 | this.$.optionRepeat.render(); 18 | 19 | const tl = new TimelineLite(); 20 | const optionElements = Array.from(this.shadowRoot.querySelectorAll('gdq-break-bid-many-option')); 21 | 22 | tl.addLabel('flickerOptions'); 23 | optionElements.forEach((optionElement, index) => { 24 | optionElement.style.opacity = 0; 25 | tl.add(MaybeRandom.createTween({ 26 | target: optionElement.style, 27 | propName: 'opacity', 28 | duration: 0.465, 29 | ease: Power4.easeIn, 30 | start: {probability: 1, normalValue: 0}, 31 | end: {probability: 0, normalValue: 1} 32 | }), `flickerOptions+=${index * 0.1}`); 33 | }); 34 | 35 | tl.addLabel('enterOptions'); 36 | optionElements.forEach((optionElement, index) => { 37 | tl.add(optionElement.enter(), `enterOptions+=${index * 0.1}`); 38 | }); 39 | 40 | return tl; 41 | } 42 | 43 | exit() { 44 | const tl = new TimelineLite(); 45 | 46 | const optionElements = Array.from(this.shadowRoot.querySelectorAll('gdq-break-bid-many-option')); 47 | 48 | tl.addLabel('flickerOptions'); 49 | optionElements.slice(0).reverse().forEach((optionElement, index) => { 50 | tl.add(MaybeRandom.createTween({ 51 | target: optionElement.style, 52 | propName: 'opacity', 53 | duration: 0.2, 54 | ease: Power4.easeIn, 55 | start: {probability: 1, normalValue: 1}, 56 | end: {probability: 0, normalValue: 0} 57 | }), `flickerOptions+=${index * 0.1}`); 58 | }); 59 | 60 | return tl; 61 | } 62 | 63 | _calcOptions(bid) { 64 | if (!bid) { 65 | return []; 66 | } 67 | 68 | return bid.options.slice(0, 5); 69 | } 70 | } 71 | 72 | customElements.define(GdqBreakBidMany.is, GdqBreakBidMany); 73 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-countdown/gdq-countdown.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const countdownRunning = nodecg.Replicant('countdownRunning'); 5 | const countdown = nodecg.Replicant('countdown'); 6 | 7 | class GdqCountdown extends Polymer.Element { 8 | static get is() { 9 | return 'gdq-countdown'; 10 | } 11 | 12 | static get properties() { 13 | return {}; 14 | } 15 | 16 | ready() { 17 | super.ready(); 18 | 19 | countdown.on('change', newVal => { 20 | this.$.timeInput.setMS(newVal.minutes, newVal.seconds); 21 | }); 22 | 23 | countdownRunning.on('change', newVal => { 24 | if (newVal) { 25 | this.$.countdownContainer.setAttribute('disabled', 'true'); 26 | this.$.start.setAttribute('disabled-running', 'true'); 27 | this.$.stop.removeAttribute('disabled'); 28 | } else { 29 | this.$.countdownContainer.removeAttribute('disabled'); 30 | this.$.start.removeAttribute('disabled-running'); 31 | this.$.stop.setAttribute('disabled', 'true'); 32 | } 33 | 34 | this.checkStartButton(); 35 | }); 36 | } 37 | 38 | start() { 39 | nodecg.sendMessage('startCountdown', this.$.timeInput.value); 40 | } 41 | 42 | stop() { 43 | nodecg.sendMessage('stopCountdown'); 44 | } 45 | 46 | _handleTimeInvalidChanged(e) { 47 | if (e.detail.value) { 48 | this.$.start.setAttribute('disabled-invalid', 'true'); 49 | } else { 50 | this.$.start.removeAttribute('disabled-invalid'); 51 | } 52 | 53 | this.checkStartButton(); 54 | } 55 | 56 | /** 57 | * Enables or disables the timer start button based on some criteria. 58 | * @returns {undefined} 59 | */ 60 | checkStartButton() { 61 | if (this.$.start.hasAttribute('disabled-invalid') || this.$.start.hasAttribute('disabled-running')) { 62 | this.$.start.setAttribute('disabled', 'true'); 63 | } else { 64 | this.$.start.removeAttribute('disabled'); 65 | } 66 | } 67 | } 68 | 69 | customElements.define(GdqCountdown.is, GdqCountdown); 70 | })(); 71 | -------------------------------------------------------------------------------- /graphics/elements/interfaces/dash-host/dash-host-currentrun.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict'; 3 | 4 | const checklistComplete = nodecg.Replicant('checklistComplete'); 5 | const stopwatch = nodecg.Replicant('stopwatch'); 6 | const currentRun = nodecg.Replicant('currentRun'); 7 | 8 | /** 9 | * @customElement 10 | * @polymer 11 | */ 12 | class DashHostCurrentrun extends Polymer.MutableData(Polymer.Element) { 13 | static get is() { 14 | return 'dash-host-currentrun'; 15 | } 16 | 17 | static get properties() { 18 | return { 19 | checklistComplete: { 20 | type: Boolean, 21 | value: false, 22 | reflectToAttribute: true 23 | }, 24 | stopwatchTime: String, 25 | stopwatchResults: Array, 26 | runners: Array 27 | }; 28 | } 29 | 30 | ready() { 31 | super.ready(); 32 | 33 | checklistComplete.on('change', newVal => { 34 | this.checklistComplete = newVal; 35 | }); 36 | 37 | currentRun.on('change', newVal => { 38 | this.$.currentRunName.innerHTML = newVal.name.replace('\\n', '
').trim(); 39 | this.runners = newVal.runners; 40 | }); 41 | 42 | stopwatch.on('change', newVal => { 43 | this.stopwatchTime = newVal.time.formatted; 44 | this.stopwatchResults = newVal.results; 45 | }); 46 | } 47 | 48 | isValidResult(result, index, runners) { 49 | return result && result !== null && runners[index] && runners[index].name; 50 | } 51 | 52 | _calcStatusText(newVal) { 53 | return newVal ? 'READY' : 'NOT READY'; 54 | } 55 | 56 | _unionRunnersAndResults(runners, results) { 57 | if (!runners || !results) { 58 | return; 59 | } 60 | 61 | return runners.map((runner, index) => { 62 | return {runner, result: results[index]}; 63 | }); 64 | } 65 | 66 | _calcRunnerStatus(result) { 67 | if (result && result.time) { 68 | return result.time.formatted; 69 | } 70 | 71 | return 'Running'; 72 | } 73 | } 74 | 75 | customElements.define(DashHostCurrentrun.is, DashHostCurrentrun); 76 | })(); 77 | -------------------------------------------------------------------------------- /dashboard/elements/gdq-timekeeper/gdq-timekeeper-runner.js: -------------------------------------------------------------------------------- 1 | class GdqTimekeeperRunner extends Polymer.Element { 2 | static get is() { 3 | return 'gdq-timekeeper-runner'; 4 | } 5 | 6 | static get properties() { 7 | return { 8 | importPath: String, // https://github.com/Polymer/polymer-linter/issues/71 9 | index: { 10 | type: Number 11 | }, 12 | runner: { 13 | type: Object 14 | }, 15 | results: Array 16 | }; 17 | } 18 | 19 | calcRunnerStatus(results, index) { 20 | if (!results) { 21 | return; 22 | } 23 | 24 | if (results[index] && results[index].time) { 25 | return results[index].time.formatted; 26 | } 27 | 28 | return 'Running'; 29 | } 30 | 31 | calcRunnerStatusClass(results, index) { 32 | if (!results) { 33 | return; 34 | } 35 | 36 | if (results[index] && !results[index].forfeit) { 37 | return 'finished'; 38 | } 39 | 40 | return ''; 41 | } 42 | 43 | calcFinishHidden(results, index) { 44 | if (!results) { 45 | return; 46 | } 47 | 48 | return results[index] && !results[index].forfeit; 49 | } 50 | 51 | calcResumeHidden(results, index) { 52 | if (!results) { 53 | return; 54 | } 55 | 56 | return !results[index]; 57 | } 58 | 59 | calcForfeitHidden(results, index) { 60 | if (!results) { 61 | return; 62 | } 63 | 64 | return results[index] && results[index].forfeit; 65 | } 66 | 67 | calcEditDisabled(results, runnerIndex) { 68 | if (!results) { 69 | return; 70 | } 71 | 72 | return !results[runnerIndex]; 73 | } 74 | 75 | finish() { 76 | nodecg.sendMessage('completeRunner', {index: this.index, forfeit: false}); 77 | } 78 | 79 | forfeit() { 80 | nodecg.sendMessage('completeRunner', {index: this.index, forfeit: true}); 81 | } 82 | 83 | resume() { 84 | nodecg.sendMessage('resumeRunner', this.index); 85 | } 86 | 87 | editTime() { 88 | this.dispatchEvent(new CustomEvent(`edit-time`, {bubbles: true, composed: true})); 89 | } 90 | } 91 | 92 | customElements.define(GdqTimekeeperRunner.is, GdqTimekeeperRunner); 93 | -------------------------------------------------------------------------------- /graphics/elements/molecules/gdq-runner-nameplate/gdq-runner-nameplate-result.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @customElement 3 | * @polymer 4 | */ 5 | class GdqNameplateResult extends Polymer.Element { 6 | static get is() { 7 | return 'gdq-runner-nameplate-result'; 8 | } 9 | 10 | static get properties() { 11 | return { 12 | showing: { 13 | type: Boolean, 14 | observer: '_showingChanged' 15 | }, 16 | side: { 17 | type: String, 18 | reflectToAttribute: true 19 | }, 20 | place: Number, 21 | time: String, 22 | firstPlace: { 23 | type: Boolean, 24 | reflectToAttribute: true 25 | }, 26 | lastPlace: { 27 | type: Boolean, 28 | reflectToAttribute: true 29 | }, 30 | _tl: { 31 | type: TimelineLite, 32 | value() { 33 | return new TimelineLite({autoRemoveChildren: true}); 34 | } 35 | } 36 | }; 37 | } 38 | 39 | ready() { 40 | super.ready(); 41 | TweenLite.set(this, {x: 0}); 42 | TweenLite.set(this.$.cover, {scaleX: 1}); 43 | TweenLite.set(this.$.place, {scaleX: 0}); 44 | } 45 | 46 | show() { 47 | const anim = new TimelineLite(); 48 | anim.to(this, 0.5, { 49 | x: this.side === 'left' ? '-100%' : '100%', 50 | ease: Power3.easeIn 51 | }); 52 | 53 | anim.to(this.$.cover, 0.5, { 54 | scaleX: 0, 55 | ease: Power3.easeOut 56 | }); 57 | 58 | anim.to(this.$.place, 0.182, { 59 | scaleX: 1, 60 | ease: Sine.easeOut 61 | }); 62 | 63 | return anim; 64 | } 65 | 66 | hide() { 67 | const anim = new TimelineLite(); 68 | anim.to(this.$.place, 0.182, { 69 | scaleX: 0, 70 | ease: Sine.easeIn 71 | }); 72 | 73 | anim.to(this.$.cover, 0.5, { 74 | scaleX: 1, 75 | ease: Power3.easeIn 76 | }); 77 | 78 | anim.to(this, 0.5, { 79 | x: '0%', 80 | ease: Power3.easeOut 81 | }); 82 | 83 | return anim; 84 | } 85 | 86 | _showingChanged(newVal) { 87 | const anim = newVal ? this.show() : this.hide(); 88 | this._tl.add(anim); 89 | } 90 | } 91 | 92 | customElements.define(GdqNameplateResult.is, GdqNameplateResult); 93 | --------------------------------------------------------------------------------