├── .github └── dependabot.yml ├── .gitignore ├── LICENSE.md ├── app ├── css │ ├── fonts │ │ └── Roboto_Mono │ │ │ ├── LICENSE.txt │ │ │ ├── README.txt │ │ │ ├── RobotoMono-Italic-VariableFont_wght.ttf │ │ │ ├── RobotoMono-VariableFont_wght.ttf │ │ │ └── static │ │ │ ├── RobotoMono-Bold.ttf │ │ │ ├── RobotoMono-BoldItalic.ttf │ │ │ ├── RobotoMono-ExtraLight.ttf │ │ │ ├── RobotoMono-ExtraLightItalic.ttf │ │ │ ├── RobotoMono-Italic.ttf │ │ │ ├── RobotoMono-Light.ttf │ │ │ ├── RobotoMono-LightItalic.ttf │ │ │ ├── RobotoMono-Medium.ttf │ │ │ ├── RobotoMono-MediumItalic.ttf │ │ │ ├── RobotoMono-Regular.ttf │ │ │ ├── RobotoMono-SemiBold.ttf │ │ │ ├── RobotoMono-SemiBoldItalic.ttf │ │ │ ├── RobotoMono-Thin.ttf │ │ │ └── RobotoMono-ThinItalic.ttf │ └── styles.css ├── forge.config.js ├── html │ ├── gui.html │ ├── readme.html │ └── render.html ├── icon.icns ├── icon.ico ├── icon.png ├── index.html ├── js │ ├── acid.js │ ├── acidgui.js │ ├── acidrender.js │ ├── gif.js │ ├── gif.js.map │ ├── gif.worker.js │ ├── gif.worker.js.map │ ├── guirenderer.js │ ├── helpers.js │ ├── renderer.js │ ├── renderrenderer.js │ └── wavetables.js ├── main.js ├── package-lock.json ├── package.json └── preload.js ├── ideas.txt ├── img ├── animated_cover.gif ├── banner.gif ├── banner_logo.gif ├── cover.gif ├── example.gif ├── screenshot-1.jpg ├── screenshot-1.png ├── screenshot-2.jpg ├── screenshot-2.png ├── screenshot-3.jpg └── screenshot-3.png └── readme.md /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "13:00" 8 | open-pull-requests-limit: 99 9 | versioning-strategy: increase 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | app/node_modules 2 | ideas.txt 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | ================== 3 | 4 | Statement of Purpose 5 | --------------------- 6 | 7 | The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). 8 | 9 | Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. 10 | 11 | For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 12 | 13 | 1. Copyright and Related Rights. 14 | -------------------------------- 15 | A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: 16 | 17 | i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; 18 | ii. moral rights retained by the original author(s) and/or performer(s); 19 | iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; 20 | iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; 21 | v. rights protecting the extraction, dissemination, use and reuse of data in a Work; 22 | vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and 23 | vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 24 | 25 | 2. Waiver. 26 | ----------- 27 | To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 28 | 29 | 3. Public License Fallback. 30 | ---------------------------- 31 | Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 32 | 33 | 4. Limitations and Disclaimers. 34 | -------------------------------- 35 | 36 | a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. 37 | b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. 38 | c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. 39 | d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. 40 | -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/README.txt: -------------------------------------------------------------------------------- 1 | Roboto Mono Variable Font 2 | ========================= 3 | 4 | This download contains Roboto Mono as both variable fonts and static fonts. 5 | 6 | Roboto Mono is a variable font with this axis: 7 | wght 8 | 9 | This means all the styles are contained in these files: 10 | Roboto_Mono/RobotoMono-VariableFont_wght.ttf 11 | Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf 12 | 13 | If your app fully supports variable fonts, you can now pick intermediate styles 14 | that aren’t available as static fonts. Not all apps support variable fonts, and 15 | in those cases you can use the static font files for Roboto Mono: 16 | Roboto_Mono/static/RobotoMono-Thin.ttf 17 | Roboto_Mono/static/RobotoMono-ExtraLight.ttf 18 | Roboto_Mono/static/RobotoMono-Light.ttf 19 | Roboto_Mono/static/RobotoMono-Regular.ttf 20 | Roboto_Mono/static/RobotoMono-Medium.ttf 21 | Roboto_Mono/static/RobotoMono-SemiBold.ttf 22 | Roboto_Mono/static/RobotoMono-Bold.ttf 23 | Roboto_Mono/static/RobotoMono-ThinItalic.ttf 24 | Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf 25 | Roboto_Mono/static/RobotoMono-LightItalic.ttf 26 | Roboto_Mono/static/RobotoMono-Italic.ttf 27 | Roboto_Mono/static/RobotoMono-MediumItalic.ttf 28 | Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf 29 | Roboto_Mono/static/RobotoMono-BoldItalic.ttf 30 | 31 | Get started 32 | ----------- 33 | 34 | 1. Install the font files you want to use 35 | 36 | 2. Use your app's font picker to view the font family and all the 37 | available styles 38 | 39 | Learn more about variable fonts 40 | ------------------------------- 41 | 42 | https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts 43 | https://variablefonts.typenetwork.com 44 | https://medium.com/variable-fonts 45 | 46 | In desktop apps 47 | 48 | https://theblog.adobe.com/can-variable-fonts-illustrator-cc 49 | https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts 50 | 51 | Online 52 | 53 | https://developers.google.com/fonts/docs/getting_started 54 | https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide 55 | https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts 56 | 57 | Installing fonts 58 | 59 | MacOS: https://support.apple.com/en-us/HT201749 60 | Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux 61 | Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows 62 | 63 | Android Apps 64 | 65 | https://developers.google.com/fonts/docs/android 66 | https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts 67 | 68 | License 69 | ------- 70 | Please read the full license text (LICENSE.txt) to understand the permissions, 71 | restrictions and requirements for usage, redistribution, and modification. 72 | 73 | You can use them freely in your products & projects - print or digital, 74 | commercial or otherwise. However, you can't sell the fonts on their own. 75 | 76 | This isn't legal advice, please consider consulting a lawyer and see the full 77 | license for all details. 78 | -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/RobotoMono-Italic-VariableFont_wght.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/RobotoMono-VariableFont_wght.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/RobotoMono-VariableFont_wght.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-Bold.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-BoldItalic.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-ExtraLight.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-ExtraLight.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-ExtraLightItalic.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-Italic.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-Light.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-LightItalic.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-Medium.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-MediumItalic.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-Regular.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-SemiBold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-SemiBold.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-SemiBoldItalic.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-Thin.ttf -------------------------------------------------------------------------------- /app/css/fonts/Roboto_Mono/static/RobotoMono-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/css/fonts/Roboto_Mono/static/RobotoMono-ThinItalic.ttf -------------------------------------------------------------------------------- /app/css/styles.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Monospace"; 3 | font-weight: 400; 4 | src: url("./fonts/Roboto_Mono/static/RobotoMono-Regular.ttf"); 5 | } 6 | @font-face { 7 | font-family: "Monospace"; 8 | font-weight: 700; 9 | src: url("./fonts/Roboto_Mono/static/RobotoMono-Bold.ttf"); 10 | } 11 | #readme{ 12 | background: black; 13 | color: white; 14 | padding: 24px; 15 | font-size: 16px; 16 | line-height: 1.5em; 17 | } 18 | #readme a{ 19 | color: white; 20 | } 21 | b,strong{ 22 | font-weight: 700; 23 | } 24 | em,i{ 25 | font-style: italic; 26 | } 27 | #canvas{ 28 | position: absolute; 29 | top: 0; 30 | left: 0; 31 | } 32 | *{ 33 | font-family: "Monospace",monospace; 34 | font-weight: 400; 35 | } 36 | .recording-marker{ 37 | position: fixed; 38 | top: 24px; 39 | left: 24px; 40 | height: 24px; 41 | width: 24px; 42 | border-radius: 50%; 43 | background: red; 44 | animation: recording 1s ease-in-out infinite; 45 | z-index: 2; 46 | display: none; 47 | } 48 | .recorder-active .recording-marker{ 49 | display: block; 50 | } 51 | .exporting-marker { 52 | position: fixed; 53 | display: none; 54 | top: 24px; 55 | left: 24px; 56 | z-index: 2; 57 | font-size: 2px; 58 | text-indent: -9999em; 59 | width: 11em; 60 | height: 11em; 61 | border-radius: 50%; 62 | background: #ff0000; 63 | background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%); 64 | background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%); 65 | background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%); 66 | background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%); 67 | background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%); 68 | -webkit-animation: load3 1.4s infinite linear; 69 | animation: load3 1.4s infinite linear; 70 | -webkit-transform: translateZ(0); 71 | -ms-transform: translateZ(0); 72 | transform: translateZ(0); 73 | } 74 | .exporting-marker:before { 75 | width: 50%; 76 | height: 50%; 77 | background: #ffffff; 78 | border-radius: 100% 0 0 0; 79 | position: absolute; 80 | top: 0; 81 | left: 0; 82 | content: ''; 83 | } 84 | .exporting-marker:after { 85 | background: #ff0000; 86 | width: 75%; 87 | height: 75%; 88 | border-radius: 50%; 89 | content: ''; 90 | margin: auto; 91 | position: absolute; 92 | top: 0; 93 | left: 0; 94 | bottom: 0; 95 | right: 0; 96 | } 97 | .export-active .exporting-marker{ 98 | display: block; 99 | } 100 | @-webkit-keyframes load3 { 101 | 0% { 102 | -webkit-transform: rotate(0deg); 103 | transform: rotate(0deg); 104 | } 105 | 100% { 106 | -webkit-transform: rotate(360deg); 107 | transform: rotate(360deg); 108 | } 109 | } 110 | @keyframes load3 { 111 | 0% { 112 | -webkit-transform: rotate(0deg); 113 | transform: rotate(0deg); 114 | } 115 | 100% { 116 | -webkit-transform: rotate(360deg); 117 | transform: rotate(360deg); 118 | } 119 | } 120 | 121 | @keyframes recording { 122 | 0%,100%{ 123 | opacity: 1; 124 | } 125 | 50%{ 126 | opacity: 0; 127 | } 128 | } 129 | #previewWindow{ 130 | top: 24px; 131 | left: 24px; 132 | width: calc(50% - 44px); 133 | height: calc(100% - 48px); 134 | position: fixed; 135 | overflow: hidden; 136 | border: 2px solid white; 137 | } 138 | #gui{ 139 | position: fixed; 140 | border-top: 2px solid white; 141 | border-bottom: 2px solid white; 142 | top: 24px; 143 | right: 24px; 144 | width: calc(50% - 40px); 145 | height: calc(100% - 48px); 146 | } 147 | @media (max-aspect-ratio: 1/1){ 148 | #previewWindow{ 149 | top: 24px; 150 | left: 24px; 151 | width: calc(100% - 52px); 152 | height: calc(50% - 40px); 153 | position: fixed; 154 | overflow: hidden; 155 | border: 2px solid white; 156 | } 157 | #gui{ 158 | position: fixed; 159 | border-top: 2px solid white; 160 | border-bottom: 2px solid white; 161 | top: auto; 162 | right: auto; 163 | bottom: 24px; 164 | left: 24px; 165 | width: calc(100% - 48px); 166 | height: calc(50% - 40px); 167 | } 168 | } 169 | 170 | #gui{ 171 | overflow: auto; 172 | white-space: nowrap; 173 | background: black; 174 | user-select: none; 175 | transition: all 0.2s ease-in-out; 176 | color: #cccccc; 177 | display: grid; 178 | overflow-y: auto; 179 | } 180 | /* .ui-active #gui{ 181 | bottom: 0; 182 | } */ 183 | /* .gui-window #gui{ 184 | left: 0; 185 | top: 0; 186 | bottom: auto; 187 | max-width: none; 188 | max-height: none; 189 | width: calc(100% - 5em); 190 | height: calc(100% - 4em); 191 | padding: 2em; 192 | padding-left: 3em; 193 | background: rgb(16,16,16) !important; 194 | } */ 195 | #gui::selection, 196 | #gui::-moz-selection{ 197 | background: white; 198 | color: black; 199 | } 200 | #gui table{ 201 | font-size: 1em; 202 | padding: 2em; 203 | padding-top: 4em; 204 | width: 100%; 205 | /* padding-top: 2em; */ 206 | /* white-space: pre; */ 207 | /* padding-left: 2em; 208 | padding-right: 2em; */ 209 | /* padding-bottom: 1em; */ 210 | position: relative; 211 | display: inline-block; 212 | margin-right: 1em; 213 | margin-bottom: 0.5em; 214 | /* border-spacing: 0.5em 0; */ 215 | /* position: absolute; 216 | top: 0; 217 | left: 0; */ 218 | border: 2px solid white; 219 | background: black; 220 | box-shadow: 1em 1em rgba(0,0,0,0.5); 221 | height: auto; 222 | /* text-transform: uppercase; */ 223 | } 224 | #gui table:not(.table-hidden){ 225 | height: 8em; 226 | } 227 | /* #gui table:before{ 228 | content: ""; 229 | background: #cccccc; 230 | position: absolute; 231 | top: 0; 232 | left: -1em; 233 | width: 2px; 234 | height: 100%; 235 | border-radius: 1px; 236 | transition: all 0.2s ease-in-out; 237 | } 238 | #gui table:after{ 239 | content: ""; 240 | background: #cccccc; 241 | position: absolute; 242 | top: 0; 243 | left: -1em; 244 | height: 2px; 245 | width: 100%; 246 | border-radius: 1px; 247 | transition: all 0.2s ease-in-out; 248 | } */ 249 | #gui tbody{ 250 | display: table-row-group; 251 | } 252 | #gui .table-toggle{ 253 | position: absolute; 254 | top: 0; 255 | left: 0; 256 | width: 100%; 257 | height: 2em; 258 | cursor: pointer; 259 | /* border-bottom: 2px solid white; */ 260 | background: white; 261 | } 262 | #gui .table-toggle:after{ 263 | content: ""; 264 | background: black; 265 | position: absolute; 266 | top: calc(1em - 1px); 267 | left: 1em; 268 | width: 3ch; 269 | height: 2px; 270 | border-radius: 1px; 271 | transition: all 0.2s ease-in-out; 272 | } 273 | 274 | #gui .table-toggle:hover:after{ 275 | width: 4ch; 276 | } 277 | #gui .table-hidden .table-toggle:hover:after{ 278 | width: 2ch; 279 | } 280 | #gui .table-hidden .table-toggle{ 281 | display: block; 282 | } 283 | #gui .table-hidden .table-toggle:after{ 284 | width: 1ch; 285 | } 286 | #gui table:not(.table-hidden) th:not(.table-name), 287 | #gui table:not(.table-hidden) td, 288 | #gui table:not(.table-hidden) span 289 | { 290 | 291 | display: none; 292 | } 293 | #gui table{ 294 | border-spacing: 0.5em; 295 | } 296 | #gui th{ 297 | color: #ffffff; 298 | text-align: left; 299 | } 300 | #gui td{ 301 | /* overflow: hidden; */ 302 | height: 1ch; 303 | /* max-width: 3ch; */ 304 | } 305 | #gui input{ 306 | width: 3ch; 307 | padding: 0; 308 | background: transparent; 309 | border: 0; 310 | outline: none; 311 | text-align: left; 312 | color: inherit; 313 | color: #cccccc; 314 | font-size: 1em; 315 | } 316 | #gui input:hover, 317 | #gui span:hover, 318 | #gui .list-action:hover, 319 | #gui .toggle-action:hover{ 320 | font-weight: bold; 321 | color: #ffffff; 322 | } 323 | #gui .toggle-action{ 324 | color: #aaaaaa; 325 | font-style: italic; 326 | font-weight: bold; 327 | /* border-bottom: 1px solid white; 328 | */ 329 | /* background: white; 330 | color: black !important; */ 331 | } 332 | #gui .toggle-action.toggle-active{ 333 | color: #ffffff; 334 | } 335 | 336 | #gui span, 337 | #gui .list-action, 338 | #gui .toggle-action{ 339 | cursor: pointer; 340 | } 341 | #gui .list-item{ 342 | margin-right: 1ch; 343 | } 344 | input[type=number]::-webkit-inner-spin-button { 345 | -webkit-appearance: none; 346 | } 347 | 348 | .for-engine{ 349 | display: none; 350 | } 351 | .engine-c2d .for-engine-c2d{ 352 | display: table-row; 353 | } 354 | .for-colormode{ 355 | display: none; 356 | } 357 | .colormode-ndx tr.for-colormode-ndx{ 358 | display: table-row; 359 | } 360 | .colormode-grd tr.for-colormode-grd{ 361 | display: table-row; 362 | } 363 | .colormode-rgb tr.for-colormode-rgb{ 364 | display: table-row; 365 | } 366 | .colormode-hsl tr.for-colormode-hsl{ 367 | display: table-row; 368 | } 369 | .for-sec-colormode, 370 | .engine-c2d .for-sec-colormode{ 371 | display: none; 372 | } 373 | .engine-c2d.sec-colormode-ndx tr.for-sec-colormode-ndx{ 374 | display: table-row; 375 | } 376 | .engine-c2d.sec-colormode-grd tr.for-sec-colormode-grd{ 377 | display: table-row; 378 | } 379 | .engine-c2d.sec-colormode-rgb tr.for-sec-colormode-rgb{ 380 | display: table-row; 381 | } 382 | .engine-c2d.sec-colormode-hsl tr.for-sec-colormode-hsl{ 383 | display: table-row; 384 | } 385 | .for-osc0-type{ 386 | display: none; 387 | } 388 | .osc0-type-osc tr.for-osc0-type-osc, 389 | .osc0-type-sqr tr.for-osc0-type-sqr, 390 | .osc0-type-saw tr.for-osc0-type-saw, 391 | .osc0-type-tri tr.for-osc0-type-tri, 392 | .osc0-type-sin tr.for-osc0-type-sin, 393 | .osc0-type-prl tr.for-osc0-type-prl, 394 | .osc0-type-plx tr.for-osc0-type-plx, 395 | .osc0-type-pwm tr.for-osc0-type-pwm, 396 | .osc0-type-org tr.for-osc0-type-org{ 397 | display: table-row; 398 | } 399 | .osc0-type-osc th.for-osc0-type-osc, 400 | .osc0-type-sqr th.for-osc0-type-sqr, 401 | .osc0-type-saw th.for-osc0-type-saw, 402 | .osc0-type-tri th.for-osc0-type-tri, 403 | .osc0-type-sin th.for-osc0-type-sin, 404 | .osc0-type-prl th.for-osc0-type-prl, 405 | .osc0-type-plx th.for-osc0-type-plx, 406 | .osc0-type-pwm th.for-osc0-type-pwm, 407 | .osc0-type-org th.for-osc0-type-org{ 408 | display: table-cell; 409 | } 410 | .for-osc1-type{ 411 | display: none; 412 | } 413 | .osc1-type-osc tr.for-osc1-type-osc, 414 | .osc1-type-sqr tr.for-osc1-type-sqr, 415 | .osc1-type-saw tr.for-osc1-type-saw, 416 | .osc1-type-tri tr.for-osc1-type-tri, 417 | .osc1-type-sin tr.for-osc1-type-sin, 418 | .osc1-type-prl tr.for-osc1-type-prl, 419 | .osc1-type-plx tr.for-osc1-type-plx, 420 | .osc1-type-pwm tr.for-osc1-type-pwm, 421 | .osc1-type-org tr.for-osc1-type-org{ 422 | display: table-row; 423 | } 424 | .osc1-type-osc th.for-osc1-type-osc, 425 | .osc1-type-sqr th.for-osc1-type-sqr, 426 | .osc1-type-saw th.for-osc1-type-saw, 427 | .osc1-type-tri th.for-osc1-type-tri, 428 | .osc1-type-sin th.for-osc1-type-sin, 429 | .osc1-type-prl th.for-osc1-type-prl, 430 | .osc1-type-plx th.for-osc1-type-plx, 431 | .osc1-type-pwm th.for-osc1-type-pwm, 432 | .osc1-type-org th.for-osc1-type-org{ 433 | display: table-cell; 434 | } 435 | .for-osc2-type{ 436 | display: none; 437 | } 438 | .osc2-type-osc tr.for-osc2-type-osc, 439 | .osc2-type-sqr tr.for-osc2-type-sqr, 440 | .osc2-type-saw tr.for-osc2-type-saw, 441 | .osc2-type-tri tr.for-osc2-type-tri, 442 | .osc2-type-sin tr.for-osc2-type-sin, 443 | .osc2-type-prl tr.for-osc2-type-prl, 444 | .osc2-type-plx tr.for-osc2-type-plx, 445 | .osc2-type-pwm tr.for-osc2-type-pwm, 446 | .osc2-type-org tr.for-osc2-type-org{ 447 | display: table-row; 448 | } 449 | .osc2-type-osc th.for-osc2-type-osc, 450 | .osc2-type-sqr th.for-osc2-type-sqr, 451 | .osc2-type-saw th.for-osc2-type-saw, 452 | .osc2-type-tri th.for-osc2-type-tri, 453 | .osc2-type-sin th.for-osc2-type-sin, 454 | .osc2-type-prl th.for-osc2-type-prl, 455 | .osc2-type-plx th.for-osc2-type-plx, 456 | .osc2-type-pwm th.for-osc2-type-pwm, 457 | .osc2-type-org th.for-osc2-type-org{ 458 | display: table-cell; 459 | } 460 | .for-osc3-type{ 461 | display: none; 462 | } 463 | .osc3-type-osc tr.for-osc3-type-osc, 464 | .osc3-type-sqr tr.for-osc3-type-sqr, 465 | .osc3-type-saw tr.for-osc3-type-saw, 466 | .osc3-type-tri tr.for-osc3-type-tri, 467 | .osc3-type-sin tr.for-osc3-type-sin, 468 | .osc3-type-prl tr.for-osc3-type-prl, 469 | .osc3-type-plx tr.for-osc3-type-plx, 470 | .osc3-type-pwm tr.for-osc3-type-pwm, 471 | .osc3-type-org tr.for-osc3-type-org{ 472 | display: table-row; 473 | } 474 | .osc3-type-osc th.for-osc3-type-osc, 475 | .osc3-type-sqr th.for-osc3-type-sqr, 476 | .osc3-type-saw th.for-osc3-type-saw, 477 | .osc3-type-tri th.for-osc3-type-tri, 478 | .osc3-type-sin th.for-osc3-type-sin, 479 | .osc3-type-prl th.for-osc3-type-prl, 480 | .osc3-type-plx th.for-osc3-type-plx, 481 | .osc3-type-pwm th.for-osc3-type-pwm, 482 | .osc3-type-org th.for-osc3-type-org{ 483 | display: table-cell; 484 | } 485 | .for-osc4-type{ 486 | display: none; 487 | } 488 | .osc4-type-osc tr.for-osc4-type-osc, 489 | .osc4-type-sqr tr.for-osc4-type-sqr, 490 | .osc4-type-saw tr.for-osc4-type-saw, 491 | .osc4-type-tri tr.for-osc4-type-tri, 492 | .osc4-type-sin tr.for-osc4-type-sin, 493 | .osc4-type-prl tr.for-osc4-type-prl, 494 | .osc4-type-plx tr.for-osc4-type-plx, 495 | .osc4-type-pwm tr.for-osc4-type-pwm, 496 | .osc4-type-org tr.for-osc4-type-org{ 497 | display: table-row; 498 | } 499 | .osc4-type-osc th.for-osc4-type-osc, 500 | .osc4-type-sqr th.for-osc4-type-sqr, 501 | .osc4-type-saw th.for-osc4-type-saw, 502 | .osc4-type-tri th.for-osc4-type-tri, 503 | .osc4-type-sin th.for-osc4-type-sin, 504 | .osc4-type-prl th.for-osc4-type-prl, 505 | .osc4-type-plx th.for-osc4-type-plx, 506 | .osc4-type-pwm th.for-osc4-type-pwm, 507 | .osc4-type-org th.for-osc4-type-org{ 508 | display: table-cell; 509 | } 510 | input[type=range] { 511 | -webkit-appearance: none; /* Hides the slider so that custom slider can be made */ 512 | width: calc(100% - 1ch) !important; /* Specific width is required for Firefox. */ 513 | background: transparent; /* Otherwise white in Chrome */ 514 | transform: translateY(-0.4ch) 515 | } 516 | .text-input{ 517 | width: 100% !important; /* Specific width is required for Firefox. */ 518 | } 519 | input[type=range]::-webkit-slider-thumb { 520 | -webkit-appearance: none; 521 | } 522 | 523 | input[type=range]:focus { 524 | outline: none; /* Removes the blue border. You should probably do some kind of focus styling for accessibility reasons though. */ 525 | } 526 | 527 | input[type=range]::-ms-track { 528 | width: 100%; 529 | cursor: pointer; 530 | 531 | /* Hides the slider so custom styles can be added */ 532 | background: transparent; 533 | border-color: transparent; 534 | color: transparent; 535 | } 536 | /* Special styling for WebKit/Blink */ 537 | input[type=range]::-webkit-slider-thumb { 538 | -webkit-appearance: none; 539 | height: 0.5em; 540 | width: 0.5em; 541 | border: none; 542 | border-radius: 50%; 543 | background: #ffffff; 544 | cursor: pointer; 545 | margin-top: -0.125em; 546 | } 547 | 548 | input[type=range]::-webkit-slider-runnable-track { 549 | width: 100%; 550 | height: 0.25em; 551 | cursor: pointer; 552 | background: #cccccc; 553 | border-radius: 0.125em; 554 | border: none; 555 | } 556 | .ui-buttons-flag-off .for-ui-buttons{ 557 | display: none; 558 | } 559 | .ui-labels-flag-off .for-ui-labels{ 560 | display: none; 561 | } 562 | #tooltip{ 563 | background: rgba(240,240,240,0.9); 564 | border-radius: 6px; 565 | font-size: 0.8em; 566 | padding: 2em; 567 | color: rgb(16,16,16); 568 | position: fixed; 569 | top: 0; 570 | left: 0; 571 | z-index: 2; 572 | opacity: 0; 573 | user-select: none; 574 | pointer-events: none; 575 | transition: opacity 0.2s ease-in-out; 576 | max-width: 30vw; 577 | white-space: normal; 578 | } 579 | #tooltip b{ 580 | font-weight: bold; 581 | text-transform: uppercase; 582 | } 583 | .tooltip-is-active #tooltip{ 584 | opacity: 1; 585 | } 586 | .fx-flag-off .for-fx-active{ 587 | display: none; 588 | } 589 | #ascii{ 590 | position: absolute; 591 | top: 50%; 592 | left: 50%; 593 | transform: translate(-50%,-50%); 594 | color: white; 595 | white-space: nowrap; 596 | font-size: 12px; 597 | line-height: 1em; 598 | letter-spacing: calc(1em - 1ch); 599 | /* mix-blend-mode: difference; */ 600 | } 601 | #ascii div{ 602 | display: inline-block; 603 | } 604 | -------------------------------------------------------------------------------- /app/forge.config.js: -------------------------------------------------------------------------------- 1 | // config.forge.js 2 | const path = require('path'); 3 | 4 | module.exports = { 5 | packagerConfig: { 6 | icon: path.resolve(__dirname, "icons/logo.icns") 7 | }, 8 | makers: [ 9 | { 10 | name: '@electron-forge/maker-squirrel', 11 | config: { 12 | // name: "ACID", 13 | // version: "0.1.0", 14 | // author: "Johannes Hassenstein", 15 | // description: "ACID is a general purpose video synthesizer.", 16 | // iconUrl: path.resolve(__dirname, "icons/logo.ico") 17 | } 18 | }, 19 | { 20 | name: "@electron-forge/maker-zip", 21 | config: { 22 | icon: path.resolve(__dirname, "icons/logo.icns") 23 | }, 24 | platforms: [ 25 | "darwin" 26 | ] 27 | }, 28 | { 29 | name: '@electron-forge/maker-dmg', 30 | config: { 31 | name: "ACID", 32 | icon: path.resolve(__dirname, "icons/logo.icns"), 33 | } 34 | }, 35 | { 36 | name: "@electron-forge/maker-deb", 37 | config: { 38 | options: { 39 | name: "ACID", 40 | maintainer: 'Johannes Hassenstein', 41 | homepage: 'https://johassenstein.de', 42 | categories: ["AudioVideo","Video","Graphics"], 43 | description: "ACID is a general purpose video synthesizer.", 44 | icon: path.resolve(__dirname, "icons/logo_512.png") 45 | } 46 | } 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /app/html/readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ACID:101 6 | 7 | 8 | 9 |

