In this tutorial, I will guide you how to create a random song lyrics generator. We will use HTML5, CSS3, and JavaScript to write this software.
You can easily copy/paste or download the complete source code of our random song lyrics generator.
Folder Structure of Random Song Lyrics Generator
- data
- dictionary_ENG.js
- syntax_ENG.dsl
- bg.jpg
- config.js
- generator.js
- index.html
- styles.css
- utils.js
data/dictionary_ENG.js
var adjectives={any:["different","used","important","every","large","available","popular","able","basic","known","various","difficult","several","united","historical","hot","useful","mental","scared","additional","emotional","old","political","similar","healthy","financial","medical","traditional","federal","entire","strong","actual","significant","successful","electrical","expensive","pregnant","intelligent","interesting","poor","happy","responsible","cute","helpful","recent","willing","nice","wonderful","impossible","serious","huge","rare","technical","typical","competitive","critical","electronic","immediate","aware","educational","environmental","global","legal","relevant","accurate","capable","dangerous","dramatic","efficient","powerful","foreign","hungry","practical","psychological","severe","suitable","numerous","sufficient","unusual","consistent","cultural","existing","famous","pure","afraid","obvious","careful","latter","obviously","unhappy","acceptable","aggressive","boring","distinct","eastern","logical","reasonable","strict","successfully","administrative","automatic","civil","former","massive","southern","unfair","visible","alive","angry","desperate","exciting","friendly","lucky","realistic","sorry","ugly","unlikely","anxious","comprehensive","curious","impressive","informal","inner","pleasant","sexual","sudden","terrible","unable","weak","wooden","asleep","confident","conscious","decent","embarrassed","guilty","lonely","mad","nervous","odd","remarkable","substantial","suspicious","tall","tiny"]} var modal_verbs={any:["might","can","must","could","may","shall","should","will","would"]} var modal_verbs_to={any:["want","like","love","need","try"]} var nouns={any:["people","history","way","art","world","information","map","two","family","government","health","system","computer","meat","year","thanks","music","person","reading","method","data","food","understanding","theory","law","bird","literature","problem","software","control","knowledge","power","ability","economics","love","internet","television","science","library","nature","fact","product","idea","temperature","investment","area","society","activity","story","industry","media","thing","oven","community","definition","safety","quality","development","language","management","player","variety","video","week","security","country","exam","movie","organization","equipment","physics","analysis","policy","series","thought","basis","boyfriend","direction","strategy","technology","army","camera","freedom","paper","environment","child","instance","month","truth","marketing","university","writing","article","department","difference","goal","news","audience","fishing","growth","income","marriage","user","combination","failure","meaning","medicine","philosophy","teacher","communication","night","chemistry","disease","disk","energy","nation","road","role","soup","advertising","location","success","addition","apartment","education","math","moment","painting","politics","attention","decision","event","property","shopping","student","wood","competition","distribution","entertainment","office","population","president","unit","category","cigarette","context","introduction","opportunity","performance","driver","flight","length","magazine","newspaper","relationship","teaching","cell","dealer","finding","lake","member","message","phone","scene","appearance","association","concept","customer","death","discussion","housing","inflation","insurance","mood","woman","advice","blood","effort","expression","importance","opinion","payment","reality","responsibility","situation","skill","statement","wealth","application","city","county","depth","estate","foundation","grandmother","heart","perspective","photo","recipe","studio","topic","collection","depression","imagination","passion","percentage","resource","setting","ad","agency","college","connection","criticism","debt","description","memory","patience","secretary","solution","administration","aspect","attitude","director","personality","psychology","recommendation","response","selection","storage","version","alcohol","argument","complaint","contract","emphasis","highway","loss","membership","possession","preparation","steak","union","agreement","cancer","currency","employment","engineering","entry","interaction","mixture","preference","region","republic","tradition","virus","actor","classroom","delivery","device","difficulty","drama","election","engine","football","guidance","hotel","owner","priority","protection","suggestion","tension","variation","anxiety","atmosphere","awareness","bath","bread","candidate","climate","comparison","confusion","construction","elevator","emotion","employee","employer","guest","height","leadership","mall","manager","operation","recording","sample","transportation","charity","cousin","disaster","editor","efficiency","excitement","extent","feedback","guitar","homework","leader","mom","outcome","permission","presentation","promotion","reflection","refrigerator","resolution","revenue","session","singer","tennis","basket","bonus","cabinet","childhood","church","clothes","coffee","dinner","drawing","hair","hearing","initiative","judgment","lab","measurement","mode","mud","orange","poetry","police","possibility","procedure","queen","ratio","relation","restaurant","satisfaction","sector","signature","significance","song","tooth","town","vehicle","volume","wife","accident","airport","appointment","arrival","assumption","baseball","chapter","committee","conversation","database","enthusiasm","error","explanation","farmer","gate","girl","hall","historian","hospital","injury","instruction","maintenance","manufacturer","meal","perception","pie","poem","presence","proposal","reception","replacement","revolution","river","son","speech","tea","village","warning","winner","worker","writer","assistance","breath","buyer","chest","chocolate","conclusion","contribution","cookie","courage","dad","desk","drawer","establishment","examination","garbage","grocery","honey","impression","improvement","independence","insect","inspection","inspector","king","ladder","menu","penalty","piano","potato","profession","professor","quantity","reaction","requirement","salad","sister","supermarket","tongue","weakness","wedding","affair","ambition","analyst","apple","assignment","assistant","bathroom","bedroom","beer","birthday","celebration","championship","cheek","client","consequence","departure","diamond","dirt","ear","fortune","friendship","funeral","gene","girlfriend","hat","indication","intention","lady","midnight","negotiation","obligation","passenger","pizza","platform","poet","pollution","recognition","reputation","shirt","sir","speaker","stranger","surgery","sympathy","tale","throat","trainer","uncle","youth"]} var verbs={any:["be","have","do","say","get","make","go","see","know","take","think","come","give","look","use","find","want","tell","put","mean","become","leave","work","need","feel","seem","ask","show","try","call","keep","provide","hold","turn","follow","begin","bring","like","going","help","start","run","write","set","move","play","pay","hear","include","believe","allow","meet","lead","live","stand","happen","carry","talk","appear","produce","sit","offer","consider","expect","suggest","let","read","require","continue","lose","add","change","fall","remain","remember","buy","speak","stop","send","receive","decide","win","understand","describe","develop","agree","open","reach","build","involve","spend","return","draw","die","hope","create","walk","sell","wait","cause","pass","lie","accept","watch","raise","base","apply","break","explain","learn","increase","cover","grow","claim","report","support","cut","form","stay","contain","reduce","establish","join","wish","achieve","seek","choose","deal","face","fail","serve","end","kill","occur","drive","represent","rise","discuss","love","pick","place","argue","prove","wear","catch","enjoy","eat","introduce","enter","present","arrive","ensure","point","plan","pull","refer","act","relate","affect","close","identify","manage","thank","compare","announce","obtain","note","forget","indicate","wonder","maintain","publish","suffer","avoid","express","suppose","finish","determine","design","listen","save","tend","treat","control","share","remove","throw","visit","exist","encourage","force","reflect","admit","assume","smile","prepare","replace","fill","improve","mention","fight","intend","miss","discover","drop","hit","push","prevent","refuse","regard","lay","reveal","teach","answer","operate","state","depend","enable","record","check","complete","cost","sound","laugh","realise","extend","arise","notice","define","examine","fit","study","bear","hang","recognise","shake","sign","attend","fly","gain","perform","result","travel","adopt","confirm","protect","demand","stare","imagine","attempt","beat","born","associate","care","marry","collect","voice","employ","issue","release","emerge","mind","aim","deny","mark","shoot","appoint","order","supply","drink","observe","reply","ignore","link","propose","ring","settle","strike","press","respond","arrange","survive","concentrate","lift","approach","cross","test","charge","experience","touch","acquire","commit","demonstrate","grant","prefer","repeat","sleep","threaten","feed","insist","launch","limit","promote","deliver","measure","own","retain","assess","attract","belong","consist","contribute","hide","promise","reject","cry","impose","invite","sing","vary","warn","address","declare","destroy","worry","divide","head","name","stick","nod","recognize","train","attack","clear","combine","handle","influence","realize","recommend","shout","spread","undertake","account","select","climb","contact","recall","secure","step","transfer","welcome","conclude","disappear","display","dress","illustrate","imply","organise","direct","escape","generate","investigate","remind","advise","afford","earn","hand","inform","rely","succeed","approve","burn","fear","vote","conduct","cope","derive","elect","gather","jump","last","match","matter","persuade","ride","shut","blow","estimate","recover","score","slip","count","hate","attach","exercise","house","lean","roll","wash","accompany","accuse","bind","explore","judge","rest","steal","comment","exclude","focus","hurt","stretch","withdraw","back","fix","justify","knock","pursue","switch","appreciate","benefit","lack","list","occupy","permit","surround","abandon","blame","complain","connect","construct","dominate","engage","paint","quote","view","acknowledge","dismiss","incorporate","interpret","proceed","search","separate","stress","alter","analyse","arrest","bother","defend","expand","implement","possess","review","suit","tie","assist","calculate","glance","mix","question","resolve","rule","suspect","wake","appeal","challenge","clean","damage","guess","reckon","restore","restrict","specify","constitute","convert","distinguish","submit","trust","urge","feature","land","locate","predict","preserve","solve","sort","struggle","cast","cook","dance","invest","lock","owe","pour","shift","kick","kiss","light","purchase","race","retire","bend","breathe","celebrate","date","fire","monitor","print","register","resist","behave","comprise","decline","detect","finance","organize","overcome","range","swing","differ","drag","guarantee","oppose","pack","pause","relax","resign","rush","store","waste","compete","expose","found","install","mount","negotiate","sink","split","whisper","assure","award","borrow","bury","capture","deserve","distribute","doubt","enhance","phone","sweep","tackle","advance","cease","concern","emphasise","exceed","qualify","slide","strengthen","transform","favour","grab","lend","participate","perceive","pose","practise","satisfy","scream","smoke","sustain","tear","adapt","adjust","ban","consult","dig","dry","highlight","outline","reinforce","shrug","snap","absorb","amount","block","confine","delay","encounter","entitle","plant","pretend","request","rid","sail","trace","trade","wave","cite","dream","flow","fulfil","lower","process","react","seize","allocate","burst","communicate","defeat","double","exploit","fund","govern","hurry","injure","pray","protest","sigh","smell","stir","swim","undergo","wander","anticipate","collapse","compose","confront","ease","eliminate","evaluate","grin","interview","remark","suspend","weigh","wipe","wrap","attribute","balance","bet","bound","cancel","condemn","convince","correspond","dare","devise","free","gaze","guide","inspire","modify","murder","prompt","reverse","rub","slow","spot","swear","telephone","wind","admire","bite","crash","disturb","greet","hesitate","induce","integrate","knit","line","load","murmur","render","shine","swallow","tap","translate","yield","accommodate","age","assert","await","book","brush","chase","comply","copy","criticise","devote","evolve","flee","forgive","initiate","interrupt","leap","mutter","overlook","risk","shape","spell","squeeze","trap","undermine","witness","beg","drift","echo","emphasize","enforce","exchange","fade","float","freeze","hire","in","object","pop","provoke","recruit","research","sense","situate","stimulate","abolish","administer","allege","command","consume","convey","correct","educate","equip","execute","fetch","frown","invent","march","park","progress","reserve","respect","twist","unite","value","assign","cater","concede","conceive","disclose","envisage","exhibit","export","extract","fancy","inherit","insert","instruct","interfere","isolate","opt","peer","persist","plead","price","regret","regulate","repair","resemble","resume","speed","spin","spring","update","advocate","assemble","boost","breed","cling","commission","conceal","contemplate","criticize","decorate","descend","drain","edit","embrace","excuse","explode","facilitate","flash","fold","function","grasp","incur","intervene","label","please","rescue","strip","tip","upset","advertise","aid","centre","classify","coincide","confess","contract","crack","creep","decrease","deem","dispose","dissolve","dump","endorse","formulate","import","impress","market","reproduce","scatter","schedule","ship","shop","spare","sponsor","stage","suck","sue","tempt","vanish","access","commence","contrast","depict","discharge","draft","enclose","enquire","erect","file","halt","hunt","inspect","omit","originate","praise","precede","relieve","reward","round","seal","signal","smash","spoil","subject","target","taste","tighten","top","tremble","tuck","warm","activate","amend","arouse","bang","bid","bow","campaign","characterise","circulate","clarify","compensate","compile","cool","couple","depart","deprive","desire","diminish","drown","embark","entail","entertain","figure","fling","guard","manufacture","melt","neglect","plunge","project","rain","reassure","rent","revive","sentence","shed","slam","spill","stem","sum","summon","supplement","suppress","surprise","tax","thrust","tour","transmit","transport","weaken","widen","bounce","calm","characterize","chat","clutch","confer","conform","confuse","convict","counter","debate","dedicate","dictate","disagree","effect","flood","forbid","grip","heat","long","manipulate","merge","part","pin","position","prescribe","proclaim","punish","rebuild","regain","sack","strain","stroke","substitute","supervise","term","time","toss","underline","abuse","accumulate","alert","arm","attain","boast","boil","carve","cheer","colour","compel","crawl","crush","curl","deposit","differentiate","dip","dislike","divert","embody","exert","exhaust","fine","frighten","fuck","gasp","honour","inhibit","motivate","multiply","narrow","obey","penetrate","picture","presume","prevail","pronounce","rate","renew","revise","rip","scan","scratch","shiver"]} var article={singular:{any:["a","the"]},plural:{any:["the"]}} var personal_pronouns_subject={singular:{first:["I"],second:["you"],third:["he","she","it"]},plural:{first:["we"],second:["you"],third:["they"]}} var personal_pronouns_object={singular:{first:["me"],second:["you"],third:["him","her","it"]},plural:{first:["us"],second:["you"],third:["them"]}} var possessive_pronouns={singular:{first:["my"],second:["your"],third:["his","her","its"]},plural:{first:["our"],second:["your"],third:["their"]}} var indefinite_pronouns={singular:{any:["anybody","anyone","anything","nobody","noone","everybody","everyone","everything"]}} var demonstrative_pronouns={singular:{any:["this","that"],},plural:{any:["these","those"]}} var persons=["first","second","third"] var number=["singular","plural"] var tenses=["present","future","futureperfect","past","presentperfect","imperfect","conditional","pastconditional","pastperfect","presentprogressive","futureprogressive"] var genders=["masculine","feminine","neuter"] var wordTypes={ART: article,NOU: nouns,VRB: verbs,ADJ: adjectives,PPS: personal_pronouns_subject,PPO: personal_pronouns_object,PSP: possessive_pronouns,MVB: modal_verbs,MVT: modal_verbs_to,IDP: indefinite_pronouns,DEP: demonstrative_pronouns}
data/syntax_ENG.dsl
# ---- Syntax documentation---- # each non-comment line in this file represents a sentence structure # every literal (e.g. XYZ) must have a corresponding field in the generator's wordTypes array, like wordTypes.XYZ, which holds all the applicable words of that type # # ---- Special characters ---- # # line comment # (blank space) and (high precedence) # | xor (low precedence) # ? optional # : apply function # "xyz": xyz as an absolute string (will not be modified) # # ============ EXAMPLE ============ # # ((A|B) C:x D? E F".") # # yields an array with 4 sentences # # A x(C) D E F. # A x(C) E F. # B x(C) D E F. # B x(C) E F. (((ART|DEP|PSP) ADJ? NOU)|PPS|IDP) (VRB:conjugate|MVB:conjugate|(MVT:conjugate VRB)) ((((ART|DEP|PSP) ADJ? NOU)|PPO) ADJ?:adverb)?("."|"!"|"...") ART ADJ NOU VRB:conjugate
bg.jpg
You can click here to download this image file.
config.js
Here we will use Ultralingua API and Datamuse API to get multilingual translation dictionary and word-finding query engine functionality respectively.
var config = { conjugationApiUrl: "http://api.ultralingua.com/api/2.0/conjugations/eng/", semanticsApiUrl: "http://api.datamuse.com/words", defaultSettings: { language: "ENG" } }
generator.js
function generator(initSettings) { var settings var sentenceStructures var initGenerator = function() { setSettings(initSettings) getDslFile("data/syntax_" + settings.language + ".dsl") } var addSentenceStructure = function(newSentenceStructure) { if(newSentenceStructure instanceof SentenceStructure) { sentenceStructures.concat(newSentenceStructure) } } var getSettings = function() { return settings } var setSettings = function(newSettings) { if(newSettings && newSettings instanceof GeneratorSettings) { settings = newSettings } else { settings = new GeneratorSettings(config.defaultSettings.language) } } var createSentence = function() { return getRandomSentence() } function conjugate() { function getConjugationResult(result) { var conjugation = result[0]["conjugations"].filter(function(c) { var tenseMatches = c["partofspeech"]["tense"] == sentence.tense var personMatches = !c["partofspeech"]["person"] || c["partofspeech"]["person"].indexOf(sentence.person) >= 0 var numberMatches = !c["partofspeech"]["number"] || c["partofspeech"]["number"].indexOf(sentence.number) >= 0 return tenseMatches && personMatches && numberMatches }) document.getElementById("lyrics").textContent = conjugation[0]["surfaceform"] } utils.conjugationApiCall(verb, sentence, getConjugationResult) } var getRandomWord = function (type, sentence, modifyFunction) { if (!type || !wordTypes[type]) { var typeKeys = Object.keys(wordTypes) type = typeKeys[Math.floor(Math.random() * typeKeys.length)] } var words = getWordArrayForSentence(wordTypes[type], sentence) return words[Math.floor(Math.random() * words.length)] } function getRandomSentence() { var person = persons[Math.floor(Math.random() * persons.length)] var personNumber = number[Math.floor(Math.random() * number.length)] var tense = tenses[Math.floor(Math.random() * tenses.length)] var gender = person == "third" && number == "singular" ? genders[Math.floor(Math.random()*genders.length)] : undefined var language = settings.language return new Sentence( "", person, personNumber, tense, gender, null, language ) } function getDslFile(url) { var request = new XMLHttpRequest(); request.open("GET", url, true) request.onreadystatechange = function (){ if(request.readyState === 4) { if(request.status === 200 || request.status == 0) { parseDsl(request.responseText); } } } request.send(null); } function validateDslLine(line) { // #1 parenthesis and quotation var parenthesisCount = 0 if(line.match(/\"/g) && line.match(/\"/g).length % 2 != 0) { console.error("DSL validation failed: bad quotation") return false } for(var c in line) { if(!line.hasOwnProperty(c)) continue if(!line[c].match(/[\w|$|\(|\)|:|\?| |\||\"]/)) { var quotationsBefore = line.substring(0, c).match(/\"/g) ? line.substring(0, c).match(/\"/g).length : [] var quotationsAfter = line.substring(parseInt(c)+1).match(/\"/g) ? line.substring(parseInt(c)+1).match(/\"/g).length : [] if(quotationsBefore % 2 != 1 || quotationsAfter % 2 != 1) { var blanks = "" var n = 0 while(n < c) { blanks += " " n++ } console.error("DSL validation failed: unexpected character - '" + line[c] + "'\n" + line + "\n" + blanks + "^") return false } } if(line[c] == "(") { parenthesisCount += 1 } else if(line[c] == ")") { parenthesisCount -= 1 if(parenthesisCount < 0) { console.error("DSL validation failed: bad parenthesis") return false } } } if(parenthesisCount != 0) { console.error("DSL validation failed: bad parenthesis") return false } return true } function createSentenceStructureFromDslLine(dslLine) { var sentenceStructure = new SentenceStructure() function resolve(str, subParts) { var parenthesisIndex = str.indexOf("(") var blankIndex = str.indexOf(" ") var pipeIndex = str.indexOf("|") if(parenthesisIndex >= 0 && parenthesisIndex < blankIndex) { var innerPartClose = str.indexOf(")") var innerPartOpen = str.lastIndexOf("(") var innerPart = str.substring(innerPartOpen, innerPartClose) } else if(blankIndex >= 0 && parenthesisIndex > blankIndex) { // var part = } else if(pipeIndex >= 0) { } } var rawParts = resolve(dslLine, []) // for(var rawPart of rawParts) { // var part = new SentenceStructurePart(type, modifyFunction) // sentenceStructure.addPart(part) // } addSentenceStructure(sentenceStructure) } function parseDsl(dslContent) { var lines = dslContent.split(/\r?\n/) lines = lines.filter(function(line) { return line && line.indexOf("#") != 0 }) for(var line of lines) { if(validateDslLine(line)) { var sentenceStructure = createSentenceStructureFromDslLine(line) addSentenceStructure(sentenceStructure) } } } function getWordArrayForSentence(array, sentence) { if(array && sentence) { if(array.any) return array.any if(array[sentence.number]) { if(array[sentence.number].any) return array[sentence.number].any else if(array[sentence.number][sentence.person]) return array[sentence.number][sentence.person] } } return null } initGenerator() return { getSettings: getSettings, setSettings: setSettings, createSentence: createSentence, addSentenceStructure: addSentenceStructure } } class Sentence { constructor(text, person, number, tense, gender, structure, language) { this.text = text this.person = person this.number = number this.tense = tense this.gender = gender this.structure = structure this.language = language } } class SentenceStructure { constructor(parts) { this.parts = parts } addPart(part) { part.added = true if(this.parts) { this.parts = this.parts.concat(part) } else { this.parts = [part] } } } class SentenceStructurePart { constructor(type, modifyFunction) { this.type = type this.modifyFunction = modifyFunction this.added = false } } class GeneratorSettings { constructor(language) { this.language = language } }
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <script src="config.js"></script> <script src="data/dictionary_ENG.js"></script> <script src="utils.js"></script> <script src="generator.js"></script> <link rel="stylesheet" href="styles.css"> <link href="https://fonts.googleapis.com/css?family=Thasadith" rel="stylesheet"> </head> <body> <div id="background-image"></div> <button onClick="generator.createSentence()">Create</button> <br> <div id="lyrics"></div> </body> <script> var generator; (function() { generator = generator() })() </script> </html>
styles.css
body { color: #92caff; } * { font-family: 'Thasadith', sans-serif; font-size: 20px; } button { background-color: rgba(146, 202, 255, 0.33); border: 1px solid rgba(146, 202, 255, 0.5); color: #92caff; transition: all .2s ease; text-shadow: 0 0 10px white; box-shadow: 0 0 0 0 rgba(146, 202, 255, 0.5); } button:hover, button:active { background-color: rgba(146, 202, 255, 0.5); color: white; cursor: pointer; box-shadow: 0 0 5px 0 rgba(146, 202, 255, 0.5); } #background-image { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-image: url(bg.jpg); background-size: cover; z-index: -999; } #lyrics { display: inline-block; max-width: calc(100% - 20px); text-overflow: ellipsis; margin: 10px; padding: 10px; border: 1px solid rgba(255,255,255,.2); background-color: rgba(0,0,0,.5); }
utils.js
var utils = { conjugationApiCall: function(verb, sentence, callback) { var xmlhttp = new XMLHttpRequest() xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == XMLHttpRequest.DONE) { if (xmlhttp.status == 200) { callback(JSON.parse(xmlhttp.response)) } } } var url = config.conjugationApiUrl + verb + "?tense=" + sentence.tense + "&person=" + sentence.person xmlhttp.open("GET", url, true); xmlhttp.send(); } } Object.prototype.getAt = function(index) { return this[Object.keys(this)[index]] } Object.prototype.getKeyAt = function(index) { return Object.keys(this)[index] }