{"payload":{"feedbackUrl":"https://github.com/orgs/community/discussions/53140","repo":{"id":620799094,"defaultBranch":"main","name":"llemmings","ownerLogin":"romland","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2023-03-29T11:53:58.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/184137?v=4","public":true,"private":false,"isOrgOwned":false},"refInfo":{"name":"","listCacheKey":"v0:1684420688.004686","currentOid":""},"activityList":{"items":[{"before":"7ad7bb2f5cce9a593fc144010fa872c5cff8b5af","after":"8cca34db0709668621beb31750c1d40270acf56c","ref":"refs/heads/main","pushedAt":"2023-06-28T00:00:55.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Yeah, and now really on level 1","shortMessageHtmlLink":"Human: Yeah, and now really on level 1"}},{"before":"223955f930651d77ebe812a0ffc3c217509efa15","after":"7ad7bb2f5cce9a593fc144010fa872c5cff8b5af","ref":"refs/heads/main","pushedAt":"2023-06-27T21:29:00.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Oops - now a decoration","shortMessageHtmlLink":"Human: Oops - now a decoration"}},{"before":"65f5b4a793bd1bf66c5a1c2f29db23434d398b48","after":"223955f930651d77ebe812a0ffc3c217509efa15","ref":"refs/heads/main","pushedAt":"2023-06-27T21:26:40.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Added water bubbles to level 1","shortMessageHtmlLink":"Human: Added water bubbles to level 1"}},{"before":"d93fcf5e4f16e769b2ae5c73d6f91b5e45f5a2ea","after":"65f5b4a793bd1bf66c5a1c2f29db23434d398b48","ref":"refs/heads/main","pushedAt":"2023-06-27T21:25:39.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Decoration: water bubbles\nChatGPT: prompt below\nIt looks a bit so-so, but I feel it should be tweakable to look okay.\n\nThis took a while to get right, mostly due to what I believe is some Chrome\nwhen we're generating the animation. Works in Firefox and Safari, but fails in\nChrome.\n\n>>> Prompt:\nIn the same vein as the snippet below, I want a function that generates a frame of\nan animation that depicts a bubble popping. It should grow slowly and then 'explode'\nin a pop where a few particles fly off it and then disappear (either through fading\nor scaling). The bubble should not be filled.\n\nThe arguments to the function must remain the same and in the same order, infer anything\nelse (e.g. center is width/2, height/2, max-radius is hardcoded, etc).\n\nThere seems to be a bug in Chrome with the arc() function, make sure radius is an int and does not\nexceed the size of the canvas.\n\nfunction drawHatch(context, width, height, currentFrameNum, totalFrameCount)\n{\n // calculate angle of rotation for each door (Human: 1.34 is just because i want it slightly more than 90 degrees)\n const angle = (currentFrameNum / totalFrameCount * 1.34) * Math.PI / 2;\n\n context.save();\n context.translate(16, 5);\n context.rotate(angle);\n context.fillRect(0, -5, 30, 5);\n context.restore();\n\n context.save();\n context.translate(76, 5);\n context.scale(-1, 1); // mirror\n context.rotate(angle);\n context.fillRect(0, -5, 30, 5);\n context.restore();\n}\n\nFeel free to use a global variable for the particles.","shortMessageHtmlLink":"Decoration: water bubbles"}},{"before":"1513048f49cf7a8472467031d8bb615ecbf26041","after":"d93fcf5e4f16e769b2ae5c73d6f91b5e45f5a2ea","ref":"refs/heads/main","pushedAt":"2023-06-23T19:46:08.000Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Typo","shortMessageHtmlLink":"Human: Typo"}},{"before":"0aebf1404412ae6df6de050ed2cbc2a5697cf9c0","after":"1513048f49cf7a8472467031d8bb615ecbf26041","ref":"refs/heads/main","pushedAt":"2023-06-20T13:29:11.510Z","pushType":"push","commitsCount":5,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: LLM forgot a catch\nIncidentally, this was exposed by what _seems_ to be a bug in Chrome ... need to investigate","shortMessageHtmlLink":"Human: LLM forgot a catch"}},{"before":"b7de1941fc6d7776a69d3b8ee26259473fd4cd65","after":"0aebf1404412ae6df6de050ed2cbc2a5697cf9c0","ref":"refs/heads/main","pushedAt":"2023-06-18T16:30:03.931Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Deep merge of levelData\nChatGPT:\nHuman: Surprised I missed that this did not work prior","shortMessageHtmlLink":"Deep merge of levelData"}},{"before":"8cc0254519cb2ec119ff9f9dbe0bca6854a0fd66","after":"b7de1941fc6d7776a69d3b8ee26259473fd4cd65","ref":"refs/heads/main","pushedAt":"2023-06-16T10:10:14.524Z","pushType":"push","commitsCount":3,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Expandable/collapsable items in Editor's CRUD\nChatGPT: prompt below\nHuman: It's still a bit awkward, but better than it was\n\n>>> Prompt:\nThis is a recursive function that generates a CRUD.\nWhen it encounters an array it will allow adding/removing elements in the array.\n\nMake it so that objects and arrays and all individual array elements are collapsable and expandable.\nWhen an item is collapsed, show a sensible label.\nThe expand/collapse button should be above the input fields, also move the add/remove\nbuttons to above the input fields. Use arrow symbols for expand/collapse.\n\nBy default, objects and arrays should be collapsed.\n\nfunction dive(obj, path, opts, lvl = 0)\n{\n if(typeof obj === \"string\") {\n obj = [ obj ]\n }\n\n for (let key in obj) {\n const lbl = document.createElement('label');\n lbl.textContent = key;\n lbl.style.marginLeft = `${20 * lvl}px`;\n path.append(lbl);\n const id = path.id + '.' + key;\n\n if (key === 'type' && opts) {\n // ignore\n } else if (key.toLowerCase().includes('color')) {\n // ignore\n } else if (typeof obj[key] === 'string') {\n // ignore\n } else if (typeof obj[key] === 'number') {\n // ignore\n } else if (typeof obj[key] === 'boolean') {\n // ignore\n } else if (Array.isArray(obj[key])) {\n const arrContainer = document.createElement('div');\n arrContainer.id = id;\n path.appendChild(arrContainer);\n const updateArr = (container) => {\n container.innerHTML = '';\n obj[key].forEach((item, idx) => {\n const itemPath = document.createElement('div');\n itemPath.id = container.id + `[${idx}]`;\n container.appendChild(itemPath);\n dive(item, itemPath, opts?.[key], lvl + 1);\n });\n\n const addButton = document.createElement('button');\n addButton.textContent = '+ ' + (singularis[key] || key);\n addButton.style.marginLeft = `${20 * lvl}px`;\n\n addButton.addEventListener('click', () => {\n obj[key].push(JSON.parse(JSON.stringify(obj[key][0])));\n updateArr(container);\n });\n\n container.appendChild(addButton);\n };\n\n updateArr(arrContainer);\n\n if (obj[key].length > 0) {\n const removeButton = document.createElement('button');\n removeButton.textContent = '- ' + (singularis[key] || key);\n removeButton.style.marginLeft = `${20 * lvl}px`;\n\n removeButton.addEventListener('click', () => {\n obj[key].pop();\n updateArr(arrContainer);\n });\n path.appendChild(removeButton);\n }\n } else if (typeof obj[key] === 'object') {\n const newObjPath = document.createElement('div');\n newObjPath.id = id;\n path.appendChild(newObjPath);\n dive(obj[key], newObjPath, opts, lvl + 1);\n }\n }\n}","shortMessageHtmlLink":"Expandable/collapsable items in Editor's CRUD"}},{"before":"eeb3d5980ae373476770d22e2374a6382880879b","after":"8cc0254519cb2ec119ff9f9dbe0bca6854a0fd66","ref":"refs/heads/main","pushedAt":"2023-06-14T09:18:15.991Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Editor parity","shortMessageHtmlLink":"Human: Editor parity"}},{"before":"109e9c6ddfa9a25cc046ecc1e3023539338ef480","after":"eeb3d5980ae373476770d22e2374a6382880879b","ref":"refs/heads/main","pushedAt":"2023-06-13T14:27:04.351Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Draw an arrow indicating direction when selected\nChatGPT:\nHuman: This is to see direction of selected when lemmings are crowding eachother.\n\nThis is a sprite in a javascript game using 2d canvas:\n class Lemming\n {\n constructor(x, y) {\n this.age = 0;\n this.width = 10;\n this.height = 20;\n this.x = x;\n this.y = y;\n this.velX = 0;\n this.velY = 0;\n }\n }\n\nabove this sprite, I want to paint a white large arrow (configurable size)\nindicating which direction along x it is currently moving. Attribute velX\ncan be positive for right, and negative for left.\n\nGet attributes of the sprite using 'this' and 'ctx' for canvas context.\n\nAnd sheesh, an arrow looks like this: -> or <-\n\nThis time, give me only the code, I don't need an explanation.","shortMessageHtmlLink":"Draw an arrow indicating direction when selected"}},{"before":"911cdae9197756a4022a3ded2510989344ae5ea9","after":"109e9c6ddfa9a25cc046ecc1e3023539338ef480","ref":"refs/heads/main","pushedAt":"2023-06-09T09:06:08.721Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"How to draw an owl\n...notes in instructions","shortMessageHtmlLink":"How to draw an owl"}},{"before":"9a65386a6c71c055759cf96252b26d8afbeb3fac","after":"911cdae9197756a4022a3ded2510989344ae5ea9","ref":"refs/heads/main","pushedAt":"2023-06-09T09:05:35.467Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"How to draw an owl\nChatGPT:\nHuman: I learned that Snowy Owls prey on lemmings\n\n>>> Prompt:\nGive me a very simple drawing of the shapes of a snowy owl on a canvas, make sure it has\nwings (as separate shapes) on each side of its body.\nGive it two bird feet.\n\nHuman: https://glebbahmutov.com/blog/images/how-to-draw-fp-owl/how-to-draw-an-owl.jpg","shortMessageHtmlLink":"How to draw an owl"}},{"before":"232991333ed4c56b4b891d197beea30891aa8560","after":"9a65386a6c71c055759cf96252b26d8afbeb3fac","ref":"refs/heads/main","pushedAt":"2023-06-06T15:28:15.232Z","pushType":"push","commitsCount":4,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"ECS Shake component for lemming finish\nChatGPT:\n>>> Prompt:\nGiven an ECS in JS, below are components and easings already\navailable.\n\nI need a new component and system that shakes or rumbles\nthe position/size/rotation of an entity for a second or so,\nso that it looks like a brief earthquake.\n\nThere should be a possiblity to restart/stop the shaking\nusing some attribute of the Shake component.\n\nComponents:\n Position : Position,\n Velocity : Velocity,\n PathFollowing : PathFollowing,\n Sprite : Sprite,\n Rotate : Rotate,\n Scale : Scale,\n Animation : Animation,\n Follow : Follow,\n AnimatedSprite : AnimatedSprite,\n\nEasings:\n easeInOutSine : easeInOutSine,\n easeInOutCubic : easeInOutCubic,\n easeInOutBounce : easeInOutBounce,\n easeOutBounce : easeOutBounce,\n easeInBack : easeInBack,\n easeOutBack : easeOutBack,\n easeInOutBack : easeInOutBack,\n easeInElastic : easeInElastic,\n easeOutElastic : easeOutElastic,\n linear : linear,\n lerp : lerp,\n lerpAngle : lerpAngle,\n\nModify a component this way:\n const id = ecs.search(\"PathFollowing Star\");\n ecs.entities[id].components.Transform.rotation += 0.003;\n\nIn a previous prompt you gave me this component, which is fine:\n class Shake extends Component {\n constructor(duration = 1, intensity = 10) {\n super();\n this.duration = duration;\n this.intensity = intensity;\n\n this._timer = 0;\n this._stopped = true;\n\n this._orgPosition = {x:0, y:0};\n this._orgRotate = 0;\n this._orgScale = {x:1,y:1};\n }\n }\n\nA system is defined (e.g.) this way:\n class MovementSystem extends ECS.System { update(dt, components) {} }\n\nIn a system, get entity id and components like this:\n for (const [id, shake] of Object.entries(components.Shake)) {\n\nIMPORTANT: A component should not call any functions in any Entity.\n\nWhen the shake is over, it should be restored to the original state (position, rotation, scale)\n\nThis time I don't need an explanation, just give me the code.","shortMessageHtmlLink":"ECS Shake component for lemming finish"}},{"before":"cad651c5b23c6209a7d7ce13c87a3cd1b0bbed54","after":"232991333ed4c56b4b891d197beea30891aa8560","ref":"refs/heads/main","pushedAt":"2023-06-06T08:35:35.575Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Got rid of code and moved code\nAnimatedSprite class is gone and is now an ECS Component. There are no longer any sprite-handling in Llemmings proper. It should all go in ECS from now on.","shortMessageHtmlLink":"Human: Got rid of code and moved code"}},{"before":"7010f1d9eba55ec22d16f1d6bcd16181b96fd546","after":"cad651c5b23c6209a7d7ce13c87a3cd1b0bbed54","ref":"refs/heads/main","pushedAt":"2023-06-05T19:31:29.732Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Moved code","shortMessageHtmlLink":"Human: Moved code"}},{"before":"646c7cdf0575d1c93f6cd0eee244ad00a88df145","after":"7010f1d9eba55ec22d16f1d6bcd16181b96fd546","ref":"refs/heads/main","pushedAt":"2023-06-05T19:14:53.986Z","pushType":"push","commitsCount":5,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Moved graphics related code to art.js","shortMessageHtmlLink":"Human: Moved graphics related code to art.js"}},{"before":"c6f743d74df01ef84acaef84005100adc00c1a01","after":"646c7cdf0575d1c93f6cd0eee244ad00a88df145","ref":"refs/heads/main","pushedAt":"2023-06-05T12:20:56.776Z","pushType":"push","commitsCount":4,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"In ECS, allow Follow of several components\nChatGPT:\n\n>>> Prompt:\nGiven these classes:\n\nclass Follow extends Component <... code of full class went here ...>\n\nclass FollowSystem extends System <... code of full class went here ...>\n\nThe above support only one Component. It's deserialized like this:\n\n\"components\": {\n \"Follow\": {\n \"entityId\": 2,\n \"componentName\": \"Position\",\n \"attributes\": [\"x\", \"y\"],\n },\n}\n\nTo facilitate several components and several attributes, I want it to be:\n\n\"components\": {\n \"Follow\": {\n \"Position\": {\n \"entityId\": 2,\n \"attributes\": [\"x\", \"y\"],\n },\n \"Scale\": {\n \"entityId\": 1,\n \"attributes\": [\"x\", \"y\"],\n },\n },\n}","shortMessageHtmlLink":"In ECS, allow Follow of several components"}},{"before":"44ad183f3acc1daaffc6e4d3e7a8e4196afcd9a1","after":"c6f743d74df01ef84acaef84005100adc00c1a01","ref":"refs/heads/main","pushedAt":"2023-06-05T09:44:23.641Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Made public","shortMessageHtmlLink":"Human: Made public"}},{"before":"86877bee10b2fa289728e013b6159362df11f52a","after":"44ad183f3acc1daaffc6e4d3e7a8e4196afcd9a1","ref":"refs/heads/main","pushedAt":"2023-06-05T09:37:02.902Z","pushType":"push","commitsCount":3,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Added ECS component: Follow\nChatGPT: one-shot\n\n>>> Prompt:\nGiven an ECS in JS.\nI need \"Follow\" component and accompanying System. It would take another entity's\nid, component name and one or more attribute names. E.g. x and y of of e.g. a\nPosition component.\n\nThe idea is that the attributes in the Follow component would take attributes from\nthe Followed Entity and apply it to its own components.\n\nThe Follow component should be declared this way:\n class Follow extends Component\n {\n constructor(entityId, componentName, attributes)\n {\n super();\n this.entityId = ...;\n ...\n }\n }\n\nIn systems, you get components like this:\nfor (const [id, pathFollowing] of Object.entries(components.Rotate)) { ... }\n\nIn systems, you get related components like this:\nconst position = components.Position[id];\n\nThe system's (FollowSystem) update should look like this: update(deltaTime, components)\n\nThis time, I don't need an explanation, just give me the code.","shortMessageHtmlLink":"Added ECS component: Follow"}},{"before":"5182c03047eb99a8619691267dfc6d73c6e24574","after":"86877bee10b2fa289728e013b6159362df11f52a","ref":"refs/heads/main","pushedAt":"2023-06-04T21:23:56.756Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"ECS Animation component fix\nChatGPT:\n\n>>> Prompt:\nThis class is part of ECS. It has a problem in that it always animates\nto/from 0. Whilst it should take the initial value of the component's\nattribute into consideration. So, e.g. it will animate from initial\nvalue to target value. The initial value is currently stored in\n_initialVals ...\n\nThe target value can be either greater or smaller than the initial\nvalue (e.g. 0.5 half size, 2.0 double size).\n\nMake sure it works for both cases. Also note that direction has nothing\nto do with that, that is only used to reverse t.\n\nclass AnimationSystem {\n update(deltaTime, components) {\n for (const [id, animation] of Object.entries(components.Animation)) {\n animation._elapsedTime += deltaTime;\n\n for (const [componentName, attributes] of Object.entries(animation.attributes)) {\n const component = components[componentName][id];\n\n if(!animation._initialVals) {\n animation._initialVals = {};\n }\n if(!animation._initialVals[componentName]) {\n animation._initialVals[componentName] = {};\n }\n\n for (const [attributeName, animationData] of Object.entries(attributes)) {\n if(!animation._initialVals[componentName][attributeName]) {\n animation._initialVals[componentName][attributeName] = component[attributeName];\n }\n\n let progress = animation._elapsedTime * animationData.speed;\n const completedRepeats = Math.floor(progress / (animationData.direction * animationData.target));\n const inReverse = animationData.reverseOnRepeat && completedRepeats % 2 !== 0;\n\n if (animationData.repeat !== -1 && completedRepeats >= animationData.repeat) {\n progress = animationData.direction * animationData.target * animationData.repeat;\n } else {\n progress = progress % (animationData.direction * animationData.target);\n if (inReverse) {\n progress = animationData.direction * animationData.target - progress;\n }\n }\n\n const easing = Easings[animationData.easing];\n const t = progress / (animationData.direction * animationData.target);\n const easedProgress = easing(t);\n\n component[attributeName] = (easedProgress * (animationData.direction * animationData.target));\n }\n }\n }\n }\n}","shortMessageHtmlLink":"ECS Animation component fix"}},{"before":"59058fff16c10277ce4d01b1ff1fc21060ab36db","after":"5182c03047eb99a8619691267dfc6d73c6e24574","ref":"refs/heads/main","pushedAt":"2023-06-04T20:19:27.724Z","pushType":"push","commitsCount":4,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Entity Component System (ECS)\nChatGPT: most of them. Prompt #7 is GPT-4.\nHuman: There is still work to do around this (i.e. split things up), but\nthe basics is now there for \"random objects\" and possible enemies.\n\n>>> Prompt 1:\nGive me a simple entity-component-system in javascript.\nIt should also include:\n- serialization and deserialization to/from json\n- include example components for position, velocity and path following\n\n>>> Prompt 2:\nGiven an ECS in Javascript where following components are already available:\n- Velocity\n- Position\n\nGive me the component for 2D Sprite.\n\n>>> Prompt 3:\nIn an ECS system, which component should display a visible component on the canvas?\n\n>>> Prompt 4:\nGiven an ECS in Javascript where following components are already available:\n- Velocity\n- Position\n- Sprite\n\nGive me the component for something that is rendered on a canvas (Renderable).\n\n>>> Prompt 5.1:\nIn Javascript, give me generic serialize/deserialize methods in a class that also\nserializes everything in the entire class hierarchy.\n\n>>> Prompt 5.2; same context window\nMake the deserialize acccept and object instead of json\n\n>>> Prompt 5.3; same context window\nMake serialize just return an object instead of json -- it should omit all variable\nnames that start with underscore\n\n>>> Prompt 6:\nGiven an ECS in JS. I want the System for this PathFollowing component:\n\nclass PathFollowing extends Component {\n constructor(path, speed = 1) {\n super();\n this.path = path; // [ { x: 1, y:1, }, ... ]\n this.speed = speed;\n this.currentPoint = 0;\n }\n}\n\nGet components like this:\nfor (const [id, pathFollowing] of Object.entries(components.PathFollowing)) { ... }\n\nGet related components like this:\nconst position = components.Position[id];\n\nThrow errors when applicable:\n- PathFollowing requires Position component\n- PathFollowing may not have Velocity component\n\nWhen reaching the end of the path, it should go to starting point and repeat.\nRegardless of distance between points, it should always move at configured speed.\n\nJust give me the update method.\n\nPrompt 7:\nNote: GPT-4\nHuman: This took a long time to explain correctly to the LLM. I could have done it\n in a fraction of the time by hand. I suppose it was a bit too abstract or\n generic or so. ChatGPT kept getting tiny details wrong around repeating\n constantly. GPT-4 did mildly better and on third attempt (minor tweaks\n inbetween), it kind of nailed it.\n\nGiven an ECS in Javascript.\n\nI want a component and accompanying system that animates any numeric attributes in\nany other named component. It should accept multiple attributes.\n\nAn animation should have the following attributes:\n- target value for attribute\n- repeat - a positive number for how many times animation should repeat between original and target value. If it is -1, it should do it until manually stopped. This must also consider reverseOnRepeat (value to target and to value again).\n- direction\n- reverseOnRepeat (when reaching target, it should go backwards to original value)\n- easing (this should be a string)\n- speed (the higher speed, the faster)\n\nYou use _elapsedTime on Animation component to keep track of state. The _ prefix just means it should not be serialized, don't name anything with the _ prefix.\n\nYou use easings like this, they are already defined:\nEasings[\"easeInOutCubic\"](t)\n\nThe following components are alrady available:\nVelocity, Position, Sprite, PathFollower, Rotate, Scale\n\nand following Systems are already available:\nMovementSystem, RenderingSystem\n\nIn systems, you get components like this:\nfor (const [id, pathFollowing] of Object.entries(components.PathFollowing)) { ... }\n\nIn systems, you get related components like this:\nconst position = components.Position[id];\n\nThe system's (AnimationSystem) update should look like this: update(deltaTime, components)\n\nThe component should be declared like this:\nclass Animation extends Component { constructor() { super(); this._elapsedTime = 0; this.attributes = {}; } }\n\nAn example usage would be:\nE.g. I want a sprite to forever animate the rotation and scale using some easing.\n\nAn example structure would be:\n\"Animation\": {\n \"attributes\" : {\n \"Rotate\": {\n \"radians\": {\n \"target\": Math.PI * 2,\n \"repeat\": -1,\n \"direction\": 1,\n \"reverseOnRepeat\": false,\n \"easing\": \"linear\",\n \"speed\": 0.001,\n },\n },\n \"Scale\": {\n \"x\": {\n \"target\": 2,\n \"repeat\": 2,\n \"direction\": 1,\n \"reverseOnRepeat\": true,\n \"easing\": \"easeInOutCubic\",\n \"speed\": 1,\n },\n },\n }\n},\n\nThis time, I don't need an explanation, just give me the code.","shortMessageHtmlLink":"Entity Component System (ECS)"}},{"before":"d18c539b65cb29a04f5eb83b462ec92fd78f9f2b","after":"59058fff16c10277ce4d01b1ff1fc21060ab36db","ref":"refs/heads/main","pushedAt":"2023-06-01T22:03:38.305Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Removed logging","shortMessageHtmlLink":"Human: Removed logging"}},{"before":"9584fe04c214535a3fccc50144aaa3d48c64d6da","after":"d18c539b65cb29a04f5eb83b462ec92fd78f9f2b","ref":"refs/heads/main","pushedAt":"2023-05-31T11:51:52.620Z","pushType":"push","commitsCount":2,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Gave more time to solve level 1","shortMessageHtmlLink":"Human: Gave more time to solve level 1"}},{"before":"33a7809e779838b32c1bcf679e909143cec2f623","after":"9584fe04c214535a3fccc50144aaa3d48c64d6da","ref":"refs/heads/main","pushedAt":"2023-05-31T09:29:28.021Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Adjust hand speed depending on velocity","shortMessageHtmlLink":"Human: Adjust hand speed depending on velocity"}},{"before":"8906486fa50eccf64c350e64dec627925773b83b","after":"33a7809e779838b32c1bcf679e909143cec2f623","ref":"refs/heads/main","pushedAt":"2023-05-31T09:18:08.629Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Animated hands on lemming\nChatGPT:\n\n>>> Prompt:\nThis is a circle that represents a hand, right now it is static.\n\nIt should move in a curve back and forth as the object walks.\nTo determine animation state, you have this.age to use.\n\nNote that:\n- it should move smoothly back and forth so just using mod age\n is not enough as it needs to move back too\n\n ctx.fillStyle = \"white\";\n ctx.beginPath();\n ctx.arc(\n this.x + this.width / 2,\n this.y + this.height / 2,\n 2, // hand-size\n 0, 2 * Math.PI\n );\n ctx.fill();\n\nThis time, just give me the code, no need for explanation.","shortMessageHtmlLink":"Animated hands on lemming"}},{"before":"ec7fc858566b2362a939a41dca4923ddf719e7fd","after":"8906486fa50eccf64c350e64dec627925773b83b","ref":"refs/heads/main","pushedAt":"2023-05-30T20:12:10.174Z","pushType":"push","commitsCount":5,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Just fiddles around score screen\nand a bit of shuffling of code.","shortMessageHtmlLink":"Human: Just fiddles around score screen"}},{"before":"c568ac4d74925d90511273c2c9d1ca0584c38ecb","after":"ec7fc858566b2362a939a41dca4923ddf719e7fd","ref":"refs/heads/main","pushedAt":"2023-05-30T10:00:58.010Z","pushType":"push","commitsCount":6,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Gah. Make intro default again","shortMessageHtmlLink":"Human: Gah. Make intro default again"}},{"before":"973777ddae77a7819192cf03ca69fc2f1f729120","after":"c568ac4d74925d90511273c2c9d1ca0584c38ecb","ref":"refs/heads/main","pushedAt":"2023-05-29T20:32:01.551Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Code shuffling. A small firework.","shortMessageHtmlLink":"Human: Code shuffling. A small firework."}},{"before":"cbef2def0614f91b63b87213d9f4be66f293792e","after":"973777ddae77a7819192cf03ca69fc2f1f729120","ref":"refs/heads/main","pushedAt":"2023-05-29T14:20:10.930Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Bugfix for digger","shortMessageHtmlLink":"Human: Bugfix for digger"}},{"before":"880f3db3fa757e6aaaaac71d557b7e2a6feddcb3","after":"cbef2def0614f91b63b87213d9f4be66f293792e","ref":"refs/heads/main","pushedAt":"2023-05-29T14:11:42.967Z","pushType":"push","commitsCount":1,"pusher":{"login":"romland","name":null,"path":"/romland","primaryAvatarUrl":"https://avatars.githubusercontent.com/u/184137?s=80&v=4"},"commit":{"message":"Human: Disable test","shortMessageHtmlLink":"Human: Disable test"}}],"hasNextPage":true,"hasPreviousPage":false,"activityType":"all","actor":null,"timePeriod":"all","sort":"DESC","perPage":30,"cursor":"djE6ks8AAAADSlY93gA","startCursor":null,"endCursor":null}},"title":"Activity ยท romland/llemmings"}