xietanu [Lexaloffle Blog Feed]https://www.lexaloffle.com/bbs/?uid=66688 Sandboxed apps not given permissions properly (can cause data loss) <p>Following some experimentation, I've found a couple of issues with sandboxed apps and how they are given permissions to read/write files outside of the 'special locations'.</p> <h3>Loading cart with sandboxed workspace app can cause data loss</h3> <p>When you load a cart, Picotron helpfully reopens the workspaces you were using to edit that cart. If one of those workspaces is a sandboxed app, however, the app appears to be given write access but not read access.</p> <p>This results in the app 'opening' the files, but just creating blank, new files and then immediately saving the blank versions over the original files in RAM. This happens without the user initiating a save or doing anything beyond loading the cart. This makes it very easy for a user to lose data if they save the cart before noticing the issue (yes, I am speaking from experience...)</p> <p>This assumes all the loading/saving is done through wrangle_working_file, I haven't tested otherwise.</p> <p>The behaviour can be replicated by creating a sandboxed copy of code.p64 and using it to edit a cart, then saving and reloading that cart.</p> <p>This should (in theory) be recoverable with anywhen, but still not ideal, and essentially prevents users from sandboxing editors they want to use to edit carts (when otherwise this should be possible)</p> <h3>Giving functions to get_hlocation &amp; set_hlocation in wrangle_working_file completely breaks sandboxed apps</h3> <p>This can be seen by creating a sandboxed copy of code.p64.</p> <p>For some reason, this seems to effect its ability to write to files but not read from them. If an app with these functions set opens a file, the behaviour varies depending on if the file is in RAM or not:</p> <p><strong>In RAM</strong>: When trying to save, the user is notified: &quot;could not store to path&quot;. Whether the save actually happens is inconsistent. I believe it works the first time you try to save, but doesn't work on subsequent attempts.</p> <p><strong>Outside RAM</strong>: Usually (but not always?) the app crashes, giving a runtime error, saying <code>/system/lib/wrangle.lua:276: attempt to index a nil value</code>. Again, whether the save actually happens is inconsistent. It seems like the save works if the app created the file, but otherwise not? I'm not confident on this, though.</p> https://www.lexaloffle.com/bbs/?tid=149013 https://www.lexaloffle.com/bbs/?tid=149013 Fri, 16 May 2025 08:41:07 UTC Strawberry Src v1.2.1 <p> <table><tr><td> <a href="/bbs/?pid=166998#p"> <img src="/bbs/thumbs/pico64_strawberry_src-4.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=166998#p"> strawberry_src</a><br><br> by <a href="/bbs/?uid=66688"> xietanu</a> <br><br><br> <a href="/bbs/?pid=166998#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Strawberry Src</h1> <p>A slightly-less-simple code &amp; text editor<br /> Author: Matt Sutton / <a href="https://www.lexaloffle.com/bbs/?uid=66688"> @xietanu</a>.bsky.social<br /> Version: 1.2.1</p> <h3>Overview</h3> <p>Strawberry Src is intended as an equivalent app to Picotron's in-built code or text editors, with a few quality or life improvements to make navigating and editing code and text easier.</p> <h2>Important notes</h2> <h3>Sandboxing</h3> <p>For now, Strawberry Src should be unsandboxed - it's my aim that this won't be the case forever (it shouldn't need to be unsandboxed), but for now there are some serious bugs in Picotron with sandboxed carts permissions. The bugs are documented here: <a href="https://www.lexaloffle.com/bbs/?tid=149013">https://www.lexaloffle.com/bbs/?tid=149013</a></p> <p>You can unsandbox the cart by either loading it using <code>load -u #strawberry_src-4</code>, or by right-clicking on a local copy and clicking 'about strawberry_src.p64', then unchecking the box in the bottom-left corner.</p> <h3>Default app</h3> <p>There's a known bug in Picotron's filenav at the moment that means that even if you try to open a text or lua file with Strawberry Src, it will generally open in your default app anyway. To overcome this, the only real option is unfortunately to set Strawberry Src to be your default app for editing the files you want to use it with.</p> <p>You can do this with this command in the terminal: <code>default_app &lt;file_extension&gt; &lt;path_to_strawberry_src&gt;</code>.</p> <p>e.g. <code>default_app lua /strawberry_src.p64</code></p> <p>Unfortunately, this one is out of my control. The bug is logged as part of this thread: <a href="https://www.lexaloffle.com/bbs/?page=9&amp;tid=140647">https://www.lexaloffle.com/bbs/?page=9&amp;tid=140647</a></p> <h3>Make sure you've not got the same file opened more than once</h3> <p>Also, make sure you've closed files in the in-built code editor (or close the editor entirely) before editting them in Strawberry Src.</p> <p>The system should notify you about this, but it could lead to changes not being saved.</p> <p>Remember the code editor automatically opens main.lua when you start Picotron.</p> <h3>Change log</h3> <h4>Version 1.2.1</h4> <ul> <li>FIX: Fixed a crash that could occur when a string preview was generated for a multi-line string. Multi-line strings currently not supported for string previews. Thanks to <a href="https://www.lexaloffle.com/bbs/?uid=107886"> <a href="https://www.lexaloffle.com/bbs/?uid=107886"> @klautless</a></a> for the bug report.</li> </ul> <h4>Version 1.2.0</h4> <ul> <li>FEATURE: Added string previews. Hover over strings to see how they would be rendered - useful when using control codes. Thanks to @CannonTheWildWulf for the suggestion. Option to disable provided.</li> <li>FEATURE: Added TODO: tracking in code files. Comments with TODO: are highlighted and logged, and can be seen in a sidebar similar to bookmarks. Clicking on the task will jump to it, clicking on the checkbox will complete it and clicking on the x will delete it.</li> <li>FEATURE: Added ctrl-pageup/pagedown to jump to the previous and next function defined.</li> <li>FIX: Fixed a freeze caused by the character ' and syntax error checking in some circumstances. Thanks to <a href="https://www.lexaloffle.com/bbs/?uid=62401"> @demiskeleton</a> for reporting the bug.</li> <li>FIX: General improvements to performance, especially with dense and large files. Should now maintain a stable 60fps under all reasonable circumstances. Thanks to @Sounds for help with this.</li> </ul> <h4>Version 1.1.0</h4> <ul> <li>FEATURE: Added file previews. See features for more info. Thanks to @CannonTheWildWulf for the suggestion.</li> <li>FEATURE: Added ctrl-click/middle click on filepath strings to open the related file.</li> <li>FEATURE: Added filepaths to autocomplete, so if you start typing a string with a filepath, completions based on your filesystem will be offered. Thanks to <a href="https://www.lexaloffle.com/bbs/?uid=107886"> <a href="https://www.lexaloffle.com/bbs/?uid=107886"> @klautless</a></a> for the suggestion.</li> <li>FEATURE: Strawberry Src now alerts you if you're running it sandboxed and prompts to unsandbox it.</li> <li>FIX: Fixed a rare crash related to the syntax error checking.</li> <li>FIX: Fixed some issues related to saving while sandboxed (however, other bugs beyond my control mean it should still not be used sandboxed)</li> </ul> <h4>Version 1.0.0</h4> <ul> <li>Initial release</li> </ul> <h2>Features</h2> <p>Note, most features can be enabled/disabled/modified in the settings menu.</p> <h3>Syntax highlighting</h3> <p>Along with all the same highlighing as in-built code editor, user defined functions (within the same file), local variables and function variables are now all highlighted.</p> <h3>Syntax error highlighting</h3> <p>If there is a syntax error in your code, this will be highlighted with a red squiggly line. Hovering over this will give more information about the error.</p> <p>Additionally, the footer indicates if there is an error, and one what line.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_18.gif" alt="" /> <h3>Function tooltips</h3> <p>Hovering over a function gives information about it. For inbuilt functions, these are drawn from the documentation. For user-defined function, they are drawn from comments immediately before or after the relevant function.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_8.gif" alt="" /> <h3>Autocomplete</h3> <p>When typing code, if you pause a list of suggestions to complete the currently typed section will appear. You can select an option with the up/down arrows and accept it with tab.</p> <p>The suggestions are drawn from inbuilt functions, user-defined function and current local and function variables.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_17.gif" alt="" /> <p>If you are typing a string with a filepath, completions are offered based on your current file system.</p> <p>E.g. typing:</p> <p><code>&quot;gf</code></p> <p>might offer completions of <code>&quot;gfx/&quot;</code> and <code>&quot;gfx/0.gfx&quot;</code></p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_36.gif" alt="" /> <h3>Bookmarks</h3> <p>Bookmarks allow for quickly jumping around between points in the current file - most commonly, jumping to the start of function definitions, but they can be defined quite flexibly, and even grouped.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_27.gif" alt="" /> <p>Bookmarks for the current file can be shown / hidden with the bookmark button in the top right.</p> <p>In code files, bookmarks are automatically created for each function. In text files, they are created for any line starting formatted like: '## title' or '<strong> title </strong>'.</p> <p>Additionally, in code files, you can create a bookmark at any point in the code by adding a comment formatted like: '--[[BOOKMARK:title]]'</p> <p>Bookmarks can also be grouped. In code files, if you're using modules or classes, their associated functions will automatically be grouped. E.g. 'function module.func()' would be placed in the 'module' group, or 'function class:func()' would be placed in the 'class' group.</p> <p>Additionally, groups can be manually created using a comment formatted like: '--[[GROUP:title]]'. Groups are ended either by starting a new group, or with '--[[GROUP]]'.</p> <p>In text files, groups are started using a line formatted like '# title' or '<em> title </em>'.</p> <p>As an example, this file uses them!</p> <p>The formatting of the bookmarks has been done to try to be broadly compatible and not cause any issues when viewing files in a another program. Happy to take feedback on if this could work better!</p> <h3>ToDo tracking</h3> <p>Comment lines in code files that include &quot;TODO:&quot; are tracked and can be viewed by clicking the checkbox in the top right. They are also highlighted a different colour.</p> <p>Clicking on the task will jump to the line where it's defined, clicking on the checkbox completes it and clicking on the x deletes it.</p> <p>e.g.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>--TODO: Test out todos! --[[ A comment TODO: More todos. ]]</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>would create a two tasks with the titles &quot;Test out todos!&quot; and &quot;More todos.&quot;</p> <h3>Rainbow brackets</h3> <p>Matching brackets are highlighted by colour, with colours varying by level. Mismatched closing brackets are shown in white for easy identification. This can be turned on/off in the settings.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src.png" alt="" /> <h3>File previews</h3> <p>If you hover your mouse over a string with a reference to a file (e.g. &quot;gfx/0.gfx&quot;), a preview of that file may be shown. This currently works for text files (with syntax highlighting for lua files), pods and gfx files (where the first 24 sprites are previewed).</p> <p>Ctrl-click or middle mouse click on the string to open the previewed file.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_37.gif" alt="" /> <h3>Changeable themes</h3> <p>There are currently 4 themes that can be selected, and can be set separately for editing text or code. Note that the system theme draws its colours from your current system theme.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/strawberry_src_30.gif" alt="" /> <h3>Smooth scrolling</h3> <p>Scrolling is now smooth. Why was this so hard to implement?</p> <p>This can be enabled/disabled in the settings.</p> <h3>Line wrapping</h3> <p>In text files, lines can now be automatically wrapped.</p> <p>This can be enabled/disabled in the settings.</p> <h2>Keyboard shortcuts</h2> <h3>Cut/Copy/Paste</h3> <p>Ctrl-x - cut<br /> Ctrl-c - copy<br /> Ctrl-v - paste<br /> Shift-del - cut<br /> Ctrl-insert - copy<br /> Shift-insert - paste</p> <h3>Commenting</h3> <p>Ctrl-b - uncomment/comment line(s)<br /> Ctrl-shift-b - block uncomment/comment selected text</p> <h3>Indent/unindent</h3> <p>Pressing tab with multiple lines selected indents all of the lines.</p> <p>Pressing shift-tab unindents the current line(s).</p> <h3>Line manipulation</h3> <p>Alt-up/down - Move line(s) up/down<br /> Ctrl-d - Duplicate line(s)</p> <h3>Search/Goto</h3> <p>Ctrl-f - open/close search box<br /> Ctrl-g - repeat the current search<br /> Ctrl-h - repeat the current replace<br /> Ctrl-l - open/close the goto line box</p> <h3>Clicks</h3> <p>Double click - select whole token<br /> Triple click - select whole line</p> <h2>How does this relate to SpaghettiCode?</h2> <p>I built this editor as an effort to de-scope and create a new, more robust basic editor. This will form the core of the next version of SpaghettiCode, which I intend to continue to develop as a more complete development environment. However, I think it's a pretty good editor by itself and addresses a lot of the issues with SpaghettiCode's central editor (like maintaining good performance on large files).</p> <h3>License</h3> <p>Strawberry Source (c) 2025 by Matthew Sutton is licensed under CC BY-NC-SA 4.0. To view a copy of this license, visit <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">https://creativecommons.org/licenses/by-nc-sa/4.0/</a></p> https://www.lexaloffle.com/bbs/?tid=148993 https://www.lexaloffle.com/bbs/?tid=148993 Wed, 14 May 2025 12:36:43 UTC unpod(&quot;str&quot;) causes out of memory error/crash to desktop <p>As the title says, attempting to unpod the string, &quot;str&quot;, whether typed directly or stored in a variable causes either an out of memory error, or fully crashes picotron to the desktop - though the latter is rarer.</p> <p>Attempting to unpod other strings just returns nil, which seems like the behaviour I would expect?</p> <p>I've not found any other strings which cause this behaviour.</p> <p>Hope this is helpful!</p> https://www.lexaloffle.com/bbs/?tid=148824 https://www.lexaloffle.com/bbs/?tid=148824 Mon, 05 May 2025 20:10:41 UTC Batch drawing sprites ignores camera <p>When using batch drawing with sprites (i.e. supplying spr with a userdata), the sprites are drawn ignoring how camera is set using camera().</p> <p>For example, if the userdata gives the position x=10, y=10, the sprite will always be drawn 10 pixels from the top of the screen and 10 from the left, regardless of how camera() has been set.</p> <p>This isn't how other batch drawing operations work (which do seem to respect the camera) or how spr() works normally, and also doesn't (by my reading) match what's documented here: <a href="https://www.lexaloffle.com/dl/docs/picotron_gfx_pipeline.html">https://www.lexaloffle.com/dl/docs/picotron_gfx_pipeline.html</a>. As such, I assume this isn't intended and is a bug?</p> https://www.lexaloffle.com/bbs/?tid=148652 https://www.lexaloffle.com/bbs/?tid=148652 Mon, 28 Apr 2025 08:21:42 UTC Fireworks over D&uuml;sseldorf <p> <table><tr><td> <a href="/bbs/?pid=165506#p"> <img src="/bbs/thumbs/pico64_dues_fireworks-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=165506#p"> dues_fireworks</a><br><br> by <a href="/bbs/?uid=66688"> xietanu</a> <br><br><br> <a href="/bbs/?pid=165506#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Fireworks over D&uuml;sseldorf</h1> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/fireworks_7.gif" alt="" /> <p>A simple demo/screensaver that came about from a desire to get my head around userdata operations, particle systems and batch drawing, along with some affection for my current home.</p> <p>Has five different displays, each of which have some variations. Cycles through them randomly, tetris-bag style.</p> <p>Code is lightly commented in case anyone wants to take a look!</p> https://www.lexaloffle.com/bbs/?tid=148402 https://www.lexaloffle.com/bbs/?tid=148402 Sun, 13 Apr 2025 20:35:51 UTC Non-deterministic results from deterministic code <p>A bit of a weird one...</p> <p>I'm getting random results from code that doesn't have any random/changing elements.</p> <p>I have a cart that, whenever I run it, it has one of two behaviours, apparently at random? However, the code doesn't involve any randomness (and I seeded the random number generator just in case), and doesn't load anything from the disk or mess around with memory in weird ways - I would expect the results of this code to be completely deterministic prior to user input. It should just execute one line at a time, with all the same initial values. However, the result is something that is inconsistent.</p> <p>This is demonstrated below. All I am doing below is hitting ctrl-r to run the cartridge. You can see when this happens by the timer at the bottom. Each time I run it, shows one of two behaviours, seemingly at random:</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/non_deter_1.gif" alt="" /> <p>This happens both when running the cart from the RAM and running it normally, it's just easier to demonstrate from the RAM.</p> <p>The code for determining the dimensions of the white rectangles is a bit complicated and involves quite a few recursive calls, which I'm guessing might be the cause of this? e.g. behind the scenes Picotron's doing some stuff in parallel that's leading to a weird race condition?</p> <p>I'm not sure if this is a bug or is some weird edge case I'm running into, but thought it was worth flagging as it's not at all clear to me why this would happen.</p> <p>This is running on the latest version of Picotron (0.2.0c).</p> <p>The cart with all the code is below - apologies, pretty messy. Happy to try to explain any parts of it if it's useful but essentially, it's implementing a gui. The width of the white rectangles is dynamically determined by the width of red card they're in, and the width of that is determined by the width of the column, and the width of that is determined by the width of the window. Each time the width of the window changes (and at start-up), it triggers updates first to the column, then the card, then the text-editor. However, elements can also change dynamically based on their contents, so checks are triggered for parent and children each time each item changes dimension. As such, there's quite a few calls happening right at start-up to potentially update/reference the same values. This is why I think a behind-the-scenes race condition problem is a possibility.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/non_deter.p64.png" alt="" /> https://www.lexaloffle.com/bbs/?tid=148102 https://www.lexaloffle.com/bbs/?tid=148102 Sat, 29 Mar 2025 09:02:39 UTC SpaghettiCode v0.2.0 <p> <table><tr><td> <a href="/bbs/?pid=161718#p"> <img src="/bbs/thumbs/pico64_spaghetticode-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=161718#p"> spaghetticode</a><br><br> by <a href="/bbs/?uid=66688"> xietanu</a> <br><br><br> <a href="/bbs/?pid=161718#p"> [Click to Play]</a> </td></tr></table> </p> <h1>SpaghettiCode - a Picotron code editor</h1> <h3>v0.2.0 - alpha</h3> <p>SpaghettiCode is a code editor for Picotron that aims to provide more features than the built-in code editor, providing a little extra help and quality of life.</p> <h3>Important notes before you start using SpaghettiCode!</h3> <h4>SpaghettiCode is in alpha</h4> <p><strong>Please back up your carts before editing them with SpaghettiCode!</strong> I am not aware of any bugs or issues that could lead to corruption or data loss, but until it has seen a bit more of a shakedown, I don't want to risk being responsible for anyone losing work.</p> <p>Also, let me know if you run into weird issues or have ideas! Feedback would be greatly appreciated.</p> <h4>Close files in the in-built code editor (or close the editor entirely)</h4> <p>Having files open in the in-built code editor will prevent them from being saved by SpaghettiCode, meaning any changes made in SpaghettiCode will be lost. <em>Remember the code editor automatically opens main.lua when you start Picotron</em>.</p> <h4>SpaghettiCode doesn't run properly embedded online</h4> <p>It doesn't seem to be able to properly access the ram - so you can get an initial look at it, but if you want to use it, please load it locally with <code>load #spaghetticode-2</code>, then <code>save spaghetticode</code> (or whatever name/location you choose). Saving it is needed so you can then load your own cart that you want to edit.</p> <h4>SpaghettiCode needs to be unsandboxed.</h4> <p>Due to accessing the RAM, SpaghettiCode doesn't work sandboxed. The current version won't run at all - I plan for it to at least partially work sandboxed, but sandboxing was introduced after this current version was written.</p> <h2>Features</h2> <ul> <li><strong>Everything the in-built code editor offers (I think?)</strong> - syntax highlighting, find/replace, equivalent keyboard shortcuts, etc.</li> <li><strong>Additional syntax highlighting</strong> <ul> <li>functions defined by the user are highlighted a slightly darker green. All files included in your main.lua are scanned automatically and functions defined in these will also be highlighted.</li> <li>local variables and function variables, allowing you to see at a glance whether you're using a global/local variable.</li> <li>table indices (e.g. in table.variable, the variable shows up a different colour, differentiating from other variables.)</li> </ul></li> <li><strong>Function tooltips</strong> - hover over an in-built or user-defined function and get a tooltip with information on syntax/arguments/use. For user-defined functions, text is drawn from any comments in the lines immediately after the function your_func() line, allowing you to write useful reminders on use for your own code.</li> </ul> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/video_26.gif" alt="" /> <ul> <li><strong>Autocompletion of function names</strong> - If you start typing a function name and pause, SpaghettiCode will suggest an autocompletion from its list of inbuilt and user-defined functions. Press tab to accept this suggestion or keep typing to ignore it (or give it more letters to make a better suggestion). Can be turned off in settings.</li> <li><strong>Up to 3, side by side files</strong> - Right click on a code file in the file navigator on the right to open a new frame side by side. Up to 3 of these can be used at once. You can even open up the same file two or three times to allow you to look at different parts of it at the same time.</li> </ul> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/video_35.gif" alt="" /> <ul> <li><strong>In built code testing</strong> - Write your tests for your functions and run them, all within SpaghettiCode. You get a summary of what passed and failed, and a message explaining why a test failed if possible. See further down for more info on how to write/run tests.</li> </ul> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/sshot_6.png" alt="" /> <h2>Using SpaghettiCode</h2> <p>Mostly, you can use SpaghettiCode very similarly to the in-built code editor - I've tried to make switching as painless as possible. There's a few things it's worth knowing about, though:</p> <h4>Saving</h4> <p>Changes made in SpaghettiCode are automatically saved to the ram (as long as the file isn't open in the in-built code editor!). Then just hit ctrl-s (as usual) to save the ram to the cart.</p> <h4>File navigator</h4> <p>This is the panel on the right side of the screen and shows all of the files currently in the ram. At present, only a cart loaded into the ram can be edited.</p> <p>The buttons on the left side of the navigator allow you to switch between views - from top to bottom: the main editor, tests, settings, help.</p> <p>Click on folders to expand them, and click on files to open them. Right clicking opens them in a new frame, side by side with the currently open file. Clicking the 'X' in the top right of a frame closes it.</p> <p>Click '+new' to add a new file/folder.</p> <p>Scrolling with the scroll wheel allows you to see more if necessary.</p> <p>You can collapse the file navigator using the arrow in the bottom left, giving you more screen space for your code.</p> <h4>Keyboard shortcuts</h4> <p>These are mostly the same as in the in-built editor, but listed here for convenience:</p> <ul> <li>ctrl-s - save the ram to the cart.</li> <li>ctrl-r - run the cart in ram.</li> <li>ctrl-c, ctrl-x, ctrl-v - standard copy, cut, paste.</li> <li>ctrl-a - select all.</li> <li>ctrl-f - open the find and replace menu for the current frame.</li> <li>ctrl-g - repeat current find.</li> <li>ctrl-z, ctrl-y - Undo/redo. Up to 25 undo steps are stored for each file.</li> <li>ctrl-b - Comment/uncomment selected line(s)</li> <li>ctrl-d - Duplicate the current line</li> <li>alt-up/down - shift the current line up/down</li> <li>ctrl-left/right - jump one word at a time.</li> </ul> <h4>Writing and running tests</h4> <p><strong>Tests are bit experimental</strong> - While fully usable, tests are the most experimental aspect of SpaghettiCode at the moment. Let me know if you run into any weird issues with them.</p> <p>Tests are used to make sure your functions do what they're meant to, and can be helpful as you write and edit code to ensure the components of your program are working how you expect.</p> <p>To write a test, create a 'tests' folder inside /ram/cart/. Within this, create a new code file, e.g. 'tests.lua'. Test can be placed in any number of files or subfolders within /ram/cart/tests to help with organisation.</p> <p>Tests within each file then look like standard Picotron functions and should call a function you've written and use an assert (or multiple) statement to ensure it's producing the expected outcome.</p> <p>For example, a simple test might look like:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function test_two_plus_2() local expected = 4 local result = two_plus(2) -- two_plus() is the func we're testing assert(result == expected, &quot;Expected 4, got &quot;..tostr(result)) end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>A file can contain as many tests as you like, just defined in different functions.</p> <p>If you've done it right, your tests should appear in the tests view (checkbox icon on the file navigator). Click 'RUN ALL' to run them.</p> <p><strong>NOTE:</strong> When testing your code, SpaghettiCode only loads the functions and DOES NOT run _init(), _update(), or _draw(). If there are any global variables that need to be initialised for your function to work, initialise these within the test.</p> <h2>Planned Updates/Features</h2> <ul> <li>Polish - currently the presentation is a bit bare-bones in a lot of ways</li> <li>Goto - jump to any file or defined function by typing its name</li> <li>Find/replace across files</li> <li>Ability to delete/move files within the file navigator</li> <li>Multi-line comment shortcut (e.g. ctrl-shift-b)</li> <li>Display of gfx pods in the editor</li> <li>Handling of different environments for user function recognition.</li> <li>Multi-cursor editing.</li> <li>Your suggestion here!</li> </ul> <h2>Changelog</h2> <p><div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <h3>v0.2.0</h3> <ul> <li>Fixed bug causing crash when undoing a new line at end of file.</li> <li>Fixed syntax highlighting of inline function definitions.</li> <li>Fixed display of multi-line comments.</li> <li>Fixed uncommenting a line at the start of a line shifting the cursor off-screen.</li> <li>Fixed delay for undo when typing.</li> <li>A reload is now triggered if a new cart is loaded into RAM, meaning this will be displayed properly.</li> <li>Fixed missing key interactions (pgup, pgdown, home, end)</li> <li>Added keyboard shortcuts (ctrl-d to duplicate line, ctrl-left/right to skip between words, alt-up/down to shift a line up or down.)</li> <li>Removed limit on number of undo steps - these will only be culled if memory becomes an issue.</li> <li>Added fullscreen option in settings (requires restart after switching)</li> <li>Added GUI buttons to save and run the code, in addition to the keyboard shortcuts.</li> <li>Added ability to open any valid text file now, not just .lua files.</li> <li>Added x position memory when moving up/down lines</li> <li>Improved x position consideration of tabs when moving up/down</li> <li>Tooltip documentation is now drawn from either above or below the function definition, and is correctly drawn from multiline comments. e.g. the following now works:</li> </ul> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/sshot_9_sml.png" alt="" /> <ul> <li>Improved display of binary and hex numbers (think there are still some edge cases here to sort).</li> <li>Improved find/replace tab - faster, smoother, ctrl-f works to close it when it's selected, selected text is copied into find when openned.</li> <li>Removed jump to function definition (for now, working out a better implementation)</li> </ul> <h3>v0.1.0</h3> <ul> <li>Initial release.<br /> </div></div></div> </li> </ul> https://www.lexaloffle.com/bbs/?tid=147028 https://www.lexaloffle.com/bbs/?tid=147028 Thu, 06 Feb 2025 10:40:36 UTC json parser <p>As part of a project I'm working on, I wrote a quick json parser that loads a json file into a picotron table and thought it might be worth sharing.</p> <p>E.g.</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>{ &quot;a&quot;:{&quot;b&quot;:1,&quot;c&quot;:-3.5}, &quot;d&quot;:[&quot;e&quot;,true,false] }</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>is converted to:</p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>{ a={ b=1, c=-3.5 }, d={&quot;e&quot;,true,false} }</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p>So if you have some data in json format already, it's easy enough to load in. Hopefully a bit useful for storing configurations or data needed by carts outside of the code itself for neatness.</p> <p>It should follow json specifications (e.g. whitespace outside of strings doesn't matter), and any null values will be handed as picotron's nil - however, because of the ways nils are added to tables, they won't work/appear in the way it does in the json itself.</p> <p>Also, if the parser runs into any issues, it tries to offer some helpful errors to identify where the problem is.</p> <p>I've done some light testing of the code, but let me know if you run into any issues with it.</p> <p>Code is hidden below:<br /> <div><div><input type="button" value=" Show " onClick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.innerText = ''; this.value = ' Hide '; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.innerText = ''; this.value = ' Show '; }"></div><div><div style="display: none;"></p> <div> <div class=scrollable_with_touch style="width:100%; max-width:800px; overflow:auto; margin-bottom:12px"> <table style="width:100%" cellspacing=0 cellpadding=0> <tr><td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> <td background=/gfx/code_bg0.png> <div style="font-family : courier; color: #000000; display:absolute; padding-left:10px; padding-top:4px; padding-bottom:4px; "> <pre>function init_json_reader() J_WHITESPACE = {} J_WHITESPACE[&quot; &quot;]=true J_WHITESPACE[&quot; &quot;]=true J_WHITESPACE[chr(10)]=true J_WHITESPACE[chr(13)]=true J_START_TABLE = &quot;{&quot; J_STOP_TABLE=&quot;}&quot; J_START_LIST=&quot;[&quot; J_STOP_LIST=&quot;]&quot; J_QUOTE=&quot;\&quot;&quot; J_COLON=&quot;:&quot; J_COMMA=&quot;,&quot; J_OBJ_STARTS={ n=read_json_null, t=read_json_true, f=read_json_false, } J_OBJ_STARTS[J_QUOTE]=read_json_key_string J_OBJ_STARTS[J_START_TABLE]=read_json_table J_OBJ_STARTS[J_START_LIST]=read_json_list J_OBJ_STARTS[&quot;-&quot;]=read_json_number for i = 0,9 do J_OBJ_STARTS[tostr(i)] = read_json_number end json_init = true end function load_json_file(filepath) -- Load and read a json file and return a list or table if not json_init then init_json_reader() end local text = fetch(filepath) assert(text!=nil,&quot;Failed to load json file: &quot;..filepath) return read_json(text) end function read_json(string) if not json_init then init_json_reader() end -- Read a json string and return a list or table. if #string == 0 then return nil end local i=skip_json_whitespace(string,1) if string[i] == J_START_TABLE then return read_json_table(string,i) elseif string[i] == J_START_LIST then return read_json_list(string,i) else assert(false,&quot;Unexpected initial character encountered in json file: &quot;..string[i]) end end function skip_json_whitespace(string,i) -- Skip to the first non-whitespace character from position i while J_WHITESPACE[string[i]] do i+=1 assert(i&lt;=#string,&quot;Unexpectedly hit end of file while skipping whitespace\nin json file&quot;) end return i end function read_json_table(string,i) local eot = false local tab = {} local k, v = nil, nil if string[i]==J_START_TABLE then i+=1 end while not eot do k, v, i = read_json_table_entry(string, i) tab[k] = v i = skip_json_whitespace(string,i) if string[i]==J_COMMA then i+=1 elseif string[i]==J_STOP_TABLE then i+=1 eot=true else assert( false, &quot;Unexpected character encounted after reading json entry with\nkey '&quot;..tostr(k)..&quot;': &quot;..tostr(string[i])..&quot; &quot; ) end end return tab, i end function read_json_table_entry(string, i) local k, v = nil, nil i = skip_json_whitespace(string,i) k, i = read_json_key_string(string,i) i = skip_json_whitespace(string,i) assert( string[i] == J_COLON, &quot;Expected colon following json key '&quot;..k..&quot;', found: &quot;..string[i] ) i = skip_json_whitespace(string,i+1) assert( J_OBJ_STARTS[string[i]]!=nil, &quot;Unexpected value encounted while reading json entry\n'&quot;..k..&quot;', found: &quot;..string[i] ) v,i=J_OBJ_STARTS[string[i]](string,i) return k, v, i end function read_json_key_string(string,i) assert( string[i]!=J_STOP_TABLE, &quot;Table ended while expecting entry, make sure you don't have a misplaced comma.&quot; ) assert( string[i]==J_QUOTE, &quot;Expected json key/string to start with double quote,\ninstead found: &quot;..sub(string,i,i+10)..&quot;...&quot; ) i+=1 local s = i while string[i]!=J_QUOTE do i+=1 assert( i&lt;=#string, &quot;Encountered end of json while reading key/string:\n&quot;..sub(string,i,i+10)..&quot;...&quot; ) end return sub(string,s,i-1), i+1 end function read_json_list(string, i) local eol = false local lis = {} local value = nil if string[i]==J_START_LIST then i+=1 end while not eol do i = skip_json_whitespace(string,i) assert( string[i]!=J_STOP_LIST, &quot;List ended while expecting entry, make sure you don't have a misplaced comma.&quot; ) assert( J_OBJ_STARTS[string[i]]!=nil, &quot;Unexpected value encounted while reading json list,\nfound: &quot;..sub(string,i,i+10)..&quot;...&quot; ) value,i=J_OBJ_STARTS[string[i]](string,i) add(lis,value) i = skip_json_whitespace(string,i) if string[i]==J_COMMA then i+=1 elseif string[i]==J_STOP_LIST then i+=1 eol=true else assert( false, &quot;Unexpected character encounted after reading json list entry: &quot;..string[i] ) end end return lis, i end function read_json_null(string,i) assert(sub(string,i,i+3)==&quot;null&quot;,&quot;Was expecting to read null during json file read, instead\nfound: &quot;..sub(string,i,i+10)..&quot;...&quot;) i+=4 return nil, i end function read_json_true(string,i) assert(sub(string,i,i+3)==&quot;true&quot;,&quot;Was expecting to read true during json file read, instead\nfound: &quot;..sub(string,i,i+10)..&quot;...&quot;) i+=4 return true, i end function read_json_false(string,i) assert(sub(string,i,i+4)==&quot;false&quot;,&quot;Was expecting to read false during json file read, instead\nfound: &quot;..sub(string,i,i+10)..&quot;...&quot;) i+=5 return false, i end function read_json_number(string,i) local s = i while not ( J_WHITESPACE[string[i]] or string[i]==J_COMMA or string[i]==J_STOP_TABLE or string[i]==J_STOP_LIST ) do i+=1 assert(i&lt;=#string,&quot;Unexpectedly hit the end of json string while reading a number.&quot;) end return tonum(sub(string,s,i-1)), i end</pre></div></td> <td background=/gfx/code_bg1.png width=16><div style="width:16px;display:block"></div></td> </tr></table></div></div> <p></div></div></div></p> https://www.lexaloffle.com/bbs/?tid=146801 https://www.lexaloffle.com/bbs/?tid=146801 Sun, 26 Jan 2025 18:17:20 UTC String Theory <p> <table><tr><td> <a href="/bbs/?pid=160827#p"> <img src="/bbs/thumbs/pico64_string_theory-1.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=160827#p"> StringTheory v1.0.0</a><br><br> by <a href="/bbs/?uid=66688"> xietanu</a> <br><br><br> <a href="/bbs/?pid=160827#p"> [Click to Play]</a> </td></tr></table> </p> <h1>String Theory</h1> <p>A simple productivity app for making <strong>evidence boards</strong> - cards with information linked by string.</p> <p>A <em>very normal</em> way of mapping all kinds of information - stories, families, conspiracies, etc.</p> <p>Includes the ability to save, load and customize boards in a variety of ways.</p> <p>(Mostly made to help learn Picotron, but hope it might be fun/useful for someone!)</p> <p><a href="https://bsky.app/profile/xietanu.bsky.social">Find me on Bluesky</a></p> https://www.lexaloffle.com/bbs/?tid=146628 https://www.lexaloffle.com/bbs/?tid=146628 Sun, 19 Jan 2025 17:43:00 UTC Terra Nova Pinball v1.1.0 <p> <table><tr><td> <a href="/bbs/?pid=116356#p"> <img src="/bbs/thumbs/pico8_terra_nova_pinball-2.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=116356#p"> Terra Nova Pinball v1.2.0</a><br><br> by <a href="/bbs/?uid=66688"> xietanu</a> <br><br><br> <a href="/bbs/?pid=116356#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Terra Nova Pinball</h1> <p>Ricochet around an alien world in this Pico-8 pinball table.</p> <p><img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/title_screen.gif" alt="" /><img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/gameover.gif" alt="" /></p> <h2>Basic Gameplay</h2> <p>Launch the ball onto the table using ⬆️/⬇️ to control the launch power and 🅾️/❎ to release the ball.</p> <p>Use the flippers (⬅️/➡️ by default, can be configured in the menu) to keep the ball from draining out the bottom of the table, hitting targets and bumpers and completing minigames (see below) to score points.</p> <p>You have 3 balls to score as many points as you can, and record a new highscore!</p> <p>If the ball drains within 15s of launching, you get a free relaunch.</p> <p>Highscores are saved on the cart and can be viewed from the main menu.</p> <h2>Table Layout</h2> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/TerraNovaMap.png" alt="" /> <h3>Skillshot</h3> <p>Launch the ball so it hits the skillshot to score 250,000 points! Can only be got straight after launching the ball.</p> <h3>Outer Lanes</h3> <p>If your ball goes down the outer lane, it'll be kicked back up onto the field - the first time. After this, the lane closes and any balls that go down them will drain out of the bottom.</p> <p>These lanes reset after the ball drains, or if you light all of the targets in the associated group (the leftmost 3 for the left lane, and the rightmost 2 for the right lane).</p> <h2>Minigames</h2> <p>Completing the following minigames can help score big points - and achieve ORBIT...</p> <h3>Slingshot</h3> <p>Shoot the ball around the top, lighting up the spinner and landing in the left kick-out hole to score a <strong>Slingshot!</strong></p> <p>This scores 50,000 points and lights up the letter <strong>'O' in ORBIT</strong>.</p> <h3>Shifting Constellation</h3> <p>Passing the ball through one of the gaps at the top of the table will trigger the associated rollover and light one of the stars in this constellation.</p> <p>If you light all 5, you'll increase the <strong>multiplier</strong>, applying a 2x, 3x or even 4x bonus to all points you score. You'll also light the <strong>'B' in ORBIT</strong>.</p> <p>To help you light them all, you can shift which stars are lit left and right using the flipper controls.</p> <h3>Mapping the Solar System</h3> <p>Bounce the ball off of the <strong>planet bumpers</strong> at the top of the table to collect data about the solar system - the bar to the right of them tracks your progress. If you can fill it up, you'll score 500,000 points and light up the letter <strong>'I' in ORBIT</strong>.</p> <p>However, beware of orbital drift - the progress bar will drain over time, so you'll need to keep hitting the planet bumpers to fill it up.</p> <h3>Refueling the Rocket</h3> <p>Each time the ball passes down over one of the rollovers in each of the lanes at the bottom of the board, the rocket will be partially refueled.</p> <p>Trigger these 4 times to fill the <strong>rocket fuel gauge</strong>, and then land your ball in the kick-out hole at the base of the rocket to ignite <strong>Blast-off!</strong>!</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/multiball.gif" alt="" /> <p>This scores 243,000 points, unleashes 3 balls onto the board (which will be automatically replaced for 20 seconds!) and lights up the letter <strong>'R' in ORBIT</strong>.</p> <p>However, if you drain the ball, the gauge will empty. And if you ignite the engine before it's fully fueled, you'll just get partial points, with no multi-ball and no 'R'.</p> <h3>Calibrating the Lasers</h3> <p>Land the ball in the rightmost kick-out hole to start some target practice to calibrate the weapons systems.</p> <p>The light in front of one of the targets will start to blink - you'll then have 30s to hit that target. Then another will light up, and you'll have another 30s. Hit five of these without the timer running out, and you'll score 500,000 points and light up the letter <strong>'T' in ORBIT</strong>.</p> <p>Landing the ball in the kick-out hole while the target practice is ongoing will reset the timer back to a full 30s, giving you a bit more time.</p> <h3>Achieving ORBIT</h3> <p>Light all 5 letters in ORBIT and you'll score 3,000,000 points and gain a bonus ball.</p> <p>The letters will even reset - if you're skilled enough to light them all again. </p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/orbit.gif" alt="" /> <h2>Version History</h2> <h3>V1.0.0 - 27/08/22</h3> <p>Initial release</p> <h3>V1.1.0 - 27/08/22</h3> <ul> <li>FIX: Fixed an issue where the launcher would sometimes get stuck if released with 0 power.</li> <li>FEATURE: Additional paddle options optimised for mobile player.</li> </ul> <h3>V1.2.0 - 02/12/22</h3> <ul> <li>FIX: Fixed a rare out-of-bounds error that could occur during multiball.</li> <li>FEATURE: Relaunching of the ball is now automatic.</li> </ul> <h2>GitHub Repository</h2> <p><a href="https://github.com/xietanu/pico8-pinball">The code is available in this GitHub repository</a>.</p> <p>While not as well organised as it maybe it should be (and littered with magic numbers as I tried to save tokens!), this is hopefully an easier way of looking through the code than reading the cart directly.</p> <p>I also promise no particular wisdom, and am sure there are better ways to approach most/all of the problems here - I just learned a lot from others in the community generously sharing their work openly, so wanted to share in return.</p> https://www.lexaloffle.com/bbs/?tid=49068 https://www.lexaloffle.com/bbs/?tid=49068 Sat, 27 Aug 2022 17:32:36 UTC Quincunx <p> <table><tr><td> <a href="/bbs/?pid=114907#p"> <img src="/bbs/thumbs/pico8_quincunx_xietanu-0.png" style="height:256px"></a> </td><td width=10></td><td valign=top> <a href="/bbs/?pid=114907#p"> quincunx_xietanu</a><br><br> by <a href="/bbs/?uid=66688"> xietanu</a> <br><br><br> <a href="/bbs/?pid=114907#p"> [Click to Play]</a> </td></tr></table> </p> <h1>Quincunx - a Bean Machine</h1> <p>A <a href="https://en.wikipedia.org/wiki/Galton_board">Quincunx</a>, otherwise known as a bean machine or Galton board, is a device designed to demonstrate how bell curves appear from combinations of random events, and so why they appear so much in nature.<br /> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/quincunx p8_0.gif" alt="" /> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/norm_dist_sim_8.gif" alt="" /></p> <h2>A physics-based statistics toy</h2> <p>This cart (roughly) simulates marbles bouncing through a grid of pegs and landing in bins at the bottom - for anyone who enjoys watching marbles fall or maybe wants to demonstrate some statistical principles themselves.</p> <p>The bins have a bell curve overlaid on them that should match the approximate pattern of the balls once they have all fallen, so you can test how consistent the simulation is with the theory.</p> <img loading="lazy" style="margin-bottom:16px" border=0 src="/media/66688/norm_dist_sim_4.gif" alt="" /> <h2>How to get started</h2> <p>Just boot up the cart and select 'Start' to start with default settings, or use the options (adjusting with <strong>&lt;</strong> and <strong>&gt;</strong>) to set the number of balls and how quickly they're dispensed.</p> <p>Press <strong>X</strong> to return to the menu from the simulation at any time.</p> <h2>Is there anything more to it than that?</h2> <p>No, not really! It's just a quick and simple toy.</p> https://www.lexaloffle.com/bbs/?tid=48674 https://www.lexaloffle.com/bbs/?tid=48674 Wed, 27 Jul 2022 22:40:06 UTC