ACID

10 |

Documentation

11 |

All values in the GUI range between 0 and 999, where 0 is the minimum value and 999 is the maximum. The GUI can be toggled either with the space bar or using the options in Menubar > Window. The GUI can also be opened in a second window.

12 |

The labels next to the sliders can be used to set a slider to specific value. The buttons next to the labels can be used to minimize, center, maximize or randomize the slider value. Both can be disabled from the set part of the GUI.

13 |

Oscilators

14 |

An oscilator is either a cyclic transfer function or a noise based algorithm. A cyclic transfer function takes a value between 0 and infinity and returns a value between 0 and 1, the exact distribution of the values inbetween is determined by the oscilators waveform. The amount of values after which the oscilator repeats is determined by its frequency.

15 |

You can use oscilators as fixed filters by setting the spd parameter to 0. This will stop the oscilator from moving entirely. You can then control the exact character of the filter with the frq, off and rot parameters.

16 |

If you need a constant fixed value from an oscilator, you can use a sqr oscilator, with a spd of 0 and a low frq. You can then control the exact value using the min or max parameter.

17 |

If you need a completely random texture, create an oscilator with a medium value and apply a high rnd effect on it.

18 |

All oscilators have an additional "run" property, which can be set to quickly mute an oscilator. You can toggle it by clicking on "osx" (where x is the oscilator number) in the GUI. The run property behaves identical to the off type, but doesnt change the type of the oscilator.

19 |

Channels

20 |

All oscilators can send to 3 different channels independently. They send the same basic value to each channel but you can attenuate the value for each channel individually. You can do so from the rgb section using the inputs for r,g and b.

21 |

Cyclical oscilators

22 |

These are the available cyclical oscilators:

23 | 32 |

For each oscilator these are the important parameters:

33 | 63 |

The osc oscilator has these additional parameters:

64 | 69 |

Noncyclical oscilators

70 |

These are the available, noncyclical oscilators:

71 | 78 |

The noncyclical oscilators use some of the cyclical oscilator settings, however they are used somewhat different:

79 | 84 |

The organic oscilator also uses the two additional settings from the osc oscilator

85 | 90 |

There are also a couple of additional settings for the two noise algorithms, as they are 3 dimensional. The oscilator settings control the z axis, the other two axis are controlled by their respective parameters. All axis have the same set of parameters.

91 |

The noise algorithms are seedable, which means same values in, same values out. You can reseed the noise algorithms from Menubar > Render > Reseed.

92 |

Effects

93 |

All oscilators can have any number of effects applied to them. Which effects are applied is set by the effects chain ("--- + " in the GUI). Clicking on "+" will add a new effect to the chain, clicking on an effect will flip through the different effect types, clicking on "---" (which will then show "clr") will clear the effect chain. Effects are passed through from left to right.

94 | 99 |

The settings for all effects in the chain are the same. However you can use the chain to apply effects in different order or multiple times. The settings are set in the fx part of the respective GUI section:

100 | 108 |

Render

109 |

The parameters for the render process can be found under "img". The render process determines how the values generated by ACID and the configuration set in the GUI are used to generate images. Not all settings are available at all times, some may only be visible when a certain color mode or render engine is active.

110 | 144 |

Feedback

145 |

The virtual feedback engine simulates true feedback when using a camera that is pointed on a screen that displays the camera image. Simulates, not duplicates. It is different. But based around the same idea. As ACID is deterministic we can now the value of each pixel at any point in time. And that is exactly how the feedback works. We simply don't show all pixels at the same point in time at the same time.

146 | 158 |

Settings

159 |

The settings part of the GUI can be found under "set". Here you can change default values, GUI styles and some global settings for the render engine.

160 | 177 |

Menubar

178 |

You can access some actions and all import and export dutys from the menubar of the application.

179 |

File

180 | 192 |

Render

193 | 203 |

Window

204 | 213 |

Help

