├── F9c83O4XEAAZ0bA.jpeg ├── LICENSE.txt ├── README.md ├── example-app.md ├── image-1.png └── image.png /F9c83O4XEAAZ0bA.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonbrander/generative-ui-playbook/3d2a72a047cde92ca8f921a968844f1c9e516d39/F9c83O4XEAAZ0bA.jpeg -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | License: CC-BY 4.0 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution 4.0 International Public License 58 | 59 | By exercising the Licensed Rights (defined below), You accept and agree 60 | to be bound by the terms and conditions of this Creative Commons 61 | Attribution 4.0 International Public License ("Public License"). To the 62 | extent this Public License may be interpreted as a contract, You are 63 | granted the Licensed Rights in consideration of Your acceptance of 64 | these terms and conditions, and the Licensor grants You such rights in 65 | consideration of benefits the Licensor receives from making the 66 | Licensed Material available under these terms and conditions. 67 | 68 | 69 | Section 1 -- Definitions. 70 | 71 | a. Adapted Material means material subject to Copyright and Similar 72 | Rights that is derived from or based upon the Licensed Material 73 | and in which the Licensed Material is translated, altered, 74 | arranged, transformed, or otherwise modified in a manner requiring 75 | permission under the Copyright and Similar Rights held by the 76 | Licensor. For purposes of this Public License, where the Licensed 77 | Material is a musical work, performance, or sound recording, 78 | Adapted Material is always produced where the Licensed Material is 79 | synched in timed relation with a moving image. 80 | 81 | b. Adapter's License means the license You apply to Your Copyright 82 | and Similar Rights in Your contributions to Adapted Material in 83 | accordance with the terms and conditions of this Public License. 84 | 85 | c. Copyright and Similar Rights means copyright and/or similar rights 86 | closely related to copyright including, without limitation, 87 | performance, broadcast, sound recording, and Sui Generis Database 88 | Rights, without regard to how the rights are labeled or 89 | categorized. For purposes of this Public License, the rights 90 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 91 | Rights. 92 | 93 | d. Effective Technological Measures means those measures that, in the 94 | absence of proper authority, may not be circumvented under laws 95 | fulfilling obligations under Article 11 of the WIPO Copyright 96 | Treaty adopted on December 20, 1996, and/or similar international 97 | agreements. 98 | 99 | e. Exceptions and Limitations means fair use, fair dealing, and/or 100 | any other exception or limitation to Copyright and Similar Rights 101 | that applies to Your use of the Licensed Material. 102 | 103 | f. Licensed Material means the artistic or literary work, database, 104 | or other material to which the Licensor applied this Public 105 | License. 106 | 107 | g. Licensed Rights means the rights granted to You subject to the 108 | terms and conditions of this Public License, which are limited to 109 | all Copyright and Similar Rights that apply to Your use of the 110 | Licensed Material and that the Licensor has authority to license. 111 | 112 | h. Licensor means the individual(s) or entity(ies) granting rights 113 | under this Public License. 114 | 115 | i. Share means to provide material to the public by any means or 116 | process that requires permission under the Licensed Rights, such 117 | as reproduction, public display, public performance, distribution, 118 | dissemination, communication, or importation, and to make material 119 | available to the public including in ways that members of the 120 | public may access the material from a place and at a time 121 | individually chosen by them. 122 | 123 | j. Sui Generis Database Rights means rights other than copyright 124 | resulting from Directive 96/9/EC of the European Parliament and of 125 | the Council of 11 March 1996 on the legal protection of databases, 126 | as amended and/or succeeded, as well as other essentially 127 | equivalent rights anywhere in the world. 128 | 129 | k. You means the individual or entity exercising the Licensed Rights 130 | under this Public License. Your has a corresponding meaning. 131 | 132 | 133 | Section 2 -- Scope. 134 | 135 | a. License grant. 136 | 137 | 1. Subject to the terms and conditions of this Public License, 138 | the Licensor hereby grants You a worldwide, royalty-free, 139 | non-sublicensable, non-exclusive, irrevocable license to 140 | exercise the Licensed Rights in the Licensed Material to: 141 | 142 | a. reproduce and Share the Licensed Material, in whole or 143 | in part; and 144 | 145 | b. produce, reproduce, and Share Adapted Material. 146 | 147 | 2. Exceptions and Limitations. For the avoidance of doubt, where 148 | Exceptions and Limitations apply to Your use, this Public 149 | License does not apply, and You do not need to comply with 150 | its terms and conditions. 151 | 152 | 3. Term. The term of this Public License is specified in Section 153 | 6(a). 154 | 155 | 4. Media and formats; technical modifications allowed. The 156 | Licensor authorizes You to exercise the Licensed Rights in 157 | all media and formats whether now known or hereafter created, 158 | and to make technical modifications necessary to do so. The 159 | Licensor waives and/or agrees not to assert any right or 160 | authority to forbid You from making technical modifications 161 | necessary to exercise the Licensed Rights, including 162 | technical modifications necessary to circumvent Effective 163 | Technological Measures. For purposes of this Public License, 164 | simply making modifications authorized by this Section 2(a) 165 | (4) never produces Adapted Material. 166 | 167 | 5. Downstream recipients. 168 | 169 | a. Offer from the Licensor -- Licensed Material. Every 170 | recipient of the Licensed Material automatically 171 | receives an offer from the Licensor to exercise the 172 | Licensed Rights under the terms and conditions of this 173 | Public License. 174 | 175 | b. No downstream restrictions. You may not offer or impose 176 | any additional or different terms or conditions on, or 177 | apply any Effective Technological Measures to, the 178 | Licensed Material if doing so restricts exercise of the 179 | Licensed Rights by any recipient of the Licensed 180 | Material. 181 | 182 | 6. No endorsement. Nothing in this Public License constitutes or 183 | may be construed as permission to assert or imply that You 184 | are, or that Your use of the Licensed Material is, connected 185 | with, or sponsored, endorsed, or granted official status by, 186 | the Licensor or others designated to receive attribution as 187 | provided in Section 3(a)(1)(A)(i). 188 | 189 | b. Other rights. 190 | 191 | 1. Moral rights, such as the right of integrity, are not 192 | licensed under this Public License, nor are publicity, 193 | privacy, and/or other similar personality rights; however, to 194 | the extent possible, the Licensor waives and/or agrees not to 195 | assert any such rights held by the Licensor to the limited 196 | extent necessary to allow You to exercise the Licensed 197 | Rights, but not otherwise. 198 | 199 | 2. Patent and trademark rights are not licensed under this 200 | Public License. 201 | 202 | 3. To the extent possible, the Licensor waives any right to 203 | collect royalties from You for the exercise of the Licensed 204 | Rights, whether directly or through a collecting society 205 | under any voluntary or waivable statutory or compulsory 206 | licensing scheme. In all other cases the Licensor expressly 207 | reserves any right to collect such royalties. 208 | 209 | 210 | Section 3 -- License Conditions. 211 | 212 | Your exercise of the Licensed Rights is expressly made subject to the 213 | following conditions. 214 | 215 | a. Attribution. 216 | 217 | 1. If You Share the Licensed Material (including in modified 218 | form), You must: 219 | 220 | a. retain the following if it is supplied by the Licensor 221 | with the Licensed Material: 222 | 223 | i. identification of the creator(s) of the Licensed 224 | Material and any others designated to receive 225 | attribution, in any reasonable manner requested by 226 | the Licensor (including by pseudonym if 227 | designated); 228 | 229 | ii. a copyright notice; 230 | 231 | iii. a notice that refers to this Public License; 232 | 233 | iv. a notice that refers to the disclaimer of 234 | warranties; 235 | 236 | v. a URI or hyperlink to the Licensed Material to the 237 | extent reasonably practicable; 238 | 239 | b. indicate if You modified the Licensed Material and 240 | retain an indication of any previous modifications; and 241 | 242 | c. indicate the Licensed Material is licensed under this 243 | Public License, and include the text of, or the URI or 244 | hyperlink to, this Public License. 245 | 246 | 2. You may satisfy the conditions in Section 3(a)(1) in any 247 | reasonable manner based on the medium, means, and context in 248 | which You Share the Licensed Material. For example, it may be 249 | reasonable to satisfy the conditions by providing a URI or 250 | hyperlink to a resource that includes the required 251 | information. 252 | 253 | 3. If requested by the Licensor, You must remove any of the 254 | information required by Section 3(a)(1)(A) to the extent 255 | reasonably practicable. 256 | 257 | 4. If You Share Adapted Material You produce, the Adapter's 258 | License You apply must not prevent recipients of the Adapted 259 | Material from complying with this Public License. 260 | 261 | 262 | Section 4 -- Sui Generis Database Rights. 263 | 264 | Where the Licensed Rights include Sui Generis Database Rights that 265 | apply to Your use of the Licensed Material: 266 | 267 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 268 | to extract, reuse, reproduce, and Share all or a substantial 269 | portion of the contents of the database; 270 | 271 | b. if You include all or a substantial portion of the database 272 | contents in a database in which You have Sui Generis Database 273 | Rights, then the database in which You have Sui Generis Database 274 | Rights (but not its individual contents) is Adapted Material; and 275 | 276 | c. You must comply with the conditions in Section 3(a) if You Share 277 | all or a substantial portion of the contents of the database. 278 | 279 | For the avoidance of doubt, this Section 4 supplements and does not 280 | replace Your obligations under this Public License where the Licensed 281 | Rights include other Copyright and Similar Rights. 282 | 283 | 284 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 285 | 286 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 287 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 288 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 289 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 290 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 291 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 292 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 293 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 294 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 295 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 296 | 297 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 298 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 299 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 300 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 301 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 302 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 303 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 304 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 305 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 306 | 307 | c. The disclaimer of warranties and limitation of liability provided 308 | above shall be interpreted in a manner that, to the extent 309 | possible, most closely approximates an absolute disclaimer and 310 | waiver of all liability. 311 | 312 | 313 | Section 6 -- Term and Termination. 314 | 315 | a. This Public License applies for the term of the Copyright and 316 | Similar Rights licensed here. However, if You fail to comply with 317 | this Public License, then Your rights under this Public License 318 | terminate automatically. 319 | 320 | b. Where Your right to use the Licensed Material has terminated under 321 | Section 6(a), it reinstates: 322 | 323 | 1. automatically as of the date the violation is cured, provided 324 | it is cured within 30 days of Your discovery of the 325 | violation; or 326 | 327 | 2. upon express reinstatement by the Licensor. 328 | 329 | For the avoidance of doubt, this Section 6(b) does not affect any 330 | right the Licensor may have to seek remedies for Your violations 331 | of this Public License. 332 | 333 | c. For the avoidance of doubt, the Licensor may also offer the 334 | Licensed Material under separate terms or conditions or stop 335 | distributing the Licensed Material at any time; however, doing so 336 | will not terminate this Public License. 337 | 338 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 339 | License. 340 | 341 | 342 | Section 7 -- Other Terms and Conditions. 343 | 344 | a. The Licensor shall not be bound by any additional or different 345 | terms or conditions communicated by You unless expressly agreed. 346 | 347 | b. Any arrangements, understandings, or agreements regarding the 348 | Licensed Material not stated herein are separate from and 349 | independent of the terms and conditions of this Public License. 350 | 351 | 352 | Section 8 -- Interpretation. 353 | 354 | a. For the avoidance of doubt, this Public License does not, and 355 | shall not be interpreted to, reduce, limit, restrict, or impose 356 | conditions on any use of the Licensed Material that could lawfully 357 | be made without permission under this Public License. 358 | 359 | b. To the extent possible, if any provision of this Public License is 360 | deemed unenforceable, it shall be automatically reformed to the 361 | minimum extent necessary to make it enforceable. If the provision 362 | cannot be reformed, it shall be severed from this Public License 363 | without affecting the enforceability of the remaining terms and 364 | conditions. 365 | 366 | c. No term or condition of this Public License will be waived and no 367 | failure to comply consented to unless expressly agreed to by the 368 | Licensor. 369 | 370 | d. Nothing in this Public License constitutes or may be interpreted 371 | as a limitation upon, or waiver of, any privileges and immunities 372 | that apply to the Licensor or You, including from the legal 373 | processes of any jurisdiction or authority. 374 | 375 | 376 | ======================================================================= 377 | 378 | Creative Commons is not a party to its public 379 | licenses. Notwithstanding, Creative Commons may elect to apply one of 380 | its public licenses to material it publishes and in those instances 381 | will be considered the “Licensor.” The text of the Creative Commons 382 | public licenses is dedicated to the public domain under the CC0 Public 383 | Domain Dedication. Except for the limited purpose of indicating that 384 | material is shared under a Creative Commons public license or as 385 | otherwise permitted by the Creative Commons policies published at 386 | creativecommons.org/policies, Creative Commons does not authorize the 387 | use of the trademark "Creative Commons" or any other trademark or logo 388 | of Creative Commons without its prior written consent including, 389 | without limitation, in connection with any unauthorized modifications 390 | to any of its public licenses or any other arrangements, 391 | understandings, or agreements concerning use of licensed material. For 392 | the avoidance of doubt, this paragraph does not form part of the 393 | public licenses. 394 | 395 | Creative Commons may be contacted at creativecommons.org. 396 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generative UI Playbook 2 | 3 | Authors: Gordon Brander, Ben Follington 4 | 5 | A collection of theories, patterns, tricks, and intuitions about generative UI. Begins with high-level theory, and works its way down to pragmatic notes on practice. 6 | 7 | # The theory of generative systems 8 | 9 | ## Emergence 10 | 11 | Generative UI should be capable of emergence. Emergence is when a system’s behavior is more than the sum of its parts. 12 | 13 | Emergent systems exhibit: 14 | 15 | - Change: emergent systems are constantly in flux. These changes are often nonlinear, and can be difficult to predict. 16 | - Patterns: generative systems aren’t just random. General structures arise and repeat. 17 | - Rules: underneath emergence is a system of rules, or a grammar. 18 | 19 | Examples of emergence: 20 | 21 | - Complex coordination emerging from ants laying down pheromone trails 22 | - Price signals emerging from market trades 23 | - Consciousness emerging from networks of neurons 24 | 25 | Required ingredients for emergence: 26 | 27 | - Mechanisms, building blocks, modules, subassemblies, that make up the “stuff” of the system. 28 | - Rules, defining how mechanisms are combined. 29 | - Feedback, where the next step is the recursive function of new information plus the sum of all previous steps. 30 | 31 | In some some sense, emergence is just the product of these ingredients. There are no extra “hidden” variables. But emergence is not *reducible* to the sum of these parts. That’s because emergent systems have a “state”, or “memory” that builds up through feedback with their environment. The particular history of a system is the irreducible “magic” ingredient that generates emergent behavior. 32 | 33 | > Emergence is above all a product of coupled, context-dependent interactions. Technically these interactions, and the resulting system, are nonlinear. (John H. Holland, 1998, Emergence) 34 | 35 | When observing an emergent system, watch for these important features: 36 | 37 | - Feedback: Produces nonlinear behavior and acts as “memory”. 38 | - Mechanisms: Specific interactions that produce effects. 39 | - Agents: Independent parts of the system where the level of internal cooperation exceeds the level of external cooperation. 40 | - Hierarchy: arises as a byproduct of recursive combination. 41 | - Tipping points: Thresholds where the system shifts from one kind of behavior to another. 42 | - [Keystone species](https://en.wikipedia.org/wiki/Keystone_species): Parts of a mature ecosystem that become load-bearing lynchpins. 43 | - Decentralization: Centralized coordination acts as a severe constraint on emergence. Decentralized systems can try more things in parallel. 44 | 45 | More reading: 46 | 47 | - [Emergence](https://www.amazon.com/Emergence-Chaos-Order-Helix-Books/dp/0738201421), John H. Holland, 1998 48 | - [Thinking in Systems](https://www.amazon.com/Thinking-Systems-Donella-H-Meadows/dp/1603580557), Donella Meadows, 2008 49 | - [Complexity, a guided tour](https://www.amazon.com/Complexity-Guided-Tour-Melanie-Mitchell/dp/0199798109), Melanie Mitchell, 2011 50 | - [More is Different](https://www.tkm.kit.edu/downloads/TKM1_2011_more_is_different_PWA.pdf), Philip Anderson, 1972 51 | - [50 Years of More is Different](https://www.nature.com/articles/s42254-022-00483-x), Steven Strogatz, Sara Walker, et al, 2022 52 | 53 | ## Evolution 54 | 55 | Evolution emerges in any system with: 56 | 57 | - Mutation 58 | - Memory 59 | - Selection 60 | 61 | You can look at many different systems through this lens, including social networks and multiplayer software. It’s not an ecosystem if it doesn’t evolve. 62 | 63 | Questions: 64 | 65 | - What parts of the system are mutating, changing? 66 | - Where is memory stored? How? Feedback? Culture? In writing? Somewhere else? 67 | - What selection pressures are present? What do they select for? Which should be present? 68 | 69 | ## Composability and compositionality 70 | 71 | Emergence arises from mechanisms combined according to some rules. We call this *composition*, or in mathematics, *compositionality*. 72 | 73 | > Compositionality is the principle that a system should be designed by composing together smaller subsystems, and reasoning about the system should be done recursively on its structure. (Jules Hedges, [On Compositionality](https://julesh.com/2017/04/22/on-compositionality/)) 74 | 75 | Other related concepts are modularity and reductionism. However compositionality takes things a step further. It is a formal mathematical property, requiring composition *without side-effects*. 76 | 77 | > More generally, I claim that the opposite of compositionality is emergent effects. The common definition of emergence is a system being “more than the sum of its parts”, and so it is easy to see that such a system cannot be understood only in terms of its parts, i.e. it is not compositional. Moreover I claim that non-compositionality is a barrier to scientific understanding, because it breaks the reductionist methodology of always dividing a system into smaller components and translating explanations into lower levels. (Jules Hedges, [On Compositionality](https://julesh.com/2017/04/22/on-compositionality/)) 78 | 79 | We said earlier that we *want* emergence, so what gives? Well, emergence is difficult to reason about using our limited symbolic cognition. 80 | 81 | Compositionality can be a useful property for parts of a system that require *proofs* of particular properties. Compositionality is easily treatable through mathematics precisely *because* it excludes the messy nonlinear effects of emergence. 82 | 83 | > Here we see that emergence in rule-governed systems comes close to being the obverse of reduction. (John H. Holland, 1998, Emergence) 84 | 85 | How do you get compositionality? Avoid state, avoid mutation, compose pure functions. 86 | 87 | Know where in the system you want emergence, and where in the system you want compositionality. 88 | 89 | More reading: 90 | 91 | - [On Compositionality](https://julesh.com/2017/04/22/on-compositionality/), Jules Hedges, 2017 92 | - [Compositional components, emergent protocols](https://subconscious.substack.com/p/compositionality), Gordon Brander 93 | 94 | ## Multiple levels of composition 95 | 96 | The most expressive generative systems compose at multiple levels. 97 | 98 | - Letters combine into words, which describe ideas. 99 | - DNA basepairs combine into genes, which encode traits. 100 | - Minecraft lets you craft new blocks with new properties from combinations of other blocks. 101 | 102 | When components of an alphabet are combined, they often express meanings which are different in kind to the alphabet that makes them up. Each new level of meaning forms another alphabet, at another level. 103 | 104 | Each level has path-dependencies on the levels beneath. Lower levels constrain higher ones. 105 | 106 | > At each level of observation the persistent combinations of the previous level constrain what emerges at the next level. (John H. Holland, 1998, Emergence) 107 | 108 | The most powerful generative systems enable composition at multiple levels. This allows for great expressive power across different kinds of meanings, at multiple levels of complexity. 109 | 110 | ## Chomsky Hierarchy 111 | 112 | Noam Chomsky famously has a theory that language is reducible to a kind of structured grammar. Maybe he’s right, maybe not. Regardless, a lot of the theoretical underpinnings he developed are tremendously useful when reasoning about grammatical systems... any system with a kit of parts and rules for combining them. 113 | 114 | The [Chomsky hierarchy of languages](https://en.wikipedia.org/wiki/Chomsky_hierarchy) became a fundamental underpinning of formal language theory and computer science. It is used to reason about everything from parsers to regular expressions. 115 | 116 | It states that four different classes of formal grammars exist, which can generate increasingly complex language: 117 | 118 | 1. Regular (simplest) 119 | 2. Context-free 120 | 3. Context-sensitive 121 | 4. Recursively enumerable (most complex) 122 | 123 | Each subsequent class can generate the language of all simpler classes, plus more. 124 | 125 | This way of reasoning about grammar systems is useful for more than just language, and can be applied to many kinds of generative system that include modularity, hierarchy, and variety (for example, see “Generative Grammars” below). 126 | 127 | ## Combinatorial space 128 | 129 | Combinatorial space maps the possible states of a system as a landscape. This way of seeing can be applied to many systems. Evolutionary biologists think of the possibility space of traits as a [fitness landscape](https://en.wikipedia.org/wiki/Fitness_landscape), or the possibility space of phenotypes as a [morphospace](https://www.cambridge.org/core/books/abs/geometry-of-evolution/concept-of-the-theoretical-morphospace/3361BD3C95773CC970DCA25F01C0C7D8). AI researchers can think of the loss function of an algorithm as a [loss landscape](https://losslandscape.com/). 130 | 131 | You will run into three kinds of combinatorial spaces: 132 | 133 | - Simple landscape: picture a landscape with a single hill. Optimization problems are simple landscapes. 134 | - Rugged landscape: imagine a mountain range with many peaks and valleys, many right and wrong answers. Optimization doesn’t work here. Hill climbing will get you stuck on the nearest peak (local maxima), thinking it is the highest peak. Tradeoffs dominate. A bit of adventurous random wandering is beneficial. 135 | - Dancing landscape: imagine the roiling waves of a stormy ocean. You can summit a peak, but the peaks don’t stand still. If you want to survive, you’ll have to keep moving. 136 | 137 | When building ecosystems, we’re trying to create a dancing landscape. 138 | 139 | More reading: 140 | 141 | - [Possibility space](https://subconscious.substack.com/p/possibility-space) 142 | - https://complexity.risd.edu/methods-insights/dancing-landscapes/ 143 | 144 | ## Open-endedness 145 | 146 | Open-endedness is a special condition that arises in some emergent systems. Many systems will settle toward a single state, or cycle through just a handful of states. 147 | 148 | We want a general-purpose generative UI system to be open-ended, because open-endedness is where innovation comes from. The innovation comes from the system surprising itself. 149 | 150 | It turns out that continually generating innovation is difficult to do. AIs and evolutionary algorithms tend to converge and get stuck. Yet, we know that some systems do seem to continually innovate: people continue to invent new things, markets continue to disrupt incumbents, life keeps evolving new species. 151 | 152 | So how do we create generative systems capable of continual innovation? That’s an ongoing area of research in AI and evolutionary computing, called “[open-endedness](https://www.oreilly.com/radar/open-endedness-the-last-grand-challenge-youve-never-heard-of/)”. We don’t have answers yet, just heuristics. 153 | 154 | A basic requirement for open-endedness is **unlimited composition**. For example, DNA has just four basepairs, but no limits on the length of the chain. If the chain were limited to 8, 10, 200 basepairs, the combinatorial space of DNA would be constrained. The lack of a limit on length acts as an enabler for open-endedness. 155 | 156 | One way to get open-endedness is to cheat and import it: 157 | 158 | - People are open-ended. 159 | - Turing-complete scripting is open-ended. 160 | 161 | What prevents open-endedness? 162 | 163 | - Fixed categories: imposing top-down categorization ends open-endedness before it has a chance to start. The categorization creates a fixed possibility space. DOA. Consider how the App Store app categories are fixed. What if you create an innovation that doesn’t fit into these categories? It’s banned, by definition. 164 | - Fixed filters: culling possibilities according to a fixed set of rules has the same effect as fixed categories. It causes convergence. The rules must evolve with the game. 165 | - Fixed roles: in nature, hierarchy and specialization arise from the bottom-up, not from the top-down. These ecosystems role are contextual and constantly changing. 166 | - Fixed fitness functions: by definition, these create fixed possibility landscapes. In [Signals and Boundaries](https://mitpress.mit.edu/9780262525930/signals-and-boundaries/), John H. Holland points out that a truly open-ended fitness function would have to take in the whole world-state as its input. In other words, fitness in nature is defined by coevolution between species. It’s constantly changing and being changed as everything else changes. 167 | 168 | More reading: 169 | 170 | - [Open-endedness: The last grand challenge you’ve never heard of](https://www.oreilly.com/radar/open-endedness-the-last-grand-challenge-youve-never-heard-of/), Kenneth O. Stanley, Joel Lehman and Lisa Soros 171 | - [Stepping stones in possibility space](https://subconscious.substack.com/p/stepping-stones-in-possibility-space) 172 | - [Why Greatness Cannot Be Planned](https://www.amazon.com/Why-Greatness-Cannot-Planned-Objective/dp/3319155237), Kenneth O. Stanley, Joel Lehman, 2015 173 | 174 | ## Requisite variety 175 | 176 | *[Variety](https://en.wikipedia.org/wiki/Variety_(cybernetics))* is a measure of how many different states a system can produce... literally by just counting them. 177 | 178 | The Law of Requisite Variety says “who has the most variety drives the plot”. 179 | 180 | > Ashby’s Law of Requisite Variety: The variety of a regulator must be at least as large as that of the system it regulates. 181 | 182 | When observing an ecosystem, ask: 183 | 184 | - Who has the most variety? 185 | - How is the variety generated? 186 | - Variety is limited by inputs. Where are the inputs? What limits them? 187 | 188 | # Generative systems in practice 189 | 190 | ## Find the building blocks 191 | 192 | Generative systems are made of mechanisms, or building blocks, or modules. 193 | 194 | Your goal in designing a generative system is to find a set of mechanisms that can be combined to generate desired behaviors, as well as other interesting behaviors beyond those you can ask for and imagine. 195 | 196 | Getting there requires a lot of play, and an eye for recognizing where you can draw a line around a building block, and which building blocks are open-ended. 197 | 198 | ## Design universal interfaces 199 | 200 | Consider the lego dot. It’s a simple interface. Every lego, no matter the shape exposes this same interface. That means every lego can be combined with every other lego. The combinatorial space of a lego pair is the exponent of every lego brick. The more universal the API, the broader the combinatorial space, the more kinds of unexpected combinations can occur. 201 | 202 | So, create universal interfaces. For example, don’t just create a verb, create a *verb that can act on many objects*. 203 | 204 | > Verbs that can act on many objects. This is possibly the single most powerful thing you can do to make an interesting game. If you give a player a gun that can only shoot bad guys, you have a very simple game. But if that same gun can be used to shoot a lock off a door, break a window, hunt for food, pop a car tire, or write a message on the wall, now you start to enter a world of many possibilities. ([The Art of Game Design](https://schellgames.com/art-of-game-design), by Jesse Schell) 205 | 206 | More reading: 207 | 208 | - [Verbs that can act on many objects](https://gordonbrander.com/pattern/verbs-that-can-act-on-many-objects/) 209 | 210 | ## Carefully select ingredients + rules + randomness 211 | 212 | A good generating system is often just carefully selected ingredients, rules, and randomness. 213 | 214 | The quality of the meal depends upon the quality of the ingredients. Garbage in, garbage out. Take a look at a successful generative system and you’ll see carefully crafted components: 215 | 216 | - Every tarot card has a rich tapestry of symbols, laden with multiple meanings. These symbols interact in rich ways when you combine different cards and layouts. 217 | - Each [Oblique Strategy](https://en.wikipedia.org/wiki/Oblique_Strategies) is calibrated to provoke maximum generative ambiguity. 218 | - Lego colors and shapes are carefully chosen to work together and combine to make interesting structures. 219 | 220 | Ingredients and rules provide guidance, randomness creates surprise. 221 | 222 | ## No wrong answers 223 | 224 | Sometimes we can create generative systems where the possibility space contains mostly good, or only good solutions. This tends to work best with more constrained generators, and where you can carefully curate the ingredients and rules. 225 | 226 | Examples: 227 | 228 | - There are no bad I-Ching hexagrams 229 | - There are no incorrect Tarot card combinations 230 | - Color palette generators can be designed to always produce useful combinations by constraining specific contrast ranges and relationships (complementary, triadic, etc) 231 | 232 | You can often create generators that are very expressive, yet consistently deliver impressive results. They seem to seek toward good outcomes. Yet, it is still worth noting that there is a fundamental tradeoff between constraint and expressivity. 233 | 234 | In practice we often want tools that ride this line between constraint and expressivity. Consider a pottery wheel. It constrains movement along one axis (vertical), but amplifies your agency to express ideas along another (horiztonal). Consider what axes of agency are meaningful in a given context. 235 | 236 | It can sometimes be useful to start with a less expressive generative system that has only “good answers”, and progressively excavate mechanisms that enable more expressivity over time. 237 | 238 | ## Unix philosophy 239 | 240 | In software, we talk about the [Unix Philosophy](https://en.wikipedia.org/wiki/Unix_philosophy): 241 | 242 | - Write programs that do one thing and do it well. 243 | - Write programs to work together. 244 | - Write programs to handle text streams, because that is a universal interface. 245 | 246 | This set of intuitions will serve us well when designing generative systems. 247 | 248 | - Create mechanisms that do one thing and do it well. 249 | - Create mechanisms to work together 250 | - Create mechanisms with universal interfaces 251 | 252 | ## You’re designing an alphabet 253 | 254 | [An interface is a language](https://mkremins.github.io/blog/controls-as-language/) for communicating with computers. When you’re designing generative UI, you’re designing an alphabet. 255 | 256 | What is an alphabet? [A kit of parts, plus rules for combining them](https://patterns.architexturez.net/doc/az-cf-173046). 257 | 258 | Consider your generative system through the lens of language: 259 | 260 | - What are the letters, words, sentences, paragraphs? 261 | - What is the grammar by which these things are combined? 262 | - What are the parts of speech (nouns, verbs, adverbs, adjectives...)? 263 | 264 | More reading: 265 | 266 | - [Systems Generating Systems](https://patterns.architexturez.net/doc/az-cf-173046), Christopher Alexander, 1968 267 | - [Controls as Language](https://mkremins.github.io/blog/controls-as-language/), Max Kreminski, 2016 268 | - [Alphabets of emergence](https://subconscious.substack.com/p/provoking-emergence-with-alphabets) 269 | - [Alphabets](https://gordonbrander.com/pattern/alphabets/) 270 | 271 | ## Small alphabets 272 | 273 | When designing alphabets for emergence, constrain the alphabet, but don't constrain what may be written with it. 274 | 275 | - Constrain the alphabet. Keeping the alphabet small makes it easy to learn. It also forces you, the designer, to create a composable alphabet. With a smaller set of letters, expressiveness is achieved by designing rules that allow letters to be composed with each other in many different ways. 276 | - ...But don't constrain what may be written with it. Alphabets that produce open-ended emergence — written language, chemistry, DNA — don't place a limit on the number of letters you may combine in sequence, or the meanings you may construct with those letters. Anything achievable within the rules of the alphabet is permissible. This generates an open-ended possibility space. 277 | 278 | DNA has a tiny alphabet (ATCG), but no limit on the number of basepairs that may be chained together, and no constraint, outside of natural selection, on the phenotypes that may be generated. The web defines a set of technologies (HTML, CSS, JavaScript), and rules for combining them, and does not censor what may be created with those technologies. This permissionless system continues to generate surprising new business models. 279 | 280 | Failure modes: 281 | 282 | - Large alphabets with many different interfaces. These don’t create large combinatorial spaces, since composition is severely constrained. 283 | - Censorship: this is a kind of post-filtering that limits downside, but also upside. 284 | 285 | When we shape the possibility space by way of shaping the alphabet, we enable open-ended innovation. When we cull generated results via fixed rules, we cause the system to converge. 286 | 287 | More reading: 288 | 289 | - [Small alphabets](https://gordonbrander.com/pattern/small-alphabets/) 290 | - [Alphabets of emergence](https://subconscious.substack.com/p/provoking-emergence-with-alphabets) 291 | 292 | ## Control vs. interest 293 | 294 | In general: 295 | 296 | 1. Putting a lower-bound on quality will restrict _variety_. When all output is “equally interesting”, nothing is interesting. “Information is the difference that makes a difference” (Gregory Bateson). Capping downside caps upside. 297 | 2. Increasing depth _or_ breadth reduces control but increases interest. Minecraft has voxels and finite block types for a reason. 298 | 299 | ## 10,000 bowls of oatmeal 300 | 301 | A generative system can be emergent, and even open-ended without being interesting. Kate Compton calls this the [10,000 bowls of oatmeal problem](https://galaxykate0.tumblr.com/post/139774965871/so-you-want-to-build-a-generator): 302 | 303 | > I can easily generate 10,000 bowls of plain oatmeal, with each oat being in a different position and different orientation, and mathematically speaking they will all be completely unique. But the user will likely just see a lot of oatmeal. (Kate Compton, [So you want to build a generator](https://galaxykate0.tumblr.com/post/139774965871/so-you-want-to-build-a-generator)) 304 | 305 | What makes a generative system interesting? **Perceptual uniqueness**. You’ll know it when you see it. 306 | 307 | ## Escaping the oatmeal with archetypes 308 | 309 | Assuming you generate a valid output, the cause of the oatmeal problem is that the observer sees "the shape of the algorithm" at work rather than the output itself. This is visible in classic Perlin-noise based terrain generation: 310 | 311 | ![](https://devforum-uploads.s3.dualstack.us-east-2.amazonaws.com/uploads/original/4X/0/4/8/0480e817c4b377c1dc603991f359b930e042686e.jpeg) 312 | 313 | Every hill, valley and coast feel the same despite actually being unique. By contrast, modern terrain generation (using Houdini) has clear archetypes we recognize from the real world with discernible "locations" on them: 314 | 315 | ![](https://i.vimeocdn.com/video/778256694-6333bffc7598ce475642aa2bcfa3ea120c8f20a3b6e66b15c36f18f5e51d6680-d?f=webp) 316 | 317 | The goal is to create outputs from a generative system that have "personality". Each should be unique but _also_ mappable into a taxonomy by a willing scientist. When composing an interesting song there must be a balance of repetition and variation, tension and release. Generative composition is no different. The taxonomy of options forms due to feedback through intentionally designed channels of the system, each with varying dynamics. 318 | 319 | ## Blending dynamics 320 | 321 | You can produce archetype-like behaviors in a generative system by mixing different dynamics. For example, Perlin noise alone makes for relatively uninteresting terrain but with the addition of erosion the landscape becomes cohesive: 322 | 323 | ![](https://www.wysilab.com/OnLineDocumentation/Nodes/images/MountainErosion.gif) 324 | 325 | In this case, we have one dynamic acting per-texel (Perlin noise) and one dynamic acting across the entire heightmap iteratively in a cellular automata (erosion). Operating across different scales and dimensions of the problem space allows for patterns that appear organic. 326 | 327 | Aside from scale and dimension, dynamics can also differ in shape. Consider a smooth vs. spiky curve: 328 | 329 | ![](https://qph.cf2.quoracdn.net/main-qimg-e32ec9ff7c6a441772eb5b0d780629f2) 330 | 331 | Mixing different shapes, scales and dimensions together results in a kind of "constrained chaos" confined to a particular manifold of the generative space. 332 | 333 | ## Permute, permute, permute 334 | 335 | You can gain an intuition for a generating system by creating scripts that generate many permutations, giving you a sample of the possibility space. 336 | 337 | > Years ago when working on a project with challenging color palette I did the craziest thing and just listed all possible color combinations and then manually selected the best ones. Turns out it was 10x faster than hunting bad cases one by one or trying to come up with an algo. https://twitter.com/marcinignac/status/1484211214477627392 338 | 339 | ## Coarse-grained vs fine-grained 340 | 341 | What if your generative system isn’t “smart enough” and keeps producing broken combinations? It might be that your generative system doesn’t have requisite variety to do what you want. Maybe you’re overshooting? 342 | 343 | In these situations you can usually get unstuck by coarse-graining the generative system. Instead of generating Lego Technic, try Lego, or even Duplo. Instead of generating stories from letters, try generating them from words or paragraphs, or pre-canned story segments. 344 | 345 | Evolutionary algorithms often get stuck this way. You try to evolve a useful digital solution from 1s and 0s, but keep getting slop. The solution? Design artificial DNA where basepairs encode whole useful traits! No wrong answers! 346 | 347 | There’s obviously a tradeoff between coarse-graining, expressivity, and open-endedness, but when you’re on the wrong side of expressivity, it can be a pragmatic solution. 348 | 349 | More reading: 350 | 351 | - [Evolutionary Design by Computers](https://www.amazon.com/Evolutionary-Design-Computers-Peter-Bentley/dp/155860605X). 352 | - [Creative Evolutionary Systems](https://www.amazon.com/Creative-Evolutionary-Kaufmann-Artificial-Intelligence/dp/1558606734) 353 | 354 | ## Excavating fine-grained mechanisms 355 | 356 | You can often start with a coarse-grained set of generative components, and progressively excavate finer-grained components over time. This approach can have advantages: 357 | 358 | - You can make progress quickly in the beginning by “black-boxing” certain complex components 359 | - You can uncover finer-grained alphabets as your generative algorithms get smarter/improve in quality 360 | - It can help nudge you toward [layered API designs](https://subconscious.substack.com/p/layered-protocols) and alphabets that compose at multiple scales. 361 | 362 | Think of this like blocking out large portions of a canvas while painting. You paint large swaths with a wide brush before moving on to the details. 363 | 364 | One IRL example of mechanism excavation is [The Extensible Web Manifesto](https://github.com/extensibleweb/manifesto), which seeks to “explain existing and new features in terms of low-level capabilities”. 365 | 366 | Note that there are also tradeoffs in becoming extremely fine-grained. As the system becomes more expressive, it shifts requisite variety away from the system and toward developers. This increases open-endedness, sacrifices the system’s ability to control certain properties. For example, on the web, we see this manifest as complaints about JavaScript bundle size (which is the other side of the tradeoff of providing many fine-grained mechanisms rather than coarse-grained platform components). Know where you want the system to uphold guarantees, and consider coarse-graining those portions to keep the requisite variety on the system’s side. 367 | 368 | ## Abstract peak to concrete valley (progressive refinement) 369 | 370 | Many procedural generation systems fail because they attempt too much in a single step. Dwarf Fortress generates an world with a [complete historical record](https://dwarffortresswiki.org/index.php/World_generation#History_length) and does so by _simulating the entire thing_ (with some smoke and mirrors). 371 | 372 | Caves of Qud generates similar histories through a layered symbolic expansion. [This presentation](https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2019/presentations/Grinblat_Jason_End-to-End_Procedural_Generation.pdf) covers their approach in detail but here is a brief sketch: 373 | 374 | We take many iterative passes to go from the Abstract Peak to the Concrete Valley: 375 | 376 | ![alt text](image.png) 377 | 378 | ``` 379 | This town was created when the founder ?name discovered it. 380 | This town was created when the founder, Jessica, discovered it while doing ?something. 381 | This town was created when the founder, Jessica, discovered it while gathering water and saw ?something. 382 | This town ?name was created when the founder, Jessica, discovered it while gathering water and saw a mole hill. 383 | This town Moleville was created when the founder, Jessica, discovered it while gathering water and saw a mole hill. 384 | ``` 385 | 386 | Each time we append more information we have the choice of drawing entities from the existing pool or generating new ones or clarifying details. Currently we know this town: 387 | 388 | 1. has a source of water 389 | 2. has a mole hill 390 | 3. is called Moleville 391 | 4. has a founder named Jessica 392 | 393 | When we come to generate the actual physical layout of this town, we might take a generic approach and then refine using these details: 394 | 395 | 1. spawn a point of interest placeholder 396 | 2. spawn 4 unlabelled houses 397 | 3. spawn a pond 398 | 4. add rooms to houses by subdividing 399 | 5. replace the point of interest with a molehill 400 | 6. label the house nearest to the point of interest as "Jessica's house" 401 | 402 | When the player arrives here, it will seem like this village organically formed, because it did! 403 | 404 | ## Cheat 405 | 406 | Pay no attention to the man behind the curtain. Sometimes it can be beneficial to break out of the generative mindset and script, design, or interfere with a step in the process: 407 | 408 | Examples: 409 | 410 | - WeChat offers AI assistants for everything from banking to restaurants. These AIs cheat on two levels. One, by breaking out of free text, and presenting structured user interfaces for chat interaction. Two, by seamlessly dropping down to a real human behind the curtain when they aren’t sure what to do. 411 | - Open world video games often have scripted sequences, story bottlenecks you have to pass through, or levels that unlock when certain story conditions are met. 412 | 413 | Questions: 414 | 415 | - Am I stuck? How can I cheat? 416 | - Can I cheat without breaking the fundamental open-endedness and generativity of the system? 417 | 418 | ## Gardener mindset 419 | 420 | Designing generative systems requires a special kind of mindset - a gardening mindset. 421 | 422 | > An architect, at least in the traditional sense, is somebody who has an in-detail concept of the final result in their head, and their task is to control the rest of nature sufficiently to get that built. Nature being things like bricks and sites and builders and so on. Everything outside has to be subject to an effort of control. 423 | > 424 | > A gardener doesn't really work like that. Unless it's, as Mark's mentioned, Versailles, which is, to me, the most grotesque of all gardens, since it's the total denial of nature and the complete expression of human control over nature. So it's a perfect forerunner to the Industrial Age, Versailles. But what I think about, I suppose my feeling about gardening, and I suppose most people's feeling about gardening now, is that what one is doing is working in collaboration with the complex and unpredictable processes of nature. And trying to insert into that some inputs that will take advantage of those processes, and as Stafford Beers said, take you in the direction that you wanted to go. 425 | > 426 | > Use the dynamics of the system to take you in the direction you wanted to go. So my feeling has been that the whole concept of how things are created and organized has been shifting for the last 40 or 50 years, and as I said, this sequence of science as cybernetics, catastrophe theory, chaos theory and complexity theory, are really all ways of us trying to get used to this idea that we have to stop thinking of top-down control as being the only way in which things could be made. 427 | > 428 | > We have to actually lose the idea of intelligent design, because that's actually what that is. The top-down theory is the same as intelligent design. And we have to actually stop thinking like that and start understanding that complexity can arise in another way and variety and intelligence and so on. So my own response to this has been, as an artist, to start to think of my work, too, as a form of gardening. So about 20 years ago I came up with this idea, this term, 'generative music,' which is a general term I use to cover not only the stuff that I do, but the kind of stuff that Reich is doing, and Terry Riley and lots and lots of other composers have been doing. (Brian Eno [Composers as Gardeners](https://www.edge.org/conversation/brian_eno-composers-as-gardeners)) 429 | 430 | More reading: 431 | 432 | - [Composers as Gardeners](https://www.edge.org/conversation/brian_eno-composers-as-gardeners), Brian Eno 433 | - [Seeing Like a State](https://www.amazon.com/Seeing-like-State-Certain-Condition/dp/0300078153), James C Scott, 1999 434 | 435 | ## If the error rate is too high, tighten the feedback loop 436 | 437 | Synchronization happens through feedback, so: 438 | 439 | - If the error rate is too high, tighten the feedback loop. 440 | - If the variety is too low, loosen the feedback loop. 441 | 442 | Instead of looking at a generative system and saying “it’s not good enough”, ask “how can I tighten the feedback loop with the user?” 443 | 444 | The brilliance of Google’s “10 blue links” is that it allows for zero-friction feedback. Google doesn’t have to get it right, it just has to get it right in 10 tries! And what if everyone clicks the third link from the top? Well, Google can bump it up. 445 | 446 | Imagine if Google only had “I’m Feeling Lucky”? That would be pretty frustrating! Yet this is how most people think about AI and generative systems. “Get it right in one try” will always be unlikely. Instead, try to find a low-friction ways to increase feedback. 447 | 448 | On the other hand, if the system is not generating enough variety, it may mean you’re *too* synchronized. Loosen up that feedback loop. 449 | 450 | More reading: 451 | 452 | - [Notes are conversations across time](https://subconscious.substack.com/p/notes-are-conversations-across-time) 453 | 454 | # Working with generative AI 455 | 456 | ## LLMs are computationally shallow 457 | 458 | That means they aren’t great at deeply recursive reasoning. For example, ask the LLM to close progressively deeper sequences of parenthesis... It will get it right, but at some high depth, it will eventually begin to fail. 459 | 460 | > It’s a pretty typical kind of thing to see in a “precise” situation like this with a neural net (or with machine learning in general). Cases that a human “can solve in a glance” the neural net can solve too. But cases that require doing something “more algorithmic” (e.g. explicitly counting parentheses to see if they’re closed) the neural net tends to somehow be “too computationally shallow” to reliably do. (By the way, even the full current ChatGPT has a hard time correctly matching parentheses in long sequences.) ([What is ChatGPT doing? And why does it work?](https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work/), Stephen Wolfram, 2023) 461 | 462 | So, LLMs don’t do well with deeply interdependent logic puzzles, or problems that have a deeply recursive structure. 463 | 464 | One way we can deal with this is to “unroll the loop”... to break our deeply recursive problem down into a sequence of steps that can be solved via multi-shot prompting. 465 | 466 | Another approach is to farm out the problem. Computations of arbitrary depth? This is exactly what computers good for. So, what if we combined LLMs with other software to get the best of both? It turns out this is exactly what many LLMs do under the hood, farming out computations they’re bad at: 467 | 468 | - Calling out [knowledge graphs](https://writings.stephenwolfram.com/2023/01/wolframalpha-as-the-way-to-bring-computational-knowledge-superpowers-to-chatgpt/) to do automated reasoning. 469 | - Using RAG and function calling to ground responses with search 470 | - Generating Python code, and then interpreting it, to solve computationally deep problems 471 | 472 | Questions: 473 | 474 | - LLMs are computationally shallow. How computationally deep is my problem? 475 | - In what ways might we combine the LLM with other systems to get the best of both? 476 | 477 | More reading: 478 | 479 | - [What is ChatGPT doing? And why does it work?](https://writings.stephenwolfram.com/2023/02/what-is-chatgpt-doing-and-why-does-it-work/), Stephen Wolfram, 2023 480 | 481 | ## LLMs pay attention to what’s in the context window 482 | 483 | ## LLMs work best with high-locality 484 | 485 | > You may not like it, but this code has high locality of behavior. I don’t have to jump through other functions and files to understand it. [@housecor](https://x.com/housecor/status/1718305190716010801?s=20) 486 | 487 | 488 | 489 | - LLMs only see what's in the context window and their training data 490 | - LLMs don't do well reasoning about deeply recursive processes. 491 | - LLMs see surface complexity and correlate high-dimensional processes. 492 | 493 | An LLM is more likely to be effective at generating code with high locality vs a complex class, where the program execution flow is indirect and threaded throughout class methods, with implicit state mutation, overriding via inheritance, etc. So: 494 | 495 | - DONT: action at a distance. 496 | - DONT: separation of concerns 497 | - DO: group related things together 498 | - DO: maximally direct code 499 | - DO: avoid indirection 500 | - DO: encapsulate code 501 | 502 | ## Text is composable, so just use text 503 | 504 | An LLM can be seen as a function of `string -> string`. This has a few important implications: 505 | 506 | - LLMs are composable: The output of an LLM can be the input to an LLM. 507 | - Code is data, data is code: natural language can be seen as an artifact, or as an instructions to the LLM. Text can serve both roles, or change roles over time. 508 | 509 | **Just use text**. The more aspects of your experience that you can express as text, or serialize as text, the more aspects can be understood by the LLM, transformed by the LLM, customized by the LLM. 510 | 511 | “Text” should be construed broadly. It can include natural language prompts, markup, JSON, short snippets of JavaScript, or the function calling API. 512 | 513 | “Just use text” means hoisting too much into the UI layer (e.g. using nodes and wires instead of prompting) is an anti-pattern. When it’s not expressible as text, you’re not leaning into the power of the medium. Consider making things like UI elements expressible as markup or as React Components that can potentially be given to an LLM, or generated by an LLM. 514 | 515 | ## LLM as godlike oracle 516 | 517 | A common metaphor for AI is that of a godlike oracle. You ask the oracle a question, it delivers an answer. 518 | 519 | Q: “What is the meaning of life?” 520 | A: 42 521 | 522 | This metaphor for AI is not very interesting, because: 523 | 524 | - It’s feed-forward 525 | - It’s convergent 526 | - It doesn’t reflect what LLMs actually do today 527 | 528 | ## LLM as autonomous agent 529 | 530 | The hot new thing is AI agents, but agency requires feedback, and LLMs are feed-forward systems. No feedback, no agency. 531 | 532 | At the same time, [feedback is all you need for agency to emerge](https://subconscious.substack.com/p/feedback-is-all-you-need). A thermostat has limited agency through feedback with its environment. Likewise, an LLM can be part of an agentic system by introducing feedback. 533 | 534 | In 2024, useful autonomous agents may be outside the adjacent possible. A system’s feedback loops evolve over time through experiences within its environment. This process starts from the bottom-up, from simple to complex, from weeds, to bushes, to rainforests. So, the first true AI agents may look more like a virus - simple replicators. 535 | 536 | From another angle, we might see LLMs as part of a larger agentic system that includes *you*. This point of view is pragmatic and empowering. IA (Intelligence Amplification) vs AI (Artificial Intelligence). 537 | 538 | More reading: 539 | 540 | - [Feedback is all you need](https://subconscious.substack.com/p/feedback-is-all-you-need) 541 | 542 | ## LLM as muse 543 | 544 | Another way to see LLMs is as creative tools, like 545 | 546 | - [ChatGPT as Muse, not Oracle](https://www.geoffreylitt.com/2023/02/26/llm-as-muse-not-oracle) 547 | 548 | ## LLM as Artificial Intuition 549 | 550 | LLMs are more like Artificial Intuition than Artificial Intelligence. 551 | 552 | Reasoning has a deep, recursive shape. LLMs are computationally shallow. An LLM guesses-next-token by assembling good candidates from a massive hyperdimensional field of associations, their model. 553 | 554 | Reasoning is deep, LLMs are broad. 555 | 556 | What else has this shape? Intuition. Our intuitions are shaped by our experience. Our unconscious draws from these impressions, assembling related impressions together to produce a gut feeling, or an insight, or a dream. 557 | 558 | So, we taught computers to do vibes. And vibes are most of what we’re doing when we think, too. The reasoning part of our brain is an aftermarket part, bolted on to our ancient intuition. 559 | 560 | What LLMs are likely to be good at: 561 | 562 | - Vibes 563 | - Common sense 564 | - Turning fuzzy impressions into concrete statements 565 | - Understanding the gist of things (summarization) 566 | 567 | Questions: 568 | 569 | - Is my problem broad or deep? 570 | - What might be better solved by intuition than reasoning? 571 | 572 | Software is getting softer. 573 | 574 | More reading: 575 | 576 | - [Artificial Intuition, not Artificial Intelligence](https://subconscious.substack.com/p/artificial-intuition-not-artificial) 577 | - [The Kekule Problem](https://nautil.us/the-kekul-problem-236574/), Cormac McCarthy, 2017 578 | - [Echopraxia](https://www.amazon.com/Echopraxia-Peter-Watts/dp/0765328038), Peter Watts, 2015 579 | - [The Origins of Wealth](https://www.amazon.com/Origin-Wealth-Remaking-Economics-Business/dp/1422121038), Eric D. Beinhocker, 2007 580 | 581 | ## LLM as coordinator 582 | 583 | ## LLM as touch-up pass 584 | 585 | Another way to use an LLM is as a touch-up or synthesis pass. 586 | 587 | For example, a generative grammar could be used to generate the outline of a story, and an LLM used to expand that outline into a few paragraphs. This gives you a high degree of control over ingredients and how they are combined. At the same time, generative grammars lack the high-dimensional structure of natural language, It can be difficult to design them in ways that generate natural-sounding paragraphs and sentences, but LLMs are great at this kind of synthesis. 588 | 589 | ## Think backwards 590 | 591 | An LLM outputs whatever logically follows from its input. Due to the personification of instructor-tuned models we tend to speak to them conversationally but this often produces poor results. Instead, think of LLMs like those "what comes next in the sequence" puzzles: 592 | 593 | ![](https://static.toiimg.com/thumb/msid-105122389,width-400,resizemode-4/105122389.jpg) 594 | 595 | A good prompt sketches out the steps of the pattern with minimal distraction surrounding them. This is why examples are so effective for LLMs, they provide evidence of a pattern to extend. Good prompting means thinking backwards from the intended output to produce the most compact set of tokens that will logically lead to it. 596 | 597 | ## Do one thing at a time 598 | 599 | Instruction-tuned LLMs struggle with open problem descriptions. More capable models can deal with more ambiguity but the best results come from extremely clear problem specification (much like the real world). 600 | 601 | ``` 602 | What is a novel theory in the field of psychology? 603 | ``` 604 | 605 | 🙅 This is a pretty bad question, even for a person. What answer are you expecting for this? 606 | 607 | ``` 608 | Find a recent psychology literative review 609 | --- 610 | Describe 5 of the the promising areas of investigation identified in a short paragraph, mentioning the original article title and author 611 | --- 612 | Suggest 5 ways these areas of investigation could be related to one another, are there opportunities for collaboration? 613 | --- 614 | Formulate each suggestion into a research question (AKA hypothesis) 615 | ``` 616 | 617 | 👍 This is a textual program that generates text, not a question. 618 | 619 | ## E2E interface generation example (context manipulation) 620 | 621 | It can be helpful to throw away the context mid-generation and tightly manipulate it through many passes. For example, let's make an app for this request: 622 | 623 | > "I want a todo application that lets me add due dates" 624 | 625 | ![alt text](image-1.png) 626 | 627 | The [full script](./example-app.md) is available, but the general steps are: 628 | 629 | 1. Generate Domain Model from description 630 | 1. Generate data API from domain model 631 | 1. Improve description by considering UI/UX implementation 632 | 1. Plan full-app build using UI + description + data API 633 | 1. Implement the plan 634 | 1. Check the app for errors, ensure it meets the specification 635 | 636 | ## Using LLMs to create structured data 637 | 638 | https://github.com/instructor-ai/instructor-js 639 | 640 | # Tools and techniques 641 | 642 | ## State machines 643 | 644 | ## Storylets 645 | 646 | [Storylets](https://emshort.blog/2019/11/29/storylets-you-want-them/) are a way of organizing procedurally generated narrative. 647 | 648 | Components of a storylet: 649 | 650 | - An atomic piece of content (line, paragraph, section, animation, cutscene...) 651 | - Prerequisites for the content to play 652 | - Effects on the world state after it plays 653 | 654 | Note that this structure can be used for more than narrative. It neatly combines atomic designed units, algorithmic guidance, user input, and randomness to enable a wide range of applications. 655 | 656 | Lots of games use this basic structure, and it’s flexible enough to support many semi-open story structures, including gauntlets, branching and bottlenecks, “sorting hats”, eternal return, and more. 657 | 658 | Examples of games that use Storylets: 659 | 660 | - [Reigns](https://www.reignsgame.com/reigns) 661 | 662 | More reading: 663 | 664 | - [Storylets: You Want Them](https://emshort.blog/2019/11/29/storylets-you-want-them/) 665 | - [Survey of storylet design](https://emshort.blog/2019/01/06/kreminski-on-storylets/) 666 | - [Sketching a map of the storylets design space](https://mkremins.github.io/publications/Storylets_SketchingAMap.pdf), Max Kreminski, 2018 667 | 668 | ## Procedural Geometry 669 | 670 | Abstract principle: begin with mostly noise and use specific mathematical operations to extract signal. 671 | 672 | ### Noise and Randomness 673 | 674 | (psuedo)randomness is the fundamental starting point for any computational process relying on variety. Mixing multiple types of noise together at different scales and parameterising them is a common way to disguise the obvious patterns of algorithmic noise. 675 | 676 | ![White Noise: per pixel randomness](https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/White-noise-mv255-240x180.png/220px-White-noise-mv255-240x180.png) 677 | 678 | Perlin Noise 679 | 680 | ![Octave Perlin Noise](https://www.researchgate.net/publication/352678572/figure/fig4/AS:1037741269737474@1624428207473/An-example-noise-image-generated-from-Perlin-noises-with-different-noise-frequencies-and.ppm) 681 | 682 | ![Worley or Voronoi Noise](https://upload.wikimedia.org/wikipedia/commons/thumb/0/00/Worley.jpg/400px-Worley.jpg) 683 | 684 | ### Wave Function Collapse 685 | 686 | WFC is effectively playing Sudoku to generate a grid-based output. First tiles are placed at random, which reduces the pool of valid tiles that can be placed next to them. If there is only one valid possibility for a space, we can safely lock it in which continues to "collapse" the wave function iteratively across the grid. Depending on the tileset it may not deterministically find a full solution. 687 | 688 | ![](https://bfnightly.bracketproductions.com/c33-s14.gif) 689 | 690 | ![](https://images1.uwa4d.com/solution/screenshot/5b565d7ad7f10a201fd954cf/thumbnail.gif) 691 | 692 | This video provides an excellent overview of the technique in practice and the sharp edges you might bump into: https://www.youtube.com/watch?v=zIRTOgfsjl0 693 | 694 | ### Signed Distance Fields 695 | 696 | ![](https://global.discourse-cdn.com/standard17/uploads/threejs/original/3X/e/a/ea9b814f059fad0b7d1425a14d6e868e1124bca2.gif) 697 | 698 | [SDF](https://en.wikipedia.org/wiki/Signed_distance_function) geometry discards the classic vertex, edge, face structure of a mesh and renders geometry using a mathematical functions to describe the volume. 699 | 700 | This allows for far deeper control over shape generation and deeply parametric design. Tools like [womp](https://womp.com/index) and people like [Inigo Quilez](https://iquilezles.org/articles/distfunctions/) (of Pixar fame) are pushing this as the next-generation approach. 701 | 702 | SDFs are also finding use in [parametric font-rendering](https://www.youtube.com/watch?v=SO83KQuuZvg). Importantly, SDFs can be re-topologized to mesh based geometry if needed. 703 | 704 | #### Diffusion Models 705 | 706 | Diffusion models have risen to popularity for image, video and audio geneation but the same principle also tranfers to SDF geometry. Gaussian splats, voxels and SDFs can be used to generate 3D models on demand, albet with compromises to the rendering performance. 707 | 708 | https://x.com/eric_heitz/status/1780979459790610503 709 | https://x.com/eric_heitz/status/1780979462256931023 710 | 711 | ![](https://i.redd.it/q2vo4eqkanzb1.gif) 712 | 713 | https://lumalabs.ai/ 714 | 715 | ## Parametric Design & Geometry Nodes 716 | 717 | Houdini, Blender, Grasshopper Rhino 718 | https://cuttle.xyz 719 | 720 | ## Generative grammars 721 | 722 | Generative grammars borrow insights from [the Chomsky hierarchy](https://en.wikipedia.org/wiki/Chomsky_hierarchy), to create a recursively-enumerable grammar that can be expanded into random-yet-structured output. 723 | 724 | The core of a generative grammar is a map of keys to lists of values: 725 | 726 | ``` 727 | { 728 | "name": ["Brittany", "Andrew"], 729 | "animal": ["wombat", "cat"], 730 | "story": [ 731 | "This is a story about #name# the #animal.capitalize#", 732 | "This is a tale about a #animal# named #name#" 733 | ] 734 | } 735 | ``` 736 | 737 | Each time the interpreter encounters a `#tag#`, it selects a random value from the corresponding key in the map. This happens recursively, until there are no more keys to replace. 738 | 739 | The random-yet-hierarchically-structured recursive shape of generative grammars is useful for a lot of different generating tasks, including generating stories, combining ingredients for a recipe, creating collections of starting equipment for a game... 740 | 741 | Generative grammars hit a sweet spot for simple and expressive: 742 | 743 | - Generative grammars are easy to implement. A basic implementation can be written [in just a few lines of code](https://github.com/gordonbrander/spandrel/blob/main/spandrel.js). 744 | - Generative grammars are also easy to author. They provide a nice balance of randomness, structure, and authorial control. You can even weight randomness by including the same option multiple times in a list. It’s fairly easy to produce generators which are “good a lot”. 745 | - Generative grammars aren’t limited to text. You can have them generate markup, JSON, file paths to image assets, etc. 746 | 747 | There might also be interesting ways to use generative grammars in tandem with LLMs. Generative grammars are stricter about structure, but also “dumber” than LLMs, while LLMs are better at doing common sense things, and “soft” things. 748 | 749 | - Use a generative grammar to generate input for an LLM, then have the LLM expand that into natural language, or something else. 750 | - Use an LLM to generate a grammar. 751 | - Use a grammar to structure “soft” outputs from an LLM. 752 | 753 | More reading: 754 | 755 | - [Tracery](https://tracery.io/), Kate Compton 756 | - [Practical procedural generation for everyone](https://www.gdcvault.com/play/1024213/Practical-Procedural-Generation-for), Kate Compton 757 | - [So you want to build a generator](https://www.tumblr.com/galaxykate0/139774965871/so-you-want-to-build-a-generator), Kate Compton 758 | 759 | 760 | ## Markov Chains 761 | 762 | > A Markov chain or Markov process is a stochastic model describing a sequence of possible events in which the probability of each event depends only on the state attained in the previous event. 763 | 764 | ![](https://miro.medium.com/v2/resize:fit:1200/1*zUYHEsETFS3yMoxc6vVLcg.gif) 765 | 766 | While primitive, Markov chains can be significantly simpler, faster and funnier than other techniques and have been used to great effect in games like Caves of Qud. 767 | 768 | https://motion.cs.umn.edu/pub/NateBuckThesis/NathanielBuck_ProceduralContent.pdf 769 | 770 | ## L-Systems 771 | 772 | ![](https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Fractal_weeds.jpg/660px-Fractal_weeds.jpg) 773 | 774 | > An L-system or Lindenmayer system is a parallel rewriting system and a type of formal grammar. An L-system consists of an alphabet of symbols that can be used to make strings, a collection of production rules that expand each symbol into some larger string of symbols, an initial "axiom" string from which to begin construction, and a mechanism for translating the generated strings into geometric structures. 775 | 776 | They happen to be excellent at generation branching structures, like plants. 777 | 778 | ``` 779 | Lindenmayer's original L-system for modelling the growth of algae. 780 | 781 | variables : A B 782 | constants : none 783 | axiom : A 784 | rules : (A → AB), (B → A) 785 | which produces: 786 | 787 | n = 0 : A 788 | n = 1 : AB 789 | n = 2 : ABA 790 | n = 3 : ABAAB 791 | n = 4 : ABAABABA 792 | n = 5 : ABAABABAABAAB 793 | n = 6 : ABAABABAABAABABAABABA 794 | n = 7 : ABAABABAABAABABAABABAABAABABAABAAB 795 | ``` 796 | 797 | ## Cellular Automata 798 | 799 | ![](https://upload.wikimedia.org/wikipedia/commons/e/e5/Gospers_glider_gun.gif) 800 | 801 | > A cellular automaton consists of a regular grid of cells, each in one of a finite number of states, such as on and off (in contrast to a coupled map lattice). The grid can be in any finite number of dimensions. For each cell, a set of cells called its neighborhood is defined relative to the specified cell. An initial state (time t = 0) is selected by assigning a state for each cell. A new generation is created (advancing t by 1), according to some fixed rule (generally, a mathematical function)[3] that determines the new state of each cell in terms of the current state of the cell and the states of the cells in its neighborhood. 802 | 803 | CA's are an extremely broad class of algorithm and despite their grid-based definition they can model all sorts of dynamics. Stephen Wolfram famously laid claim to them and sketched out a vision for their importance in his book [A New Kind of Science](https://www.wolframscience.com/nks/). 804 | 805 | ## Continuous Cellular Automata 806 | 807 | Rather than storing discrete quantities in each grid cell, we _could_ store continuous floating point values and even store multiple different quantities in each cell. This approach is, approximately, how most compute shader simulations work: 808 | 809 | ![Reaction Diffusion](https://i.pinimg.com/originals/ad/3d/7c/ad3d7c7ee72c4bcea4e046e0dbf547f8.gif) 810 | ![Differential Growth](https://n-e-r-v-o-u-s.com/blog/wp-content/uploads/2015/06/colors.gif) 811 | ![Navier-Stokes](https://www.karlsims.com/flow-jets.gif) 812 | ![Boids](https://miro.medium.com/v2/resize:fit:1400/1*yIBh1VALCOGlgZxxQfAUdg.gif) 813 | ![Slime Mould](https://payload.cargocollective.com/1/18/598881/13800048/explosion.gif) 814 | ![Lenia](https://hegl.mathi.uni-heidelberg.de/wp-content/uploads/2023/04/example_increasing_mass.gif) 815 | ![Lenia](https://upload.wikimedia.org/wikipedia/commons/7/72/Peek_2021-10-12_22-29.gif) 816 | 817 | This is an active research frontier, especially beyond 2D, see the work of [Sage Jensen](https://n-e-r-v-o-u-s.com/blog/?p=9137). 818 | 819 | ## LLMs 820 | 821 | # More reading 822 | 823 | - [Systems Generating Systems](https://patterns.architexturez.net/doc/az-cf-173046), Christopher Alexander, 1968 824 | - [Computational Design Thinking](https://www.wiley.com/en-us/Computational+Design+Thinking%3A+Computation+Design+Thinking-p-9780470665701), Achim Menges, Sean Ahlquist, 2011 825 | - [Procedural Generation in Game Design](https://www.amazon.com/Procedural-Generation-Design-Tanya-Short/dp/1498799191) 826 | - [Procedural Storytelling in Game Design](https://www.amazon.com/Procedural-Storytelling-Design-Tanya-Short/dp/1138595314) 827 | - [Emily Short's Interactive Storytelling](https://emshort.blog/) 828 | - [So you want to build a generator](https://galaxykate0.tumblr.com/post/139774965871/so-you-want-to-build-a-generator) 829 | 830 | # Meta 831 | 832 | #generativedesign #generativegrammar #ai #design #complexty #ui #ux 833 | -------------------------------------------------------------------------------- /example-app.md: -------------------------------------------------------------------------------- 1 | ## Step 1: enhance user input to spec 2 | 3 | ``` 4 | You are a user interface specification expert. You specialize in converting user feature requests into a list of user stories. Expand on this request: 5 | 6 | "I want a todo application that lets me add due dates" 7 | ``` 8 | 9 | ``` 10 | As a user, I want to add due dates to my tasks, so that I can manage my deadlines effectively. 11 | As a user, I want to view the due dates on my tasks in a list, so that I can quickly see when each task is due. 12 | As a user, I want to easily edit the due dates of my tasks, so that I can adjust my plans as they change. 13 | As a user, I want to receive notifications about my tasks as they approach their due dates, so that I can be reminded to complete them on time. 14 | As a user, I want to enter due dates in various formats (e.g., DD/MM/YYYY, MM/DD/YYYY), so that I can use the format I am most comfortable with. 15 | As a user, I want to view my tasks with due dates in a calendar format, so that I can better understand how my tasks are distributed over time. 16 | As a user, I want to sort my tasks by their due dates, so that I can prioritize tasks that are due sooner. 17 | As a user, I want to filter tasks by due date, so that I can focus on tasks that need immediate attention or are due within a certain timeframe. 18 | As a user, I want to set due dates based on different time zones, so that I can manage tasks that are tied to specific geographical locations. 19 | As a user, I want to set up recurring tasks with due dates, so that I don't have to manually set a due date each time the task recurs. 20 | ``` 21 | 22 | ## Step 2: create domain model 23 | 24 | ``` 25 | You are a domain modelling expert. You generate simple Typescript types to express the domain model from a list of user stories. Create a model for this application, considering only the data and persistence aspects and NOT the user interface itself: 26 | 27 | (...stories from above) 28 | ``` 29 | 30 | ```ts 31 | // Represents a single task with optional due date and recurrence 32 | type Task = { 33 | id: string; // Unique identifier for the task 34 | title: string; // Title or description of the task 35 | dueDate?: Date; // Optional due date for the task 36 | timeZone?: string; // Optional time zone if the task is tied to a specific geographical location 37 | recurrence?: Recurrence; // Optional recurrence details 38 | }; 39 | 40 | // Recurrence details, indicating the frequency and optionally end date of recurrence 41 | type Recurrence = { 42 | frequency: RecurrenceFrequency; // How often the task recurs 43 | endDate?: Date; // Optional date when the recurrence ends 44 | }; 45 | 46 | // Enum for possible recurrence frequencies 47 | enum RecurrenceFrequency { 48 | Daily = "DAILY", 49 | Weekly = "WEEKLY", 50 | Monthly = "MONTHLY", 51 | Yearly = "YEARLY" 52 | } 53 | 54 | // Settings for user-specific preferences, like date format 55 | type UserPreferences = { 56 | dateFormat: DateFormat; // Preferred date format for displaying dates 57 | }; 58 | 59 | // Enum for supported date formats 60 | enum DateFormat { 61 | DD_MM_YYYY = "DD/MM/YYYY", 62 | MM_DD_YYYY = "MM/DD/YYYY" 63 | }; 64 | ``` 65 | 66 | ``` 67 | Assume you have access to the follow data persistence functions: 68 | 69 | type Object = { id: string, type: string, data: object } 70 | async function write(id: string, obj: Object) {} 71 | async function read(id: string): Object {} 72 | async function list(type: string): Object[] {} 73 | 74 | Implement a data access API using these primitives to perform the key operations. 75 | ``` 76 | 77 | ```ts 78 | // Task-related constants 79 | const TASK_TYPE = 'Task'; 80 | 81 | // Function to create a new task 82 | async function createTask(taskData: Task): Promise { 83 | const obj: Object = { 84 | id: taskData.id, 85 | type: TASK_TYPE, 86 | data: taskData 87 | }; 88 | await write(taskData.id, obj); 89 | } 90 | 91 | // Function to update an existing task 92 | async function updateTask(taskId: string, newTaskData: Partial): Promise { 93 | const existingTaskObj = await read(taskId); 94 | if (existingTaskObj.type !== TASK_TYPE) { 95 | throw new Error("Task with given ID does not exist"); 96 | } 97 | 98 | const updatedTaskData = { ...existingTaskObj.data, ...newTaskData }; 99 | const updatedTaskObj: Object = { 100 | id: taskId, 101 | type: TASK_TYPE, 102 | data: updatedTaskData 103 | }; 104 | await write(taskId, updatedTaskObj); 105 | } 106 | 107 | // Function to retrieve a task by its ID 108 | async function getTask(taskId: string): Promise { 109 | const obj = await read(taskId); 110 | if (obj.type !== TASK_TYPE) { 111 | throw new Error("Task with given ID does not exist"); 112 | } 113 | return obj.data as Task; 114 | } 115 | 116 | // Function to list all tasks 117 | async function listTasks(): Promise { 118 | const objs = await list(TASK_TYPE); 119 | return objs.map(obj => obj.data as Task); 120 | } 121 | ``` 122 | 123 | ## Step 3: Consider UX 124 | 125 | ``` 126 | You are a skilled UX designer. Consider the following domain model, API specification and description of user stories and highlight any ambiguities, excessively complex features or nonsensical requirements. 127 | 128 | (... domain, api, stories) 129 | ``` 130 | 131 | Reviewing your provided domain model, API specification, and user stories, here are some ambiguities and potential areas of complexity or improvement: 132 | 133 | ### Ambiguities 134 | 1. **Time Zone Handling for Notifications:** 135 | - The model allows tasks to be set in different time zones, but it is unclear how the system handles these for notifications. For example, will the notifications adjust according to the user’s current time zone or the task’s set time zone? 136 | 137 | 2. **DateFormat Handling in API:** 138 | - The user preference for date formats (DD/MM/YYYY or MM/DD/YYYY) is stored, but it is not clear how this preference is applied when dates are input or output through the API. There needs to be clarity on whether the API expects dates in a standard format or if it dynamically adjusts based on user preferences. 139 | 140 | 3. **Recurrence Details Specificity:** 141 | - The `Recurrence` type specifies `frequency` and an optional `endDate`, but it lacks details such as the day of the week for weekly recurrences, or which day of the month for monthly recurrences. This can lead to ambiguity in how exactly the tasks are meant to recur. 142 | 143 | ### Excessively Complex Features 144 | 1. **Multiple Date Formats:** 145 | - Supporting multiple date formats for input can complicate parsing logic and increase the potential for errors. A standardized ISO format for backend processing, with user-specific formats applied only in the UI, might simplify implementation. 146 | 147 | 2. **Time Zone Specific Tasks:** 148 | - While setting tasks in different time zones can be useful, it adds significant complexity to the system. Considerations include converting times for display, sorting, and notification purposes. This could be overly complex depending on the scope of your application. 149 | 150 | ### Potential Improvements 151 | 1. **API Error Handling:** 152 | - The API functions `updateTask` and `getTask` throw errors if a task does not exist. It might be beneficial to also return specific error messages for different kinds of failures (e.g., database read/write errors) to help with debugging and user feedback. 153 | 154 | 2. **Recurrence Handling:** 155 | - Enhance the `Recurrence` model to include more specific scheduling options (such as start times, specific weekdays, etc.), which will help in creating more flexible and useful recurring tasks. 156 | 157 | 3. **Simplification of Date Handling:** 158 | - Consider simplifying how dates are handled by using a consistent format in the back end and converting to/from the user's preferred format in the front end only. This approach reduces complexity in the data layer and isolates format-specific logic to the presentation layer. 159 | 160 | 4. **Task Sorting and Filtering API:** 161 | - While the user stories mention sorting and filtering tasks by due date, the API specification does not include methods for these functionalities. Implementing API endpoints that support filtering and sorting based on parameters like due date and recurrence can enhance usability. 162 | 163 | 5. **Use of `async/await` in API Functions:** 164 | - The API uses `async/await`, but it's not clear if the underlying `read`, `write`, and `list` functions support asynchronous execution. Ensure that these data access methods are properly handling asynchronous operations to avoid potential runtime issues in a production environment. 165 | 166 | Overall, the user stories suggest a comprehensive task management application, but refining the details in the API specification and simplifying some of the more complex features could make implementation more straightforward and robust. 167 | 168 | ``` 169 | Rewrite the list of user stories to remove the excessive complexity and nonsense as well as clarifying and simplifying where possible. 170 | ``` 171 | 172 | ``` 173 | Manage Deadlines: 174 | As a user, I want to add due dates to my tasks using a standard date format (YYYY-MM-DD), so I can manage my deadlines effectively. 175 | View Due Dates: 176 | As a user, I want to view the due dates on my tasks in a list, so I can quickly see when each task is due. 177 | Edit Due Dates: 178 | As a user, I want to easily edit the due dates of my tasks, so that I can adjust my plans as they change. 179 | Task Notifications: 180 | As a user, I want to receive notifications about my tasks as they approach their due dates, to be reminded to complete them on time. 181 | Calendar View of Tasks: 182 | As a user, I want to view my tasks with due dates in a calendar format, so that I can better understand how my tasks are distributed over time. 183 | Sort Tasks by Due Date: 184 | As a user, I want to sort my tasks by their due dates, so that I can prioritize tasks that are due sooner. 185 | Filter Tasks by Due Date: 186 | As a user, I want to filter tasks by due date, so that I can focus on tasks that need immediate attention or are due within a specific timeframe. 187 | Set Up Recurring Tasks: 188 | As a user, I want to set up recurring tasks with a clear specification of recurrence rules (daily, weekly, monthly, yearly) and an optional end date, so I don't have to manually set a due date each time the task recurs. 189 | ``` 190 | 191 | ## Step 4: Plan the App Build 192 | 193 | ``` 194 | You are a web application generator. You take a list of user stories, a data model and a set of API methods and implement accessible and beautiful web applications using lit-html and web components. 195 | 196 | (... data ...) 197 | ``` 198 | 199 | 1. Set up the project: 200 | - Create a new project directory and initialize it with a package.json file. 201 | - Install the necessary dependencies, including lit-html and any other required libraries. 202 | 203 | 2. Create the main web component: 204 | - Create a new file, e.g., `task-manager.js`, to define the main web component. 205 | - Import lit-html and define the `TaskManager` class that extends `LitElement`. 206 | - Implement the `render` method to define the component's template using lit-html. 207 | 208 | 3. Implement task creation: 209 | - Add an input field and a button in the `TaskManager` component's template for creating new tasks. 210 | - Handle the button click event to create a new task using the `createTask` function from the provided data API. 211 | - Clear the input field after creating the task. 212 | 213 | 4. Display the list of tasks: 214 | - Fetch the list of tasks using the `listTasks` function from the data API. 215 | - Render the list of tasks in the `TaskManager` component's template using lit-html's `repeat` directive. 216 | - Display the task title and due date (if available) for each task. 217 | 218 | 5. Implement task editing: 219 | - Add an edit button next to each task in the task list. 220 | - When the edit button is clicked, show an input field populated with the current task title and due date. 221 | - Handle the save button click event to update the task using the `updateTask` function from the data API. 222 | - Update the task list to reflect the changes. 223 | 224 | 6. Add due date functionality: 225 | - Modify the task creation and editing forms to include an input field for the due date. 226 | - Use the `` element to provide a user-friendly date picker. 227 | - Store the due date as a `Date` object in the `Task` data model. 228 | 229 | 7. Implement task sorting and filtering: 230 | - Add options to sort tasks by due date (ascending or descending) and filter tasks by a specific date range. 231 | - Update the task list based on the selected sorting and filtering options. 232 | 233 | 8. Implement task notifications: 234 | - Use the browser's Notification API to display notifications for tasks approaching their due dates. 235 | - Periodically check for tasks with upcoming due dates and show notifications accordingly. 236 | 237 | 9. Add recurring tasks: 238 | - Extend the task creation and editing forms to include options for setting up recurring tasks. 239 | - Allow users to specify the recurrence frequency (daily, weekly, monthly, yearly) and an optional end date. 240 | - Store the recurrence details in the `Task` data model. 241 | - Automatically create new task instances based on the recurrence rules. 242 | 243 | 10. Implement user preferences: 244 | - Create a separate web component, e.g., `UserPreferences`, to handle user-specific settings. 245 | - Allow users to select their preferred date format (DD/MM/YYYY or MM/DD/YYYY). 246 | - Store the user preferences using the provided data API. 247 | - Apply the selected date format when displaying dates throughout the application. 248 | 249 | 11. Implement accessibility: 250 | - Ensure that the application is keyboard-accessible by adding proper tabindex and aria attributes. 251 | - Use semantic HTML elements and provide appropriate labels and descriptions for form fields and buttons. 252 | - Test the application with assistive technologies to ensure compatibility. 253 | 254 | 12. Style the application: 255 | - Create a separate CSS file to define the styles for the web components. 256 | - Use CSS variables to maintain a consistent color scheme and typography throughout the application. 257 | - Ensure responsiveness and a mobile-friendly layout. 258 | 259 | ``` 260 | Now implement the plan. 261 | 262 | Remember: use web standards, lit-html and web components. Return all code as one file. Do not leave any placeholders, implement all functions or omit them if they cannot be written. Assume that any component named `` will be rendered automatically, do not provide an html page. 263 | ``` 264 | 265 | ```ts 266 | import { LitElement, html, css } from 'lit'; 267 | import { repeat } from 'lit/directives/repeat.js'; 268 | 269 | // Task-related constants 270 | const TASK_TYPE = 'Task'; 271 | 272 | // Function to create a new task 273 | async function createTask(taskData) { 274 | const obj = { 275 | id: taskData.id, 276 | type: TASK_TYPE, 277 | data: taskData 278 | }; 279 | await write(taskData.id, obj); 280 | } 281 | 282 | // Function to update an existing task 283 | async function updateTask(taskId, newTaskData) { 284 | const existingTaskObj = await read(taskId); 285 | if (existingTaskObj.type !== TASK_TYPE) { 286 | throw new Error("Task with given ID does not exist"); 287 | } 288 | 289 | const updatedTaskData = { ...existingTaskObj.data, ...newTaskData }; 290 | const updatedTaskObj = { 291 | id: taskId, 292 | type: TASK_TYPE, 293 | data: updatedTaskData 294 | }; 295 | await write(taskId, updatedTaskObj); 296 | } 297 | 298 | // Function to retrieve a task by its ID 299 | async function getTask(taskId) { 300 | const obj = await read(taskId); 301 | if (obj.type !== TASK_TYPE) { 302 | throw new Error("Task with given ID does not exist"); 303 | } 304 | return obj.data; 305 | } 306 | 307 | // Function to list all tasks 308 | async function listTasks() { 309 | const objs = await list(TASK_TYPE); 310 | return objs.map(obj => obj.data); 311 | } 312 | 313 | class TaskManager extends LitElement { 314 | static get properties() { 315 | return { 316 | tasks: { type: Array }, 317 | newTaskTitle: { type: String }, 318 | newTaskDueDate: { type: String }, 319 | sortBy: { type: String }, 320 | filterDate: { type: String } 321 | }; 322 | } 323 | 324 | constructor() { 325 | super(); 326 | this.tasks = []; 327 | this.newTaskTitle = ''; 328 | this.newTaskDueDate = ''; 329 | this.sortBy = 'dueDate'; 330 | this.filterDate = ''; 331 | } 332 | 333 | async connectedCallback() { 334 | super.connectedCallback(); 335 | this.tasks = await listTasks(); 336 | } 337 | 338 | async createTask() { 339 | const newTask = { 340 | id: Date.now().toString(), 341 | title: this.newTaskTitle, 342 | dueDate: this.newTaskDueDate ? new Date(this.newTaskDueDate) : undefined 343 | }; 344 | await createTask(newTask); 345 | this.tasks = [...this.tasks, newTask]; 346 | this.newTaskTitle = ''; 347 | this.newTaskDueDate = ''; 348 | } 349 | 350 | async updateTask(taskId, newTaskData) { 351 | await updateTask(taskId, newTaskData); 352 | this.tasks = this.tasks.map(task => task.id === taskId ? { ...task, ...newTaskData } : task); 353 | } 354 | 355 | async deleteTask(taskId) { 356 | await deleteTask(taskId); 357 | this.tasks = this.tasks.filter(task => task.id !== taskId); 358 | } 359 | 360 | sortTasks(tasks) { 361 | if (this.sortBy === 'dueDate') { 362 | return tasks.sort((a, b) => a.dueDate - b.dueDate); 363 | } 364 | return tasks; 365 | } 366 | 367 | filterTasks(tasks) { 368 | if (this.filterDate) { 369 | const filterDateObj = new Date(this.filterDate); 370 | return tasks.filter(task => task.dueDate && task.dueDate.toDateString() === filterDateObj.toDateString()); 371 | } 372 | return tasks; 373 | } 374 | 375 | render() { 376 | const filteredTasks = this.filterTasks(this.tasks); 377 | const sortedTasks = this.sortTasks(filteredTasks); 378 | 379 | return html` 380 |
381 |

Create Task

382 | this.newTaskTitle = e.target.value} placeholder="Task title"> 383 | this.newTaskDueDate = e.target.value}> 384 | 385 |
386 | 387 |
388 |

Task List

389 | 392 | this.filterDate = e.target.value}> 393 | 394 |
    395 | ${repeat(sortedTasks, task => task.id, task => html` 396 |
  • 397 | ${task.title} 398 | ${task.dueDate ? task.dueDate.toDateString() : ''} 399 | 400 | 401 |
  • 402 | `)} 403 |
404 |
405 | `; 406 | } 407 | 408 | static get styles() { 409 | return css` 410 | /* Add your styles here */ 411 | `; 412 | } 413 | } 414 | 415 | customElements.define('task-manager', TaskManager); 416 | ``` 417 | 418 | # Output 419 | 420 | ![alt text](image-1.png) -------------------------------------------------------------------------------- /image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonbrander/generative-ui-playbook/3d2a72a047cde92ca8f921a968844f1c9e516d39/image-1.png -------------------------------------------------------------------------------- /image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gordonbrander/generative-ui-playbook/3d2a72a047cde92ca8f921a968844f1c9e516d39/image.png --------------------------------------------------------------------------------