{"id":19030717,"url":"https://github.com/hackclub/muse","last_synced_at":"2025-04-23T16:08:04.871Z","repository":{"id":42478378,"uuid":"411394091","full_name":"hackclub/muse","owner":"hackclub","description":"🎸 a simple language for jamming!","archived":false,"fork":false,"pushed_at":"2022-04-04T05:08:07.000Z","size":1070,"stargazers_count":84,"open_issues_count":3,"forks_count":6,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-23T16:07:59.497Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://muse.hackclub.com","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hackclub.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-28T18:20:04.000Z","updated_at":"2025-03-08T19:50:40.000Z","dependencies_parsed_at":"2022-09-13T15:02:17.172Z","dependency_job_id":null,"html_url":"https://github.com/hackclub/muse","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackclub%2Fmuse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackclub%2Fmuse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackclub%2Fmuse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hackclub%2Fmuse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hackclub","download_url":"https://codeload.github.com/hackclub/muse/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250468270,"owners_count":21435452,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T21:19:14.263Z","updated_at":"2025-04-23T16:08:04.852Z","avatar_url":"https://github.com/hackclub.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# 🎸 Muse: a simple language for jamming!\n\n**[Launch the Muse Editor →](https://muse.hackclub.com)**\n\nMuse is a simple language embedded in a JavaScript environment.\n\nThis is a documentation page. For some tips on composing with Muse check out this [workshop](https://workshops.hackclub.com/muse/). A video introducing Muse can also be found [here](https://www.youtube.com/watch?v=hAcQ2x1PTYM).\n\nTo create a song create a muse and pass in your code.\n\n```js\ncreateMuse().play`a4+ ;- [ c5 ; e5 ] x 4`\n```\n\nThe language has notes: `a`, `a#`, `b`, `c`, `c#`, `d`, `d#`, `e`, `f`, `f#`, `g` \u0026 `g#`  with an optional number suffix (from `1` to `10`) for pitch. For example:\n\n```\na4\n```\n\nYou can lengthen notes by appending a `+`:\n\n```\na4+\na4++\na4+++\n```\n\nor shorten them by appending a `-`:\n\n```\na4-\na4--\na4---\n```\n\nEach `+` or `-` corresponds to a power of 2.\n\nA pause is `;` which can also be lengthened or shortened.\n\nSo an arpeggio is:\n\n```\na4 ; c5 ; e5\n```\n\nAnd a chord is:\n\n```\na4 c5 e5\n```\n\nA group is denoted with brackets `[ ]`:\n\n```\n[ a4 c5 e5 ]++\n```\n\nTo repeat something use `x` and some number:\n\n```\n[ a4 c5 e5 ; ] x 4\n```\n\n`createMuse` also takes some optional arguments for beats per minute and wave type:\n\n```js\ncreateMuse({ bpm: 10, type: \"sine\" }) // type can be sine | sawtooth | triangle | square\n```\n\nYou can also use samples that are listed to the right of the editor:\n\n```js\ncreateMuse().play`bubbles ; bubbles -`\n```\n\nTo play multiple tracks just call play multiple times:\n\n```js\nconst muse = createMuse()\nmuse.play`[ a4 ; e4 ; d5 ; ]`\nmuse.play`[ a5 ; e5 ; d6 ; ]`\n```\n\nOffset notes up by half steps with a `^`:\n\n```js\nconst muse = createMuse()\nmuse.play`[ a4 ; e4 ; d5 ; ]`\nmuse.play`[ a4 ; e4 ; d5 ; ] ^ 3`\n```\n\nOffset notes down by half steps with a `_`.\n\n```js\nconst muse = createMuse()\nmuse.play`[ a4 ; e4 ; d5 ; ]`\nmuse.play`[ a4 ; e4 ; d5 ; ] _ 3`\n```\n\nYou can also bind functions to keys with the `bindKey` function. The key will correspond to the `keydown` event key and the value to the callback function.\n\nHere is an example keyboard with the `bindKey` function:\n\n```js\nconst key = 4\nconst type = \"triangle\" // sine | triangle | square | sawtooth\n\nconst a = () =\u003e createMuse({ type }).play`a${key}`\nconst s = () =\u003e createMuse({ type }).play`b${key}`\nconst d = () =\u003e createMuse({ type }).play`c${key+1}`\nconst f = () =\u003e createMuse({ type }).play`d${key+1}`\nconst g = () =\u003e createMuse({ type }).play`e${key+1}`\nconst h = () =\u003e createMuse({ type }).play`f#${key+1}`\nconst j = () =\u003e createMuse({ type }).play`g${key+1}`\nconst k = () =\u003e createMuse({ type }).play`a${key+1}`\nconst l = () =\u003e createMuse({ type }).play`b${key+1}`\n\n// these keys get bound\nbindKeys({ \n  a, \n  s, \n  d, \n  f, \n  g, \n  h, \n  j, \n  k, \n  l \n})\n```\n\nThe console on the right of the editor just logs whatever was played.\n\nIf the playback is becoming choppy, just refresh the browser. Your current project won't be deleted. \n\n\n## Advanced\n\nCreate your own custom modifier by interpolating in a function:\n\n```js\nconst muse = createMuse();\nmuse.play`[ a4 ; e4 ; d5 ; ]  ${x =\u003e x.reverse()}`\n```\n\nThe function will be called with the preceding notes in a compiled array form: `[symbol, beats]`.\n\nAn array in this form can be returned or passed in directly.\n\nThis custom modifier with shorten pauses and lengthen other notes:\n\n```js\nconst customModifier = x =\u003e x.map( ([sym, dur]) =\u003e sym === \";\" \n  ? [sym, dur * .2] \n  : [sym, dur * 2]\n)\n\ncreateMuse().play`\n  [ a4 ; e4 ; d5 ; c5 ; e4 ; d5 ; ] ${customModifier}\n`\n```\n\n## Importing Muse\n\nThe `Muse` class can be imported through modules. For example:\n\n```js\nimport { Muse } from \"https://muse.hackclub.dev/exports.js\";\nimport confetti from 'https://cdn.skypack.dev/canvas-confetti';\n\nconst samples = {\n  \"confetti\": (ctx, duration) =\u003e confetti()\n}\nconst muse = new Muse({ samples });\nmuse.play`\n  a4; c5 confetti; e5;\n  confetti ;\n`\n```\n\n## Acknowledgements\n\nCode editor created using the amazing [CodeMirror](https://codemirror.net/).\n\nAudio samples come from [Patatap](https://www.patatap.com/), a delightful interactive art piece.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackclub%2Fmuse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhackclub%2Fmuse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhackclub%2Fmuse/lists"}