214 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /app/html/render.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ACID:RENDER 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/icon.icns -------------------------------------------------------------------------------- /app/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/icon.ico -------------------------------------------------------------------------------- /app/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/app/icon.png -------------------------------------------------------------------------------- /app/js/acid.js: -------------------------------------------------------------------------------- 1 | function ACID(storage,ipc,canvas,textlayer,env){ 2 | this.env = env 3 | this.storage = storage 4 | this.ipc = ipc 5 | this.config = {} 6 | this.seed = 0 7 | this.canvas = canvas 8 | this.ascii = textlayer 9 | this.initiated = false 10 | this.canvasCapturerer = { 11 | requestGifFrame: function(delay){ 12 | if(this.canvasCapturerer.addFrames){ 13 | this.canvasCapturerer.gif.addFrame(this.canvas, {delay: delay}); 14 | } 15 | }.bind(this) 16 | } 17 | this.export = function(fileType,capture){ 18 | if(capture){ 19 | switch(fileType){ 20 | case "webm": 21 | if(this.canvasCapturerer.recorder){ 22 | this.canvasCapturerer.recorder.stop() 23 | this.toggleRecorderUI(false) 24 | this.toggleExporterUI(true) 25 | this.canvasCapturerer.recorder.save(this.getExportFilename("webm")) 26 | this.toggleExporterUI(false) 27 | this.save() 28 | this.canvasCapturerer.recorder = false 29 | this.exporting = false 30 | } 31 | break 32 | case "gif": 33 | this.canvasCapturerer.addFrames = false 34 | this.toggleRecorderUI(false) 35 | this.toggleExporterUI(true) 36 | this.canvasCapturerer.gif.on('finished', function(blob) { 37 | this.download(blob,this.getExportFilename("gif"),true) 38 | this.canvasCapturerer.gif = false 39 | this.toggleExporterUI(false) 40 | }.bind(this)); 41 | this.canvasCapturerer.gif.render(); 42 | 43 | break; 44 | } 45 | } 46 | else if(!this.exporting){ 47 | this.exporting = true 48 | switch(fileType){ 49 | case "jpg": 50 | this.canvas.toBlob(function(blob) { 51 | this.download(blob,this.getExportFilename("jpg"),true) 52 | }.bind(this),'image/jpeg', 0.95) 53 | break 54 | case "png": 55 | this.canvas.toBlob(function(blob) { 56 | this.download(blob,this.getExportFilename("png"),true) 57 | }.bind(this),'image/png') 58 | break 59 | case "webm": 60 | this.toggleRecorderUI(true) 61 | this.canvasCapturerer.recorder = new CanvasRecorder(this.canvas) 62 | this.canvasCapturerer.recorder.start() 63 | break 64 | case "gif": 65 | this.toggleRecorderUI(true) 66 | this.canvasCapturerer.gif = new GIF({ 67 | workers: 2, 68 | quality: 10, 69 | workerScript: "./js/gif.worker.js" 70 | }); 71 | this.canvasCapturerer.addFrames = true 72 | break 73 | 74 | } 75 | } 76 | } 77 | this.getExportFilename = function(type){ 78 | return "acid." + type; 79 | } 80 | this.download = function(blob,name,isexport){ 81 | const url = window.URL.createObjectURL(blob); 82 | const a = document.createElement('a'); 83 | a.style.display = 'none'; 84 | a.href = url; 85 | a.download = name; 86 | document.body.appendChild(a); 87 | a.click(); 88 | if(isexport){ 89 | this.exporting = false 90 | this.save() 91 | } 92 | setTimeout(() => { 93 | document.body.removeChild(a); 94 | window.URL.revokeObjectURL(url); 95 | }, 100); 96 | } 97 | this.store = function(){ 98 | let blob = new Blob([JSON.stringify(this.config)], {type: 'text/plain'}); 99 | this.download(blob,"config.txt",false) 100 | } 101 | this.save = function(){ 102 | this.storage.set("config", JSON.stringify(this.config), function(error) { 103 | if (error){ 104 | throw error 105 | } 106 | else{ 107 | this.ipc.send("requestUpdate",""); 108 | } 109 | }.bind(this)); 110 | } 111 | this.exporting = false 112 | this.t = 0 113 | this.dynamics = { 114 | t: 0, 115 | d: 0 116 | } 117 | this.reseed = function(){ 118 | this.wavetables.random 119 | for(let i = 0; i < 100; i++){ 120 | let r = Math.round(Math.random() * 1000) / 1000 121 | this.wavetables.random.push(r) 122 | } 123 | this.seed = Math.random() * 1000 124 | noise.seed(Math.random() * 1000) 125 | } 126 | this.toggleRecorderUI = function(flag){ 127 | if(flag){ 128 | document.body.classList.add("recorder-active") 129 | } 130 | else { 131 | document.body.classList.remove("recorder-active") 132 | } 133 | } 134 | this.toggleExporterUI = function(flag){ 135 | if(flag){ 136 | document.body.classList.add("export-active") 137 | } 138 | else { 139 | document.body.classList.remove("export-active") 140 | } 141 | } 142 | this.createRender = function(){ 143 | new ACIDRENDER(this.storage,this.ipc,this.canvas,this.ascii,this,this.env) 144 | } 145 | this.fx = { 146 | exp: function(n,i){ 147 | return Math.pow(n,1 + i) 148 | }.bind(this), 149 | cmp: function(n,i){ 150 | return Math.pow(n,1 - i) 151 | }.bind(this), 152 | bit: function(n,i){ 153 | return Math.floor(n * (Math.pow(1 - i,2) * 765)) / (Math.pow(1 - i,2) * 765) 154 | }.bind(this), 155 | rnd: function(n,i){ 156 | return Math.max(0,Math.min(1,(n + (-i + (Math.random() * i * 2))))) 157 | }.bind(this), 158 | drv: function(n,i){ 159 | return Math.min(1,Math.pow((1 + n),((1 + i))) - 1) 160 | }.bind(this) 161 | } 162 | this.wavetables = { 163 | rotation: [[0,1],[0.011,0.989],[0.022,0.978],[0.033,0.967],[0.044,0.956],[0.056,0.944],[0.067,0.933],[0.078,0.922],[0.089,0.911],[0.1,0.9],[0.111,0.889],[0.122,0.878],[0.133,0.867],[0.144,0.856],[0.156,0.844],[0.167,0.833],[0.178,0.822],[0.189,0.811],[0.2,0.8],[0.211,0.789],[0.222,0.778],[0.233,0.767],[0.244,0.756],[0.256,0.744],[0.267,0.733],[0.278,0.722],[0.289,0.711],[0.3,0.7],[0.311,0.689],[0.322,0.678],[0.333,0.667],[0.344,0.656],[0.356,0.644],[0.367,0.633],[0.378,0.622],[0.389,0.611],[0.4,0.6],[0.411,0.589],[0.422,0.578],[0.433,0.567],[0.444,0.556],[0.456,0.544],[0.467,0.533],[0.478,0.522],[0.489,0.511],[0.5,0.5],[0.511,0.489],[0.522,0.478],[0.533,0.467],[0.544,0.456],[0.556,0.444],[0.567,0.433],[0.578,0.422],[0.589,0.411],[0.6,0.4],[0.611,0.389],[0.622,0.378],[0.633,0.367],[0.644,0.356],[0.656,0.344],[0.667,0.333],[0.678,0.322],[0.689,0.311],[0.7,0.3],[0.711,0.289],[0.722,0.278],[0.733,0.267],[0.744,0.256],[0.756,0.244],[0.767,0.233],[0.778,0.222],[0.789,0.211],[0.8,0.2],[0.811,0.189],[0.822,0.178],[0.833,0.167],[0.844,0.156],[0.856,0.144],[0.867,0.133],[0.878,0.122],[0.889,0.111],[0.9,0.1],[0.911,0.089],[0.922,0.078],[0.933,0.067],[0.944,0.056],[0.956,0.044],[0.967,0.033],[0.978,0.022],[0.989,0.011],[1,0],[0.989,-0.011],[0.978,-0.022],[0.967,-0.033],[0.956,-0.044],[0.944,-0.056],[0.933,-0.067],[0.922,-0.078],[0.911,-0.089],[0.9,-0.1],[0.889,-0.111],[0.878,-0.122],[0.867,-0.133],[0.856,-0.144],[0.844,-0.156],[0.833,-0.167],[0.822,-0.178],[0.811,-0.189],[0.8,-0.2],[0.789,-0.211],[0.778,-0.222],[0.767,-0.233],[0.756,-0.244],[0.744,-0.256],[0.733,-0.267],[0.722,-0.278],[0.711,-0.289],[0.7,-0.3],[0.689,-0.311],[0.678,-0.322],[0.667,-0.333],[0.656,-0.344],[0.644,-0.356],[0.633,-0.367],[0.622,-0.378],[0.611,-0.389],[0.6,-0.4],[0.589,-0.411],[0.578,-0.422],[0.567,-0.433],[0.556,-0.444],[0.544,-0.456],[0.533,-0.467],[0.522,-0.478],[0.511,-0.489],[0.5,-0.5],[0.489,-0.511],[0.478,-0.522],[0.467,-0.533],[0.456,-0.544],[0.444,-0.556],[0.433,-0.567],[0.422,-0.578],[0.411,-0.589],[0.4,-0.6],[0.389,-0.611],[0.378,-0.622],[0.367,-0.633],[0.356,-0.644],[0.344,-0.656],[0.333,-0.667],[0.322,-0.678],[0.311,-0.689],[0.3,-0.7],[0.289,-0.711],[0.278,-0.722],[0.267,-0.733],[0.256,-0.744],[0.244,-0.756],[0.233,-0.767],[0.222,-0.778],[0.211,-0.789],[0.2,-0.8],[0.189,-0.811],[0.178,-0.822],[0.167,-0.833],[0.156,-0.844],[0.144,-0.856],[0.133,-0.867],[0.122,-0.878],[0.111,-0.889],[0.1,-0.9],[0.089,-0.911],[0.078,-0.922],[0.067,-0.933],[0.056,-0.944],[0.044,-0.956],[0.033,-0.967],[0.022,-0.978],[0.011,-0.989],[0,-1],[-0.011,-0.989],[-0.022,-0.978],[-0.033,-0.967],[-0.044,-0.956],[-0.056,-0.944],[-0.067,-0.933],[-0.078,-0.922],[-0.089,-0.911],[-0.1,-0.9],[-0.111,-0.889],[-0.122,-0.878],[-0.133,-0.867],[-0.144,-0.856],[-0.156,-0.844],[-0.167,-0.833],[-0.178,-0.822],[-0.189,-0.811],[-0.2,-0.8],[-0.211,-0.789],[-0.222,-0.778],[-0.233,-0.767],[-0.244,-0.756],[-0.256,-0.744],[-0.267,-0.733],[-0.278,-0.722],[-0.289,-0.711],[-0.3,-0.7],[-0.311,-0.689],[-0.322,-0.678],[-0.333,-0.667],[-0.344,-0.656],[-0.356,-0.644],[-0.367,-0.633],[-0.378,-0.622],[-0.389,-0.611],[-0.4,-0.6],[-0.411,-0.589],[-0.422,-0.578],[-0.433,-0.567],[-0.444,-0.556],[-0.456,-0.544],[-0.467,-0.533],[-0.478,-0.522],[-0.489,-0.511],[-0.5,-0.5],[-0.511,-0.489],[-0.522,-0.478],[-0.533,-0.467],[-0.544,-0.456],[-0.556,-0.444],[-0.567,-0.433],[-0.578,-0.422],[-0.589,-0.411],[-0.6,-0.4],[-0.611,-0.389],[-0.622,-0.378],[-0.633,-0.367],[-0.644,-0.356],[-0.656,-0.344],[-0.667,-0.333],[-0.678,-0.322],[-0.689,-0.311],[-0.7,-0.3],[-0.711,-0.289],[-0.722,-0.278],[-0.733,-0.267],[-0.744,-0.256],[-0.756,-0.244],[-0.767,-0.233],[-0.778,-0.222],[-0.789,-0.211],[-0.8,-0.2],[-0.811,-0.189],[-0.822,-0.178],[-0.833,-0.167],[-0.844,-0.156],[-0.856,-0.144],[-0.867,-0.133],[-0.878,-0.122],[-0.889,-0.111],[-0.9,-0.1],[-0.911,-0.089],[-0.922,-0.078],[-0.933,-0.067],[-0.944,-0.056],[-0.956,-0.044],[-0.967,-0.033],[-0.978,-0.022],[-0.989,-0.011],[-1,0],[-0.989,0.011],[-0.978,0.022],[-0.967,0.033],[-0.956,0.044],[-0.944,0.056],[-0.933,0.067],[-0.922,0.078],[-0.911,0.089],[-0.9,0.1],[-0.889,0.111],[-0.878,0.122],[-0.867,0.133],[-0.856,0.144],[-0.844,0.156],[-0.833,0.167],[-0.822,0.178],[-0.811,0.189],[-0.8,0.2],[-0.789,0.211],[-0.778,0.222],[-0.767,0.233],[-0.756,0.244],[-0.744,0.256],[-0.733,0.267],[-0.722,0.278],[-0.711,0.289],[-0.7,0.3],[-0.689,0.311],[-0.678,0.322],[-0.667,0.333],[-0.656,0.344],[-0.644,0.356],[-0.633,0.367],[-0.622,0.378],[-0.611,0.389],[-0.6,0.4],[-0.589,0.411],[-0.578,0.422],[-0.567,0.433],[-0.556,0.444],[-0.544,0.456],[-0.533,0.467],[-0.522,0.478],[-0.511,0.489],[-0.5,0.5],[-0.489,0.511],[-0.478,0.522],[-0.467,0.533],[-0.456,0.544],[-0.444,0.556],[-0.433,0.567],[-0.422,0.578],[-0.411,0.589],[-0.4,0.6],[-0.389,0.611],[-0.378,0.622],[-0.367,0.633],[-0.356,0.644],[-0.344,0.656],[-0.333,0.667],[-0.322,0.678],[-0.311,0.689],[-0.3,0.7],[-0.289,0.711],[-0.278,0.722],[-0.267,0.733],[-0.256,0.744],[-0.244,0.756],[-0.233,0.767],[-0.222,0.778],[-0.211,0.789],[-0.2,0.8],[-0.189,0.811],[-0.178,0.822],[-0.167,0.833],[-0.156,0.844],[-0.144,0.856],[-0.133,0.867],[-0.122,0.878],[-0.111,0.889],[-0.1,0.9],[-0.089,0.911],[-0.078,0.922],[-0.067,0.933],[-0.056,0.944],[-0.044,0.956],[-0.033,0.967],[-0.022,0.978],[0,1]], 164 | random: [0.834,0.924,0.075,0.335,0.517,0.13,0.101,0.646,0.389,0.947,0.385,0.353,0.512,0.494,0.946,0.999,0.621,0.341,0.049,0.05,0.279,0.315,0.465,0.405,0.019,0.669,0.545,0.752,0.793,0.23,0.814,0.348,0.979,0.277,0.404,0.215,0.073,0.065,0.026,0.039,0.579,0.382,0.864,0.92,0.139,0.712,0.506,0.29,0.805,0.4,0.775,0.901,0.563,0.764,0.813,0.558,0.744,0.871,0.225,0.273,0.988,0.357,0.141,0.145,0.008,0.271,0.137,0.325,0.342,0.847,0.455,0.837,0.247,0.565,0.461,0.034,0.54,0.161,0.341,0.156,0.565,0.004,0.286,0.105,0.418,0.713,0.615,0.229,0.143,0.205,0.64,0.948,0.292,0.433,0.047,0.062,0.704,0.342,0.147,0.935], 165 | } 166 | this.get = function(x,y,z,t){ 167 | let n = [0,0,0,0] 168 | let _n = 0 169 | var i = 0 170 | while(i < 5){ 171 | let osc = this.config.osc[i] 172 | if(osc.run && osc.type != "off"){ 173 | /*processing the oscilator*/ 174 | switch(osc.typ){ 175 | case "org": 176 | _n = (noise.simplex3( 177 | ((x + (t * (0.4994994994994995 - osc.config.x.off) * 1000)) * osc.config.x.frq * 0.1), 178 | ((y + (t * (0.4994994994994995 - osc.config.y.off) * 1000)) * osc.config.y.frq * 0.1), 179 | ((z + (t * (0.4994994994994995 - osc.config.z.off) * 100)) * osc.config.z.frq * 0.01) 180 | ) + 1) * 0.5 181 | let r = _n * (1 - osc.config.z.shp) + (_n + this.wavetables.random[Math.round(_n * osc.config.z.cen * 99)]) * osc.config.z.shp 182 | _n = r < 0 ? 0 : r > 1 ? 1 : r 183 | break 184 | case "prl": 185 | _n = (noise.perlin3( 186 | ((x + (t * (0.4994994994994995 - osc.config.x.off) * 1000)) * osc.config.x.frq * 0.05), 187 | ((y + (t * (0.4994994994994995 - osc.config.y.off) * 1000)) * osc.config.y.frq * 0.05), 188 | ((z + (t * (0.4994994994994995 - osc.config.z.off) * 100)) * osc.config.z.frq * 0.01) 189 | ) + 1) * 0.5 190 | break 191 | case "plx": 192 | _n = (noise.simplex3( 193 | ((x + (t * (0.4994994994994995 - osc.config.x.off) * 1000)) * osc.config.x.frq * 0.05), 194 | ((y + (t * (0.4994994994994995 - osc.config.y.off) * 1000)) * osc.config.y.frq * 0.05), 195 | ((z + (t * (0.4994994994994995 - osc.config.z.off) * 100)) * osc.config.z.frq * 0.01) 196 | ) + 1) * 0.5 197 | break 198 | default: 199 | let v = ( 200 | ( 201 | this.wavetables.rotation[Math.round((1 - osc.config.z.mod) * 359)][0] * x + 202 | this.wavetables.rotation[Math.round((1 - osc.config.z.mod) * 359)][1] * y 203 | ) * 204 | osc.config.z.frq * 0.1 + 205 | ( 206 | t * osc.config.z.len * 1 207 | ) + 208 | osc.config.z.off 209 | ) % 1 210 | switch(osc.typ){ 211 | case "saw": 212 | _n = v 213 | break 214 | case "rmp": 215 | _n = 1 - v 216 | break 217 | case "sqr": 218 | _n = v < 0.5 ? 1 : 0 219 | break 220 | case "pwm": 221 | _n = v < osc.config.z.cen ? 1 : 0 222 | break 223 | case "tri": 224 | _n = v < 0.5 ? v * 2 : 1 - ((v - 0.5) * 2) 225 | break 226 | case "sin": 227 | let tri = v < 0.5 ? v * 2 : 1 - ((v - 0.5) * 2) 228 | _n = (1 + Math.sin((1.5 + tri) * Math.PI)) * 0.5 229 | break 230 | case "osc": 231 | /*Shape*/ 232 | let center = osc.config.z.cen 233 | let shape = osc.config.z.shp 234 | let t 235 | if((v % 1) < center){ 236 | t = (v % 1) * 1 / center 237 | } 238 | else{ 239 | t = 1 - (((v % 1) - center) * (1 / (1 - center))) 240 | } 241 | let sin = ((1 + Math.sin((1.5 + t) * Math.PI)) * 0.5) 242 | let sqr = t < center ? 0 : 1 243 | if(shape <= 0.5){ 244 | _n = t * ((0.5 - shape) * 2) + sin * (shape * 2) 245 | } 246 | else{ 247 | _n = sin * (2 - shape * 2) + sqr * ((shape - 0.5) * 2) 248 | } 249 | break 250 | } 251 | } 252 | /*applying all fx in effects chain*/ 253 | if(this.config.render.optimization.effects == "on"){ 254 | var f = 0 255 | while(f < osc.fx.c.length){ 256 | let fx = osc.fx.c[f] 257 | _n = this.fx[fx](_n,osc.fx[fx]) 258 | f++ 259 | } 260 | } 261 | 262 | /*scaling and final amplification*/ 263 | _n = (osc.min + ((osc.max - osc.min) * _n)) 264 | if(_n >= (osc.filter.hpf * (osc.max - osc.min)) + osc.min && _n <= osc.min + (1 - osc.filter.lpf) * (osc.max - osc.min) ){ 265 | // _n *= osc.amp 266 | switch(osc.mix){ 267 | case "add": 268 | n[0] += _n * osc.channels.r 269 | n[1] += _n * osc.channels.g 270 | n[2] += _n * osc.channels.b 271 | n[3] += _n * osc.channels.a 272 | break 273 | case "sub": 274 | n[0] -= _n * osc.channels.r 275 | n[1] -= _n * osc.channels.g 276 | n[2] -= _n * osc.channels.b 277 | n[3] -= _n * osc.channels.a 278 | break 279 | case "mlt": 280 | n[0] *= _n * osc.channels.r 281 | n[1] *= _n * osc.channels.g 282 | n[2] *= _n * osc.channels.b 283 | n[3] *= _n * osc.channels.a 284 | break 285 | case "div": 286 | n[0] /= _n * osc.channels.r 287 | n[1] /= _n * osc.channels.g 288 | n[2] /= _n * osc.channels.b 289 | n[3] /= _n * osc.channels.a 290 | break 291 | } 292 | } 293 | } 294 | i++ 295 | } 296 | /*Different amp behaviors for clipping values*/ 297 | switch(this.config.typ){ 298 | /*Simply clips of the signal*/ 299 | case "clp": 300 | n[0] = Math.max(0,Math.min(1,n[0])) 301 | n[1] = Math.max(0,Math.min(1,n[1])) 302 | n[2] = Math.max(0,Math.min(1,n[2])) 303 | n[3] = Math.max(0,Math.min(1,n[3])) 304 | break 305 | /*Uses mod on the signal, turning a signal of 1.1 to 0.1*/ 306 | case "mod": 307 | n[0] = n[0] > 1 ? n[0] % 1 : n[0] 308 | n[1] = n[1] > 1 ? n[1] % 1 : n[1] 309 | n[2] = n[2] > 1 ? n[2] % 1 : n[2] 310 | n[3] = n[3] > 1 ? n[3] % 1 : n[3] 311 | break 312 | /*Dynamically determines maximum amplitude over time and scales all signals accordingly*/ 313 | case "dyn": 314 | if(n[0] > this.dynamics.d){ 315 | this.dynamics.d = n[0] 316 | } 317 | if(n[1] > this.dynamics.d){ 318 | this.dynamics.d = n[1] 319 | } 320 | if(n[2] > this.dynamics.d){ 321 | this.dynamics.d = n[2] 322 | } 323 | if(n[3] > this.dynamics.d){ 324 | this.dynamics.d = n[3] 325 | } 326 | n[0] = n[0] / this.dynamics.d 327 | n[1] = n[1] / this.dynamics.d 328 | n[2] = n[2] / this.dynamics.d 329 | n[3] = n[3] / this.dynamics.d 330 | if(t != this.dynamics.t){ 331 | this.dynamics.t = t 332 | this.dynamics.d = 0 333 | } 334 | break 335 | } 336 | return n 337 | } 338 | this.update = function(callback){ 339 | this.storage.get("config", function(error, data) { 340 | if(error){ 341 | throw error 342 | } 343 | else if(isNotEmptyObject(data)){ 344 | this.config = JSON.parse(data) 345 | if(!this.initiated){ 346 | this.createRender() 347 | this.initiated = true 348 | } 349 | } 350 | }.bind(this)); 351 | } 352 | this.init = function(){ 353 | this.reseed() 354 | this.ipc.on("requireUpdate", function () { 355 | this.update() 356 | }.bind(this)); 357 | this.ipc.on("requireReseed", function () { 358 | this.reseed() 359 | }.bind(this)); 360 | if(env == "main"){ 361 | this.ipc.on("requirePNG", function () { 362 | this.export("png") 363 | }.bind(this)); 364 | this.ipc.on("requireJPG", function () { 365 | this.export("jpg") 366 | }.bind(this)); 367 | this.ipc.on("requireWEBMStart", function () { 368 | this.export("webm",false) 369 | }.bind(this)); 370 | this.ipc.on("requireWEBMStop", function () { 371 | this.export("webm",true) 372 | }.bind(this)); 373 | this.ipc.on("requireGIFStart", function () { 374 | this.export("gif",false) 375 | }.bind(this)); 376 | this.ipc.on("requireGIFStop", function () { 377 | this.export("gif",true) 378 | }.bind(this)); 379 | this.ipc.on("requireSave", function () { 380 | this.store() 381 | }.bind(this)); 382 | } 383 | this.update() 384 | } 385 | this.init() 386 | } 387 | -------------------------------------------------------------------------------- /app/js/acidrender.js: -------------------------------------------------------------------------------- 1 | function ACIDRENDER(storage,ipc,canvas,textlayer,mothership,env){ 2 | this.analytics = { 3 | msPerFrame: 0, 4 | frameTime: 0, 5 | fps: 0, 6 | fpsDisplay: document.getElementById("analyticsFPS"), 7 | widthDisplay: document.getElementById("analyticsWidth"), 8 | heightDisplay: document.getElementById("analyticsHeight") 9 | } 10 | this.env = env 11 | this.storage = storage 12 | this.ipc = ipc 13 | this.canvas = canvas 14 | this.ascii = textlayer 15 | this.gl = this.canvas.getContext('webgl',{preserveDrawingBuffer: true}); 16 | this.mothership = mothership 17 | this.config = {} 18 | this.storage = storage 19 | this.count = 1000 20 | this.particles = [], 21 | this.upCount = function(){ 22 | this.count += this.env == "main" ? 1 / this.config.render.previewframerate : 1 / this.config.settings.framerate 23 | if(this.count > 2147483646){ 24 | this.count = 1000 25 | } 26 | } 27 | this.initiated = false 28 | this.running = true 29 | this.stopped = false 30 | this.play = function(){ 31 | if(this.stopped){ 32 | this.stopped = false 33 | this.render() 34 | } 35 | this.running = true 36 | } 37 | this.pause = function(){ 38 | this.running = false 39 | } 40 | this.stop = function(){ 41 | this.running = false 42 | this.stopped = true 43 | } 44 | this.jump = function(n){ 45 | if(!this.running){ 46 | this.upCount() 47 | if(this.stopped){ 48 | this.render() 49 | } 50 | } 51 | } 52 | this.refresh = function(){ 53 | if(this.stopped){ 54 | this.render() 55 | } 56 | } 57 | this.update = function(callback){ 58 | this.storage.get("config", function(error, data) { 59 | if(error){ 60 | throw error 61 | } 62 | else if(isNotEmptyObject(data)){ 63 | this.config = JSON.parse(data) 64 | for(let c in this.config.render.clrs){ 65 | this.config.render.clrs[c] = hexToRgb(this.config.render.clrs[c]) 66 | } 67 | if(!this.initiated){ 68 | this.render() 69 | this.initiated = true 70 | } 71 | this.refresh() 72 | } 73 | }.bind(this)); 74 | } 75 | this.dimensions = { 76 | width: 0, 77 | height: 0 78 | } 79 | this.resize = function(){ 80 | this.dimensions.width = window.innerWidth 81 | this.dimensions.height = window.innerHeight 82 | this.canvas.width = this.dimensions.width 83 | this.canvas.height = this.dimensions.height 84 | this.gl.viewport(0,0,this.canvas.width,canvas.height); 85 | if(env == "main"){ 86 | this.analytics.widthDisplay.innerText = this.canvas.width 87 | this.analytics.heightDisplay.innerText = this.canvas.height 88 | } 89 | } 90 | this.render = function(){ 91 | //RECURSIVE LOOP 92 | if(!this.stopped){ 93 | let t = this.env == "main" ? 60000 / (this.config.render.previewframerate * 60) : 60000 / (this.config.settings.framerate * 60) 94 | setTimeout(function () { 95 | requestAnimationFrame(function(){ 96 | this.render() 97 | }.bind(this)) 98 | }.bind(this), t); 99 | } 100 | //ANALYTICS 101 | if(env == "main"){ 102 | this.analytics.msPerFrame = performance.now() - this.analytics.frameTime 103 | this.analytics.frameTime = performance.now() 104 | this.analytics.fps = Math.round(1000 / this.analytics.msPerFrame * 100) / 100 105 | this.analytics.fpsDisplay.innerText = this.analytics.fps 106 | } 107 | //WEBGL GENERATION 108 | gl = this.gl 109 | let colors = [] 110 | let vertices = [] 111 | var verticeN = 0 112 | let height = this.dimensions.height 113 | let d = (this.dimensions.width + this.dimensions.height) * 0.5 114 | let res = this.env == "main" ? 2 + this.config.render.preview * 48 : 2 + this.config.render.resolution * 48 115 | gl.uniform1f(this.resolutionLocation, res + 0.1); 116 | let subpixels = this.config.render.optimization.subpixels == "on" 117 | let feedback = this.config.render.optimization.feedback == "on" 118 | let colormodes = this.config.render.optimization.colormodes == "on" 119 | let timeshiftQuantization = this.config.render.feedback.quantization != 0 120 | let grayscale = this.config.render.grayscale 121 | var y = 0 122 | var x = 0 123 | var r,g,b,a,rgb,bw,timeshift,relX,relY,centeredRelX,centeredRelX,n,m,isEdge,lShift,sShift,darken,q, mono 124 | 125 | var lastLine = -1 126 | var currentLine = 0 127 | var writeLine = false 128 | var lastCell = -1 129 | var currentCell = 0 130 | var writeCell = false 131 | var asciiString = "" 132 | var asciiFlag = this.config.render.optimization.ascii == "on" 133 | var monoFlag = this.config.render.mono 134 | var clipBackground = this.config.render.ascii.fixedBackground == "on" 135 | var applyToCharacters = this.config.render.ascii.applyToCharacters == "on" 136 | // var fontWidth = this.env == "main" ? Math.round(this.config.render.ascii.previewfontwidth) : Math.round(this.config.render.ascii.fontwidth) 137 | // var fontHeight = this.env == "main" ? Math.round(this.config.render.ascii.previewfontsize) : Math.round(this.config.render.ascii.fontsize) 138 | var fontWidth = Math.round(this.config.render.ascii.fontwidth) 139 | var fontHeight = Math.round(this.config.render.ascii.fontsize) 140 | var fontSpacing = 0 || this.config.render.ascii.spacing 141 | var upperLine = Math.floor(Math.floor(this.dimensions.height / fontHeight) * 0.5 * fontSpacing) 142 | // var upperLine = 0 143 | var lowerLine = Math.floor(this.dimensions.height / fontHeight) - upperLine 144 | var leftCell = Math.floor(Math.floor(this.dimensions.width / fontWidth) * 0.5 * fontSpacing) 145 | var rightCell = Math.floor(this.dimensions.width / fontWidth) - leftCell 146 | 147 | while(y < this.dimensions.height){ 148 | if(asciiFlag){ 149 | writeLine = false 150 | writeCell = false 151 | lastCell = -1 152 | currentLine = Math.floor(y / fontHeight) 153 | if(currentLine > lastLine){ 154 | lastLine = currentLine 155 | writeLine = true 156 | } 157 | } 158 | while(x < this.dimensions.width){ 159 | if(writeLine){ 160 | writeCell = false 161 | currentCell = Math.floor(x / fontWidth) 162 | if(currentCell > lastCell){ 163 | lastCell = currentCell 164 | writeCell = true 165 | } 166 | } 167 | if(feedback){ 168 | relX = x / this.dimensions.width // 0 - 1 169 | centeredRelX = relX <= this.config.render.feedback.centerX ? relX / this.config.render.feedback.centerX : 1- ((relX - this.config.render.feedback.centerX) / (1 - this.config.render.feedback.centerX))// 0 - 1 - 0 170 | relY = y / this.dimensions.height // 0 - 1 171 | centeredRelY = relY <= (1 - this.config.render.feedback.centerY) ? relY / (1 - this.config.render.feedback.centerY) : 1 - ((relY - (1 - this.config.render.feedback.centerY)) / this.config.render.feedback.centerY)// 0 - 1 - 0 172 | n = centeredRelX * this.config.render.feedback.skew + centeredRelY * (1 - this.config.render.feedback.skew) 173 | m = n * this.config.render.feedback.bend + this.config.render.feedback.mix * (1 - this.config.render.feedback.bend) 174 | lShift = centeredRelX * m + centeredRelY * (1 - m) 175 | sShift = Math.min(centeredRelX * m * 2, centeredRelY * (1 - m) * 2) 176 | timeshift = sShift * this.config.render.feedback.step + lShift * (1 - this.config.render.feedback.step) 177 | if(timeshiftQuantization){ 178 | q = this.config.render.feedback.quantization * this.config.render.feedback.quantization 179 | timeshift = Math.round(timeshift * (1 / q)) * q//QUANTIZE 180 | } 181 | timeshift = 1 - timeshift 182 | darken = (timeshift * this.config.render.feedback.darken + (1 - this.config.render.feedback.darken)) * 0.99 + 0.01 183 | rgb = this.mothership.get(x,y,0,this.count + timeshift * this.config.render.feedback.intensity * 100) 184 | r = this.config.render.channels.r.active ? ((this.config.render.channels.r.base + rgb[0] * this.config.render.channels.r.mod) * this.config.render.channels.r.amp) * darken: 0 185 | g = this.config.render.channels.g.active ? ((this.config.render.channels.g.base + rgb[1] * this.config.render.channels.g.mod) * this.config.render.channels.g.amp) * darken: 0 186 | b = this.config.render.channels.b.active ? ((this.config.render.channels.b.base + rgb[2] * this.config.render.channels.b.mod) * this.config.render.channels.b.amp) * darken: 0 187 | a = this.config.render.channels.a.active ? ((this.config.render.channels.a.base + rgb[3] * this.config.render.channels.a.mod) * this.config.render.channels.a.amp) * darken: 0 188 | } 189 | else{ 190 | rgb = this.mothership.get(x,y,0,this.count) 191 | r = this.config.render.channels.r.active ? ((this.config.render.channels.r.base + rgb[0] * this.config.render.channels.r.mod) * this.config.render.channels.r.amp): 0 192 | g = this.config.render.channels.g.active ? ((this.config.render.channels.g.base + rgb[1] * this.config.render.channels.g.mod) * this.config.render.channels.g.amp): 0 193 | b = this.config.render.channels.b.active ? ((this.config.render.channels.b.base + rgb[2] * this.config.render.channels.b.mod) * this.config.render.channels.b.amp): 0 194 | a = this.config.render.channels.a.active ? ((this.config.render.channels.a.base + rgb[3] * this.config.render.channels.a.mod) * this.config.render.channels.a.amp): 0 195 | } 196 | bw = (0.2126 * r + 0.7152 * g + 0.0722 * b) 197 | mono = bw > 0.5 198 | 199 | // isEdge = !((Math.floor(bw * 100) * 0.1) % 1) && bw > 0.1 && bw < 0.9 && false 200 | // let bw = 1 201 | if(this.config.render.mod != "rgb" && colormodes && !monoFlag){ 202 | switch(this.config.render.mod){ 203 | case "ndx": 204 | let c = this.config.render.clrs[Math.min(Math.floor(this.config.render.clrs.length * bw),(this.config.render.clrs.length - 1))] || {r:0,g:0,b:0} 205 | r = c.r 206 | g = c.g 207 | b = c.b 208 | break 209 | case "grd": 210 | let start = this.config.render.clrs[Math.min(Math.floor(this.config.render.clrs.length * bw),(this.config.render.clrs.length - 1))] || {r:0,g:0,b:0} 211 | let end = this.config.render.clrs[Math.min(Math.ceil(this.config.render.clrs.length * bw),(this.config.render.clrs.length - 1))] || {r:1,g:1,b:1} 212 | let colorMix = (bw * this.config.render.clrs.length) % 1 213 | r = start.r * (1 - colorMix) + end.r * colorMix 214 | g = start.g * (1 - colorMix) + end.g * colorMix 215 | b = start.b * (1 - colorMix) + end.b * colorMix 216 | break 217 | } 218 | } 219 | if(subpixels && !monoFlag){ 220 | colors.push(r * (1-grayscale) + bw * grayscale,this.config.render.burn,this.config.render.burn,this.config.render.burn,g * (1-grayscale) + bw * grayscale,this.config.render.burn,this.config.render.burn,this.config.render.burn,b * (1-grayscale) + bw * grayscale) 221 | vertices.push((x / this.dimensions.width * 2) - 1,-((y / this.dimensions.height * 2) - 1),(x / this.dimensions.width * 2) - 1,-(((y + 0.33333333 * res) / this.dimensions.height * 2) - 1),(x / this.dimensions.width * 2) - 1,-(((y + 0.66666666 * res) / this.dimensions.height * 2) - 1)) 222 | verticeN+=3 223 | } 224 | else{ 225 | colors.push(r * (1-grayscale) + bw * grayscale,g * (1-grayscale) + bw * grayscale,b * (1-grayscale) + bw * grayscale) 226 | vertices.push( 227 | ((x / this.dimensions.width * 2) - 1), 228 | -((y / this.dimensions.height * 2) - 1) 229 | ) 230 | verticeN+=1 231 | } 232 | if(writeCell && (currentLine >= upperLine) && (currentLine <= lowerLine) && (currentCell >= leftCell) && (currentCell <= rightCell)){ 233 | let char = Math.floor(a * this.config.render.ascii.chars.length) || 0 234 | let c = Math.floor(a * this.config.render.ascii.colors.length) || 0 235 | let color, background 236 | char = char > (this.config.render.ascii.chars.length - 1) ? (this.config.render.ascii.chars.length - 1) : char 237 | if(applyToCharacters){ 238 | //TODO 239 | color = "rgb(" + (r * (1-grayscale) + bw * grayscale) * 255 + "," + (g * (1-grayscale) + bw * grayscale) * 255 + "," + (b * (1-grayscale) + bw * grayscale) * 255 + ")" 240 | // console.log(color); 241 | background = this.config.render.ascii.colors[c] 242 | } 243 | else{ 244 | color = this.config.render.ascii.colors[c] 245 | background = "transparent" 246 | } 247 | asciiString += "
" + this.config.render.ascii.chars.charAt(char) + "
" 248 | } 249 | x += clipBackground ? fontWidth : res 250 | } 251 | x = 0 252 | y += clipBackground ? fontHeight : res 253 | if(writeLine){ 254 | asciiString += "
" 255 | } 256 | } 257 | //WEBGL RENDER 258 | let colorBuffer = gl.createBuffer(); 259 | gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); 260 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); 261 | let aColor = gl.getAttribLocation(this.shaderProgram, 'aColor'); 262 | gl.vertexAttribPointer(aColor, 3 , gl.FLOAT, false, 0, 0); 263 | gl.enableVertexAttribArray(aColor); 264 | let vertex_buffer = gl.createBuffer(); 265 | gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer); 266 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 267 | let coord = gl.getAttribLocation(this.shaderProgram, "coord"); 268 | gl.vertexAttribPointer(coord, 2 , gl.FLOAT, false, 0, 0); 269 | gl.enableVertexAttribArray(coord); 270 | gl.clear(gl.COLOR_BUFFER_BIT); 271 | gl.drawArrays(gl.POINTS, 0, verticeN) 272 | //ASCII RENDER 273 | if(asciiFlag){ 274 | this.ascii.style.fontSize = this.config.render.ascii.fontsize + "px" 275 | this.ascii.style.lineHeight = this.config.render.ascii.fontsize + "px" 276 | this.ascii.style.opacity = this.config.render.ascii.opacity 277 | this.ascii.style.mixBlendMode = this.config.render.ascii.mix 278 | this.ascii.innerHTML = asciiString 279 | } 280 | else{ 281 | this.ascii.innerHTML = "" 282 | } 283 | //UPCOUNT 284 | if(this.running){ 285 | this.upCount() 286 | this.mothership.canvasCapturerer.requestGifFrame(60000 / (this.config.settings.framerate * 60)) 287 | } 288 | } 289 | this.init = function(){ 290 | let gl = this.gl 291 | gl.clearColor(0,0,0,1); 292 | 293 | let vertCode = 294 | 'attribute vec4 coord;'+ 295 | 'attribute vec4 aColor;'+ 296 | 'varying vec4 vColor;'+ 297 | 'uniform float resolution;'+ 298 | 299 | 300 | 'void main(void) {'+ 301 | 'gl_Position = coord;'+ 302 | 'gl_PointSize = resolution;'+ 303 | 'vColor = aColor;'+ 304 | '}' 305 | let vertShader = gl.createShader(gl.VERTEX_SHADER); 306 | gl.shaderSource(vertShader, vertCode); 307 | gl.compileShader(vertShader); 308 | let fragCode = 309 | 'precision mediump float;'+ 310 | 311 | 'varying vec4 vColor;'+ 312 | 313 | 'void main() {'+ 314 | 'gl_FragColor = vColor;'+ 315 | '}' 316 | let fragShader = gl.createShader(gl.FRAGMENT_SHADER); 317 | gl.shaderSource(fragShader, fragCode); 318 | gl.compileShader(fragShader); 319 | let shaderProgram = gl.createProgram(); 320 | gl.attachShader(shaderProgram, vertShader); 321 | gl.attachShader(shaderProgram, fragShader); 322 | gl.linkProgram(shaderProgram); 323 | gl.useProgram(shaderProgram); 324 | this.shaderProgram = shaderProgram 325 | this.resolutionLocation = gl.getUniformLocation(shaderProgram, "resolution"); 326 | this.ipc.on("requireUpdate", function () { 327 | this.update() 328 | }.bind(this)); 329 | this.ipc.on("requirePause", function () { 330 | this.pause() 331 | }.bind(this)); 332 | this.ipc.on("requirePlay", function () { 333 | this.play() 334 | }.bind(this)); 335 | this.ipc.on("requireStop", function () { 336 | this.stop() 337 | }.bind(this)); 338 | this.ipc.on("requireOneFramejump", function () { 339 | this.jump(1) 340 | }.bind(this)); 341 | this.ipc.on("requireRefresh", function () { 342 | this.refresh() 343 | }.bind(this)); 344 | this.ipc.on("requireTenFramesjump", function () { 345 | this.jump(10) 346 | }.bind(this)); 347 | window.addEventListener("resize",function(){ 348 | this.resize() 349 | }.bind(this)) 350 | this.resize() 351 | this.update() 352 | } 353 | this.init() 354 | } 355 | -------------------------------------------------------------------------------- /app/js/gif.js: -------------------------------------------------------------------------------- 1 | // gif.js 0.2.0 - https://github.com/jnordberg/gif.js 2 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.GIF=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0&&this._events[type].length>m){this._events[type].warned=true;console.error("(node) warning: possible EventEmitter memory "+"leak detected. %d listeners added. "+"Use emitter.setMaxListeners() to increase limit.",this._events[type].length);if(typeof console.trace==="function"){console.trace()}}}return this};EventEmitter.prototype.on=EventEmitter.prototype.addListener;EventEmitter.prototype.once=function(type,listener){if(!isFunction(listener))throw TypeError("listener must be a function");var fired=false;function g(){this.removeListener(type,g);if(!fired){fired=true;listener.apply(this,arguments)}}g.listener=listener;this.on(type,g);return this};EventEmitter.prototype.removeListener=function(type,listener){var list,position,length,i;if(!isFunction(listener))throw TypeError("listener must be a function");if(!this._events||!this._events[type])return this;list=this._events[type];length=list.length;position=-1;if(list===listener||isFunction(list.listener)&&list.listener===listener){delete this._events[type];if(this._events.removeListener)this.emit("removeListener",type,listener)}else if(isObject(list)){for(i=length;i-- >0;){if(list[i]===listener||list[i].listener&&list[i].listener===listener){position=i;break}}if(position<0)return this;if(list.length===1){list.length=0;delete this._events[type]}else{list.splice(position,1)}if(this._events.removeListener)this.emit("removeListener",type,listener)}return this};EventEmitter.prototype.removeAllListeners=function(type){var key,listeners;if(!this._events)return this;if(!this._events.removeListener){if(arguments.length===0)this._events={};else if(this._events[type])delete this._events[type];return this}if(arguments.length===0){for(key in this._events){if(key==="removeListener")continue;this.removeAllListeners(key)}this.removeAllListeners("removeListener");this._events={};return this}listeners=this._events[type];if(isFunction(listeners)){this.removeListener(type,listeners)}else if(listeners){while(listeners.length)this.removeListener(type,listeners[listeners.length-1])}delete this._events[type];return this};EventEmitter.prototype.listeners=function(type){var ret;if(!this._events||!this._events[type])ret=[];else if(isFunction(this._events[type]))ret=[this._events[type]];else ret=this._events[type].slice();return ret};EventEmitter.prototype.listenerCount=function(type){if(this._events){var evlistener=this._events[type];if(isFunction(evlistener))return 1;else if(evlistener)return evlistener.length}return 0};EventEmitter.listenerCount=function(emitter,type){return emitter.listenerCount(type)};function isFunction(arg){return typeof arg==="function"}function isNumber(arg){return typeof arg==="number"}function isObject(arg){return typeof arg==="object"&&arg!==null}function isUndefined(arg){return arg===void 0}},{}],2:[function(require,module,exports){var UA,browser,mode,platform,ua;ua=navigator.userAgent.toLowerCase();platform=navigator.platform.toLowerCase();UA=ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/)||[null,"unknown",0];mode=UA[1]==="ie"&&document.documentMode;browser={name:UA[1]==="version"?UA[3]:UA[1],version:mode||parseFloat(UA[1]==="opera"&&UA[4]?UA[4]:UA[2]),platform:{name:ua.match(/ip(?:ad|od|hone)/)?"ios":(ua.match(/(?:webos|android)/)||platform.match(/mac|win|linux/)||["other"])[0]}};browser[browser.name]=true;browser[browser.name+parseInt(browser.version,10)]=true;browser.platform[browser.platform.name]=true;module.exports=browser},{}],3:[function(require,module,exports){var EventEmitter,GIF,browser,extend=function(child,parent){for(var key in parent){if(hasProp.call(parent,key))child[key]=parent[key]}function ctor(){this.constructor=child}ctor.prototype=parent.prototype;child.prototype=new ctor;child.__super__=parent.prototype;return child},hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;iref;i=0<=ref?++j:--j){results.push(null)}return results}.call(this);numWorkers=this.spawnWorkers();if(this.options.globalPalette===true){this.renderNextFrame()}else{for(i=j=0,ref=numWorkers;0<=ref?jref;i=0<=ref?++j:--j){this.renderNextFrame()}}this.emit("start");return this.emit("progress",0)};GIF.prototype.abort=function(){var worker;while(true){worker=this.activeWorkers.shift();if(worker==null){break}this.log("killing active worker");worker.terminate()}this.running=false;return this.emit("abort")};GIF.prototype.spawnWorkers=function(){var j,numWorkers,ref,results;numWorkers=Math.min(this.options.workers,this.frames.length);(function(){results=[];for(var j=ref=this.freeWorkers.length;ref<=numWorkers?jnumWorkers;ref<=numWorkers?j++:j--){results.push(j)}return results}).apply(this).forEach(function(_this){return function(i){var worker;_this.log("spawning worker "+i);worker=new Worker(_this.options.workerScript);worker.onmessage=function(event){_this.activeWorkers.splice(_this.activeWorkers.indexOf(worker),1);_this.freeWorkers.push(worker);return _this.frameFinished(event.data)};return _this.freeWorkers.push(worker)}}(this));return numWorkers};GIF.prototype.frameFinished=function(frame){var i,j,ref;this.log("frame "+frame.index+" finished - "+this.activeWorkers.length+" active");this.finishedFrames++;this.emit("progress",this.finishedFrames/this.frames.length);this.imageParts[frame.index]=frame;if(this.options.globalPalette===true){this.options.globalPalette=frame.globalPalette;this.log("global palette analyzed");if(this.frames.length>2){for(i=j=1,ref=this.freeWorkers.length;1<=ref?jref;i=1<=ref?++j:--j){this.renderNextFrame()}}}if(indexOf.call(this.imageParts,null)>=0){return this.renderNextFrame()}else{return this.finishRendering()}};GIF.prototype.finishRendering=function(){var data,frame,i,image,j,k,l,len,len1,len2,len3,offset,page,ref,ref1,ref2;len=0;ref=this.imageParts;for(j=0,len1=ref.length;j=this.frames.length){return}frame=this.frames[this.nextFrame++];worker=this.freeWorkers.shift();task=this.getTask(frame);this.log("starting frame "+(task.index+1)+" of "+this.frames.length);this.activeWorkers.push(worker);return worker.postMessage(task)};GIF.prototype.getContextData=function(ctx){return ctx.getImageData(0,0,this.options.width,this.options.height).data};GIF.prototype.getImageData=function(image){var ctx;if(this._canvas==null){this._canvas=document.createElement("canvas");this._canvas.width=this.options.width;this._canvas.height=this.options.height}ctx=this._canvas.getContext("2d");ctx.setFill=this.options.background;ctx.fillRect(0,0,this.options.width,this.options.height);ctx.drawImage(image,0,0);return this.getContextData(ctx)};GIF.prototype.getTask=function(frame){var index,task;index=this.frames.indexOf(frame);task={index:index,last:index===this.frames.length-1,delay:frame.delay,transparent:frame.transparent,width:this.options.width,height:this.options.height,quality:this.options.quality,dither:this.options.dither,globalPalette:this.options.globalPalette,repeat:this.options.repeat,canTransfer:browser.name==="chrome"};if(frame.data!=null){task.data=frame.data}else if(frame.context!=null){task.data=this.getContextData(frame.context)}else if(frame.image!=null){task.data=this.getImageData(frame.image)}else{throw new Error("Invalid frame")}return task};GIF.prototype.log=function(){var args;args=1<=arguments.length?slice.call(arguments,0):[];if(!this.options.debug){return}return console.log.apply(console,args)};return GIF}(EventEmitter);module.exports=GIF},{"./browser.coffee":2,events:1}]},{},[3])(3)}); 3 | //# sourceMappingURL=gif.js.map 4 | -------------------------------------------------------------------------------- /app/js/gif.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["node_modules/browser-pack/_prelude.js","node_modules/events/events.js","src/browser.coffee","src/gif.coffee"],"names":["f","exports","module","define","amd","g","window","global","self","this","GIF","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length","1","EventEmitter","_events","_maxListeners","undefined","prototype","defaultMaxListeners","setMaxListeners","isNumber","isNaN","TypeError","emit","type","er","handler","len","args","listeners","error","isObject","arguments","err","context","isUndefined","isFunction","Array","slice","apply","addListener","listener","m","newListener","push","warned","console","trace","on","once","fired","removeListener","list","position","splice","removeAllListeners","key","ret","listenerCount","evlistener","emitter","arg","UA","browser","mode","platform","ua","navigator","userAgent","toLowerCase","match","document","documentMode","name","version","parseFloat","parseInt","extend","child","parent","hasProp","ctor","constructor","__super__","superClass","defaults","frameDefaults","workerScript","workers","repeat","background","quality","width","height","transparent","debug","dither","delay","copy","options","base","value","running","frames","freeWorkers","activeWorkers","setOptions","setOption","_canvas","results","addFrame","image","frame","ImageData","data","CanvasRenderingContext2D","WebGLRenderingContext","getContextData","childNodes","getImageData","render","j","numWorkers","ref","nextFrame","finishedFrames","imageParts","spawnWorkers","globalPalette","renderNextFrame","abort","worker","shift","log","terminate","Math","min","forEach","_this","Worker","onmessage","event","indexOf","frameFinished","index","finishRendering","k","len1","len2","len3","offset","page","ref1","ref2","pageSize","cursor","round","Uint8Array","set","Blob","task","getTask","postMessage","ctx","createElement","getContext","setFill","fillRect","drawImage","last","canTransfer"],"mappings":"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","sourceRoot":"","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 0 && this._events[type].length > m) {\n this._events[type].warned = true;\n console.error('(node) warning: possible EventEmitter memory ' +\n 'leak detected. %d listeners added. ' +\n 'Use emitter.setMaxListeners() to increase limit.',\n this._events[type].length);\n if (typeof console.trace === 'function') {\n // not supported in IE 10\n console.trace();\n }\n }\n }\n\n return this;\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.once = function(type, listener) {\n if (!isFunction(listener))\n throw TypeError('listener must be a function');\n\n var fired = false;\n\n function g() {\n this.removeListener(type, g);\n\n if (!fired) {\n fired = true;\n listener.apply(this, arguments);\n }\n }\n\n g.listener = listener;\n this.on(type, g);\n\n return this;\n};\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener = function(type, listener) {\n var list, position, length, i;\n\n if (!isFunction(listener))\n throw TypeError('listener must be a function');\n\n if (!this._events || !this._events[type])\n return this;\n\n list = this._events[type];\n length = list.length;\n position = -1;\n\n if (list === listener ||\n (isFunction(list.listener) && list.listener === listener)) {\n delete this._events[type];\n if (this._events.removeListener)\n this.emit('removeListener', type, listener);\n\n } else if (isObject(list)) {\n for (i = length; i-- > 0;) {\n if (list[i] === listener ||\n (list[i].listener && list[i].listener === listener)) {\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (list.length === 1) {\n list.length = 0;\n delete this._events[type];\n } else {\n list.splice(position, 1);\n }\n\n if (this._events.removeListener)\n this.emit('removeListener', type, listener);\n }\n\n return this;\n};\n\nEventEmitter.prototype.removeAllListeners = function(type) {\n var key, listeners;\n\n if (!this._events)\n return this;\n\n // not listening for removeListener, no need to emit\n if (!this._events.removeListener) {\n if (arguments.length === 0)\n this._events = {};\n else if (this._events[type])\n delete this._events[type];\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n for (key in this._events) {\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = {};\n return this;\n }\n\n listeners = this._events[type];\n\n if (isFunction(listeners)) {\n this.removeListener(type, listeners);\n } else if (listeners) {\n // LIFO order\n while (listeners.length)\n this.removeListener(type, listeners[listeners.length - 1]);\n }\n delete this._events[type];\n\n return this;\n};\n\nEventEmitter.prototype.listeners = function(type) {\n var ret;\n if (!this._events || !this._events[type])\n ret = [];\n else if (isFunction(this._events[type]))\n ret = [this._events[type]];\n else\n ret = this._events[type].slice();\n return ret;\n};\n\nEventEmitter.prototype.listenerCount = function(type) {\n if (this._events) {\n var evlistener = this._events[type];\n\n if (isFunction(evlistener))\n return 1;\n else if (evlistener)\n return evlistener.length;\n }\n return 0;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n return emitter.listenerCount(type);\n};\n\nfunction isFunction(arg) {\n return typeof arg === 'function';\n}\n\nfunction isNumber(arg) {\n return typeof arg === 'number';\n}\n\nfunction isObject(arg) {\n return typeof arg === 'object' && arg !== null;\n}\n\nfunction isUndefined(arg) {\n return arg === void 0;\n}\n","### CoffeeScript version of the browser detection from MooTools ###\n\nua = navigator.userAgent.toLowerCase()\nplatform = navigator.platform.toLowerCase()\nUA = ua.match(/(opera|ie|firefox|chrome|version)[\\s\\/:]([\\w\\d\\.]+)?.*?(safari|version[\\s\\/:]([\\w\\d\\.]+)|$)/) or [null, 'unknown', 0]\nmode = UA[1] == 'ie' && document.documentMode\n\nbrowser =\n name: if UA[1] is 'version' then UA[3] else UA[1]\n version: mode or parseFloat(if UA[1] is 'opera' && UA[4] then UA[4] else UA[2])\n\n platform:\n name: if ua.match(/ip(?:ad|od|hone)/) then 'ios' else (ua.match(/(?:webos|android)/) or platform.match(/mac|win|linux/) or ['other'])[0]\n\nbrowser[browser.name] = true\nbrowser[browser.name + parseInt(browser.version, 10)] = true\nbrowser.platform[browser.platform.name] = true\n\nmodule.exports = browser\n","{EventEmitter} = require 'events'\nbrowser = require './browser.coffee'\n\nclass GIF extends EventEmitter\n\n defaults =\n workerScript: 'gif.worker.js'\n workers: 2\n repeat: 0 # repeat forever, -1 = repeat once\n background: '#fff'\n quality: 10 # pixel sample interval, lower is better\n width: null # size derermined from first frame if possible\n height: null\n transparent: null\n debug: false\n dither: false # see GIFEncoder.js for dithering options\n\n frameDefaults =\n delay: 500 # ms\n copy: false\n\n constructor: (options) ->\n @running = false\n\n @options = {}\n @frames = []\n\n @freeWorkers = []\n @activeWorkers = []\n\n @setOptions options\n for key, value of defaults\n @options[key] ?= value\n\n setOption: (key, value) ->\n @options[key] = value\n if @_canvas? and key in ['width', 'height']\n @_canvas[key] = value\n\n setOptions: (options) ->\n @setOption key, value for own key, value of options\n\n addFrame: (image, options={}) ->\n frame = {}\n frame.transparent = @options.transparent\n for key of frameDefaults\n frame[key] = options[key] or frameDefaults[key]\n\n # use the images width and height for options unless already set\n @setOption 'width', image.width unless @options.width?\n @setOption 'height', image.height unless @options.height?\n\n if ImageData? and image instanceof ImageData\n frame.data = image.data\n else if (CanvasRenderingContext2D? and image instanceof CanvasRenderingContext2D) or (WebGLRenderingContext? and image instanceof WebGLRenderingContext)\n if options.copy\n frame.data = @getContextData image\n else\n frame.context = image\n else if image.childNodes?\n if options.copy\n frame.data = @getImageData image\n else\n frame.image = image\n else\n throw new Error 'Invalid image'\n\n @frames.push frame\n\n render: ->\n throw new Error 'Already running' if @running\n\n if not @options.width? or not @options.height?\n throw new Error 'Width and height must be set prior to rendering'\n\n @running = true\n @nextFrame = 0\n @finishedFrames = 0\n\n @imageParts = (null for i in [0...@frames.length])\n numWorkers = @spawnWorkers()\n # we need to wait for the palette\n if @options.globalPalette == true\n @renderNextFrame()\n else\n @renderNextFrame() for i in [0...numWorkers]\n\n @emit 'start'\n @emit 'progress', 0\n\n abort: ->\n loop\n worker = @activeWorkers.shift()\n break unless worker?\n @log 'killing active worker'\n worker.terminate()\n @running = false\n @emit 'abort'\n\n # private\n\n spawnWorkers: ->\n numWorkers = Math.min(@options.workers, @frames.length)\n [@freeWorkers.length...numWorkers].forEach (i) =>\n @log \"spawning worker #{ i }\"\n worker = new Worker @options.workerScript\n worker.onmessage = (event) =>\n @activeWorkers.splice @activeWorkers.indexOf(worker), 1\n @freeWorkers.push worker\n @frameFinished event.data\n @freeWorkers.push worker\n return numWorkers\n\n frameFinished: (frame) ->\n @log \"frame #{ frame.index } finished - #{ @activeWorkers.length } active\"\n @finishedFrames++\n @emit 'progress', @finishedFrames / @frames.length\n @imageParts[frame.index] = frame\n # remember calculated palette, spawn the rest of the workers\n if @options.globalPalette == true\n @options.globalPalette = frame.globalPalette\n @log 'global palette analyzed'\n @renderNextFrame() for i in [1...@freeWorkers.length] if @frames.length > 2\n if null in @imageParts\n @renderNextFrame()\n else\n @finishRendering()\n\n finishRendering: ->\n len = 0\n for frame in @imageParts\n len += (frame.data.length - 1) * frame.pageSize + frame.cursor\n len += frame.pageSize - frame.cursor\n @log \"rendering finished - filesize #{ Math.round(len / 1000) }kb\"\n data = new Uint8Array len\n offset = 0\n for frame in @imageParts\n for page, i in frame.data\n data.set page, offset\n if i is frame.data.length - 1\n offset += frame.cursor\n else\n offset += frame.pageSize\n\n image = new Blob [data],\n type: 'image/gif'\n\n @emit 'finished', image, data\n\n renderNextFrame: ->\n throw new Error 'No free workers' if @freeWorkers.length is 0\n return if @nextFrame >= @frames.length # no new frame to render\n\n frame = @frames[@nextFrame++]\n worker = @freeWorkers.shift()\n task = @getTask frame\n\n @log \"starting frame #{ task.index + 1 } of #{ @frames.length }\"\n @activeWorkers.push worker\n worker.postMessage task#, [task.data.buffer]\n\n getContextData: (ctx) ->\n return ctx.getImageData(0, 0, @options.width, @options.height).data\n\n getImageData: (image) ->\n if not @_canvas?\n @_canvas = document.createElement 'canvas'\n @_canvas.width = @options.width\n @_canvas.height = @options.height\n\n ctx = @_canvas.getContext '2d'\n ctx.setFill = @options.background\n ctx.fillRect 0, 0, @options.width, @options.height\n ctx.drawImage image, 0, 0\n\n return @getContextData ctx\n\n getTask: (frame) ->\n index = @frames.indexOf frame\n task =\n index: index\n last: index is (@frames.length - 1)\n delay: frame.delay\n transparent: frame.transparent\n width: @options.width\n height: @options.height\n quality: @options.quality\n dither: @options.dither\n globalPalette: @options.globalPalette\n repeat: @options.repeat\n canTransfer: (browser.name is 'chrome')\n\n if frame.data?\n task.data = frame.data\n else if frame.context?\n task.data = @getContextData frame.context\n else if frame.image?\n task.data = @getImageData frame.image\n else\n throw new Error 'Invalid frame'\n\n return task\n\n log: (args...) ->\n return unless @options.debug\n console.log args...\n\n\nmodule.exports = GIF\n"]} 2 | -------------------------------------------------------------------------------- /app/js/gif.worker.js: -------------------------------------------------------------------------------- 1 | // gif.worker.js 0.2.0 - https://github.com/jnordberg/gif.js 2 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=ByteArray.pageSize)this.newPage();this.pages[this.page][this.cursor++]=val};ByteArray.prototype.writeUTFBytes=function(string){for(var l=string.length,i=0;i=0)this.dispose=disposalCode};GIFEncoder.prototype.setRepeat=function(repeat){this.repeat=repeat};GIFEncoder.prototype.setTransparent=function(color){this.transparent=color};GIFEncoder.prototype.addFrame=function(imageData){this.image=imageData;this.colorTab=this.globalPalette&&this.globalPalette.slice?this.globalPalette:null;this.getImagePixels();this.analyzePixels();if(this.globalPalette===true)this.globalPalette=this.colorTab;if(this.firstFrame){this.writeLSD();this.writePalette();if(this.repeat>=0){this.writeNetscapeExt()}}this.writeGraphicCtrlExt();this.writeImageDesc();if(!this.firstFrame&&!this.globalPalette)this.writePalette();this.writePixels();this.firstFrame=false};GIFEncoder.prototype.finish=function(){this.out.writeByte(59)};GIFEncoder.prototype.setQuality=function(quality){if(quality<1)quality=1;this.sample=quality};GIFEncoder.prototype.setDither=function(dither){if(dither===true)dither="FloydSteinberg";this.dither=dither};GIFEncoder.prototype.setGlobalPalette=function(palette){this.globalPalette=palette};GIFEncoder.prototype.getGlobalPalette=function(){return this.globalPalette&&this.globalPalette.slice&&this.globalPalette.slice(0)||this.globalPalette};GIFEncoder.prototype.writeHeader=function(){this.out.writeUTFBytes("GIF89a")};GIFEncoder.prototype.analyzePixels=function(){if(!this.colorTab){this.neuQuant=new NeuQuant(this.pixels,this.sample);this.neuQuant.buildColormap();this.colorTab=this.neuQuant.getColormap()}if(this.dither){this.ditherPixels(this.dither.replace("-serpentine",""),this.dither.match(/-serpentine/)!==null)}else{this.indexPixels()}this.pixels=null;this.colorDepth=8;this.palSize=7;if(this.transparent!==null){this.transIndex=this.findClosest(this.transparent,true)}};GIFEncoder.prototype.indexPixels=function(imgq){var nPix=this.pixels.length/3;this.indexedPixels=new Uint8Array(nPix);var k=0;for(var j=0;j=0&&x1+x=0&&y1+y>16,(c&65280)>>8,c&255,used)};GIFEncoder.prototype.findClosestRGB=function(r,g,b,used){if(this.colorTab===null)return-1;if(this.neuQuant&&!used){return this.neuQuant.lookupRGB(r,g,b)}var c=b|g<<8|r<<16;var minpos=0;var dmin=256*256*256;var len=this.colorTab.length;for(var i=0,index=0;i=0){disp=dispose&7}disp<<=2;this.out.writeByte(0|disp|0|transp);this.writeShort(this.delay);this.out.writeByte(this.transIndex);this.out.writeByte(0)};GIFEncoder.prototype.writeImageDesc=function(){this.out.writeByte(44);this.writeShort(0);this.writeShort(0);this.writeShort(this.width);this.writeShort(this.height);if(this.firstFrame||this.globalPalette){this.out.writeByte(0)}else{this.out.writeByte(128|0|0|0|this.palSize)}};GIFEncoder.prototype.writeLSD=function(){this.writeShort(this.width);this.writeShort(this.height);this.out.writeByte(128|112|0|this.palSize);this.out.writeByte(0);this.out.writeByte(0)};GIFEncoder.prototype.writeNetscapeExt=function(){this.out.writeByte(33);this.out.writeByte(255);this.out.writeByte(11);this.out.writeUTFBytes("NETSCAPE2.0");this.out.writeByte(3);this.out.writeByte(1);this.writeShort(this.repeat);this.out.writeByte(0)};GIFEncoder.prototype.writePalette=function(){this.out.writeBytes(this.colorTab);var n=3*256-this.colorTab.length;for(var i=0;i>8&255)};GIFEncoder.prototype.writePixels=function(){var enc=new LZWEncoder(this.width,this.height,this.indexedPixels,this.colorDepth);enc.encode(this.out)};GIFEncoder.prototype.stream=function(){return this.out};module.exports=GIFEncoder},{"./LZWEncoder.js":2,"./TypedNeuQuant.js":3}],2:[function(require,module,exports){var EOF=-1;var BITS=12;var HSIZE=5003;var masks=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];function LZWEncoder(width,height,pixels,colorDepth){var initCodeSize=Math.max(2,colorDepth);var accum=new Uint8Array(256);var htab=new Int32Array(HSIZE);var codetab=new Int32Array(HSIZE);var cur_accum,cur_bits=0;var a_count;var free_ent=0;var maxcode;var clear_flg=false;var g_init_bits,ClearCode,EOFCode;function char_out(c,outs){accum[a_count++]=c;if(a_count>=254)flush_char(outs)}function cl_block(outs){cl_hash(HSIZE);free_ent=ClearCode+2;clear_flg=true;output(ClearCode,outs)}function cl_hash(hsize){for(var i=0;i=0){disp=hsize_reg-i;if(i===0)disp=1;do{if((i-=disp)<0)i+=hsize_reg;if(htab[i]===fcode){ent=codetab[i];continue outer_loop}}while(htab[i]>=0)}output(ent,outs);ent=c;if(free_ent<1<0){outs.writeByte(a_count);outs.writeBytes(accum,0,a_count);a_count=0}}function MAXCODE(n_bits){return(1<0)cur_accum|=code<=8){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}if(free_ent>maxcode||clear_flg){if(clear_flg){maxcode=MAXCODE(n_bits=g_init_bits);clear_flg=false}else{++n_bits;if(n_bits==BITS)maxcode=1<0){char_out(cur_accum&255,outs);cur_accum>>=8;cur_bits-=8}flush_char(outs)}}this.encode=encode}module.exports=LZWEncoder},{}],3:[function(require,module,exports){var ncycles=100;var netsize=256;var maxnetpos=netsize-1;var netbiasshift=4;var intbiasshift=16;var intbias=1<>betashift;var betagamma=intbias<>3;var radiusbiasshift=6;var radiusbias=1<>3);var i,v;for(i=0;i>=netbiasshift;network[i][1]>>=netbiasshift;network[i][2]>>=netbiasshift;network[i][3]=i}}function altersingle(alpha,i,b,g,r){network[i][0]-=alpha*(network[i][0]-b)/initalpha;network[i][1]-=alpha*(network[i][1]-g)/initalpha;network[i][2]-=alpha*(network[i][2]-r)/initalpha}function alterneigh(radius,i,b,g,r){var lo=Math.abs(i-radius);var hi=Math.min(i+radius,netsize);var j=i+1;var k=i-1;var m=1;var p,a;while(jlo){a=radpower[m++];if(jlo){p=network[k--];p[0]-=a*(p[0]-b)/alpharadbias;p[1]-=a*(p[1]-g)/alpharadbias;p[2]-=a*(p[2]-r)/alpharadbias}}}function contest(b,g,r){var bestd=~(1<<31);var bestbiasd=bestd;var bestpos=-1;var bestbiaspos=bestpos;var i,n,dist,biasdist,betafreq;for(i=0;i>intbiasshift-netbiasshift);if(biasdist>betashift;freq[i]-=betafreq;bias[i]+=betafreq<>1;for(j=previouscol+1;j>1;for(j=previouscol+1;j<256;j++)netindex[j]=maxnetpos}function inxsearch(b,g,r){var a,p,dist;var bestd=1e3;var best=-1;var i=netindex[g];var j=i-1;while(i=0){if(i=bestd)i=netsize;else{i++;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist=0){p=network[j];dist=g-p[1];if(dist>=bestd)j=-1;else{j--;if(dist<0)dist=-dist;a=p[0]-b;if(a<0)a=-a;dist+=a;if(dist>radiusbiasshift;if(rad<=1)rad=0;for(i=0;i=lengthcount)pix-=lengthcount;i++;if(delta===0)delta=1;if(i%delta===0){alpha-=alpha/alphadec;radius-=radius/radiusdec;rad=radius>>radiusbiasshift;if(rad<=1)rad=0;for(j=0;j{document.body.removeChild(c),window.URL.revokeObjectURL(r)},100)};var t=[],d=null,n=null,r=e.captureStream();if(null==typeof r||!r)return;const c=document.createElement("video");function i(e){e.data&&e.data.size>0&&t.push(e.data)}function a(e){console.log("Recorder stopped: ",e);const o=new Blob(t,{type:d});c.src=window.URL.createObjectURL(o)}c.style.display="none"} 46 | 47 | /* 48 | * A speed-improved perlin and simplex noise algorithms for 2D. 49 | * 50 | * Based on example code by Stefan Gustavson (stegu@itn.liu.se). 51 | * Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). 52 | * Better rank ordering method by Stefan Gustavson in 2012. 53 | * Converted to Javascript by Joseph Gentle. 54 | * 55 | * Version 2012-03-09 56 | * 57 | * This code was placed in the public domain by its original author, 58 | * Stefan Gustavson. You may use it as you see fit, but 59 | * attribution is appreciated. 60 | * 61 | */ 62 | (function(global){var module=window.noise={};function Grad(x,y,z){this.x=x;this.y=y;this.z=z} 63 | Grad.prototype.dot2=function(x,y){return this.x*x+this.y*y};Grad.prototype.dot3=function(x,y,z){return this.x*x+this.y*y+this.z*z};var grad3=[new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)];var p=[151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];var perm=new Array(512);var gradP=new Array(512);module.seed=function(seed){if(seed>0&&seed<1){seed*=65536} 64 | seed=Math.floor(seed);if(seed<256){seed|=seed<<8} 65 | for(var i=0;i<256;i++){var v;if(i&1){v=p[i]^(seed&255)}else{v=p[i]^((seed>>8)&255)} 66 | perm[i]=perm[i+256]=v;gradP[i]=gradP[i+256]=grad3[v%12]}};module.seed(0);var F2=0.5*(Math.sqrt(3)-1);var G2=(3-Math.sqrt(3))/6;var F3=1/3;var G3=1/6;module.simplex2=function(xin,yin){var n0,n1,n2;var s=(xin+yin)*F2;var i=Math.floor(xin+s);var j=Math.floor(yin+s);var t=(i+j)*G2;var x0=xin-i+t;var y0=yin-j+t;var i1,j1;if(x0>y0){i1=1;j1=0}else{i1=0;j1=1} 67 | var x1=x0-i1+G2;var y1=y0-j1+G2;var x2=x0-1+2*G2;var y2=y0-1+2*G2;i&=255;j&=255;var gi0=gradP[i+perm[j]];var gi1=gradP[i+i1+perm[j+j1]];var gi2=gradP[i+1+perm[j+1]];var t0=0.5-x0*x0-y0*y0;if(t0<0){n0=0}else{t0*=t0;n0=t0*t0*gi0.dot2(x0,y0)} 68 | var t1=0.5-x1*x1-y1*y1;if(t1<0){n1=0}else{t1*=t1;n1=t1*t1*gi1.dot2(x1,y1)} 69 | var t2=0.5-x2*x2-y2*y2;if(t2<0){n2=0}else{t2*=t2;n2=t2*t2*gi2.dot2(x2,y2)} 70 | return 70*(n0+n1+n2)};module.simplex3=function(xin,yin,zin){var n0,n1,n2,n3;var s=(xin+yin+zin)*F3;var i=Math.floor(xin+s);var j=Math.floor(yin+s);var k=Math.floor(zin+s);var t=(i+j+k)*G3;var x0=xin-i+t;var y0=yin-j+t;var z0=zin-k+t;var i1,j1,k1;var i2,j2,k2;if(x0>=y0){if(y0>=z0){i1=1;j1=0;k1=0;i2=1;j2=1;k2=0}else if(x0>=z0){i1=1;j1=0;k1=0;i2=1;j2=0;k2=1}else{i1=0;j1=0;k1=1;i2=1;j2=0;k2=1}}else{if(y0 { 15 | requireUpdate() 16 | }) 17 | function requireUpdate(){ 18 | mainWindow.webContents.send("requireUpdate"); 19 | if(guiWindow){ 20 | guiWindow.webContents.send("requireUpdate"); 21 | } 22 | if(renderWindow){ 23 | renderWindow.webContents.send("requireUpdate"); 24 | } 25 | } 26 | function checkForEmptyStorage(){ 27 | storage.get("config", function(error, data) { 28 | if(error){ 29 | throw error 30 | } 31 | else if(!isNotEmptyObject(data)){ 32 | resetStorage() 33 | } 34 | }) 35 | function isNotEmptyObject(obj){ 36 | return !(obj && Object.keys(obj).length === 0 && obj.constructor === Object) 37 | } 38 | } 39 | function resetStorage(){ 40 | let data = "{\"typ\":\"mod\",\"settings\":{\"defaultColor\":\"#ffffff\",\"defaultFx\":\"drv\",\"framerate\":\"10\",\"zoom\":0.2972972972972973,\"tips\":\"off\",\"labels\":\"on\",\"buttons\":\"on\",\"transparency\":0.5495495495495496},\"render\":{\"resolution\":0.3,\"preview\":0.3,\"previewframerate\":10,\"grayscale\":0.5,\"mod\":\"rgb\",\"burn\":0,\"clrs\":[],\"optimization\":{\"effects\":\"on\",\"subpixels\":\"on\",\"feedback\":\"on\",\"colormodes\":\"on\"},\"feedback\":{\"quantization\":0,\"intensity\":0,\"mix\":0.5,\"bend\":1,\"skew\":0.8,\"centerY\":0.5,\"centerX\":0.5,\"step\":0.5,\"darken\":0.5},\"channels\":{\"r\":{\"amp\":1,\"base\":0,\"mod\":1,\"active\":true},\"g\":{\"amp\":1,\"base\":0,\"mod\":1,\"active\":true},\"b\":{\"amp\":1,\"base\":0,\"mod\":1,\"active\":true},\"a\":{\"amp\":1,\"base\":0,\"mod\":1,\"active\":true}}},\"osc\":[{\"typ\":\"sin\",\"min\":0,\"max\":0.6676676676676677,\"mix\":\"add\",\"run\":true,\"fx\":{\"c\":[\"exp\",\"rnd\",\"bit\"],\"bit\":0.9009009009009009,\"cmp\":0,\"exp\":0.6846846846846847,\"rnd\":0.03903903903903904,\"drv\":0},\"filter\":{\"lpf\":0,\"hpf\":0},\"config\":{\"x\":{\"frq\":0.4994994994994995,\"off\":0},\"y\":{\"frq\":0.08608608608608609,\"off\":0},\"z\":{\"frq\":0.028028028028028028,\"off\":0,\"len\":0.16216216216216217,\"mod\":0.07307307307307308,\"cen\":0.22422422422422422,\"shp\":0.16216216216216217}},\"channels\":{\"r\":1,\"g\":1,\"b\":1,\"a\":1}},{\"typ\":\"prl\",\"min\":0,\"max\":0.6476476476476476,\"mix\":\"mlt\",\"run\":true,\"fx\":{\"c\":[\"exp\",\"drv\"],\"bit\":0,\"cmp\":0.7107107107107107,\"exp\":0.4174174174174174,\"rnd\":0,\"drv\":0.5555555555555556},\"filter\":{\"lpf\":0,\"hpf\":0},\"config\":{\"x\":{\"frq\":0.1891891891891892,\"off\":0.4994994994994995},\"y\":{\"frq\":0.19519519519519518,\"off\":0.4994994994994995},\"z\":{\"frq\":0.35235235235235235,\"off\":0,\"len\":0.5,\"mod\":0.36236236236236236,\"cen\":0.22422422422422422,\"shp\":0.2962962962962963}},\"channels\":{\"r\":1,\"g\":1,\"b\":1,\"a\":1}},{\"typ\":\"osc\",\"min\":0.44744744744744747,\"max\":1,\"mix\":\"div\",\"run\":true,\"fx\":{\"c\":[\"cmp\"],\"bit\":0,\"cmp\":0.7567567567567568,\"exp\":0,\"rnd\":0,\"drv\":0},\"filter\":{\"lpf\":0,\"hpf\":0},\"config\":{\"x\":{\"frq\":0.5005005005005005,\"off\":0},\"y\":{\"frq\":0.5005005005005005,\"off\":0},\"z\":{\"frq\":0.026026026026026026,\"off\":0,\"len\":0.12512512512512514,\"mod\":0.3023023023023023,\"cen\":0.7387387387387387,\"shp\":0.2902902902902903}},\"channels\":{\"r\":1,\"g\":1,\"b\":1,\"a\":1}},{\"typ\":\"plx\",\"min\":0,\"max\":0.21021021021021022,\"mix\":\"add\",\"run\":true,\"fx\":{\"c\":[\"exp\",\"rnd\"],\"bit\":0,\"cmp\":0,\"exp\":0.8588588588588588,\"rnd\":0.12112112112112113,\"drv\":0},\"filter\":{\"lpf\":0,\"hpf\":0.18018018018018017},\"config\":{\"x\":{\"frq\":0.5005005005005005,\"off\":0.4994994994994995},\"y\":{\"frq\":0.07807807807807808,\"off\":1},\"z\":{\"frq\":0.5195195195195195,\"off\":0.8648648648648649,\"len\":0.17617617617617617,\"mod\":0.16016016016016016,\"cen\":0.5,\"shp\":0.5}},\"channels\":{\"r\":1,\"g\":1,\"b\":1,\"a\":1}},{\"typ\":\"osc\",\"min\":0.43743743743743746,\"max\":0.9819819819819819,\"mix\":\"div\",\"run\":true,\"fx\":{\"c\":[],\"bit\":0,\"cmp\":0,\"exp\":0,\"rnd\":0,\"drv\":0},\"filter\":{\"lpf\":0,\"hpf\":0},\"config\":{\"x\":{\"frq\":0.5005005005005005,\"off\":0},\"y\":{\"frq\":0.5005005005005005,\"off\":0},\"z\":{\"frq\":0,\"off\":0.4994994994994995,\"len\":0.8818818818818819,\"mod\":0,\"cen\":0.8308308308308309,\"shp\":0.7907907907907908}},\"channels\":{\"r\":1,\"g\":1,\"b\":1,\"a\":1}}]}" 41 | storage.set("config", data, function(error) { 42 | if (error){ 43 | throw error 44 | } 45 | else{ 46 | requireUpdate() 47 | } 48 | }) 49 | } 50 | function randomPatch(save){ 51 | let config = {} 52 | storage.get("config", function(error, data) { 53 | if(error){ 54 | throw error 55 | } 56 | else{ 57 | config = JSON.parse(data) 58 | let oscTypes = ["off","prl","plx","org","osc","sqr","pwm","saw","tri","sin"] 59 | let mixTypes = ["add","sub","mlt","div"] 60 | // let colorModes = ["rgb","grd","ndx"] 61 | let fxTypes = ["drv","cmp","exp","rnd","bit"] 62 | // let generateRandomColors = function(n){ 63 | // let target = Math.floor(Math.random() * n) 64 | // let pool = [] 65 | // for(let i = 0; i < target; i++){ 66 | // pool.push("#" + ('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6)) 67 | // } 68 | // return pool 69 | // } 70 | let generateRandomFx = function(n){ 71 | let target = Math.floor(Math.random() * n) 72 | let pool = [] 73 | for(let i = 0; i < target; i++){ 74 | pool.push(fxTypes[Math.floor(Math.random() * 0.99 * fxTypes.length)]) 75 | } 76 | return pool 77 | } 78 | let newData = { 79 | typ: config.typ, 80 | settings: config.settings, 81 | render: { 82 | resolution: config.render.resolution, 83 | preview: config.render.preview, 84 | previewframerate: config.render.previewframerate, 85 | previewwidth: 240, 86 | previewheight: 240, 87 | grayscale: config.render.grayscale, 88 | mod: config.render.mod, 89 | burn: config.render.burn, 90 | clrs:config.render.clrs, 91 | ascii: { 92 | font: "monospace", 93 | fontsize: config.render.ascii.fontsize, 94 | previewfontsize: config.render.ascii.previewfontsize, 95 | fontwidth: config.render.ascii.fontwidth, 96 | previewfontwidth: config.render.ascii.previewfontwidth, 97 | spacing: config.render.ascii.spacing, 98 | opacity: config.render.ascii.opacity, 99 | mix: config.render.ascii.mix, 100 | colors: config.render.ascii.colors, 101 | chars: "-+*", 102 | fixedBackground: config.render.ascii.fixedBackground, 103 | applyToCharacters: config.render.ascii.applyToCharacters 104 | }, 105 | optimization: { 106 | ascii: config.render.optimization.ascii, 107 | effects: config.render.optimization.effects, 108 | subpixels: config.render.optimization.subpixels, 109 | feedback: config.render.optimization.feedback, 110 | colormodes: config.render.optimization.colormodes 111 | }, 112 | feedback: { 113 | quantization: Math.random(), 114 | intensity: Math.random(), 115 | mix: Math.random(), 116 | bend: Math.random(), 117 | skew: Math.random(), 118 | centerY: Math.random(), 119 | centerX: Math.random(), 120 | step: Math.random(), 121 | darken: Math.random() 122 | }, 123 | channels: config.render.channels 124 | }, 125 | osc: [ 126 | { 127 | typ: oscTypes[Math.floor(Math.random() * 0.99 * oscTypes.length)], 128 | min: save ? 0.5 * Math.random() : Math.random(), 129 | max: save ? 0.5 + Math.random() * 0.5 : Math.random(), 130 | mix: save ? "add" : mixTypes[Math.floor(Math.random() * 0.99 * mixTypes.length)], 131 | run: true, 132 | fx: { 133 | c: generateRandomFx(3), 134 | bit: Math.random(), 135 | cmp: Math.random(), 136 | exp: Math.random(), 137 | rnd: Math.random(), 138 | drv: Math.random() 139 | }, 140 | filter: { 141 | lpf: save ? 0.8 * Math.random() : Math.random(), 142 | hpf: save ? 0.8 * Math.random() : Math.random() 143 | }, 144 | config: { 145 | x: { 146 | frq: save ? Math.random() * 0.1 : Math.random(), 147 | off: Math.random() 148 | }, 149 | y: { 150 | frq: save ? Math.random() * 0.1 : Math.random(), 151 | off: Math.random() 152 | }, 153 | z: { 154 | frq: save ? Math.random() * 0.1 : Math.random(), 155 | off: Math.random(), 156 | len: save ? Math.random() * 0.4 : Math.random(), 157 | mod: Math.random(), 158 | cen: Math.random(), 159 | shp: Math.random() 160 | } 161 | }, 162 | channels: { 163 | r: Math.random(), 164 | g: Math.random(), 165 | b: Math.random(), 166 | a: Math.random() 167 | } 168 | }, 169 | { 170 | typ: oscTypes[Math.floor(Math.random() * 0.99 * oscTypes.length)], 171 | min: 0.5 * Math.random(), 172 | max: 0.5 + Math.random() * 0.5, 173 | mix: save ? "add" : mixTypes[Math.floor(Math.random() * 0.99 * mixTypes.length)], 174 | run: true, 175 | fx: { 176 | c: generateRandomFx(3), 177 | bit: Math.random(), 178 | cmp: Math.random(), 179 | exp: Math.random(), 180 | rnd: Math.random(), 181 | drv: Math.random() 182 | }, 183 | filter: { 184 | lpf: 0.8 * Math.random(), 185 | hpf: 0.8 * Math.random() 186 | }, 187 | config: { 188 | x: { 189 | frq: Math.random() * 0.1, 190 | off: Math.random() 191 | }, 192 | y: { 193 | frq: Math.random() * 0.1, 194 | off: Math.random() 195 | }, 196 | z: { 197 | frq: Math.random() * 0.1, 198 | off: Math.random(), 199 | len: Math.random() * 0.4, 200 | mod: Math.random(), 201 | cen: Math.random(), 202 | shp: Math.random() 203 | } 204 | }, 205 | channels: { 206 | r: Math.random(), 207 | g: Math.random(), 208 | b: Math.random(), 209 | a: Math.random() 210 | } 211 | }, 212 | { 213 | typ: oscTypes[Math.floor(Math.random() * 0.99 * oscTypes.length)], 214 | min: 0.5 * Math.random(), 215 | max: 0.5 + Math.random() * 0.5, 216 | mix: save ? "add" : mixTypes[Math.floor(Math.random() * 0.99 * mixTypes.length)], 217 | run: true, 218 | fx: { 219 | c: generateRandomFx(3), 220 | bit: Math.random(), 221 | cmp: Math.random(), 222 | exp: Math.random(), 223 | rnd: Math.random(), 224 | drv: Math.random() 225 | }, 226 | filter: { 227 | lpf: 0.8 * Math.random(), 228 | hpf: 0.8 * Math.random() 229 | }, 230 | config: { 231 | x: { 232 | frq: Math.random() * 0.1, 233 | off: Math.random() 234 | }, 235 | y: { 236 | frq: Math.random() * 0.1, 237 | off: Math.random() 238 | }, 239 | z: { 240 | frq: Math.random() * 0.1, 241 | off: Math.random(), 242 | len: Math.random() * 0.4, 243 | mod: Math.random(), 244 | cen: Math.random(), 245 | shp: Math.random() 246 | } 247 | }, 248 | channels: { 249 | r: Math.random(), 250 | g: Math.random(), 251 | b: Math.random(), 252 | a: Math.random() 253 | } 254 | }, 255 | { 256 | typ: oscTypes[Math.floor(Math.random() * 0.99 * oscTypes.length)], 257 | min: 0.5 * Math.random(), 258 | max: 0.5 + Math.random() * 0.5, 259 | mix: save ? "add" : mixTypes[Math.floor(Math.random() * 0.99 * mixTypes.length)], 260 | run: true, 261 | fx: { 262 | c: generateRandomFx(3), 263 | bit: Math.random(), 264 | cmp: Math.random(), 265 | exp: Math.random(), 266 | rnd: Math.random(), 267 | drv: Math.random() 268 | }, 269 | filter: { 270 | lpf: 0.8 * Math.random(), 271 | hpf: 0.8 * Math.random() 272 | }, 273 | config: { 274 | x: { 275 | frq: Math.random() * 0.1, 276 | off: Math.random() 277 | }, 278 | y: { 279 | frq: Math.random() * 0.1, 280 | off: Math.random() 281 | }, 282 | z: { 283 | frq: Math.random() * 0.1, 284 | off: Math.random(), 285 | len: Math.random() * 0.4, 286 | mod: Math.random(), 287 | cen: Math.random(), 288 | shp: Math.random() 289 | } 290 | }, 291 | channels: { 292 | r: Math.random(), 293 | g: Math.random(), 294 | b: Math.random(), 295 | a: Math.random() 296 | } 297 | }, 298 | { 299 | typ: oscTypes[Math.floor(Math.random() * 0.99 * oscTypes.length)], 300 | min: 0.5 * Math.random(), 301 | max: 0.5 + Math.random() * 0.5, 302 | mix: save ? "add" : mixTypes[Math.floor(Math.random() * 0.99 * mixTypes.length)], 303 | run: true, 304 | fx: { 305 | c: generateRandomFx(3), 306 | bit: Math.random(), 307 | cmp: Math.random(), 308 | exp: Math.random(), 309 | rnd: Math.random(), 310 | drv: Math.random() 311 | }, 312 | filter: { 313 | lpf: 0.8 * Math.random(), 314 | hpf: 0.8 * Math.random() 315 | }, 316 | config: { 317 | x: { 318 | frq: Math.random() * 0.1, 319 | off: Math.random() 320 | }, 321 | y: { 322 | frq: Math.random() * 0.1, 323 | off: Math.random() 324 | }, 325 | z: { 326 | frq: Math.random() * 0.1, 327 | off: Math.random(), 328 | len: Math.random() * 0.4, 329 | mod: Math.random(), 330 | cen: Math.random(), 331 | shp: Math.random() 332 | } 333 | }, 334 | channels: { 335 | r: Math.random(), 336 | g: Math.random(), 337 | b: Math.random(), 338 | a: Math.random() 339 | } 340 | } 341 | ] 342 | } 343 | newData = JSON.stringify(newData) 344 | storage.set("config", newData, function(error) { 345 | if (error){ 346 | throw error 347 | } 348 | else{ 349 | requireUpdate() 350 | } 351 | }) 352 | } 353 | }) 354 | } 355 | function displayGUI(flag){ 356 | if(flag){ 357 | mainWindow.webContents.send("requireShowGUI"); 358 | } 359 | else{ 360 | mainWindow.webContents.send("requireHideGUI"); 361 | } 362 | } 363 | function toggleGUI(){ 364 | mainWindow.webContents.send("requireToggleGUI"); 365 | } 366 | function requireAction(sender,prefix){ 367 | prefix = prefix || "" 368 | mainWindow.webContents.send("require" + prefix + sender.label); 369 | } 370 | function requireOneFramejump(){ 371 | mainWindow.webContents.send("requireOneFramejump"); 372 | } 373 | function requireTenFramesjump(){ 374 | mainWindow.webContents.send("requireTenFramesjump"); 375 | } 376 | function requireRefresh(){ 377 | mainWindow.webContents.send("requireRefresh"); 378 | if(renderWindow){ 379 | renderWindow.webContents.send("requireRefresh"); 380 | } 381 | } 382 | 383 | function openFile(){ 384 | dialog.showOpenDialog(mainWindow, { 385 | properties: ['openFile'] 386 | }).then(result => { 387 | if(!result.canceled && result.filePaths.length > 0){ 388 | let filepath = result.filePaths[0] 389 | fs.readFile(filepath, 'utf-8', (err, data) => { 390 | if(err){ 391 | alert("An error ocurred reading the file :" + err.message); 392 | return; 393 | } 394 | else{ 395 | storage.set("config", data, function(error) { 396 | if (error){ 397 | console.log("Error storing JSON " + error) 398 | } 399 | else{ 400 | requireUpdate() 401 | } 402 | }) 403 | } 404 | }) 405 | } 406 | }) 407 | } 408 | 409 | 410 | function createWindow () { 411 | mainWindow = new BrowserWindow({ 412 | width: 600, 413 | height: 600, 414 | minWidth: 200, 415 | minHeight: 200, 416 | backgroundColor: '#000000', 417 | icon: path.join(__dirname, { darwin: 'icon.icns', linux: 'icon.png', win32: 'icon.ico' }[process.platform] || 'icon.ico'), 418 | // frame: process.platform !== 'darwin', 419 | // skipTaskbar: process.platform === 'darwin', 420 | // autoHideMenuBar: process.platform === 'darwin', 421 | webPreferences: { 422 | devTools: true, 423 | enableRemoteModule: true, 424 | nodeIntegration: true, 425 | contextIsolation: false, 426 | preload: path.join(__dirname, 'preload.js') 427 | } 428 | }) 429 | mainWindow.on('close', function() { 430 | if(guiWindow){ 431 | guiWindow.close() 432 | } 433 | if(docWindow){ 434 | docWindow.close() 435 | } 436 | }); 437 | mainWindow.on('unresponsive', () => { 438 | console.log('ERROR 61 - Window does not respond, let\'s quit') 439 | app.quit() 440 | }) 441 | 442 | mainWindow.webContents.on('crashed', () => { 443 | console.log('ERROR 62 - Webcontent renderer crashed, let\'s quit') 444 | app.quit() 445 | }) 446 | 447 | mainWindow.webContents.on('destroyed', () => { 448 | console.log('ERROR 63 - Webcontent destroyed, let\'s quit') 449 | app.quit() 450 | }) 451 | mainWindow.loadFile('index.html') 452 | } 453 | function createGUI () { 454 | if(!guiWindow){ 455 | guiWindow = new BrowserWindow({ 456 | width: 800, 457 | height: 400, 458 | backgroundColor: '#000000', 459 | icon: path.join(__dirname, { darwin: 'icon.icns', linux: 'icon.png', win32: 'icon.ico' }[process.platform] || 'icon.ico'), 460 | // frame: process.platform !== 'darwin', 461 | // skipTaskbar: process.platform === 'darwin', 462 | // autoHideMenuBar: process.platform === 'darwin', 463 | webPreferences: { 464 | devTools: true, 465 | enableRemoteModule: true, 466 | nodeIntegration: true, 467 | contextIsolation: false, 468 | preload: path.join(__dirname, 'preload.js') 469 | } 470 | }) 471 | guiWindow.on('close', function() { 472 | guiWindow = false 473 | }); 474 | guiWindow.loadFile('html/gui.html') 475 | } 476 | } 477 | function destroyGUI () { 478 | if(guiWindow){ 479 | guiWindow.close() 480 | } 481 | } 482 | function createRender () { 483 | if(!renderWindow){ 484 | renderWindow = new BrowserWindow({ 485 | width: 800, 486 | height: 400, 487 | backgroundColor: '#000000', 488 | icon: path.join(__dirname, { darwin: 'icon.icns', linux: 'icon.png', win32: 'icon.ico' }[process.platform] || 'icon.ico'), 489 | // frame: process.platform !== 'darwin', 490 | // skipTaskbar: process.platform === 'darwin', 491 | // autoHideMenuBar: process.platform === 'darwin', 492 | webPreferences: { 493 | devTools: true, 494 | enableRemoteModule: true, 495 | nodeIntegration: true, 496 | contextIsolation: false, 497 | preload: path.join(__dirname, 'preload.js') 498 | } 499 | }) 500 | renderWindow.on('close', function() { 501 | renderWindow = false 502 | }); 503 | renderWindow.loadFile('html/render.html') 504 | } 505 | } 506 | function destroyRender () { 507 | if(renderWindow){ 508 | renderWindow.close() 509 | } 510 | } 511 | 512 | function createDoc() { 513 | if(!docWindow){ 514 | docWindow = new BrowserWindow({ 515 | width: 600, 516 | height: 800, 517 | backgroundColor: '#000000', 518 | icon: path.join(__dirname, { darwin: 'icon.icns', linux: 'icon.png', win32: 'icon.ico' }[process.platform] || 'icon.ico'), 519 | webPreferences: { 520 | devTools: false, 521 | enableRemoteModule: false, 522 | nodeIntegration: false, 523 | contextIsolation: true 524 | } 525 | }) 526 | docWindow.on('close', function() { 527 | docWindow = false 528 | }); 529 | docWindow.loadFile('html/readme.html') 530 | } 531 | } 532 | 533 | function createMenu(){ 534 | 535 | const isMac = process.platform === 'darwin' 536 | 537 | const template = [ 538 | // { role: 'appMenu' } 539 | ...(isMac ? [{ 540 | label: app.name, 541 | submenu: [ 542 | { role: 'about' }, 543 | { type: 'separator' }, 544 | { role: 'services' }, 545 | { type: 'separator' }, 546 | { role: 'hide' }, 547 | { role: 'hideothers' }, 548 | { role: 'unhide' }, 549 | { type: 'separator' }, 550 | { role: 'quit' } 551 | ] 552 | }] : []), 553 | // { role: 'fileMenu' } 554 | { 555 | label: 'File', 556 | submenu: [ 557 | { click (s){requireAction(s);}, type: 'normal', label: 'Save',accelerator: 'CommandOrControl+S'}, 558 | { click (s){openFile();}, type: 'normal', label: 'Open',accelerator: 'CommandOrControl+O' }, 559 | { type: 'separator' }, 560 | { 561 | label: 'Export As', 562 | submenu: [ 563 | { click (s){requireAction(s);}, type: 'normal', label: 'JPG', accelerator: 'CommandOrControl+Shift+E' }, 564 | { click (s){requireAction(s);}, type: 'normal', label: 'PNG', accelerator: 'CommandOrControl+E' } 565 | ] 566 | }, 567 | { type: 'separator' }, 568 | { 569 | label: 'Record GIF', 570 | submenu: [ 571 | { click (s){requireAction(s,"GIF");}, type: 'normal', label: 'Start' }, 572 | { click (s){requireAction(s,"GIF");}, type: 'normal', label: 'Stop' } 573 | ] 574 | }, 575 | { 576 | label: 'Record WEBM', 577 | submenu: [ 578 | { click (s){requireAction(s,"WEBM");}, type: 'normal', label: 'Start' }, 579 | { click (s){requireAction(s,"WEBM");}, type: 'normal', label: 'Stop' } 580 | ] 581 | }, 582 | { type: 'separator' }, 583 | { click (s){resetStorage()}, type: 'normal', label: 'Reset Patch',accelerator: process.platform === 'darwin' ? 'Alt+Cmd+R' : 'Alt+Shift+R'}, 584 | { click (s){randomPatch(true)}, type: 'normal', label: 'Random Patch', accelerator: 'CommandOrControl+N'}, 585 | { click (s){randomPatch(false)}, type: 'normal', label: 'True Random Patch', accelerator: 'CommandOrControl+Shift+N'}, 586 | isMac ? { role: 'close' } : { role: 'quit' } 587 | ] 588 | }, 589 | { 590 | label: 'Render', 591 | submenu: [ 592 | { click (s){requireAction(s);}, type: 'normal', label: 'Play'}, 593 | { click (s){requireAction(s);}, type: 'normal', label: 'Pause' }, 594 | { click (s){requireAction(s);}, type: 'normal', label: 'Stop' }, 595 | { type: 'separator' }, 596 | { click (s){requireOneFramejump();}, type: 'normal', label: 'Jump 1 Frame' }, 597 | { click (s){requireTenFramesjump(10);}, type: 'normal', label: 'Jump 10 Frames' }, 598 | { type: 'separator' }, 599 | { click (s){requireRefresh();}, type: 'normal', label: 'Refresh' }, 600 | { click (s){requireAction(s);}, type: 'normal', label: 'Reseed' }, 601 | ] 602 | }, 603 | // { role: 'viewMenu' } 604 | { 605 | label: 'View', 606 | submenu: [ 607 | { role: 'reload' }, 608 | { role: 'forceReload' }, 609 | { role: 'togglefullscreen' }, 610 | { role: 'toggleDevTools' } 611 | ] 612 | }, 613 | // { role: 'windowMenu' } 614 | { 615 | label: 'Window', 616 | submenu: [ 617 | { role: 'minimize' }, 618 | { role: 'zoom' }, 619 | { type: 'separator' }, 620 | { label: 'Toggle GUI', click (s){toggleGUI();}, type: 'normal',accelerator: 'Space'}, 621 | { label: 'Show GUI', click (s){displayGUI(true);}, type: 'normal'}, 622 | { label: 'Hide GUI', click (s){displayGUI(false);}, type: 'normal'}, 623 | { type: 'separator' }, 624 | // { label: 'Undock GUI',click (s){createGUI();}, type: 'normal', }, 625 | // { label: 'Destroy GUI',click (s){destroyGUI();}, type: 'normal', }, 626 | { label: 'Undock Render',click (s){createRender();}, type: 'normal', }, 627 | { label: 'Destroy Render',click (s){destroyRender();}, type: 'normal', }, 628 | ...(isMac ? [ 629 | { type: 'separator' }, 630 | { role: 'front' }, 631 | { type: 'separator' }, 632 | { role: 'window' } 633 | ] : [ 634 | { role: 'close' } 635 | ]) 636 | ] 637 | }, 638 | { 639 | role: 'help', 640 | submenu: [ 641 | { label: 'Open Documentation',click (s){createDoc();}, type: 'normal', } 642 | ] 643 | } 644 | ] 645 | 646 | const menu = Menu.buildFromTemplate(template) 647 | Menu.setApplicationMenu(menu) 648 | } 649 | 650 | app.whenReady().then(() => { 651 | checkForEmptyStorage() 652 | createMenu() 653 | createWindow() 654 | app.on('activate', function () { 655 | if (BrowserWindow.getAllWindows().length === 0) createWindow() 656 | }) 657 | app.on('gpu-process-crashed', () => { 658 | console.log('ERROR 64 - App GPU process has crashed, let\'s quit') 659 | app.quit() 660 | }) 661 | 662 | process.on('uncaughtException', function (err) { 663 | console.log('ERROR 60 - process thrown exception, let\'s quit') 664 | console.log(err) 665 | app.quit() 666 | }) 667 | }) 668 | 669 | app.on('window-all-closed', function () { 670 | if (process.platform !== 'darwin') app.quit() 671 | }) 672 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ACID", 3 | "version": "0.1.2", 4 | "description": "ACID is short for Algorithms Create Image Data. ACID is a general purpose video synthesizer.", 5 | "main": "main.js", 6 | "scripts": { 7 | "start": "electron .", 8 | "build_osx": "electron-packager . ACID --platform=darwin --arch=x64 --out ~/Documents/ --overwrite --icon=icon.icns ; echo 'Built for OSX'", 9 | "build_linux": "electron-packager . ACID --platform=linux --arch=x64 --out ~/Documents/ --overwrite --icon=icon.ico ; echo 'Built for LINUX'", 10 | "build_win": "electron-packager . ACID --platform=win32 --arch=x64 --out ~/Documents/ --overwrite --icon=icon.ico ; echo 'Built for WIN'", 11 | "build_deb": "electron-installer-debian --src ~/Documents/ACID-linux-x64 --dest ~/Documents/ --overwrite --icon=icon.ico --arch amd64" 12 | }, 13 | "repository": "https://github.com/electron/electron-quick-start", 14 | "keywords": [], 15 | "author": "Johannes Hassenstein", 16 | "license": "CC0-1.0", 17 | "devDependencies": { 18 | "electron": "^11.3.0", 19 | "electron-installer-debian": "^3.1.0", 20 | "electron-packager": "^15.1.0" 21 | }, 22 | "dependencies": { 23 | "electron-json-storage": "^4.3.0" 24 | }, 25 | "config": { 26 | "forge": "./forge.config.js" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/preload.js: -------------------------------------------------------------------------------- 1 | // All of the Node.js APIs are available in the preload process. 2 | // It has the same sandbox as a Chrome extension. 3 | window.addEventListener('DOMContentLoaded', () => { 4 | const replaceText = (selector, text) => { 5 | const element = document.getElementById(selector) 6 | if (element) element.innerText = text 7 | } 8 | 9 | for (const type of ['chrome', 'node', 'electron']) { 10 | replaceText(`${type}-version`, process.versions[type]) 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /ideas.txt: -------------------------------------------------------------------------------- 1 | Invert edge param 2 | 3 | ASCII Layer 4 | "ascii": { 5 | "fontsize": 24, 6 | "spacing": 0.2, 7 | "color": "#ffffff", 8 | "chars": "-#+*", 9 | "font": "mon", 10 | "opacity": 0.8, 11 | "mix": "nrm", 12 | "update": 5 13 | }, 14 | this.ascii.style.fontSize = this.config.render.ascii.fontsize + "px" 15 | this.ascii.style.opacity = this.config.render.ascii.opacity 16 | this.ascii.style.color = this.config.render.ascii.color 17 | let asciiStyle = "normal" 18 | switch(this.config.render.ascii.mode){ 19 | case "col": 20 | asciiStyle = "color" 21 | break 22 | case "brn": 23 | asciiStyle = "color-burn" 24 | break 25 | case "dod": 26 | asciiStyle = "color-dodge" 27 | break 28 | case "drk": 29 | asciiStyle = "darken" 30 | break 31 | case "dif": 32 | asciiStyle = "difference" 33 | break 34 | case "exc": 35 | asciiStyle = "exclusion" 36 | break 37 | case "hlg": 38 | asciiStyle = "hard-light" 39 | break 40 | case "hue": 41 | asciiStyle = "hue" 42 | break 43 | case "lgt": 44 | asciiStyle = "lighten" 45 | break 46 | case "lum": 47 | asciiStyle = "luminosity" 48 | break 49 | case "mlt": 50 | asciiStyle = "multiply" 51 | break 52 | case "ovr": 53 | asciiStyle = "overlay" 54 | break 55 | case "sat": 56 | asciiStyle = "saturation" 57 | break 58 | case "scr": 59 | asciiStyle = "screen" 60 | break 61 | case "slg": 62 | asciiStyle = "soft-light" 63 | break 64 | } 65 | this.ascii.style["mix-blend-mode"] = asciiStyle 66 | 67 | BITMAP 68 | 69 | Bitmap Editor 70 | - clear 71 | - load image 72 | - x and y 73 | - store 74 | 75 | Bitmap oscilator 76 | - sources 77 | - scale and stretch 78 | - interpolate 79 | - scroll x and y 80 | - animation: blend/jump/vertical/horizontal 81 | - animationspeed 82 | 83 | 84 | MATRIX 85 | Inputs on 1 Axis 86 | Outpouts on other axis 87 | Connections can change intensity 88 | 89 | Basic Outputs 90 | Main Clock 91 | Render X 92 | Render Y 93 | 94 | Basic Inputs 95 | Render R 96 | Render G 97 | Render B 98 | -------------------------------------------------------------------------------- /img/animated_cover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/animated_cover.gif -------------------------------------------------------------------------------- /img/banner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/banner.gif -------------------------------------------------------------------------------- /img/banner_logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/banner_logo.gif -------------------------------------------------------------------------------- /img/cover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/cover.gif -------------------------------------------------------------------------------- /img/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/example.gif -------------------------------------------------------------------------------- /img/screenshot-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/screenshot-1.jpg -------------------------------------------------------------------------------- /img/screenshot-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/screenshot-1.png -------------------------------------------------------------------------------- /img/screenshot-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/screenshot-2.jpg -------------------------------------------------------------------------------- /img/screenshot-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/screenshot-2.png -------------------------------------------------------------------------------- /img/screenshot-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/screenshot-3.jpg -------------------------------------------------------------------------------- /img/screenshot-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softboydev/acid/cdb44a43b7d2c47faf7fcfd6d4c55846ba84c844/img/screenshot-3.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![](./img/banner_logo.gif) 2 | # ACID 3 | 4 | ACID is short for **A**lgorithms **C**reate **I**mage **D**ata and is a simple, general purpose video synthesizer for creating live visuals and computer generated images and animations. It works somewhat similar to an analog synthesizer with a little bit of Photoshop thrown in. 5 | 6 | ACID features a clean graphic user interface that can be detached. ACID has built in export to PNG and JPG and can record GIFs and WEBM videos of any length straight out of the program. The render window can be detached to use ACID for live visuals. 7 | 8 | This is how the interface looks: 9 | 10 | ![](./img/screenshot-1.jpg) 11 | 12 | *GUI is opened in the main window* 13 | 14 | ![](./img/screenshot-2.jpg) 15 | 16 | *GUI is undocked* 17 | 18 | ![](./img/screenshot-3.jpg) 19 | 20 | *GUI and Render are both undocked* 21 | 22 | ![](./img/example.gif) 23 | 24 | This is how a patch could look. There are currently no available presets but you can use the "Random Patch" function in the menu to get started. You can see 100 random patches in this video: https://www.youtube.com/watch?v=u_rGDhfu_Qk 25 | 26 | ## Installation 27 | 28 | You can either install a build for your platform or run ACID yourself with `npm`. 29 | 30 | To download a build for your platform head over to [acidatm.itch.io/acid](https://acidatm.itch.io/acid) and download a build there. The download is free, there is only an optional donation. 31 | 32 | 33 | Presets can be found in the `/presets` directory or can be downloaded on *itch.io* as well. 34 | 35 | 36 | To run ACID withen *electron.js*, install `npm` and `git` (if you don't have them installed), then open your terminal and run: 37 | 38 | ```bash 39 | git clone https://github.com/acidatm/acid 40 | cd acid/app/ 41 | npm install 42 | npm start 43 | ``` 44 | 45 | ## Acknowledgement 46 | 47 | I was enspired by the works of these people: 48 | 49 | - The ORCA sequencer by Rekka & Devine: https://hundredrabbits.itch.io/ 50 | - The works of Viznut, especially IBNIT: http://countercomplex.blogspot.com/2011/12/ibniz-hardcore-audiovisual-virtual.html 51 | - And various stuff found on esoteric.codes: https://esoteric.codes/s 52 | 53 | ## Documentation 54 | 55 | All values in the GUI range between 0 and 999, where 0 is the minimum value and 999 is the maximum. The GUI can be toggled either with the space bar or using the options in *Menubar > Window*. The GUI can also be opened in a second window. 56 | 57 | The labels next to the sliders can be used to set a slider to specific value. The buttons next to the labels can be used to minimize, center, maximize or randomize the slider value. Both can be disabled from the *set* part of the GUI. 58 | 59 | ### Oscilators 60 | 61 | An oscilator is either a cyclic transfer function or a noise based algorithm. A cyclic transfer function takes a value between 0 and infinity and returns a value between 0 and 1, the exact distribution of the values inbetween is determined by the oscilators waveform. The amount of values after which the oscilator repeats is determined by its frequency. 62 | 63 | You can use oscilators as fixed filters by setting the *spd* parameter to 0. This will stop the oscilator from moving entirely. You can then control the exact character of the filter with the *frq*, *off* and *rot* parameters. 64 | 65 | If you need a constant fixed value from an oscilator, you can use a *sqr* oscilator, with a *spd* of 0 and a low *frq*. You can then control the exact value using the *min* or *max* parameter. 66 | 67 | If you need a completely random texture, create an oscilator with a medium value and apply a high *rnd* effect on it. 68 | 69 | All oscilators have an additional "run" property, which can be set to quickly mute an oscilator. You can toggle it by clicking on "osx" (where x is the oscilator number) in the GUI. The run property behaves identical to the *off* type, but doesnt change the type of the oscilator. 70 | 71 | #### Channels 72 | 73 | All oscilators can send to 3 different channels independently. They send the same basic value to each channel but you can attenuate the value for each channel individually. You can do so from the *rgb* section using the inputs for *r*,*g* and *b*. 74 | 75 | #### Cyclical oscilators 76 | 77 | These are the available cyclical oscilators: 78 | 79 | - **sqr** (Square) - will create a squarewave, that is either high or low, but has no inbetween states 80 | - **pwm** (Pulse) - will create a pulse oscilator (and *Pulse Width Modulation* will be available in the near future) 81 | - **saw** (Sawtooth) - will create a sawtooth wave, that starts high and falls to low in a linear fashion 82 | - **tri** (Triangle) - will create a triangle wave, that switches between high and low in linear fashion 83 | - **sin** (Sine) - will create a sine wave, that switches between high and low in non linear fashion 84 | - **osc** (Oscilator) - will create a flexible oscilator, which can take any shape between a pure triangle over a pure sine to pure square. The pulse width can be modified, which can turn a triangle into a ramp or saw, or change the width of a squarewave. But it can also do any shape inbetween. 85 | 86 | 87 | For each oscilator these are the important parameters: 88 | 89 | - **typ** (Type) - will determine the type of oscilator to use 90 | - **min** (Minimum) - sets the minimum amplitude (normally 0) 91 | - **max** (Maximum) - sets the maximum amplitude (normally 999) 92 | - **lpf** (Low Pass Filter) - Values above this threshold will be cut. The filter behaves relative to *min* and *max* 93 | - **hpf** (High Pass Filter) - Values below this treshold will be cut. The filter behaves relative to *min* and *max* 94 | - **mix** (Mixing) - The way this oscilator should be mixed with other oscilators 95 | - *ADD* (Additive) - Add the value to the mix 96 | - *SUB* (Subtractive) - Removes the value from the mix 97 | - *MLT* (Multiply) - Multiplies the mix with the value 98 | - *DIV* (Divide) - Divides the mix by the value 99 | - **rot** (Oscilator Rotation) - Will rotate the oscilator in 2D space 100 | - **frq** (Oscilator Frequency) - Determines the frequency of the oscilation 101 | - **spd** (Oscilator Speed) - Determines how fast the oscilator moves through 2D space in the direction set by *rot* 102 | - **off** (Oscilator Offset) - Will change the phase of the oscilation, which us really only useful when *speed* is at 0 103 | 104 | The *osc* oscilator has these additional parameters: 105 | 106 | - **cen** (Oscilator Center) - sets the high point of the oscilation relative to the wavelength. 0 means right at the start (which would make a triangle wave a saw wave), 999 means right at the end (which would make a triangle wave a ramp wave) 107 | - **shp** (Oscilator Shape) - determines the general shape of the oscilator. It does so by fading between pure triangle wave (0), pure sine wave (499) and pure squarewave (999) 108 | 109 | #### Noncyclical oscilators 110 | 111 | These are the available, noncyclical oscilators: 112 | 113 | - **plx** (Simplex Noise) - An advanced correlating noise algorithm 114 | - **prl** (Perlin Noise) - A less advanced correlating noise algorithm 115 | - **org** (Organic) - A noise algorithm that creates "organic" shapes like water ripples or woodgrain (it is simplex noise passed through a seeded random number generator) 116 | - **off** (Off) - turns the oscilator off 117 | 118 | The noncyclical oscilators use some of the cyclical oscilator settings, however they are used somewhat different: 119 | 120 | - **frq** (Oscilator Frequency) - Determines the frequency of the noise plane, which will feel more like its resolution or graininess maybe 121 | - **off** (Oscilator Offset) - Will move to a fixed value on the plane of the noise 122 | 123 | The organic oscilator also uses the two additional settings from the *osc* oscilator 124 | 125 | - **cen** (Oscilator Center) - determines how many different steps or layers are generated 126 | - **shp** (Oscilator Shape) - blends between quantised and unquantised noise 127 | 128 | There are also a couple of additional settings for the two noise algorithms, as they are 3 dimensional. The oscilator settings control the z axis, the other two axis are controlled by their respective parameters. All axis have the same set of parameters. 129 | 130 | The noise algorithms are seedable, which means same values in, same values out. You can reseed the noise algorithms from *Menubar > Render > Reseed*. 131 | 132 | ### Effects 133 | 134 | All oscilators can have any number of effects applied to them. Which effects are applied is set by the effects chain ("--- + " in the GUI). Clicking on "+" will add a new effect to the chain, clicking on an effect will flip through the different effect types, clicking on "---" (which will then show "clr") will clear the effect chain. Effects are passed through from left to right. 135 | 136 | - **---** (List) - marks the presence of a list. Clicking will clear the list 137 | - **+** (Add) - can be clicked to add new entrys to the list. 138 | 139 | The settings for all effects in the chain are the same. However you can use the chain to apply effects in different order or multiple times. The settings are set in the *fx* part of the respective GUI section: 140 | 141 | - **bit** (Bitreduction) - Will reduce the number of possible values down to only a single one. 0 means no reduction, 999 means maximum reduction. 142 | - **cmp** (Compression) - Will make lower values higher while influencing higher values less. 143 | - **exp** (Expansion) - Will make lower values even lower while influencing higher values less. Works somewhat in reverse to compression. 144 | - **rnd** (Randomization) - Will randomly change values. A low setting will result in a more "analog" look, while a high setting will make things very glitchy 145 | - **drv** (Drive) - Will amplify all values equally. Can be used as a preamp or overdrive. 146 | 147 | ### Render 148 | 149 | The parameters for the render process can be found under "img". The render process determines how the values generated by ACID and the configuration set in the GUI are used to generate images. Not all settings are available at all times, some may only be visible when a certain color mode or render engine is active. 150 | 151 | - **frm** (Framerate) - the desired framerate for the undocked render window. To not display visible jumbs between frames the render process will render frame after frame and not skip frames. This can result in exported GIFs looking faster. You can see the true FPS in the settings tab 152 | - **res** (Resolution) - resolution for the undocked render window 153 | - **pre** 154 | - **res** (Preview Resolution) - resolution for the main window 155 | - **frm** (Preview Framerate) - framerate for the main window 156 | - **bw** (Black and White) - blends between color and black and white 157 | - **brn** (Burn) - can be used to lighten the image when subpixels are enabled 158 | - **drv** (Drivetype) - this is the clipping stage of the master amplifier, there are 3 settings available: 159 | - **clp** (Clip) - Will simply clip all values over 1 and make them 1 160 | - **mod** (Modify) - Will wrap all values over 1 until they are below 1. 1.5 would become 0.5, 2.3 would become 0.3 and so on. 161 | - **dyn** (Dynamic) - Will redistribute all values on a range between the frames lowest and highest value, making it impossible to clip the amp (however you can use a compressor or drive and a low pass filter to achieve the effect on an oscilator level) 162 | - **clr** (Colormode) - Changes the colormode. You can click on the GUI label to activate a fixed HSL based color mode, which can be helpfull to see how the oscilators effect each other. 163 | - *rgb* (Linear RGB) - ACID can effect a linear RGB space 164 | - *grd* (Gradient) - ACID can effect the value on a range between any amount of colors. The colors are determined by the values in the color list. The black and white values between 0 and 1 are used to determine the position on the gradient. 165 | - *ndx* (Indexed) - works just like gradient. Except its not a gradient but a stepped gradient with no mix between the steps. 166 | 167 | #### Feedback 168 | 169 | The virtual feedback engine simulates true feedback when using a camera that is pointed on a screen that displays the camera image. Simulates, not duplicates. It is different. But based around the same idea. As ACID is deterministic we can now the value of each pixel at any point in time. And that is exactly how the feedback works. We simply don't show all pixels at the same point in time at the same time. 170 | 171 | - **int** (Feedback Intensity) - Intensity of the feedback, basically how far into the future we go at max 172 | - **edg** (Feedback Quantization) - How much the feedback is quantized. This will lead to visible jumps/edges 173 | - **x** (Feedback Center X) - relative x position of the center of the feedback 174 | - **y** (Feedback Center Y) - relative y position of the center of the feedback 175 | - **mix** (Feedback Mix) - mixes between horizontal and vertical feedback 176 | - **bnd** (Feedback Bend) - mixes between linear and feedbacked feedback (you read that right, the feedback can feedback on it self). This will lead to more bended lines then straight lines 177 | - **skw** (Feedback Skew) - mixes between horizontal and vertical bend 178 | - **sqr** (Feedback Squaring/Linearity) - mixes between a linear and a stepped version of the feedback. Linear look like a triangle, stepped like a square (so like classic tv feedback) 179 | - **drk** (Feedback Darken) - makes the feedback darker the further back it is in time (like classic tv feedbacks) 180 | 181 | ### Settings 182 | 183 | The settings part of the GUI can be found under "set". Here you can change default values, GUI styles and some global settings for the render engine. 184 | 185 | - **fps** (True FPS) - display the true FPS 186 | - **wid** (Width) - displays the width of the main window in pixels 187 | - **hei** (Height) - displays the height of the main window in pixels 188 | - **dcl** (Default Color) - Sets the default color when adding a new color in indexed color mode 189 | - **dfx** (Default Effect) - Sets the default effect when adding a new effect to an effects chain 190 | - **fx** (Toggle Effects) - Toggles the usage of effects 191 | - **sub** (Toggle Subpixels) - Toggles the render of subpixels 192 | - **fdb** (Toggle Feedbacl) - Toggles the virtual feedback engine 193 | - **col** (Toggle Colormodes) - Toggles the availability of color modes 194 | - **zom** (Zoom) - Sets the size of the GUI 195 | - **trn** (Transparency) - Sets the transpareny of the GUI in the main window 196 | - **tip** (Tooltips) - Toggles the display of tooltip boxes when hovering over a parameter name 197 | - **lab** (Labels) - Toggles the display of labels next to sliders 198 | - **btn** (Buttons) - Toggles the display of buttons next to sliders 199 | 200 | ### Menubar 201 | 202 | You can access some actions and all import and export dutys from the menubar of the application. 203 | 204 | #### File 205 | 206 | - Save - Save the current patch as a .txt file 207 | - Open - Open a saved patch 208 | - Exports As > JPG - Export the current frame as a JPG of the render (GUI will not be visible) 209 | - Exports As > PNG - Export the current frame as a PNG of the render (GUI will not be visible) 210 | - Record GIF > Start - starts the recording of a GIF of the render (GUI will not be visible). A flashing red dot will appear (the dot is not visible in the GIF). 211 | - Record GIF > Stop - ends the recording of a GIF, creates a .gif file and opens a save dialog 212 | - Record WEBM > Start - recording of a WEBM video of the render (GUI will not be visible). A flashing red dot will appear (the dot is not visible in the WEBM) 213 | - Record WEBM > Stop - ends the recording of a WEBM video, creates a .webm file and opens a save dialog 214 | - Reset Patch - Clears the internal storage and loads the default patch 215 | 216 | #### Render 217 | 218 | - Play - Start the clock for the renderprocess 219 | - Pause - Pauses the clock for the renderprocess 220 | - Stop - Turns the renderprocess off until play is clicked 221 | - Jump 1 Frame - Increments the clock for the render process once and renders once. Useful when trying to get to specific look when having the render paused or stopped. 222 | - Jump 10 Framse - Increments the clock for the render process by 10 and renders once. Useful when trying to get to specific look when having the render paused or stopped. 223 | - Refresh - Simply renders again when the render is stopped manually. Normally any parameter change will trigger a refresh as well 224 | - Reseed - Reseed all noise oscilators and the SRNG for the global effects 225 | 226 | #### Window 227 | 228 | - Open GUI - Opens the GUI in the main window 229 | - Close GUI - Closes the GUI in the main window 230 | - Undock GUI - Creates a new window with the GUI in it, so you can control the render from a seperate window, optimal for VJing 231 | - Destroy GUI - Destroys a created GUI window 232 | - Undock Render - Creates a new window with the render in it, so you can display it in a seperate window, optimal for VJing 233 | - Destroy Render - Destroys a created render window 234 | 235 | #### Help 236 | 237 | - Open Documentation - Opens a new window containing the full documentation (this document) 238 | 239 | ## Releases 240 | 241 | Below you can find release notes on all major releases that had a dedicated build available. Look into the devlog over at [acidatm.itch.io/acid](https://acidatm.itch.io/acid) for more details. 242 | 243 | - **0.1.2** WebGL Update 244 | - ACID is now using WebGL instead of simple canvas which increases performance dramatically 245 | - A new subpixel option to get a more tv or analog look and feel 246 | - A new virtual feedback mode that simulates real camera to tv to camera feedback 247 | - A dedicated render only window can be undocked now, which makes use for VJing way better 248 | - Specific settings for framerate and resolution in main and undocked window 249 | - Additional settings for black and white fading and color burn out 250 | - Color modes are now based on 3 color channels instead of a singular value 251 | - Gradient color modes can now have any amount of steps 252 | - Many performance optimisations in the code 253 | - Additional optimization settings that can disable certain parts of the program for a better performance 254 | - Two new oscilators added: *pwm*, which is a pulse oscilator, and *org* which is a noise algorithm specialised for organic shape creation 255 | - A new random patch option in the menu 256 | - Keyboard shortcuts for various menu functions 257 | - Added analytics such as true framerate, width and height 258 | - Removed hsl color mode (but will be back soon, no worries) 259 | - Removed different render engines for now 260 | - Removed some unused parameters from the codebase 261 | - Removed some unnecessary settings in the GUI 262 | - Reverted to old window styles on Mac OS 263 | - Oscilator frequency as no longer linked to resolution 264 | - Renderloop is now called recursive at the start of the loop, making each frame roughly equal, no matter the calculation time 265 | - **0.1.1** Release of the full alpha version 266 | - Reworked the *lpf* and *hpf* parameters to be relative to the *min* and *max* property 267 | - Removed the *amp* parameter on all oscilators, as it's behavior can be duplicated using the *max* parameter 268 | - Reworked the *amp* parameter on the bus to not be able to overdrive the sum (use a *drv* effect instead) 269 | - Reworked all algorithmic oscilators to use fewer parameters 270 | - Added *off* as an oscilator type. Works just like toggling the oscilator when clicking on *osx* 271 | - Added *hsl* as a color mode 272 | - Enabled full 360 degree turning of oscilators with the *mod* parameter and removed the *rmp* oscilator shape (as its just a rotated *saw* oscilator) 273 | - Added a new oscilator shape *osc*, that can be faded between pure triangle over pure sine to pure square and also has pulse width modulation capabilitys. 274 | - Added sliders to the GUI, made number input optional, added optional buttons 275 | - Made the GUI have linear values for zoom and transparency, instead of different, fixed settings 276 | - Removed global effects (*err*) and instead added two more oscilators 277 | - Reworked the complex 2D render engine (*c2d*) to have dedicated values for the radius of all corners and the padding on all sides as well as a simple 2d render engine running "below" it, to control the background color of each cell 278 | - Made the compressor (*cmp*) work in one direction only, added a new expander (*exp*) effect that now works in reverse to compression 279 | - Added optional tooltips to the GUI 280 | - Added automatic load of a default patch upon first (or resetted) start up 281 | - Added a patch reset option to clear out a faulty storage and to automatically load a default patch 282 | - Added a stop option, to completely disable the rerender of the scene until play is hit 283 | - Added a framejump option, to increment the t value, when the render is paused or stopped 284 | - Fixed a bug, where the GUI would jump when an input was changed 285 | - Removed deprecated electron.js functions 286 | - Added proper error handling in case of crashes 287 | - Did some visual changes on the GUI 288 | - Unused parameters are now hidden in the UI until they are needed 289 | - **0.1.0** Release of the initial alpha version 290 | 291 | ## Future Plans 292 | 293 | This is a very early state of this software, I plan to extend it regularly. I currently plan to do these things: 294 | 295 | - Adding LFOs and sequencers 296 | - Adding an FM based oscilator 297 | - Adding multiple presets within one patch file 298 | - Adding audioreactive functionality 299 | - Adding multiple render engines 300 | - Adding bitmaps, image to bitmap import and tools to manipulate and animate both 301 | - Adding a built-in, keyframe based timeline to automate parameter changes in a video editor like fashion 302 | - Adding basic MIDI support, so that parameters can be controlled with CC and presets may be changed with PCM 303 | - Adding OSC support, so that parameters can be controlled with software like ORCA 304 | - Adding a Serial Port implementation, so that parameters can be controlled with microcontroller based hardware and/or sensors 305 | - Reworking the GUI to use React.js 306 | - Reworking the GUI to use modular patching 307 | - Adding a shell like interface with a command line 308 | - Adding a custom live coding environment 309 | - Restructuring the code to be more dev friendly, so other people can write new engines, effects, oscilators and so on 310 | - Adding live performance features such as momentary effects and preprogrammed parameter changes in scenes 311 | 312 | At this point you know all there is to know. Now go and make something on ACID :) 313 | --------------------------------------------------------------------------------