CPCWiki forum

General Category => Programming => Topic started by: zhulien on 17:54, 12 February 25

Title: Julian's Long List of Ideas Thread
Post by: zhulien on 17:54, 12 February 25
Hi,

I figured I will start this thread and try keep my ideas in here, up to you if you want to ignore them or read them.

:D
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:59, 12 February 25
- UNIDOS Stream ROM - in progress, proven some cool things can be done to extend BASIC, coded in Z80
 

This ideas was to create an easy way of exposing drivers or other functionality to BASIC in a way that BASIC only has to read/write to them like files.  As of now, in a POC state, proves the idea works.

https://github.com/PrimalNinja/Streamer
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:01, 12 February 25
- 8bitology API and SDK: for in-game lobby, messaging, achievements (mostly running and live at 8bitology.net), coded in JS and PHP

This idea is to provide internet functions for CPC, sort of like a proxy.  The API is available and running now, the status of it is documented in the AIP Ref section of the website

http://8bitology.net/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:02, 12 February 25
- 8BML browser to bring web browsing to CPC, protocol and SDK already available for years at 8bitology.net as well as logic for the browser (not yet coded on CPC), coded in JS and PHP

The SDK and protocol is documented and working now for some years, I didn't yet create a real 8BML client yet though.  There is documentation on the website.

http://8bitology.net/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:22, 12 February 25
- Virtual Display Units (VDU) for CPC API: been online for ages, please someone put support for it in your game and / or utilities - it gives CPC software the ability to display stuff on any of your old redundant displays laying around that may include a web browser: Wii, PS4, Xbox One, PC, Android Phones/Tablets, iPhones/iPads and smart TVs - an unlimited number of them!!! graphics can be added, we could put sound if wanted but it isn't there yet. display debug info in there when you are programming, run-time game comentary for anyone in the World to view... it's sort of a BETA but been online for years now, coded in JS and PHP

A POC is here.

http://8bitology.net/poc/vdu/

Documentation currently as follows: ( previously posted here: https://www.cpcwiki.eu/forum/programming/unlimited-number-of-networked-displays-api-for-m4-and-other-connected-devices/ )

I have created the first working version of my networked display API.  There is very little left to do to make it useful, then it can only get more useful from then as I add further commands to the API.


What is it?


Imagine you have all these old devices laying around your place, some useless old phones, tablets, smart TVs, PS3s, Wiis, PCs etc... or you just want some extra screen real-estate... so you stick them all on your desk and wall near your CPC... or you want to display information for the World to watch... status information?  debug information? etc...


You can now do that from your CPC.  With an unlimited number of networked screens for your game or application, with CPC-style Windows support too.  And they generally update at 10 frames per second from the server - almost suitable for real-time internet games!!!


How does it work?


First setup a channel.  You need a private channel GUID (or code) that no-one else knows.  It shouldn't be told to anyone as it is what gives you permissions to update the screens and windows within your channel.  You can give your channel a unique public name though which everyone can know - of course you can even create a private channel that is not known to anyone but yourself (and set it visible later if you like, or never - don't put really private stuff in there though, as there is no HTTPS for now on CPC is there).  This private channel GUID should really be read from a central config file on your SDCard so that all your games and apps can use your channel.


Second setup a screen, or as many screens as you need.  These screens you would normally create dynamically when your game or application starts - afterall, if you have a bunch of CPCs that you all use your channel, you don't want them all writing to the same screen do you?  But you can also have as many screens for your one game or application as you like - a status screen?  a debug screen?  a 24bit graphics screen?  All updated in realtime from your CPC to the rest of the World and your other devices.


Thirdly (optionally) setup some Windows, CPC style on your screens.  These are just labelled regions of your screen which you can use relative locating and printing to...


Fourthly, do something on your screen.  Locate, Print, clear the screen... more to come...  The screens are not static, they are 100% dynamically updated over the internet as fast as your internet connection allows on your display devices - but i have capped it at 10fps for now.


Lastly...  Connect your devices!  Yep, you can go to the channel index, or directly to your own channel to see all your screens.  Alternatively you can even bookmark a specific screen if you know the code (it should be dynamic, but depends how you choose to use them).


Commands for the POC environment:


NOTE: All the below examples, prefix with the following:  http://8bitology.net/poc/vdu/vdu.php (http://8bitology.net/poc/vdu/vdu.php)


newchannel:


?function=channel&cmd=newchannel&ownerguid=<your private channel guid>&channel=<your public channel name>&description=<a text description of your channel>
eg: ?function=channel&cmd=newchannel&ownerguid=ABCD&channel=batman&description=I%20really%20am%20Batman


newscreen:



?function=screen&cmd=newscreen&owner=<your private channel guid>&ownerguid=<your private screen GUID>&publicguid=<your public screen guid>
eg: ?function=screen&cmd=newscreen&owner=ABCD&ownerguid=XYZ&publicguid=batmask


newwindow:



?function=window&cmd=newwindow&screen=<your private screen guid>&window=<your windowcode>&x=<x position>&y=<y position>&w=<width>&h=<height>
eg: ?function=window&cmd=newwindow&screen=XYZ&window=1&x=1&y=10&w=40&h=5


locate:


?function=window&cmd=locate&screen=<your private screen guid>&window=<your windowcode>&x=<x position>&y=<y position>
eg: ?function=window&cmd=locate&screen=XYZ&window=1&x=15&y=1


print:


?function=window&cmd=print&screen=<your private screen guid>&window=<your windowcode>&text=<the text to print>
eg: ?function=window&cmd=print&screen=XYZ&window=1&text=I am Batman!


Channel Index:  http://8bitology.net/poc/vdu/ (http://8bitology.net/poc/vdu/)


Internet Call Demo: http://8bitology.net/poc/framework/itpdemo.htm (http://8bitology.net/poc/framework/itpdemo.htm)


Sprite Demo: http://8bitology.net/poc/framework/spritedemo.htm (http://8bitology.net/poc/framework/spritedemo.htm) (yep, I have coded sprites too but not yet collision detection).  These sprites will soon be in the networked display and more.



optional &tag=<tag> can now be added to all window functions.


What this allows is eg: you setup a display, you can simply update a tagged function in-place with a single call instead of having to re-create the display.


Some uses:


You can put a score somewhere with print given a tag of score (?function=window&cmd=print&screen=XYZ&window=1&tag=score&text=0).  You can then just update the score by issuing a replacement command for that specific tag (?function=window&cmd=print&screen=XYZ&window=1&tag=score&text=100).



You can put something somewhere on the screen and locate with a tag such as position (?function=window&cmd=locate&screen=XYZ&window=1&tag=position&x=1&y=1).  You can then just update the position by issuing a replacement command for that specific tag (?function=window&cmd=locate&screen=XYZ&window=1&tag=position&x=1&y=2).  Repeat this and it animates.


Anyone think this is useful enought to continue with?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:23, 12 February 25
- JSASM (proven) the dev environment can work, translator to z80 is not started, coded in JS*

* I was thinking of making my VB6 cross compiler and JS cross compiler all share the same code generator in the end... but if anyone is to use them but me, input is most welcome...

https://www.cpcwiki.eu/forum/programming/jsasm-js-virtual-assembler/
https://github.com/PrimalNinja/jsasm

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:24, 12 February 25
- Visual BASIC 6 (very large subset) cross compiler for CPC, and it can correctly parse itself - the code generator is unfinished, coded in VB5/VB6 (either work) *

Visual BASIC cross compiler, not completed but you can see where it's going and it can compile itself

https://github.com/PrimalNinja/vbcc
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:26, 12 February 25
- JavaScript (subset) cross compiler for CPC, and it can correctly parse itself - the code generator is unfinished, coded in JS (cannot compile itself) *

https://github.com/PrimalNinja/jscc

more of a POC at the moment, I have now some other ideas relating to this.

https://youtube.com/video/q8kBgWHT944
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:31, 12 February 25
- I created a POC of virtual Z80s as a webservice where you can prepare a memory model and have it execute code and return a response.  The POC is no longer online and was based on an open source GB Z80 (missing some typical Z80 instructions).

Any use? You could make a cluster of 1000s of them in AWS.

https://www.cpcwiki.eu/forum/programming/z80-clusters/

note: I did get a 2nd CPLink card so multiple can run at once in the same CPC too - the goal of this is related to the virtual Z80 in the cloud.  If I can finalise the API to work with 2, then it can also be 4 (across to a 2nd wifi connected CPC) or more (to the cloud) via a single API.

btw, EVERYONE please get yourself a CPC-CPLINK card or two!!!    https://www.cpcwiki.eu/forum/amstrad-cpc-hardware/cpc-cplink-a-coprocessor-interface-card-for-all-cpcs
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:35, 12 February 25
- Stack Programming.

I am planning to code a better demonstration of highly performant Z80 code.  I've been brainstorming a BASIC compiler to 'optionally' generate this code too so both typical code and stack based code can be directly compared.  Likely a subset of Locomotive BASIC - which relates to my JSCC ideas above - why not allow subsets of JS, Locomotive BASIC and C all compile to the same source.

https://www.cpcwiki.eu/forum/programming/stack-programming/msg245465
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:37, 12 February 25
- PrimalOS: let's call it early alpha is there in github, to allow multiple computers to run the same software - in itially text-only, but... not limited to that if you don't mind breaking compatability... it's not that complex like FutureOS or Symbos... but also at this moment not so important, coded in Z80

https://docs.google.com/spreadsheets/d/14JQa3cTEd9fIz9lyoQRkzVc5xBz5FhEdr_DC41xPkJs/edit
https://github.com/PrimalNinja/Primal

Still more to do, I did a minor update late last year so it is a work in progress I plan to finish.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:41, 12 February 25
- MCP / MOS - Multitasking mini kernel for AMSDOS drivers, proven and working but doesn't do a lot yet - perhaps this can share drivers with PrimalOS? feedback welcome, coded in Z80

https://drive.google.com/drive/folders/1Xvirgaep8dHFQUSaQxa5aQRV_SIbAfbR

What I think is cool is the current POC code there (you can build the ROM and play) allows you to run code in the background, even reset the CPC and have it optionally resume.

Why? Before the advent of M4 cards and such where we can store autoexecs on the SDCARD, there was no way to resume something...

I'd love to work with someone in the CPC World on a driver standard if they don't like what I've done so far.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:43, 12 February 25
- Locomotive Shell ROM - in progress, proven a custom shell based on BASIC is very viable, the plan could be to integrate MOS with Primal compatible drivers and design a very nice user experience as an alternative to BASIC, coded in Z80

and

- Locomotive BASIC 2 ROM - in progress, proven the language can be extended, and likely in a backward compatible way (at least to a high percentage) with current BASIC, coded in Z80

These are very closely related - they are new replacements for the existing Locomotive BASIC based on Bread80s ROM disassembly.

https://www.cpcwiki.eu/forum/programming/extending-locomotive-basic

Very interesting results and if anyone wants it put online to continue working on it, happy to do so.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:48, 12 February 25
- My first hardware project (beyond simple switches and piggybacked ROMs), I guess a bit dead in the water after having obtained all the parts necessary.  Although I have lots of research suggesting it is possible to use a standard Pi to behave as a CPU, whether the timings can be tight enough for a CPC hardware expansion are uncertain still.  Lots of docs here and maybe Pi 5 is now faster enough?  CPLink gives an awesome "different" way to give some features in software, that is proven!

https://www.cpcwiki.eu/forum/amstrad-cpc-hardware/cpc-raspberry-pi-bridge-card/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:50, 12 February 25
- Network Card driver for a game I am making, game is mostly designed but I am having difficulty developing it for now when I don't have a usable monitor for my CPC where I live.  The driver will be coded in Z80 (and work with 2 CPC network cards), game details will be anounced when I get the driver working.

yes, I failed to do simple data transfers in both the M4 as well as they Cyboard.  Grrr

If I can resolve that, I can then create a ROM that gives an 8bitology API RSX set and examples in assembly for using it in games.  Also if included in MCP ROM above, then we can simply send and receive messages between CPC users via CPC Basic RSXs.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:51, 12 February 25
- CPC online multiplayer games, server-side POC already up and running, prove that we can design a game together, coded in JS and PHP

Server Side has been online for ages, can't find the thread now in the forums - but the Network Card code I need working first before I can make a real CPC talk to it.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:52, 12 February 25
- Web based development environment with source control, modules and more (I think it's somewhat cool), coded in Z80 - would be more useful when the JavaScript cross compiler is more working... but can work with Z80 now if people wanted it to, just still thinking of the features to expose, coded in JS and PHP (this is the only somewhat closed source project of them all - but it could turn into the World's best dev environment - or not)

This is currently working but not currently public.  Debating whether it's worth to extend this to allow for an online dev environment for CPC (and other platforms).
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:59, 12 February 25
- Web based environment for new SlaveOS.  I am debating using the Web based development environment above vs a fresh open source minimal for this... mainly because the environment already has a document repo and ESB (enterprise service bus) built in.

Imagine you code an implementation of SlaveOS for your Commodore 64 (Blah 64) and your Amstrad CPC (Blah CPC).  Could just be a ROM on CPC you type |iamslave,"BLAHCPC","PUBLIC" or |iamslave,"BLAHCPC","PRIVATE" <-- CPC displays a code, or QRCode or 2D barcode

what it would do is connect to the server, and say, hey, I have speech synthesizer capability and AY-8-8912 music file playback capability and text output.  Or a C64 might say I have SID playback capability and text output.

Another program, on another computer that isn't a slave, can connect to the server and say, hey, what slaves are available for me?  SID Playback on Blah 64, text output on Blah 64, AY-3-8912 playback on Blah CPC, text output on Blah CPC.  This 'another' computer could be another CPC, C64, Smart Phone, PC or whatever anywhere around the World.  Any capabilities can be published and subscribed to and... our beloved old computers can joing the IOT World.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 19:10, 12 February 25
SlaveOS API

|iamslave,"BLAHCPC","PUBLIC" or "PRIVATE", the computer becomes a slave, either publshing a set of services from a local config file, or maybe a 2nd parameter to the RSX

|slaves, would ask the server to list all slaves
|slaves,"AY-3-8912", would ask for a list of all slaves with SID playback
|slave,"BLAHCPC" would list all services on BLAHCPC
|order,"BLAHCPC"," AY-3-8912 ",<sidfile> would send the server the AY-3-8912 file for BLAHCPC to play


Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 22:34, 12 February 25
Quote from: zhulien on 18:35, 12 February 25- Stack Programming.


Here is an example if someone wants to fill in the fast print char function (remember: don't use call or push).  and... the mode command, or just change the kw_mode to kw_cls

I put my hand coded example in the comments too, the purpose is not to create the most optimal assembly language program - that is likely by hand but... interestingly depending on some factors the stack programming can actually be faster AND smaller than the hand coded.

** if a program spends more time calling keywords in a function than calling functions, then the stack programming approach is positive **

but the goal is... to see how well potentially compiled code can be.  I am aware I can generate better examples of compiled code too with the keywords provided, just trying to think how a simple compiler might execute without much optimisation.  such as jumping over the loop to return is slower than a return_iftrue...


;restrictions
; interrupts must be disabled
; don't use call or push

;prefix key
; fn = subroutine called via kw_gosub, returned via kw_return
; kw = keyword statement, ends in any ret

;keywords implemented:

;flow control:
; kw_gosub, <label>
; kw_gosub_iftrue, <label>
; kw_gosub_iffalse, <label>
; kw_goto, <label>
; kw_goto_iftrue, <label>
; kw_goto_iffalse, <label>
; kw_return
; kw_return_iftrue
; kw_return_iffalse
; kw_stop

;logic:
; kw_dec8, <label>
; kw_dec16, <label>
; kw_inc8, <label>
; kw_inc16, <label>
; kw_iszero8, <label>
; kw_iszero16, <label>
; kw_let8, <label>, <value>
; kw_let16, <label>, <value>

;other:
; kw_cls
; kw_locate, <x>, <y>
; kw_mode, <n>
; kw_print, <stringaddr>

; ==============================================================================

; setup code

org #100

di
ld sp, main
ret

; ==============================================================================

; 10  gosub 30
; 20  stop

; 30  mode 1
; 40  for counter = 1 to 5
; 50    print "Hello"
; 60    print "Goodbye"
; 70    print "Hello"
; 80    print "Goodbye"
; 90    print "Hello"
; 100   print "Goodbye"
; 110   print "Hello"
; 120   print "Goodbye"
; 130 next counter
; 140 return

; typical handcoded:
;
; main:
; call fn_printscreen ; 3 bytes, 5 nops
; ret ; 1 byte, 3 nops
;
; fn_printscreen:
; ld a, 1 ; 2 bytes, 2 nops
; call kw_mode ; 3 bytes, 5+3 nops
;
; ld b, 5 ; 2 bytes, 2 nops
; fn_printscreen1:
; push bc ; 1 byte, 4 nops

; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_hello ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops
; ld hl, msg_goodbye ; 3 bytes, 3 nops
; call kw_print ; 3 bytes, 5+3 nops loopwork: 48 bytes, 88 nops x 5 = 440 nops

; pop bc ; 1 byte, 4 nops
; djnz fn_printscreen1 ; 3 bytes, 5 nops work: 5 bytes, 13 nops x 5 = 65 nops

; ret ; 1 byte, 3 nops
; ; total 65 bytes, 528 nops (caters for the 5 iterations)

main:
dw kw_gosub, fn_printscreen ; 10, 2 words, ? nops
dw kw_stop ; 20, 1 word, 3 nops

fn_printscreen: ; 30
dw kw_mode, 1 ; 30, 2 words, 3 nops
dw kw_let8, var_counter, 5 ; 40, 3 words, 3 nops

fn_printscreen1: ; 40
dw kw_iszero8, var_counter, kw_goto_iftrue, fn_printscreen2 ; 40, 4 words, 6 nops
dw kw_print, msg_hello ; 50, 2 words, 3 nops
dw kw_print, msg_goodbye ; 60, 2 words, 3 nops
dw kw_print, msg_hello ; 70, 2 words, 3 nops
dw kw_print, msg_goodbye ; 80, 2 words, 3 nops
dw kw_print, msg_hello ; 90, 2 words, 3 nops
dw kw_print, msg_goodbye ; 100, 2 words, 3 nops
dw kw_print, msg_hello ; 110, 2 words, 3 nops
dw kw_print, msg_goodbye ; 120, 2 words, 3 nops loopwork: 8 words (16 bytes), 24 nops x 5 = 120 nops
dw kw_dec8, var_counter, kw_goto, fn_printscreen1 ; 130, 4 words, 6 nops loop: 8 words (16 bytes), 12 nops x 5 = 60 nops

fn_printscreen2: ; 40

dw kw_return ; 140, 1 word, ? nops
; total 33 words (66 bytes), 189+ nops (caters for the 5 iterations)

; ------------------------------------------------------------------------------

var_counter: db 0

msg_hello: db "Hello", 0
msg_goodbye: db "Goodbye", 0

; ==============================================================================

kw_gosub:
pop bc ; where do we want to go, pop it first as we want
; the next statement upon kw_return

ld hl, 0 ; hl = hsp
add hl, sp

ld de,(ssp) ; de = ssp
ex de, hl ; hl = ssp, de = hsp

ld (hl), e ; push hsp on the ssp
dec hl ;
ld (hl), d ;
dec  hl ;

ld (ssp), hl ; store the new ssp

ld l, c
ld h, b
ld sp, hl
;end of kw_gosub

kw_gosub_iftrue:
pop bc ; where do we want to go, pop it first as we want
; the next statement upon kw_return
ret z

ld hl, 0 ; hl = hsp
add hl, sp

ld de,(ssp) ; de = ssp
ex de, hl ; hl = ssp, de = hsp

ld (hl), e ; push hsp on the ssp
dec hl ;
ld (hl), d ;
dec  hl ;

ld (ssp), hl ; store the new ssp

ld l, c
ld h, b
ld sp, hl
;end of kw_gosub_iftrue

kw_gosub_iffalse:
pop bc ; where do we want to go, pop it first as we want
; the next statement upon kw_return
ret nz

ld hl, 0 ; hl = hsp
add hl, sp

ld de,(ssp) ; de = ssp
ex de, hl ; hl = ssp, de = hsp

ld (hl), e ; push hsp on the ssp
dec hl ;
ld (hl), d ;
dec  hl ;

ld (ssp), hl ; store the new ssp

ld l, c
ld h, b
ld sp, hl
;end of kw_gosub_iffalse

kw_goto:
pop hl
ld sp, hl
;end of kw_goto

kw_goto_iftrue:
pop hl
ret z

ld sp, hl
;end of kw_goto_iftrue

kw_goto_iffalse:
pop hl
ret nz

ld sp, hl
;end of kw_goto_iffalse

kw_return: ; do a software return

ld hl, (ssp) ; get the ssp

inc hl ; pop hsp from ssp
ld d, (hl) ;
inc hl ;
ld e, (hl) ;

ld (ssp), hl ; store the new ssp

ex de, hl ; hl = hsp, de = ssp
ld sp, hl
;end of kw_return

kw_return_iftrue:
ret nz ; if z we want to do a software return

ld hl, (ssp) ; get the ssp

inc hl ; pop hsp from ssp
ld d, (hl) ;
inc hl ;
ld e, (hl) ;

ld (ssp), hl ; store the new ssp

ex de, hl ; hl = hsp, de = ssp
ld sp, hl
;end of kw_return_iftrue

kw_return_iffalse:
ret z ; if nz we want to do a software return

ld hl, (ssp) ; get the ssp

inc hl ; pop hsp from ssp
ld d, (hl) ;
inc hl ;
ld e, (hl) ;

ld (ssp), hl ; store the new ssp

ex de, hl ; hl = hsp, de = ssp
ld sp, hl
;end of kw_return_iffalse

kw_stop:
halt
;end of kw_stop

; ------------------------------------------------------------------------------

kw_dec8:
pop hl
dec (hl)
ret
;end of kw_dec16

kw_dec16:
pop hl
ld e,(hl)
inc hl
ld d, (hl)
dec de
ld (hl), d
dec hl
ld (hl), e
ret
;end of kw_dec16

kw_inc8:
pop hl
inc (hl)
ret
;end of kw_dec16
;end of kw_inc

kw_inc16:
pop hl
ld e,(hl)
inc hl
ld d, (hl)
inc de
ld (hl), d
dec hl
ld (hl), e
ret
;end of kw_inc

kw_iszero8:
pop hl
ld a, (hl)
or a
ret
;end of kw_iszero8

kw_iszero16:
pop hl
ld e, (hl)
inc hl
ld d, (hl)
ld a, e
or e
ret
;end of kw_iszero16

kw_let8:
pop hl
pop de
ld (hl), e
ret
;end of kw_let8

kw_let16:
pop hl
pop de
ld (hl), e
inc hl
ld (hl), d
ret
;end of kw_let16

; ------------------------------------------------------------------------------

kw_cls:
ld hl,#c000
ld de,#c001
ld bc,#3fff
xor a
ld (hl), a
ldir
ret
;end of kw_cls

kw_locate:
pop de
ld (var_cursorx), de
pop de
ld (var_cursory), de
ret
;end of kw_locate

kw_mode:
;TODO: set the mode

ret
;end of kw_mode

kw_print:
pop hl
kw_print1: ld a,(hl)
or a
ret z

;TODO: output a char

inc hl
jr kw_print1
;end of kw_print

; ------------------------------------------------------------------------------

ssp: dw sss ; software stack pointer
ssb: ds 128 ; bottom of software stack
sss:
; start of software stack

; ------------------------------------------------------------------------------

var_cursorx: dw 0
var_cursory: dw 0

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 22:35, 12 February 25
- Stack Programming.

Just a thought... I might be able to optimise the software stack a little too, but it serves the demonstration purpose. Code is untested but it does assemble.

Typical code example:

Total bytes: 65
Total nops: 528

Stack example:

Total bytes: 66
Total nops: 189+

The + for total nops in the stack example is because the software stack overhead of the single software call.  The DJNZ also helps a lot in the handcoded example.


timings from: https://www.cpcwiki.eu/imgs/b/b4/Z80_CPC_Timings_cheat_sheet.20230709.pdf


The thing I never got with all traditional programming, why return back to the logic after calling a keyword just to go back to the next keyword... this allows keywords to go directly from one to the next.  If only they made a  cpu with 2 stacks, an execution stack and a call stack.
Title: Re: Julian's Long List of Ideas Thread
Post by: Prodatron on 23:51, 12 February 25
I wonder why you don't finally complete one of your ideas and turn it into a useful product?
Title: Re: Julian's Long List of Ideas Thread
Post by: Pollo on 00:42, 13 February 25
Ideas are a dime a dozen. It's execution that counts.
— Frank Herbert
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 01:56, 13 February 25
Quote from: Prodatron on 23:51, 12 February 25I wonder why you don't finally complete one of your ideas and turn it into a useful product?
Complete or make useable?  I have many completed (depending on your definition) but so far no uptake, so more ideas come and will become Siamese ideas when combined.

Nobody wants online highscores or achievements or game lobby in cpc games it seems... so maybe I need to make a ROM so basic programmers can. Maybe they still won't. Maybe a 8bml browser but the  Maybe only me makes websites with the sdk.   

Maybe nobody wants to display debug info from their cpc or game info or commentary on remote displays private on their desk or across the world like a chess game commentary.

But... for me it is fun creating them.
Title: Re: Julian's Long List of Ideas Thread
Post by: eto on 08:54, 13 February 25
How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 02:05, 14 February 25
Quote from: eto on 08:54, 13 February 25How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
You need an M4 card or a Cyboard.
Title: Re: Julian's Long List of Ideas Thread
Post by: eto on 08:14, 14 February 25
Quote from: zhulien on 02:05, 14 February 25
Quote from: eto on 08:54, 13 February 25How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
You need an M4 card or a Cyboard.
So nothing on the CPC side, but an endpoint on a webserver?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 09:01, 14 February 25
Quote from: eto on 08:14, 14 February 25
Quote from: zhulien on 02:05, 14 February 25
Quote from: eto on 08:54, 13 February 25How can I use the VDU from the CPC? All the examples just specify the URL but what hardware/software on the CPC is required?
You need an M4 card or a Cyboard.
So nothing on the CPC side, but an endpoint on a webserver?
Yes, you do an http get with the rsx provided by m4

I have been thinking of making a library of rsx commands to make it easier for those who never called webserviced before
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 14:57, 26 February 25
Today on the way home from work, I was thinking, I have lots of RAM on my CPC, why can't i run lots of BASICs at the same time.

Now, this is far from doing that, but as an initial POC, I was thinking, from memory there is nothing stored in the OS ROMs that do anything with banking, so... we should in theory be able to store lots of the first 64kb into the other banks, and swap between them.  To make it "safer" for now, to avoid e.g. keyboard presses to swap tasks, we could use RSXs, like |1, |2, |3 (first 192kb of 256kb memory expansion).  the 4th bank first block initially to preserve the registers and anything else we may need to preserve.

Anyway, it is ALMOST finished, but was wondering is there any reason it shouldn't work?  If the entire state of the computer is stored (ok, as much as we can store) in each 64kb bank upon system reset, then we could do some BASIC in |1, change to |2 to do something else, maybe an other BASIC program, |3 to do something else etc...  If this POC works, it could be extended to be more useful - maybe instead of preserving just 64kb, maybe preserve 128kb on 1mb computers, and have |1 to |2.  Maybe then an alt+tab extension, or ctrl+1, ctrl+2...

Code so far (a little to do to make a working POC):

; TODO:
; honor lower ROM enabling
; enable and disable upper ROM in the ramlam function
; preserve initial registers correctly (including alternate and SP)
;
;FUTURE:
; can we fit a |4 within the 256kb extra RAM?
; perhaps support 128kb machines with memory swap-in-place
; dynamically detect memory sizes
; don't use macros? but we have plenty of ROM space for now

TXT_OUT_CHAR equ #bb5a
RAM_LAM equ #2000

org #c000

write direct -1,1,#C0

macro block_main
push bc
ld bc,  #7fc0
out (c), c
pop bc
endm

macro block_4
ld bc,  #7fc4
out (c), c
endm

macro block_5
ld bc,  #7fc5
out (c), c
endm

macro block_6
ld bc,  #7fc6
out (c), c
endm

macro block_7
ld bc,  #7fc7
out (c), c
endm

macro block_8
ld bc,  #7fcc
out (c), c
endm

macro block_9
ld bc,  #7fcd
out (c), c
endm

macro block_10
ld bc,  #7fce
out (c), c
endm

macro block_11
ld bc,  #7fcf
out (c), c
endm

macro block_12
ld bc,  #7fd4
out (c), c
endm

macro block_13
ld bc,  #7fd5
out (c), c
endm

macro block_14
ld bc,  #7fd6
out (c), c
endm

macro block_15
ld bc,  #7fd7
out (c), c
endm

macro block_registers
push bc
ld bc,  #7fdc
out (c), c
pop bc
endm

macro save_reg1 ;save registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#4000)

block_main
endm

macro save_reg2 ;save registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#5000)

block_main
endm

macro save_reg3 ;save registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#6000)

block_main
endm

macro load_reg1 ;load registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#4000)

block_main
endm

macro load_reg2 ;load registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#5000)

block_main
endm

macro load_reg3 ;load registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#6000)

block_main
endm

macro bank_0to1
;copy block 0 to 4
block_4
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 3 to 7 via 0 (corrupts block 0)
ld hl, ramlam
ld de, RAM_LAM
ld bc, ramlam_end - ramlam
ldir
block_7
call RAM_LAM

;copy block 1 to 5 via 0 (corrupts block 0)
block_main
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_5
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;restore block 0
block_4
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 2 to 6
block_6
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

block_main
endm

macro bank_0to2
;copy block 0 to 8
block_8
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 3 to 11 via 0 (corrupts block 0)
ld hl, ramlam
ld de, RAM_LAM
ld bc, ramlam_end - ramlam
ldir
block_11
call RAM_LAM

;copy block 1 to 9 via 0 (corrupts block 0)
block_main
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_9
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;restore block 0
block_8
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 2 to 10
block_10
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

block_main
endm

macro bank_0to3
;copy block 0 to 12
block_12
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 3 to 15 via 0 (corrupts block 0)
ld hl, ramlam
ld de, RAM_LAM
ld bc, ramlam_end - ramlam
ldir
block_15
call RAM_LAM

;copy block 1 to 13 via 0 (corrupts block 0)
block_main
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_13
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;restore block 0
block_12
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 2 to 14
block_14
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

block_main
endm

macro bank_1to0
;copy block 5 to 1 via 0
block_5
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_main
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 4 to 0
block_4
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 6 to 2
block_6
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 7 to 3, LOSES STACK
block_7
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

macro bank_2to0
;copy block 9 to 1 via 0
block_9
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_main
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 8 to 0
block_8
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 10 to 2
block_10
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 11 to 3 LOSES STACK
block_11
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

macro bank_3to0
;copy block 13 to 1 via 0
block_13
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir
block_main
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir

;copy block 12 to 0
block_12
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 14 to 2
block_10
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 15 to 3 LOSES STACK
block_11
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; CPC ROM header
               
defb 1 ; background ROM
defb 1 ; mark
defb 0 ; version
defb 0 ; modification

defw rsx_names

; RSX jumpblock

jp rom_init

; general

jp rsx_help
jp rsx_1
jp rsx_2
jp rsx_3

rsx_names: defb 'FLIPP', 'Y'+#80

defb 'FLIPPYHEL', 'P'+#80
defb '1'+#80
defb '2'+#80
defb '3'+#80

defb 0

; --------------------------------------------------

; help for RSXs are in the order that we want to display the entire online help

hlp_all:

hlp_help: defb '|flippyhelp - Displays online help.', 0
hlp_1: defb '|1 - Change to task 1.', 0
hlp_2: defb '|2 - Change to task 2.', 0
hlp_3: defb '|3 - Change to task 3.', 0

defb 0 ; terminator for |help

; system statuses & messages

msg_signon: defb ' FLIPPY V0.9 ROM BY VORAX 2025', 0
msg_version: defb '0.9', 0
msg_newline: defb 13, 10, 0

rom_init: di
ld a,(#8000) ;skip initialisation if not the first block
cp 1 ;as we don't want to get into an infinite loop
jp nz, init_end ;#8000 is used not #be80 as #8000 is zeroed out by
;the boot process

;#be80 is used to know which current bank we are in
;currently use bank 4 for register preservation & rom state

;for |3
ld a,3
ld (#be80), a
bank_0to3
save_reg3

;for |2
ld a,2
ld (#be80), a
bank_0to2
save_reg2

;for |1
ld a,1
ld (#be80), a
bank_0to1
save_reg1

init_end:
push af
push bc
push de
push hl

xor a
ld (#8000), a

ld hl, msg_signon ; signon
call str_output

ld hl, msg_newline
call str_output

pop hl
pop de
pop bc
pop af

ei
ret

rsx_1: di
push af
push bc

ld a,(#be80)
cp 2
jp z, rsx_1store2
cp 3
jp z, rsx_1store3

pop bc
pop af
ei
ret

rsx_1store2:
pop bc
pop af
save_reg2
bank_0to2
jp rsx_1end

rsx_1store3:
pop bc
pop af
save_reg3
bank_0to3

rsx_1end: bank_1to0
load_reg1
ei
ret

rsx_2: di
push af
push bc

ld a,(#be80)
cp 1
jp z, rsx_2store1
cp 3
jp z, rsx_2store3

pop bc
pop af
ei
ret

rsx_2store1:
pop bc
pop af
save_reg1
bank_0to1
jp rsx_2end

rsx_2store3:
pop bc
pop af
save_reg3
bank_0to3

rsx_2end: bank_2to0
load_reg2
ei
ret

rsx_3: di
push af
push bc

ld a,(#be80)
cp 1
jp z, rsx_3store1
cp 1
jp z, rsx_3store2

pop bc
pop af
ei
ret

rsx_3store1:
pop bc
pop af
save_reg1
bank_0to1
jp rsx_3end

rsx_3store2:
pop bc
pop af
save_reg2
bank_0to2

rsx_3end: bank_3to0
load_reg3
ei
ret

; ------------------------- display help

rsx_help: and a
jr z, fn_help
               
ld hl, hlp_help
jp str_outputln

fn_help: ld hl, hlp_all
fn_help_lp: ld a, (hl)
and a
ret z ; no more help
call str_outputln
inc hl
jr fn_help_lp

; ------------------------- ramlam

ramlam:
; TODO: disable upper rom
ld hl, #c000
ld de, #4000
ld bc, #4000
ldir
; TODO: enable upper rom
ret
ramlam_end:

; ------------------------- string output - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_output: ld a, (hl)
and a
ret z
call TXT_OUT_CHAR
inc hl
jr str_output

; ------------------------- string output and a newline - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_outputln:
call str_output
push hl
ld hl, msg_newline
call str_output
pop hl
ret



Any thoughts?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:05, 26 February 25
fixed quite a few things, search for TODO to see what there is TODO

How is the best way to get the current state of the upper and lower ROMS and re-enable them without firmware?

I wreckon someone smarter than me could have this running in 20 minutes :D
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:42, 26 February 25
Someone suggested ROM space is a good place to put maths functions - because... likely you can store lots of precalculated tables.

Some ideas for inclusion within a MATHS ROM which lots of future programs 'could' use.

- multiplication tables, integer
- division tables, integer
- remainder tables, integer
- sin, cos, tan
- matrix transformations using table lookups

are float functions worth putting in also? i guess why not put the best ones available.  The good thing about a standard MATHS rom, it would behave like an Amiga library or a Windows DLL, when better routines get put in, software gets faster.
Title: Re: Julian's Long List of Ideas Thread
Post by: andycadley on 15:58, 26 February 25
Quote from: zhulien on 14:57, 26 February 25Today on the way home from work, I was thinking, I have lots of RAM on my CPC, why can't i run lots of BASICs at the same time.

Now, this is far from doing that, but as an initial POC, I was thinking, from memory there is nothing stored in the OS ROMs that do anything with banking, so... we should in theory be able to store lots of the first 64kb into the other banks, and swap between them.  To make it "safer" for now, to avoid e.g. keyboard presses to swap tasks, we could use RSXs, like |1, |2, |3 (first 192kb of 256kb memory expansion).  the 4th bank first block initially to preserve the registers and anything else we may need to preserve.


I'm not sure you'd really need to preserve the registers, since RSX's by definition don't so presumably the ROM calling code is good as it is. And interrupts will presumably always be enabled. The Stack pointer would need preserving, but I think that's about it.

The trickiest part would be juggling ROM/RAM usage around to be able to copy all 64K around, but that shouldn't be insurmountable (I'm not sure I've had enough coffee or thinking time to convince myself of the best approach).
Title: Re: Julian's Long List of Ideas Thread
Post by: andycadley on 16:00, 26 February 25
Quote from: zhulien on 15:42, 26 February 25Someone suggested ROM space is a good place to put maths functions - because... likely you can store lots of precalculated tables.

Some ideas for inclusion within a MATHS ROM which lots of future programs 'could' use.

- multiplication tables, integer
- division tables, integer
- remainder tables, integer
- sin, cos, tan
- matrix transformations using table lookups

are float functions worth putting in also? i guess why not put the best ones available.  The good thing about a standard MATHS rom, it would behave like an Amiga library or a Windows DLL, when better routines get put in, software gets faster.
I think this could be a great idea. Especially if clear machine code entry points were provided as well as RSX entry points (so that it could be used in cartridges that don't include the firmware). And as long as people don't license it up the wazoo with GPL and such.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:07, 26 February 25
Quote from: andycadley on 15:58, 26 February 25
Quote from: zhulien on 14:57, 26 February 25Today on the way home from work, I was thinking, I have lots of RAM on my CPC, why can't i run lots of BASICs at the same time.

Now, this is far from doing that, but as an initial POC, I was thinking, from memory there is nothing stored in the OS ROMs that do anything with banking, so... we should in theory be able to store lots of the first 64kb into the other banks, and swap between them.  To make it "safer" for now, to avoid e.g. keyboard presses to swap tasks, we could use RSXs, like |1, |2, |3 (first 192kb of 256kb memory expansion).  the 4th bank first block initially to preserve the registers and anything else we may need to preserve.


I'm not sure you'd really need to preserve the registers, since RSX's by definition don't so presumably the ROM calling code is good as it is. And interrupts will presumably always be enabled. The Stack pointer would need preserving, but I think that's about it.

The trickiest part would be juggling ROM/RAM usage around to be able to copy all 64K around, but that shouldn't be insurmountable (I'm not sure I've had enough coffee or thinking time to convince myself of the best approach).
The juggling is already coded there, i am in the process of testing now, it is copying the ROM content though as the ROM is enabled.  I created my own ramlam sort of, it copies a small routing from ROM into RAM to disable ROMs and copy the screen RAM, but... still i have to figure out how to disable and enable the ROMs.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:25, 26 February 25
fixed the RAMLAMs other than the rom disabling/enabling

; TODO:
; honor lower ROM enabling
; enable and disable upper ROM in the ramlam function
; preserve initial registers correctly (including alternate and SP)
;
;FUTURE:
; can we fit a |4 within the 256kb extra RAM?
; perhaps support 128kb machines with memory swap-in-place
; dynamically detect memory sizes
; don't use macros? but we have plenty of ROM space for now

TXT_OUT_CHAR equ #bb5a
RAM_LAM_0000 equ #8000 ; above lower ROM and below upper ROM, copies RAM under lower ROM
RAM_LAM_C000 equ #8100 ; above lower ROM and below upper ROM, copies RAM under upper ROM

org #c000

;write direct -1,1,#C0

macro block_main
push bc
ld bc,  #7fc0
out (c), c
pop bc
endm

macro block_1_0
ld bc,  #7fc4
out (c), c
endm

macro block_1_1
ld bc,  #7fc5
out (c), c
endm

macro block_1_2
ld bc,  #7fc6
out (c), c
endm

macro block_1_3
ld bc,  #7fc7
out (c), c
endm

macro block_2_0
ld bc,  #7fcc
out (c), c
endm

macro block_2_1
ld bc,  #7fcd
out (c), c
endm

macro block_2_2
ld bc,  #7fce
out (c), c
endm

macro block_2_3
ld bc,  #7fcf
out (c), c
endm

macro block_3_0
ld bc,  #7fd4
out (c), c
endm

macro block_3_1
ld bc,  #7fd5
out (c), c
endm

macro block_3_2
ld bc,  #7fd6
out (c), c
endm

macro block_3_3
ld bc,  #7fd7
out (c), c
endm

macro block_registers
push bc
ld bc,  #7fdc
out (c), c
pop bc
endm

macro save_reg1 ;save registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#4000)

block_main
endm

macro save_reg2 ;save registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#5000)

block_main
endm

macro save_reg3 ;save registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100 ;set new sp so we can push the other registers faster
push af
push bc
push de
push hl
push ix
push iy
exx
push bc
push de
push hl
exx

ld sp, (#6000)

block_main
endm

macro load_reg1 ;load registers for bank 1
block_registers

ld (#4000), sp

ld sp, #4100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#4000)

block_main
endm

macro load_reg2 ;load registers for bank 2
block_registers

ld (#5000), sp

ld sp, #5100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#5000)

block_main
endm

macro load_reg3 ;load registers for bank 3
block_registers

ld (#6000), sp

ld sp, #6100-18 ;set new sp so we can pop the other registers faster
exx
pop hl
pop de
pop bc
exx
pop iy
pop ix
pop hl
pop de
pop bc
pop af

ld sp, (#6000)

block_main
endm

macro bank_0to1
;copy block 0_2 to 1_2
block_1_2
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy ramlams into 0_2 (corrupts block 0_2)
ld hl, ramlam_l
ld de, RAM_LAM_0000
ld bc, ramlam_l_end - ramlam_l
ldir

ld hl, ramlam_h
ld de, RAM_LAM_C000
ld bc, ramlam_h_end - ramlam_h
ldir

;copy block 0_0 to 1_0
block_1_0
call RAM_LAM_0000

;copy block 0_3 to 1_3
block_1_3
call RAM_LAM_C000

;copy block 0_1 to 1_1 via into 0_2 (corrupts block 0_2)
block_main
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_1_1
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;restore block 0_2
block_1_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

block_main
endm

macro bank_0to2
;copy block 0_2 to 2_2
block_2_2
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy ramlams into 0_2 (corrupts block 0_2)
ld hl, ramlam_l
ld de, RAM_LAM_0000
ld bc, ramlam_l_end - ramlam_l
ldir

ld hl, ramlam_h
ld de, RAM_LAM_C000
ld bc, ramlam_h_end - ramlam_h
ldir

;copy block 0_0 to 2_0
block_2_0
call RAM_LAM_0000

;copy block 0_3 to 2_3
block_2_3
call RAM_LAM_C000

;copy block 0_1 to 2_1 via into 0_2 (corrupts block 0_2)
block_main
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_2_1
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;restore block 0_2
block_2_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

block_main
endm

macro bank_0to3
;copy block 0_2 to 3_2
block_3_2
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy ramlams into 0_2 (corrupts block 0_2)
ld hl, ramlam_l
ld de, RAM_LAM_0000
ld bc, ramlam_l_end - ramlam_l
ldir

ld hl, ramlam_h
ld de, RAM_LAM_C000
ld bc, ramlam_h_end - ramlam_h
ldir

;copy block 0_0 to 3_0
block_3_0
call RAM_LAM_0000

;copy block 0_3 to 3_3
block_3_3
call RAM_LAM_C000

;copy block 0_1 to 3_1 via into 0_2 (corrupts block 0_2)
block_main
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_3_1
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;restore block 0_2
block_3_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

block_main
endm

; no need for RAMLAMs here because all writes to ROM go to underlying RAM
macro bank_1to0
;copy block 5 to 1 via 2
block_1_1
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_main
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy block 4 to 0
block_1_0
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 6 to 2
block_1_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 7 to 3, LOSES STACK
block_1_3
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; no need for RAMLAMs here because all writes to ROM go to underlying RAM
macro bank_2to0
;copy block 9 to 1 via 2
block_2_1
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_main
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy block 8 to 0
block_2_0
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 10 to 2
block_2_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 11 to 3 LOSES STACK
block_2_3
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; no need for RAMLAMs here because all writes to ROM go to underlying RAM
macro bank_3to0
;copy block 13 to 1 via 2
block_3_1
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir
block_main
ld hl, #8000
ld de, #4000
ld bc, #4000
ldir

;copy block 12 to 0
block_3_0
ld hl, #4000
ld de, #0000
ld bc, #4000
ldir

;copy block 14 to 2
block_2_2
ld hl, #4000
ld de, #8000
ld bc, #4000
ldir

;copy block 15 to 3 LOSES STACK
block_2_3
ld hl, #4000
ld de, #c000
ld bc, #4000
ldir
endm

; CPC ROM header
               
defb 1 ; background ROM
defb 1 ; mark
defb 0 ; version
defb 0 ; modification

defw rsx_names

; RSX jumpblock

jp rom_init

; general

jp rsx_help
jp rsx_1
jp rsx_2
jp rsx_3

rsx_names: defb 'FLIPP', 'Y'+#80

defb 'FLIPPYHEL', 'P'+#80
defb '1'+#80
defb '2'+#80
defb '3'+#80

defb 0

; --------------------------------------------------

; help for RSXs are in the order that we want to display the entire online help

hlp_all:

hlp_help: defb '|flippyhelp - Displays online help.', 0
hlp_1: defb '|1 - Change to task 1.', 0
hlp_2: defb '|2 - Change to task 2.', 0
hlp_3: defb '|3 - Change to task 3.', 0

defb 0 ; terminator for |help

; system statuses & messages

msg_signon: defb ' FLIPPY V0.9 ROM BY VORAX 2025', 0
msg_version: defb '0.9', 0
msg_newline: defb 13, 10, 0
msg_task1: defb 'Task 1', 0
msg_task2: defb 'Task 2', 0
msg_task3: defb 'Task 3', 0

rom_init: di
push af
push bc
push de
push hl

ld a,(#8000) ;skip initialisation if not the first block
cp 1 ;as we don't want to get into an infinite loop
jp nz, init_end ;#8000 is used not #be80 as #8000 is zeroed out by
;the boot process

;#be80 is used to know which current bank we are in
;currently use bank 4 for register preservation & rom state

;for |3
ld a,3
ld (#be80), a
bank_0to3
save_reg3

;for |2
ld a,2
ld (#be80), a
bank_0to2
save_reg2

;for |1
ld a,1
ld (#be80), a
bank_0to1
save_reg1

init_end:
xor a
ld (#8000), a

ld hl, msg_signon
call str_output

ld hl, msg_newline
call str_output

pop hl
pop de
pop bc
pop af

ei
ret

rsx_1: di
push af
push bc
push de
push hl

ld a,(#be80)
cp 2
jp z, rsx_1store2
cp 3
jp z, rsx_1store3

pop hl
pop de
pop bc
pop af
ei
ret

rsx_1store2:
pop hl
pop de
pop bc
pop af
save_reg2
bank_0to2
jp rsx_1end

rsx_1store3:
pop hl
pop de
pop bc
pop af
save_reg3
bank_0to3

rsx_1end: bank_1to0
load_reg1

push af
push hl
ld hl, msg_task1
call str_output

ld hl, msg_newline
call str_output
pop hl
pop af

ei
ret

rsx_2: di
push af
push bc
push de
push hl

ld a,(#be80)
cp 1
jp z, rsx_2store1
cp 3
jp z, rsx_2store3

pop hl
pop de
pop bc
pop af
ei
ret

rsx_2store1:
pop hl
pop de
pop bc
pop af
save_reg1
bank_0to1
jp rsx_2end

rsx_2store3:
pop hl
pop de
pop bc
pop af
save_reg3
bank_0to3

rsx_2end: bank_2to0
load_reg2

push af
push hl
ld hl, msg_task2
call str_output

ld hl, msg_newline
call str_output
pop hl
pop af

ei
ret

rsx_3: di
push af
push bc
push de
push hl

ld a,(#be80)
cp 1
jp z, rsx_3store1
cp 2
jp z, rsx_3store2

pop hl
pop de
pop bc
pop af
ei
ret

rsx_3store1:
pop hl
pop de
pop bc
pop af
save_reg1
bank_0to1
jp rsx_3end

rsx_3store2:
pop hl
pop de
pop bc
pop af
save_reg2
bank_0to2

rsx_3end: bank_3to0
load_reg3

push af
push hl
ld hl, msg_task3
call str_output

ld hl, msg_newline
call str_output
pop hl
pop af

ei
ret

; ------------------------- display help

rsx_help: and a
jr z, fn_help
               
ld hl, hlp_help
jp str_outputln

fn_help: ld hl, hlp_all
fn_help_lp: ld a, (hl)
and a
ret z ; no more help
call str_outputln
inc hl
jr fn_help_lp

; ------------------------- ramlam

ramlam_l:
; TODO: disable lower rom
ld hl, #0000
ld de, #4000
ld bc, #4000
ldir
; TODO: enable lower rom
ret
ramlam_l_end:

ramlam_h:
; TODO: disable upper rom
ld hl, #c000
ld de, #4000
ld bc, #4000
ldir
; TODO: enable upper rom
ret
ramlam_h_end:

; ------------------------- string output - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_output: ld a, (hl)
and a
ret z
call TXT_OUT_CHAR
inc hl
jr str_output

; ------------------------- string output and a newline - no interrupts?
; -- parameters:
; -- HL = zero terminated string
; -- return:
; --
; -- corrupt:
; -- AF, HL

str_outputln:
call str_output
push hl
ld hl, msg_newline
call str_output
pop hl
ret

Title: Re: Julian's Long List of Ideas Thread
Post by: andycadley on 17:18, 26 February 25
Quote from: zhulien on 16:07, 26 February 25The juggling is already coded there, i am in the process of testing now, it is copying the ROM content though as the ROM is enabled.  I created my own ramlam sort of, it copies a small routing from ROM into RAM to disable ROMs and copy the screen RAM, but... still i have to figure out how to disable and enable the ROMs.

But when an RSX is called the ROM state should already be known, your ROM will be the active upper ROM and I think the Lower ROM is always paged in (may need to verify that). So you don't need to record how they were set as long as you put your ROM back in the foreground.

It may be possible to do the copying without every having to put a routine in RAM, although it may not be worth it.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:21, 26 February 25
let's say i use the firmware,  do i need to search for my own ROM so i can reenable it with the right ROM number?
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:22, 26 February 25

yes, you can use the firmware RAMLAM, but that will be slow as it is per byte.  I juggle the memory around so i can do it in LDIRs of 16kb at a time, it's very fast - of course a bit buggy for now (ROMS always enabled to start).  I will resume tomorrow or another day, 3am here
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 21:14, 03 March 25
I just finished coding Home Computer JavaScript over the weekend.

Enjoy!!!

https://www.cpcwiki.eu/forum/off-topic/home-computer-javascript/ (in offtopic, but I will make it relevant to CPC soon)

About 50 commands with Locomotive BASIC inspired JavaScript environment.  Create any JS (only for now) program you like as if you were using a modern CPC that used JavaScript.

CPC-like API coming soon! inspired by Locomotive BASIC!

http://8bitology.com/

I even got WhatsApp to create a hangman game for you to play in it.

next to create some libraries to make coding easier.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 08:58, 05 March 25
Thanks, I have now put the code for Open Home Computer JS into github for those who want to self-host or host at home for their xbox ones.

https://github.com/PrimalNinja/ohcjs
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 08:32, 06 March 25
RC4 available, you can now edit more than one file at once.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:48, 06 March 25
RC5 online, RC4 in github.

http://8bitology.com/
https://github.com/PrimalNinja/ohcjs

added support for the following human languages: chinese (simplified), chinese (traditional), english, french, german, indonesian, klingon (limited), russian, spanish, tagalog

please kindly give me some feedback if you speak one of those languages.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 00:00, 07 March 25
languages now: arabic, chinese, chineset, czech, english, french, german, greek, hindi, italian, japanese, javanese, klingon (limited), korean, russian, spanish, tagalog, thai, vietnamese
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 20:04, 07 March 25
I'm all languaged out...

arabic, chinese, chineset, czech, dutch, english, french, german, greek, hebrew, hindi, italian, japanese, javanese, klingon, korean, persian, polish, portuguese, romanian, russian, spanish, swahili, swedish, tagalog, thai, turkish, vietnamese

i spent a lot of time to make the RTL languages work correctly, very interesting exercise.

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:25, 07 June 25
OCR support added  as well as the ability to drag files into the browser if using a desktop computer.  Mime type detection added  ocr is more POC for now, drag a pdf or image and type ocr and it displays, soon this will be changed to create a new file for the text.  Also some basic transformation ability is underway with a link to command to link files. The purpose is to allow any number of linked files to be automatically updated when editing a file, such as JS to Z80 compilation or, english to chinese translation..  whatever the transformer happens to do.

And a rebranding in progress to CyboegShell because it is the best environment for AI agents. (As well as for mobile phones and xbox ones).

I will be creating a user guide in the vein of 80s BASIC programming manuals but for JS on CyborgShell.

I will be adding my potentjs game libraries (sprites, canvas, itp,  ai and a mini neuralnet for NPCs with a variant of aclib for world state management).  Whether a JS plugin can ever be good enough to convert these to Z80, likely beyond my capabilities.

Finally for those wanting a json conversion for z80... ideal for read-only json objects, if you don't want to recode the following logic to z80... its easy to parse the json binary on the z80.

Json to bin

JSON (JavaScript Object Notation) directly supports the following data types:

1. Strings (e.g., "hello")
2. Numbers (e.g., 42, 3.14)
3. Booleans (e.g., true, false)
4. Arrays (e.g., [1, 2, 3])
5. Objects (e.g., {"name": "John", "age": 30})
6. Null (e.g., null)

{
  "name": "John",
  "age": 30,
  "address": {
    "street": "123 Main St",
    "city": "Anytown"
  }
}


db OBJ_TYPE, 3
      db STRING_TYPE
      dw name_str, john_str

      db NUMBER_TYPE
      dw age_str, 30

      db OBJ_TYPE, 2
        db STRING_TYPE
        dw street_str, main_st_str

        db STRING_TYPE
        dw city_str, anytown_str

name_str: db "name", 00h
age_str: db "age", 00h
addr_str: db "address", 00h
street_str: db "street", 00h
city_str: db "city", 00h
john_str: db "John", 00h
main_st_str: db "123 Main St", 00h
anytown_str: db "Anytown", 00h


function jsonToBin(json) {
    var result = [];
    function encode(obj) {
        if (typeof obj === 'object' && !Array.isArray(obj)) {
            result.push(0x00); // Object type
            result.push(obj.length & 0xFF); // Property count (low byte)
            result.push((obj.length >> 8) & 0xFF); // Property count (high byte)
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    var keyBytes = stringToBytes(key);
                    result.push(0x00); // String type for key
                    result.push(keyBytes.length & 0xFF); // Key length (low byte)
                    result.push((keyBytes.length >> 8) & 0xFF); // Key length (high byte)
                    result.push.apply(result, keyBytes);
                    var value = obj[key];
                    if (typeof value === 'string') {
                        result.push(0x10); // String type
                        var valueBytes = stringToBytes(value);
                        result.push(valueBytes.length & 0xFF); // Value length (low byte)
                        result.push((valueBytes.length >> 8) & 0xFF); // Value length (high byte)
                        result.push.apply(result, valueBytes);
                    } else if (typeof value === 'number') {
                        result.push(0x20); // Number type
                        result.push(value & 0xFF); // Number value (low byte)
                        result.push((value >> 8) & 0xFF); // Number value (high byte)
                        result.push((value >> 16) & 0xFF); // Number value (high byte)
                        result.push((value >> 24) & 0xFF); // Number value (high byte)
                    } else if (typeof value === 'object') {
                        result.push(0x00); // Object type
                        encode(value);
                    }
                }
            }
        }
    }
    function stringToBytes(str) {
        var bytes = [];
        for (var i = 0; i < str.length; i++) {
            bytes.push(str.charCodeAt(i));
        }
        bytes.push(0x00); // Null terminator
        return bytes;
    }
    encode(json);
    return new Uint8Array(result);
}

function binToJson(bin) {
    var offset = 0;
    function decode() {
        var type = bin[offset++];
        if (type === 0x00) { // Object type
            var propertyCount = bin[offset++] | (bin[offset++] << 8);
            var obj = {};
            for (var i = 0; i < propertyCount; i++) {
                var keyLength = bin[offset++] | (bin[offset++] << 8);
                var key = bytesToString(bin, offset, keyLength);
                offset += keyLength + 1; // Skip null terminator
                var valueType = bin[offset++];
                if (valueType === 0x10) { // String type
                    var valueLength = bin[offset++] | (bin[offset++] << 8);
                    obj[key] = bytesToString(bin, offset, valueLength);
                    offset += valueLength + 1; // Skip null terminator
                } else if (valueType === 0x20) { // Number type
                    obj[key] = bin[offset++] | (bin[offset++] << 8) | (bin[offset++] << 16) | (bin[offset++] << 24);
                } else if (valueType === 0x00) { // Object type
                    obj[key] = decode();
                }
            }
            return obj;
        }
    }
    function bytesToString(bin, offset, length) {
        var str = '';
        for (var i = 0; i < length; i++) {
            str += String.fromCharCode(bin[offset + i]);
        }
        return str;
    }
    return decode();
}



var json = {
    name: 'John',
    age: 30,
    address: {
        street: '123 Main St',
        city: 'Anytown'
    }
};

var bin = jsonToBin(json);
console.log(bin);

var jsonFromBin = binToJson(bin);
console.log(jsonFromBin);
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:24, 15 June 25
CyborgShell now moved to http://cyborgshell.com/

Note yet CPC-capable development tool, but... soon 
Title: Re: Julian's Long List of Ideas Thread
Post by: mv on 23:16, 26 June 25
Quote from: zhulien on 18:24, 15 June 25CyborgShell now moved to http://cyborgshell.com/
Note yet CPC-capable development tool, but... soon
Interesting project — I find the idea of combining JavaScript with a CPC-style environment very appealing.

When working with LocoBasic, I sometimes wondered: could we start from (simple) JavaScript and compile it into Locomotive BASIC? Or even run a LocoBasic shell and compiler directly on a CPC?

I tried out CyborgShell — nice concept! A few impressions and suggestions:
    • There's a blinking cursor, when the shell is active. For some reason I always try to press Enter but nothing happens.
    • Copy & paste works into the shell, but it would be great to support copying from the shell too.
    • Command history would be a real productivity boost... ;)
    • Command auto-completion would also help with discoverability.
    • Some of the public examples like hello.js and cat.js appear to be binary files and can't be run as-is.
    • I (accidentally!) deleted 3d.js from the public space during testing.
    • I downloaded cat.js from GitHub and used drag & drop to upload it — nothing changed in the UI, so at first I thought it didn't work, but I later found it in the editor.
      Just tried that const {cls, print} = api; cls(); print(...); also works.
    • Minor quirk: I kept typing load"file, but it seems it must be load "file" — maybe a bit more leniency would help.


Looking forward to seeing how the CPC-style API evolves. Keep it up!
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:05, 27 June 25
Quote from: mv on 23:16, 26 June 25
Quote from: zhulien on 18:24, 15 June 25CyborgShell now moved to http://cyborgshell.com/
Note yet CPC-capable development tool, but... soon
Interesting project — I find the idea of combining JavaScript with a CPC-style environment very appealing.

When working with LocoBasic, I sometimes wondered: could we start from (simple) JavaScript and compile it into Locomotive BASIC? Or even run a LocoBasic shell and compiler directly on a CPC?

I tried out CyborgShell — nice concept! A few impressions and suggestions:
    • There's a blinking cursor, when the shell is active. For some reason I always try to press Enter but nothing happens.
    • Copy & paste works into the shell, but it would be great to support copying from the shell too.
    • Command history would be a real productivity boost... ;)
    • Command auto-completion would also help with discoverability.
    • Some of the public examples like hello.js and cat.js appear to be binary files and can't be run as-is.
    • I (accidentally!) deleted 3d.js from the public space during testing.
    • I downloaded cat.js from GitHub and used drag & drop to upload it — nothing changed in the UI, so at first I thought it didn't work, but I later found it in the editor.
      Just tried that const {cls, print} = api; cls(); print(...); also works.
    • Minor quirk: I kept typing load"file, but it seems it must be load "file" — maybe a bit more leniency would help.


Looking forward to seeing how the CPC-style API evolves. Keep it up!

Thanks for the feedback,

I plan to allow uploading and downloading from the shell. Currently you can drag files there and they are added to the memory-resident files, you can then just type saveall to save them usually.  You can paste code with line numbers on the first line and it will assume line numbers on every other, otherwise it will assume it's not code / or line numbered and allocate line numbers.  I plan to add an upload command (with popup file selector) and a download command soon, download might also support zipping lots of files.

I plan to add a full screen editor, perhaps type fed or somethings to edit the currently selected file fullscreen, but ultimately it's a secondary feature for those using a PC to code and not their phone or an AI.

If you open files with the extension they will be treated with the mime type of that extension otherwise they will be treated as binary.  The intent is that you can edit both ways, and later i intend to allow binary to be saved again.

We could make enter create a blank line, just didn't think of it.

Command history would be possible, auto completion likely possible too but not the immediate priority, i will add them to the todo list.

I'm fine with deleting from the public area, that was my first ever THREE.js program - the public area is intended for people to do what they like.

i do plan to support " in filenames, but more to allow for spaces within filenames.  For now, it is "load cat.js" to load it as a JS or "load cat" to load it as a bin.

I haven't updated the help, but you can use the mimetype command to change it after it's loaded also, eg "mimetype text/octet-stream" - there does seem to be an issue currently in converting JavaScript to and from binary.

An example of linking is like this.

reset with F5
type "files" to see the one file that you have
type "newfile" to create a new file
type "files" to see you now have 2 of them, and your current file is now file 2
type "linkto 1" to link file 2 to file 1
type "files" again to see the link is in place
type "file 1" to go back to file 1
type a new program in, ie: "10 api.print("Hello, World!");
type "files" again, the linked files are now the same as file 1.

Currently as many linked files as you like can be made, but only 1 level deep (a bug for me to fix).
It's only a POC the linking, but the intent is... links can be associated with a translation plugin.  
A real World example would be to setup the links and translators, save the project (which saves the linkages).
Type in your program for example in JavaScript, or LocoBasic, and like magic the linked files are compiled in realtime - like my youtube video from JS to Z80.

It's designed for programming as well as other tasks, that's why you can drag JPGs or PDFs there, then type "ocr" to turn them into a file that you can list and save.

But you can also as manus.im to do tasks on cyborgshell, and it's pretty cool to watch that it can do something with no prior knowledge - just type to manus.im "go to cyborgshell.com, read the help, then do blah", or  "go to cyborgshell.com, read the help, then do what is contained in blah.txt" (if you want multiple agents to do things concurrently).  Can be work-flow based, or programming related, all works to some degree.  I will put together a single page instructions for the AI agents so it can load it in a single go rather than it taking several minutes to read each one.  You can likely download openmanus if you want to try a free AI agent with it.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:27, 27 June 25
Actually i have big plans for CyborgShell and all things are intended to fall into place oneday.

CyborgShell is where i plan to be able to code in JS to get Z80 output, or perhaps other languages etc  The JS translator I do want to be able to eventually cross compile itself to Z80, but likely that will be commandline based.  Maybe directly to Z80, or via JSASM (my JS based assembly language).  JSASM is much easier to then translate to Z80 or 6502.

Primal is my cross platform Z80 kernel, oneday this will be finished - it isn't intended to be a full OS like FutureOS or Symbos, but rather a way to code once and run it on many platforms - including FutureOS and Symbos.

potent.js is my game framework which of course works fine in JS and will be available in CyborgShell - i suspect this might never be cross-compilable to Z80, but who knows.  This includes JCanvas, JSprites (Automatic Sprite Animations, Collision detections etc), JGameLoop, JITP (internet connectivity), ACLIB, JNeuralNet (very lightweight enforcement training decision maker) and dAIbolic for NPC behaviour.  Although ACLib was designed for text adventure structure, it actually suits game state management nicely. dAIbolic is a JS tree-based AI for which you can influence behaviour by interacting with it's senses, it can use LLMs for comms or JNeuralNet for identifying things. So as an example, you can talk to an NPC, it can note some things about you, let's say what you are wearing, or what sex you are, what your hair colour might be, later if you met the same NPC, it might recognise you - just like a human, it's based on probability. 
Title: Re: Julian's Long List of Ideas Thread
Post by: mv on 09:41, 29 June 25
Quote from: zhulien on 15:05, 27 June 25Thanks for the feedback,

I plan to allow uploading and downloading from the shell. Currently you can drag files there and they are added to the memory-resident files...
Thanks for the detailed description.
It seems I've only scratched the surface of what's already possible, and what's coming next.


The ability to drag files into memory and use "saveall" is very handy. I had missed that behavior, so thanks for pointing it out. Also great to hear that upload/download commands, command history, and auto-completion are on your radar.

JavaScript with line numbers? Interesting, maybe just for visualization in the future full-screen editor?
In LocoBasic, I tend to avoid line numbers where possible. They're useful for marking call targets. In JavaScript, the structure comes more naturally through functions anyway.

When loading files, I tried the BASIC-style LOAD "cat.js", but that also treated the file as binary. I thought LOAD cat.js or LOAD cat was just a convenience, but now I understand it depends on the MIME type handling.

I also tried some JavaScript output from LocoBasic, but found the API quite limited for now, and api.print behaves differently (it appends a newline and accepts only one parameter). Of course, I can always fall back to putting more functionality directly into the script.

The linking and translator system sounds powerful. I hadn't realized how far you're taking the cross-language and real-time transformation concept.
When I typed "files", I saw that there's a second level of file management, "linked" in-memory files. What's the main benefit of having that second layer which cannot be done in one layer?


The AI agent integration is wild. I took the opportunity to try manus.im, and yes, it could do it:
"Go to cyborgshell.com, read the help, then run cat.js and print the result".
I also gave it a try getting the result of the "Nine Digits Puzzle" using LocoBasic. It struggled a lot with the UI, checking the long example selection list again and again. But after some nudges and about 6 minutes, it finally pulled it off. Maybe the LocoBasic UI could be a bit more AI-agent-friendly in the future.

So you are building a whole ecosystem here, with Primal, potent.js, and dAIbolic... Looking forward to seeing how all these parts come together.

Keep up the great work!
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 14:50, 29 June 25
The line numbers are only in the line editor so you can edit and insert etc.  A fullscreen editor would remove the line numbers and put them back after exiting the fullscreen editor. Since I'm beautifying the JS code automatically it is a tiny more involved than just stripping the numbers - I'd probably beautify it with tabs for fullscreen, not spaces like the line editor.

There are two reasons it's JS and not something else - JS came almost for free without much development and AI LLMs seem to be good at JS, and unfortunately not as good at some others especially they are bad at assembly language.

It seems AI agents are a bit dumb when you tell them to it's "a line editor" only, I found i had to tell manus.im and another "it's a line editor just like 80s BASIC but using JavaScript instead" and it got it.  All this i will put in a programming prompt text file at some stage along with more detailed instructions in a single file - it takes manus some time to go through all the separate pages.  When it realises it's a line editor though it usually zips through.

bits of the JS framework are here: https://8bitology.net/poc/
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 15:07, 06 July 25
I was doing some more coding the other day with Primal (my kernel) and had an interesting problem - that was, with my current memory routines how to deal with 4mb+ RAM to access all 256 16kb blocks plus internal memory with a single byte.  I came up with a solution,  I now have 3 heaps - An application heap, a system heap and a buffers heap.  keeping the API currently almost as it was, I added a Heap selector which lets me change heaps then use the other APIs like bankselect etc... for 4mb+ systems, I gave 3mb+ to applications, and 512kb to system and buffers each.  For 2mb+ systems, half that, until down to 128kb systems (that's 64kb extra ram - so 128kb total), they only have the 3 heaps are merged.  This sharing of heaps as a fallback works extremely well on paper at least - meaning if there is an abundance of RAM, the system can guarantee it's own RAM and RAM for buffers, but if there is not much RAM, they fall back to a single heap where it's more a typical CPC program (shared space for program, jumpblock, buffers).  The loader now defaults to working with unexpanded 464 or 664 and gives about 35kb available shared after the kernel is loaded no longer requiring an expanded memory driver.  I'm not yet overwriting the firmware jumpblock - but in time I will to use all RAM up to #C000.  But I also created a virtual memory variant for unexpanded machines which gives 1 x 64kb+ heap and 2 x 64kbMemory heaps - which will work fine on M4 or other Mass Storage - obviously not useable for Tapes or Floppy Discs.  This Virtual Memory isn't best for expanded machines but of course will work... a more intelligent virtual memory version would be best, that is to use a LIFO model for swapping files into physical expansion RAM - maybe in future I will code this.

Actually I could create a 4th pseudo-heap which is like a reserved, do not use heap - so that if someone was e.g. using an AMSDOS RAM expansion, we can not corrupt it, but

Next. to recode my Malloc (SysHeapAlloc) and Free (SysHeapFree) to use a better system than the slow iterate through banks, then iterate through lists - it takes quite a bit of time (fractions of a second though) to find a free block after e.g. 500 filled blocks.

I'm going to reinvestigate my RAT (RAM Allocation Table idea) - I think that is likely best, it's definitely the fastest, but it does have byte-aligned blocks which are the minimum memory allocation size even if you want smaller.

It isn't runnable yet, some code can be stepped through.

Latest Coding Status here:
https://docs.google.com/spreadsheets/d/14JQa3cTEd9fIz9lyoQRkzVc5xBz5FhEdr_DC41xPkJs/edit?usp=sharing
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 22:55, 07 July 25
For all you adventuring "Text Adventure" (that's Interactive Fiction for all you newbies) fanatics, I have released Potent JS Adventure Creation Framework which lets you create some pretty cool Text Adventure games in JavaScript.  It is available for download at the Cyborg Unicorn website or if you follow the links from https://potentjs.com where you can also play a sample game created with it. You can create text adventure games with multiple playable characters. Think a RPG adventure game where you can be every member of the party which interesting puzzles they each can contibute to solve.

Now on github:

https://github.com/PrimalNinja/cyborgwiki
https://github.com/PrimalNinja/potentjsacf
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 04:10, 08 July 25
It's cool what a tiny bit of JS can do...

Initialising.

Ready.

In the shadow-shrouded realm of Delos, where the moon dipped into darkness and the wind whispered secrets to the trees, Xusia, the evil sorcerer, wove a web of deceit and malice. With a cackle that sent shivers through the land, he snatched Alana, the radiant starlight maiden, destined to be Talon's bride in mere days.

You are Alana.

I lie captive in the darkness of Xusia's lair, the cold stone beneath me a harsh reminder of my fate. You took me, Xusia, but why? What purpose do I serve in your twisted games? The hours tick by, each one a slow crawl of uncertainty. My thoughts are consumed by Talon, the one I'm to marry in just a few short days. Will he come for me? Does he even know I'm trapped here? I scan my prison, searching for any weakness, any chance to escape. The iron bars, the locked door, the guards patrolling outside... but I won't give up. I have to hold on to hope, to the thought of Talon's strong arms and his gentle touch. Maybe, just maybe, he'll find a way to rescue me before our wedding day. Until then, I'll plot, I'll plan, and I'll wait... for Talon, or for my chance to break free.

You are in a room with a red door to the south.

You can see: Xusia

> look

You are in a room with a red door to the south.

You can see: Xusia

> look xusia

Xusia is very scary.

> look door

The door is red.

It is closed.

> i

You are carrying:

├─ back pack
└─ dagger
> take dagger

You have the dagger already.

> look backpack

The back pack is a typical nylon type used by most school students.

It is closed.

> open backpack

You open the back pack.

> look backpack

The back pack is a typical nylon type used by most school students.

It is open.

It contains:

- rock

> get rock

You get the rock.

> i

You are carrying:

├─ back pack
├─ dagger
└─ rock
> look

You are in a room with a red door to the south.

You can see: Xusia

> talon

You are now Talon.

You burst through the door, expecting to be greeted by Alana's warm smile, but instead, you're met with an eerie silence. You call out, 'Honey, I'm home!' but there's no response. That's when you see Alana's little brother, his face frantic with worry, running towards you. 'Help! Help! Alana's been kidnapped by Xusia!' he cries, tugging at your leg.

Without hesitation, you grip your trusty Tri-Sword, its familiar weight a comfort in the face of danger. Our wedding is just a few days away, and you won't let Xusia ruin it. You set off towards Xusia's lair, determination burning within you. As you enter the dark, foreboding caverns, you feel a sudden, searing pain in the back of your neck. Everything goes dark, and you crumple to the ground.

When you come to, your head throbs, and your vision blurs. You're disoriented, but as your senses return, you realize you're in Xusia's lair, and... where's Alana? You struggle against your restraints, a growing sense of urgency and fear driving you. What has Xusia done to her? You need to find out, and fast. You glance around, taking stock of your surroundings, searching for any opportunity to escape and rescue your beloved Alana before it's too late.

You are in a room with a red door to the north.

You can see: black box, sword

> get swword

I don't see that here.

> get sword

You get the sword.

> get box

You get the black box.

> i

You are carrying:

├─ sword
└─ black box
> look box

The box is made of wood and painted black, it feels quite strong.

It is closed.

> open box

You open the black box.

> look box

The box is made of wood and painted black, it feels quite strong.

It is open.

It contains:

- red key

> get key

You get the red key.

> look box

The box is made of wood and painted black, it feels quite strong.

It is open.

It is empty.

> i

You are carrying:

├─ sword
├─ black box
└─ red key
> open door

The door is locked.

> unlock door

You unlock the door.

> open door

You open the door.

> go door

You enter the red door.

You are in a room with a red door to the south.

You can see: Alana, Xusia

> look alana

Such a beautiful lass.

> look xusia

Xusia is very scary.

> kiss alana

You put your hands on Alana's hips and give her a long intimate kiss.

> kiss xusia

Yuk! That's gross.

> alana

You are now Alana.

You are in a room with a red door to the south.

You can see: Xusia, Talon

> i

You are carrying:

├─ back pack
├─ dagger
└─ rock
> put dagger into bag

I don't see that here.

> put rock in bag

I don't see that here.

> i

You are carrying:

├─ back pack
├─ dagger
└─ rock
> put dagger into backpack

You put the dagger into the back pack.

> put rock into backpack

You put the rock into the back pack.

> i

You are carrying:

└─ back pack
   ├─ dagger
   └─ rock
> look back pack

The back pack is a typical nylon type used by most school students.

It is open.

It contains:

- dagger

- rock

> close back pack

You close the back pack.

> i

You are carrying:

└─ back pack
> give back pack to talon

You give the back pack to Talon.

> talon

You are now Talon.

You are in a room with a red door to the south.

You can see: Alana, Xusia

> i

You are carrying:

├─ sword
├─ black box
├─ red key
└─ back pack
> open box

The black box is already open.

> i

You are carrying:

├─ sword
├─ black box
├─ red key
└─ back pack
> open back pack

You open the back pack.

> o

I don't see that here.

> i

You are carrying:

├─ sword
├─ black box
├─ red key
└─ back pack
   ├─ dagger
   └─ rock
> look xusia

Xusia is very scary.

> kill xusia

After a long and hard-fought battle, you kill Xusia with the Tri-Sword.

I hold Alana's hand tight, feeling her warmth and love radiating towards me. The memory of Xusia's defeat still fresh in my mind, I'm grateful to have saved the woman I love. As we walk towards our future, I glance at Alana, her beauty and strength captivating me.

With Xusia's darkness vanquished, our path is clear. Our wedding awaits, and I'm eager to start our life together. Alana's smile lights up the world, and I'm honored to be her partner, her protector, and her love.

I look into her eyes, and she sees the sincerity in mine. 'I'll always protect you, Alana,' I promise, my voice filled with conviction. 'Together, we'll face whatever comes next, side by side.'

With Alana by my side, I know we'll conquer any challenge. Our love will flourish, and our bond will grow stronger with each passing day. As we step into our new life, I'm excited to see what the future holds for us, together.

> look xusia

Xusia is dead.

The following catches your attention:

- gold pouch

> get pouch

I don't see that here.

> get pouch from xusia

You take the gold pouch from the Xusia.

> i

You are carrying:

├─ sword
├─ black box
├─ red key
├─ back pack
│  ├─ dagger
│  └─ rock
└─ gold pouch
   └─ gold pieces
> put pouch into box

You put the gold pouch into the black box.

> i

You are carrying:

├─ sword
├─ black box
│  └─ gold pouch
│     └─ gold pieces
├─ red key
└─ back pack
   ├─ dagger
   └─ rock
> put box into back pack

You put the black box into the back pack.

> i

You are carrying:

├─ sword
├─ red key
└─ back pack
   ├─ dagger
   ├─ rock
   └─ black box
      └─ gold pouch
         └─ gold pieces
> close back pack

You close the back pack.

> i

You are carrying:

├─ sword
├─ red key
└─ back pack
> get gold

You get the gold pieces.

> i

You are carrying:

├─ sword
├─ red key
├─ back pack
└─ gold pieces
> look gold

Oooh, nice and shiny. Now you can afford a fantastic honeymoon!

> kiss alana

You put your hands on Alana's hips and give her a long intimate kiss.

> alana

You are now Alana.

You are in a room with a red door to the south.

You can see: Xusia, Talon

> kiss talon

You put your arms around Talon and give him a long intimate kiss.

> i

You are not carrying anything.

> alana

You are now Alana.

You are in a room with a red door to the south.

You can see: Xusia, Talon

> i

You are not carrying anything.

> take alana

You can't take the Alana.

> i

You are not carrying anything.

> talon

You are now Talon.

You are in a room with a red door to the south.

You can see: Alana, Xusia

> i

You are carrying:

├─ sword
├─ red key
├─ back pack
└─ gold pieces
> l

You are in a room with a red door to the south.

You can see: Alana, Xusia

> take xusia

You can't take the Xusia.

> i

You are carrying:

├─ sword
├─ red key
├─ back pack
└─ gold pieces
> open back pack

You open the back pack.

> i

You are carrying:

├─ sword
├─ red key
├─ back pack
│  ├─ dagger
│  ├─ rock
│  └─ black box
│     └─ gold pouch
└─ gold pieces
> put the key into the backpack

You put the red key into the back pack.

> i

You are carrying:

├─ sword
├─ back pack
│  ├─ dagger
│  ├─ rock
│  ├─ black box
│  │  └─ gold pouch
│  └─ red key
└─ gold pieces
> put the key into the black box

You're not carrying that.

> get the key

You get the red key.

> put the key into the black box

You put the red key into the black box.

> i

You are carrying:

├─ sword
├─ back pack
│  ├─ dagger
│  ├─ rock
│  └─ black box
│     ├─ gold pouch
│     └─ red key
└─ gold pieces
Title: Re: Julian's Long List of Ideas Thread
Post by: ervin on 08:52, 08 July 25
Tri-sword?
Xusia?

Sounds like the Sword and the Sorcerer.
GREAT movie!  :)
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:54, 08 July 25
Quote from: ervin on 08:52, 08 July 25Tri-sword?
Xusia?

Sounds like the Sword and the Sorcerer.
GREAT movie!  :)
It's The Sorcerer and the Sword  :D
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 05:21, 11 July 25
I have started coding CyborgDesktop which you can try my first days work at

https://cyborgshell.com/

just type run desktop.js

Imagine, just like the shell where you can login on your xbox, your phone, you PC, your Mac and seamlessly walk around and use them all and develop or type in your latest novel where-ever you happen to be - for those that don't like CLIs can use a desktop.  

Soon will be applications that you can code in there, for now, the only working bit is the Terminal which shows the shell in the desktop in a window.  But... lots of cool features to come.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 07:39, 14 July 25
For those who like OSs, my Cyborg Desktop is now progressing.  Why another desktop - ok another not immediately CPC-related thing... 

cyborgdesktop.com  (yes, it takes you to another instance of CyborgShell.  type "run desktop.js"

This is a tabletop operating system.  it is very colourful as i get the gist of it working.  You press the people button and you can arrange people around the table, that allows for different screen regions to be setup - as the root, you can be at the side or the end, doesn't matter, but it affects how the regions are initialised.  You can change the orientation of anyone.  For now, only the shell is there, you can open it from any user, and it will open in their orientation.  You can drag it to any other user, and it will change to their orientation.

The purpose?  Multiple, but when I make the regions transparent and some applications instead of terminal, then you can perhaps have a tabletop D&D game on your 70 inch touchscreen TV with a nice seamless OS to interact with.

Other than in the movies, i couldn't find any solution to this yet.  Now imagine i allow multiple players to play The Sorcerer and the Sword... that might be one of the first games on it.  At least as a POC.

Applications for such an OS?  Multi-user live or non-live music creation / editing tool?  Sit around the desk at school and teach kids how to program?  Tabletop games? etc.
Title: Re: Julian's Long List of Ideas Thread
Post by: mv on 23:53, 22 July 25
When I start https://cyborgshell.com/ and type run desktop.js, a "splash screen" appears and disappears and it shows "Sorry! Something went wrong.". And there is an error in the console:  "Google Maps JavaScript API error: RefererNotAllowedMapError".

A map with the city of Melbourne is shown for https://cyborgdesktop.com/ .

Ah, maybe I should try the "Users" button at the botton...
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 19:01, 23 July 25
Quote from: mv on 23:53, 22 July 25When I start https://cyborgshell.com/ and type run desktop.js, a "splash screen" appears and disappears and it shows "Sorry! Something went wrong.". And there is an error in the console:  "Google Maps JavaScript API error: RefererNotAllowedMapError".

A map with the city of Melbourne is shown for https://cyborgdesktop.com/ .

Ah, maybe I should try the "Users" button at the botton...
yes, cyborgshell.com domain is not configured to have google maps, cyborgdesktop.com is

i just removed the desktop for now from cyborgshell and updated it on cyborgdesktop to handle multitouch better. you can add multiple users, then each user can freely drag their windows around at the same time as each other.

the purpose isn't really to be a google map, but imagine moreso a tiled dungeon, where anyone can drag their things around freely.  imagine the windows aren't so big but, are like a transparent base on a graphical character which you can drag.  Of course there are real google maps use cases, but tabletop gaming might be more fun.  to allow people to type at the same time, i need to code my own onscreen keyboard - for some strange reasons, most browsers - even the ones that do support multitouch - all the latest ones do... do not let you type on multiple keyboards at once. if i can imagine a game with almost no typing, and i suspect that some nice game design is best without typing, all will be good without an onscreen keyboard.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 19:24, 23 July 25

https://www.youtube.com/watch?v=Y_wVb6AET2I

https://www.youtube.com/watch?v=ourblTZfgtg

Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:40, 24 July 25
i will likely deploy this over the next day... you best to NOT put your API key in there, but!!! if you are running a local ai, you can of course adapt the plugins to run locally.  this is an example of cascading AI interaction with transformers.

Quoteproject load aitest
File loaded: aitest_prompt.txt
File loaded: aitest_story.txt
File loaded: aitest_chinese.txt
File loaded: aitest_japanese.txt
File loaded: chatgpt.xfrm
File loaded: tochinese.xfrm
File loaded: tojapanese.xfrm
Project loaded: aitest
Ready
files
Project name: aitest
Project filename: aitest.prj
Files:
  1 *  aitest_prompt.txt 129 bytes/3 lines (text/javascript:text)
  2    aitest_story.txt 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm
  3    aitest_chinese.txt 12 bytes/1 lines (text/javascript:text) Linked to 2:tochinese.xfrm
  4    aitest_japanese.txt 27 bytes/1 lines (text/javascript:text) Linked to 2:tojapanese.xfrm
  5    chatgpt.xfrm [PLUGIN] 6323 bytes/221 lines (text/javascript transformer:text)
  6    tochinese.xfrm [PLUGIN] 2790 bytes/91 lines (text/javascript transformer:text)
  7    tojapanese.xfrm [PLUGIN] 2793 bytes/91 lines (text/javascript transformer:text)
* current file, D dirty file
Ready
list
    10 // AI IGNORE
    20 AI PROMPT write me a 3 paragraph story about a little kitten that got lost and tried to find it's way home.
    30 AI END
Ready
edit 10
10 // AI IGNORE x
Ready
ChatGPT processed 1 prompt(s)
Text translated to Chinese
Text translated to Japanese
files
Project name: aitest
Project filename: aitest.prj
Files:
  1 *D aitest_prompt.txt 131 bytes/3 lines (text/javascript:text)
  2  D aitest_story.txt 1490 bytes/6 lines (text/javascript:text) Linked to 1:chatgpt.xfrm
  3  D aitest_chinese.txt 442 bytes/5 lines (text/javascript:text) Linked to 2:tochinese.xfrm
  4  D aitest_japanese.txt 647 bytes/5 lines (text/javascript:text) Linked to 2:tojapanese.xfrm
  5    chatgpt.xfrm [PLUGIN] 6323 bytes/221 lines (text/javascript transformer:text)
  6    tochinese.xfrm [PLUGIN] 2790 bytes/91 lines (text/javascript transformer:text)
  7    tojapanese.xfrm [PLUGIN] 2793 bytes/91 lines (text/javascript transformer:text)
* current file, D dirty file
Ready
file 2
Ready
list
    10 // AI IGNORE x
    20 Whiskers, a tiny gray kitten with bright green eyes, woke up one sunny afternoon to find herself alone in a vast garden. The tall flowers swayed gently in the breeze, and the chirping birds filled the air with cheerful melodies. Curious and adventurous, she had wandered too far from her cozy home in search of a butterfly. Now, with no familiar scents or sounds to guide her, Whiskers felt a flutter of panic in her little heart.
    30
    40 Determined to return, Whiskers started her journey through the garden, her tiny paws padding softly on the warm earth. She sniffed at the air, hoping to catch a whiff of her mother's comforting presence. Along the way, she encountered friendly creatures: a wise old tortoise who offered directions, and a playful squirrel who showed her the way to the edge of the garden. Each encounter brought her closer to her goal, but the path was winding and filled with distractions that made her forget her purpose for a moment.
    50
    60 As dusk began to settle, casting a warm golden hue over the landscape, Whiskers finally spotted a familiar sight—a small wooden fence that surrounded her home. With renewed energy, she dashed toward it, her heart pounding with excitement. As she squeezed through a gap in the fence, she heard her mother's gentle call. Within moments, she was enveloped in the warmth of her mother's embrace, safe at last. The adventure had been daunting, but Whiskers knew she would always find her way home, no matter how lost she felt.
Ready
file 3
Ready
list
    10 小猫胡须,拥有明亮绿色眼睛的灰色小猫,在一个阳光明媚的下午醒来,发现自己独自一人身处一个广阔的花园中。高高的花朵在微风中轻轻摇曳,鸟儿的啁啾声充满了空气,奏响了欢快的旋律。好奇又冒险的她,为了寻找一只蝴蝶而走得离自己舒适的家太远。现在,周围没有熟悉的气味或声音来指引她,胡须感到小心脏里一阵慌乱。
    20
    30 决心要回家,胡须开始在花园中踏上旅程,她的小爪子轻轻踩在温暖的土壤上。她嗅了嗅空气,希望能闻到母亲安慰的气息。在途中,她遇到了友好的生物:一只提供方向的聪明老龟,以及一只带她到花园边缘的顽皮松鼠。每一次相遇都让她离目标更近,但道路弯曲且充满了干扰,让她一时忘记了自己的目的。
    40
    50 黄昏开始降临,给景色披上温暖的金色光辉,胡须终于看到了一个熟悉的景象——一个围绕着她家的小木栅栏。她重新充满了力量,朝它冲去,心中充满了兴奋的跳动。当她挤过栅栏的缝隙时,听到了母亲温柔的呼唤。几秒钟后,她被母亲的怀抱包围,终于安全了。冒险虽然令她感到畏惧,但胡须知道无论她感到多么迷失,她总能找到回家的路。
Ready
file 4
Ready
list
    10 ウィスカーズは、明るい緑の目を持つ小さな灰色の子猫で、ある晴れた午後に広大な庭で一人目覚めました。高い花々はそよ風に揺れ、さえずる鳥たちが空気を楽しいメロディーで満たしていました。好奇心旺盛で冒険心にあふれた彼女は、蝶を探すために居心地の良い家から遠くに迷い込んでしまったのです。今、馴染みのある香りや音がない中で、ウィスカーズの小さな心にはパニックの動悸が感じられました。
    20
    30 帰る決意を固めたウィスカーズは、庭を通り抜ける旅を始めました。彼女の小さな足は温かい土の上で柔らかく踏みしめられました。母の心地よい存在の香りを嗅ぎ取ろうと、彼女は空気を吸い込みました。途中で、彼女は親切な生き物たちに出会いました。道を教えてくれる賢い老亀や、庭の端までの道を示してくれる遊び好きのリスです。それぞれの出会いが彼女を目標に近づけましたが、道は曲がりくねっており、時折目的を忘れさせるような気を散らすものがありました。
    40
    50 夕暮れが訪れ、風景に温かい金色の色合いを投げかけると、ウィスカーズはついに見覚えのある光景を見つけました。彼女の家を囲む小さな木のフェンスです。新たなエネルギーを得て、彼女はそれに向かって駆け出しました。心臓は興奮で高鳴っています。フェンスの隙間を通り抜けると、母の優しい呼び声が聞こえました。数瞬後、彼女は母の抱擁の温もりに包まれ、ついに安全な場所に戻ったのです。冒険は厳しいものでしたが、ウィスカーズは、自分がどれだけ迷っても、いつも家に帰る道を見つけられると知っていました。
Ready
[/color]
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:42, 24 July 25
you can hand-code transformers too if you don't want to use an AI
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:21, 24 July 25
Quote from: mv on 23:16, 26 June 25
Quote from: zhulien on 18:24, 15 June 25CyborgShell now moved to http://cyborgshell.com/
Note yet CPC-capable development tool, but... soon
Interesting project — I find the idea of combining JavaScript with a CPC-style environment very appealing.
When working with LocoBasic, I sometimes wondered: could we start from (simple) JavaScript and compile it into Locomotive BASIC? Or even run a LocoBasic shell and compiler directly on a CPC?

I tried out CyborgShell — nice concept! A few impressions and suggestions:
    • There's a blinking cursor, when the shell is active. For some reason I always try to press Enter but nothing happens.
    • Copy & paste works into the shell, but it would be great to support copying from the shell too.
    • Command history would be a real productivity boost... ;)
    • Command auto-completion would also help with discoverability.
    • Some of the public examples like hello.js and cat.js appear to be binary files and can't be run as-is.
    • I (accidentally!) deleted 3d.js from the public space during testing.
    • I downloaded cat.js from GitHub and used drag & drop to upload it — nothing changed in the UI, so at first I thought it didn't work, but I later found it in the editor.
      Just tried that const {cls, print} = api; cls(); print(...); also works.
    • Minor quirk: I kept typing load"file, but it seems it must be load "file" — maybe a bit more leniency would help.

Looking forward to seeing how the CPC-style API evolves. Keep it up!
udpated cyborgshell.com and cyborgdesktop.com - type notes for today's notes.

commandline history included!

you now run js files simply by typing the filename without extension, i.e. "desktop" will run the desktop, "3d" will run 3d.js.


Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 22:34, 25 July 25
A massive update, you can now store your API Keys in your local storage.  Time to code those transformer plugins to generate some CPC code!

Late breaking release notes.

New Features 26th July 2025:

- You can now save your AI API Keys to your local storage on devices where local storage is available.

config save <identifer> <value>, e.g.

to configure your chatgpt API key, config save chatgpt AbC123
to configure your aihandler to chatgpt, config save aihandler chatgpt (this will use the chatgpt.js handler)

note: you don't need to hardcode APIKeys in the JS, it will use what's in your local storage. Take care
  that you only run trusted programs though that do NOT steal your APIKeys.
 
  note: prompting for permissions is coming soon!!! but if you are coding your own plugins or such
in your own space, then it's unlikely you will have issues.

config delete <identifer> to delete your previously saved config option. e.g. to delete your chatgpt API Key,
config delete chatgpt will do that.

- You can now cd to the new 'local' space with cd local. You can dir it also. For now file functionality is limited
  but you can see your configuration files there.  cd back to home or public or another space to do something useful.

- If you setup an aihandler, you can use the ! AI prefix within Cyborg Shell. e.g. !what is the meaning of life?
  Simply entering ! by itself if configured with the provided chatgpt.js will display some help for managing chatgpt
  sessions. You can use multiple sessions, load and save them, clear them etc. This allows you to create sessions of
  knowledge up to a point, save them and restore them as required. Sessions info is saved in your currently selected
  space when you save them.

New Features 25th July 2025:

- To run a js file, simply type the filename. i.e. to run bm.js, simply type 'bm'.
- Transient programs are now loaded into file space 0 so they don't corrupt user editing.
- Commandline history is now implemented allowing for up and down arrows to navigate.
- You can now code transformer plugins so that linked files can be transformed dynamically in realtime.
- Your transformers are loaded as files so you can develop them as per every other file.
- You can now save your current files and links as a project and load a project to restore the files and links.
- If you setup chatgpt.js, you can use chatgpt within Cyborg Shell. e.g. chatgpt give me a random number

- 3 AI transformer plugins provided chatgpt.xfrm, tolanguage.xfrm, null.xfrm

The AI transformer plugins require an API Key to be useful. You should NOT put any plugins in here on our servers
if you are putting your own API Keys directly into the code. Better you fetch it from local storage as per these plugins.

You can install ollama locally and modify your copy of plugins to use your own ollama which is also free and
you control your own local security. 

Also you can use these transformer plugins as a guide to how you may like to create your own.

chatgpt.xfrm:  this plugin has some commands within:
============

AI IGNORE - if you place AI IGNORE at the start of the file, AI will not be called while it is there.
This allows you to have AI IGNORE there while you create your prompts, and then either remove it or slightly modify it
to trigger the AI to proceed.

The chatgpt plugin has session logic to remember your training data for prompts. You can create and manage different
knowledge blocks with sessions.

AI SESSION CLEAR - will clear all AI session memory stored on in your browser

AI SESSION CLEAR <sessionname>, e.g. AI SESSION CLEAR database will clear only the database session.

AI SESSION START <sessionname> - start of a session block, multiple blocks can share the same session name to build up knowledge.
AI SESSION END <sessionname> - end of a session block, multiple blocks can share the same session name to build up knowledge.

AI PROMPT <sessionname> <prompt> - you can place as many AI PROMPT / AI PROMPT END blocks within your file as you like and each will make
separate AI calls and substitute the AI PROMPT block with the response.  Prompts may be embedded within session blocks.

AI PROMPT END <sessionname> - indicates the end of the prompt.

null.xfrm: if there is any input, return it, otherwise no output
=========

tolanguage.xfrm: if there is any input, transform it, if there is no input, return no output.  It takes the language you want to translate to as an argument.
===============

- New/Enhanced commands below:

file <filenumber>, will now create new files up to the specified filenumber if not already
linkto <sourcefilenumber> <plugin> <arguments>, will now create new files up to the specified filenumber if not already. arguments will be passed to the plugin so you can use the same plugin for different purposes.
link <targetfilenumber> <sourcefilenumber> <plugin> <arguments>, e.g. link 4 2 null will link a null transformer plugin on file 4 to file 2
newfile [<filename>], you can now create a new file but go to the file specified without having to go to the new file
touch <filenumber>, e.g. touch 1 to manually cause all transformers linked to file 1 and cascaded ones to process
project <projectname>, e.g. project test
project load <projectname>, e.g. project load test
project save <projectname>, e.g. project save test
linkto <filenumber> <transformername>, e.g. linkto 1, chatgpt

type ai-example1.txt or type ai-example2.txt for examples of transformer chains.

New Features 16th June 2025:

- You can now login with login yourusername [press enter], then have the password not visible when typing it in.

New Features 15th June 2025:

- Some support for Mime Types.
- Text and non-Text Mime Types can be listed and edited.
- Images and PDF can be OCRd, type 'ocr' after loaded by dragging (for now). New files will be created with any OCRd text.
- OCR currently is a separate module, but is going to evolve into a plugin facility.

New Features 9th March 2025:

- Files can now be dragged onto the editor from your computer.
- You can now paste text into the line editor. Files with line numbers on the first line preserve the numbers without are autonumbered.
- Listing files will now show which files are dirty (with a D).
- 'saveall' will save all named files.

Programming API:

- added input command,
e.g. api.cls(); api.print('enter your name:'); api.input(function(str_a) { api.print('hello ' + str_a); api.stop(); });

Work in Progress:

- ability to upload and download via the commandline.
- ability to schedule and manage the scheduling of JS files via the commandline.
- Saving edited binary Mime Types as binary.

Other notes:

- HCJS rebranded to CyborgShell.
- resolved xbox one browser's autocapitalisation issues by using email instead of text input types.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 18:15, 26 July 25
Another update, this was really needed. You can now use the new csconfig utility to configure handlers, providers and services which are all stored in local storage, as well as an autorun program when you reset - such as desktop. 

handlers, really only 1 for now 'ai' for the ! command.
providers, you can configure them all to use different services or the same service, up to you.
services, you can now use any service that follows the typical gpt API, such as chatgpt or even locally installed ollama - both tested here. 

I hope it makes sense.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 16:28, 27 July 25
maybe i am thinking to have a feature to turn on or off, the realtime code generation, why invoke the transformers for each line of code - maybe just a touch <filenumber> should do it... or another command as touch sets things to dirty, and the transformers are currently monitoring dirty files.  It's quite good if they are local transformers, but when they are calling AI, it isn't the best. to see all those messages come up.

having said that, it's pretty cool to see in no effort differnt things happen.

project load aicode
Could not load code.txt
Could not load code.c
Could not load code.pas
Could not load code.cs
Could not load code.z80
Could not load code.x86
Could not load code.c64
Could not load code.bas
Could not load code.js
File loaded: chatgpt.xfrm
Project loaded:
Ready
files
Project filename: aicode.prj
Files:
  0    Run Space 0 bytes/0 lines (text/javascript:text)
  1 *  code.txt 0 bytes/0 lines (text/javascript:text)
  2    code.c 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into c
  3    code.pas 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into pascal
  4    code.cs 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into c#
  5    code.z80 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into z80 assembly language for CP/M
  6    code.x86 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into 8086 assembly language for MSDOS
  7    code.c64 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into 6502 assembly language for a Commodore 64
  8    code.bas 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into Amstrad CPC Locomotive BASIC
  9    code.js 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into javascript ES5
 10    Unnamed File 0 bytes/0 lines (text/javascript:text)
 11    chatgpt.xfrm [PLUGIN] 15544 bytes/548 lines (text/javascript transformer:text)

* current file, D dirty file
Ready
10 FOR A = 1 TO 10: PRINT "Hello, World!":NEXT
Ready
openai processed argument prompt re-code this into javascript ES5
openai processed argument prompt re-code this into c#
openai processed argument prompt re-code this into pascal
openai processed argument prompt re-code this into Amstrad CPC Locomotive BASIC
openai processed argument prompt re-code this into c
openai processed argument prompt re-code this into 8086 assembly language for MSDOS
openai processed argument prompt re-code this into 6502 assembly language for a Commodore 64
openai processed argument prompt re-code this into z80 assembly language for CP/M
files
Project filename: aicode.prj
Files:
  0    Run Space 0 bytes/0 lines (text/javascript:text)
  1 *D code.txt 43 bytes/1 lines (text/javascript:text)
  2  D code.c 125 bytes/8 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into c
  3  D code.pas 56 bytes/4 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into pascal
  4  D code.cs 74 bytes/4 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into c#
  5  D code.z80 878 bytes/31 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into z80 assembly language for CP/M
  6  D code.x86 217 bytes/16 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into 8086 assembly language for MSDOS
  7  D code.c64 417 bytes/14 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into 6502 assembly language for a Commodore 64
  8  D code.bas 59 bytes/3 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into Amstrad CPC Locomotive BASIC
  9  D code.js 67 bytes/3 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:re-code this into javascript ES5
 10    Unnamed File 0 bytes/0 lines (text/javascript:text)
 11    chatgpt.xfrm [PLUGIN] 15544 bytes/548 lines (text/javascript transformer:text)

* current file, D dirty file
Ready
saveall
Ready
dir
Directory of home:

                3d.js 5612 bytes
      ai-example1.txt 2736 bytes
      ai-example2.txt 14643 bytes
           aicode.prj 2307 bytes
           aitest.prj 1941 bytes
   aitest_chinese.txt 1478 bytes
   aitest_english.txt 1588 bytes
aitest_indonesian.txt 1769 bytes
  aitest_japanese.txt 2009 bytes
    aitest_prompt.txt 175 bytes
     aitest_story.txt 1588 bytes
   aitest_tagalog.txt 1971 bytes
            arabic.js 339 bytes
         blocker.xfrm 1037 bytes
                bm.js 3401 bytes
               bm.txt 2668 bytes
               cat.js 442 bytes
           chatgpt.js 15077 bytes
         chatgpt.xfrm 15544 bytes
           cliform.js 2681 bytes
             code.bas 55 bytes
               code.c 117 bytes
             code.c64 394 bytes
              code.cs 73 bytes
              code.js 66 bytes
             code.pas 57 bytes
             code.txt 43 bytes
             code.x86 196 bytes
             code.z80 836 bytes
             count.js 136 bytes
csconfig.english.json 4346 bytes
          csconfig.js 15487 bytes
        csconfig.json 513 bytes
              data.js 1855 bytes
          desktop.css 8292 bytes
           desktop.js 50582 bytes
       desktop_api.js 31260 bytes
          filetest.js 606 bytes
           hangman.js 4125 bytes
         helloform.js 1142 bytes
           inc-idb.js 17718 bytes
         language.txt 7 bytes
            lorem.png 4990 bytes
            null.xfrm 806 bytes
             ocr.xfrm 6489 bytes
     passthrough.xfrm 837 bytes
            primes.js 1251 bytes
         simplegpt.js 2941 bytes
              tabs.js 258 bytes
             todo.txt 760 bytes
           tosell.txt 73 bytes
       translate.xfrm 5164 bytes
               ug.txt 2024 bytes
Ready
dir code.*
Directory of home:

code.bas 55 bytes
  code.c 117 bytes
code.c64 394 bytes
 code.cs 73 bytes
 code.js 66 bytes
code.pas 57 bytes
code.txt 43 bytes
code.x86 196 bytes
code.z80 836 bytes
Ready
type code.bas
Ready
     10 10 FOR A = 1 TO 10
     20 20 PRINT "Hello, World!"
     30 30 NEXT A
Ready
type code.c
Ready
     10 #include <stdio.h>
     20
     30 int main() {
     40 for (int A = 1; A <= 10; A++) {
     50 printf("Hello, World!\n");
     60 }
     70 return 0;
     80 }
Ready
type code.c64
Ready
     10 ```
     20 LDX #$01       ; Initialize X register to 1
     30 loop:
     40 LDA message    ; Load the address of the message
     50 JSR $FFD2      ; Call the Kernal to print the string
     60 INX            ; Increment X
     70 CPX #$0A      ; Compare X with 10
     80 BNE loop       ; If X is not 10, repeat
     90 RTS            ; Return from subroutine
    100
    110 message:
    120 .ASC "Hello, World!"
    130 .BYTE $00      ; Null terminator for the string
    140 ```
Ready
type code.cs
Ready
     10 for (int A = 1; A <= 10; A++)
     20 {
     30 Console.WriteLine("Hello, World!");
     40 }
Ready
type code.js
Ready
     10 for (var A = 1; A <= 10; A++) {
     20 console.log("Hello, World!");
     30 }
Ready
type code.pas
Ready
     10 FOR A := 1 TO 10 DO
     20 BEGIN
     30 WRITE('Hello, World!');
     40 END;
Ready
type code.x86
Ready
     10 MOV CX, 10
     20 MOV DX, OFFSET msg
     30
     40 print_loop:
     50 ; Print "Hello, World!"
     60 MOV AH, 09h
     70 INT 21h
     80
     90 ; Decrement CX
    100 LOOP print_loop
    110
    120 ; Exit program
    130 MOV AX, 4C00h
    140 INT 21h
    150
    160 msg DB 'Hello, World!$'
Ready
type code.z80
Ready
     10 ```
     20 ORG 100h          ; Starting address for CP/M
     30 START:
     40 LD C, 10          ; Set loop counter (C = 10)
     50 LD B, 1           ; Initialize A (B = 1)
     60
     70 PRINT_LOOP:
     80 LD HL, MESSAGE     ; Load address of message
     90 CALL PRINT_STRING   ; Call subroutine to print string
    100
    110 INC B              ; Increment A
    120 DEC C              ; Decrement loop counter
    130 JP NZ, PRINT_LOOP  ; Repeat until C = 0
    140
    150 RET                 ; Return from program
    160
    170 PRINT_STRING:
    180 LD A, (HL)         ; Load character
    190 CP 0               ; Check for null terminator
    200 RET Z              ; Return if end of string
    210 CALL PRINT_CHAR    ; Print character
    220 INC HL             ; Move to next character
    230 JP PRINT_STRING    ; Repeat for next character
    240
    250 PRINT_CHAR:
    260 ; Code to print character in A goes here
    270 RET
    280
    290 MESSAGE:
    300 DB 'Hello, World!', 0 ; Null-terminated string
    310 ```
Ready
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 19:09, 27 July 25
I just created the rpggpt game.  You need to setup your provider to play it.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 12:22, 28 July 25
here is an example of the aicoder project.

Project filename: aicoder.prj
Files:
  0    Run Space 0 bytes/0 lines (text/javascript:text)
  1 *  coder.js 0 bytes/0 lines (text/javascript:text) Linked to 2:passthrough.xfrm:
  2    coderai.js 0 bytes/0 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:process the file prompts start with # or // #
  3    coderbackup.js 0 bytes/0 lines (text/javascript:text) Linked to 1:passthrough.xfrm:
  4    passthrough.xfrm [PLUGIN] 837 bytes/24 lines (text/javascript transformer:text)
  5    chatgpt.xfrm [PLUGIN] 15544 bytes/548 lines (text/javascript transformer:text)

file 0 is where stuff runs, 1 is where we are coding, 2 is the chatgpt transformer output that takes input from file 1 (note the link) and follows the instructions in the args (which then takes further instructions from my # within the editor). 3. passthrough (aka copy, in case chatgpt stuffs up too badly). 4. another copy, copy the output which is 2, and put it back into 1 for the next round. 5. the actual plugin added as a result of the link/linkto command.

Interactive 'anything'...

i used as follows, within a few minutes i get output which is close to what i want, basically a projectcreator js.  it's at the point i can manually fix it faster than the AI, but... i got to this point in a only a minute or so.

project load aicoder
Could not load coder.js
Could not load coderai.js
Could not load coderbackup.js
File loaded: passthrough.xfrm
File loaded: chatgpt.xfrm
Project loaded:
Ready
preserve line numbers
10 #we want a ES5 createProject function that takes an array for input arrInput_a of filename strings.  and puts them into a json object which i will describe soon
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(arrInput_a) {
     20 var project = {};
     30 for (var i = 0; i < arrInput_a.length; i++) {
     40 var filename = arrInput_a[i];
     50 project[filename] = {}; // Add an empty object for each filename
     60 }
     70 return project;
     80 }
Ready
5 # add a test harness to this file
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(arrInput_a) {
     20 var project = {};
     30 for (var i = 0; i < arrInput_a.length; i++) {
     40 var filename = arrInput_a[i];
     50 project[filename] = {}; // Add an empty object for each filename
     60 }
     70 return project;
     80 }
     90
    100 // Test harness
    110 function testCreateProject() {
    120 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    130 var expectedOutput = {
    140 'file1.txt': {},
    150 'file2.txt': {},
    160 'file3.txt': {}
    170 };
    180 var result = createProject(input);
    190 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    200 console.log('Test passed!');
    210 }
    220
    230 testCreateProject();
Ready
5 add a strProjectName_a parameter. the output json is in this format.  {"projectName": "","files": []} for now make the files an array of objects with a single fn property to store the filename
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(arrInput_a, strProjectName_a) {
     20 var project = {
     30 projectName: strProjectName_a,
     40 files: []
     50 };
     60 for (var i = 0; i < arrInput_a.length; i++) {
     70 var filename = arrInput_a[i];
     80 project.files.push({ fn: filename });
     90 }
    100 return project;
    110 }
    120
    130 // Test harness
    140 function testCreateProject() {
    150 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    160 var expectedOutput = {
    170 projectName: 'Test Project',
    180 files: [
    190 { fn: 'file1.txt' },
    200 { fn: 'file2.txt' },
    210 { fn: 'file3.txt' }
    220 ]
    230 };
    240 var result = createProject(input, 'Test Project');
    250 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    260 console.log('Test passed!');
    270 }
    280
    290 testCreateProject();
Ready
# make the projectname contain no spaces, it can contain hyphens
File not found.
5 # make the projectname contain no spaces, it can contain hyphens
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(arrInput_a, strProjectName_a) {
     20 strProjectName_a = strProjectName_a.replace(/\s+/g, '-');
     30 var project = {
     40 projectName: strProjectName_a,
     50 files: []
     60 };
     70 for (var i = 0; i < arrInput_a.length; i++) {
     80 var filename = arrInput_a[i];
     90 project.files.push({ fn: filename });
    100 }
    110 return project;
    120 }
    130
    140 function testCreateProject() {
    150 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    160 var expectedOutput = {
    170 projectName: 'Test-Project',
    180 files: [
    190 { fn: 'file1.txt' },
    200 { fn: 'file2.txt' },
    210 { fn: 'file3.txt' }
    220 ]
    230 };
    240 var result = createProject(input, 'Test Project');
    250 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    260 console.log('Test passed!');
    270 }
    280
    290 testCreateProject();
Ready
5 #swap your createProject parameters around
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(strProjectName_a, arrInput_a) {
     20 strProjectName_a = strProjectName_a.replace(/\s+/g, '-');
     30 var project = {
     40 projectName: strProjectName_a,
     50 files: []
     60 };
     70 for (var i = 0; i < arrInput_a.length; i++) {
     80 var filename = arrInput_a[i];
     90 project.files.push({ fn: filename });
    100 }
    110 return project;
    120 }
    130
    140 function testCreateProject() {
    150 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    160 var expectedOutput = {
    170 projectName: 'Test-Project',
    180 files: [
    190 { fn: 'file1.txt' },
    200 { fn: 'file2.txt' },
    210 { fn: 'file3.txt' }
    220 ]
    230 };
    240 var result = createProject('Test Project', input);
    250 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    260 console.log('Test passed!');
    270 }
    280
    290 testCreateProject();
Ready
autonumber
# in the output json, each file regardless of filetype should have an entry like (leave mt and mte): {"fn": "actionFMSActiveServicesFetch.php","mt": "text/javascript","mte": "text","ln": null,"pl": "","arg": "","fl": "","st": ""}, for each file added, add them again with a slight modification to the json object and filename. prefix the filename with 'output-', ln should refer to the index+1 of the file when added the first time. pl is the chatgpt.xfrm plugin, and the prompt args as per this example. {"fn": "output-actionFMSActiveServicesFetch.php","mt": "text/javascript","mte": "text","ln": 1,"pl": "chatgpt.xfrm","arg": "please outline any bugs, missing variables or security issues","fl": "","st": ""}.  these files are to be output files referencing the input files. finally add 1 more entry to the object array which is the transformer referenced in the other files, just 1 shared by all: {"fn": "chatgpt.xfrm","mt": "text/javascript transformer","mte": "text","ln": null,"pl": "","arg": "","fl": "","st": ""}
Ready
list
     10 function createProject(strProjectName_a, arrInput_a) {
     20 strProjectName_a = strProjectName_a.replace(/\s+/g, '-');
     30 var project = {
     40 projectName: strProjectName_a,
     50 files: []
     60 };
     70 for (var i = 0; i < arrInput_a.length; i++) {
     80 var filename = arrInput_a[i];
     90 project.files.push({ fn: filename });
    100 }
    110 return project;
    120 }
    130
    140 function testCreateProject() {
    150 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    160 var expectedOutput = {
    170 projectName: 'Test-Project',
    180 files: [
    190 { fn: 'file1.txt' },
    200 { fn: 'file2.txt' },
    210 { fn: 'file3.txt' }
    220 ]
    230 };
    240 var result = createProject('Test Project', input);
    250 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    260 console.log('Test passed!');
    270 }
    280
    290 testCreateProject();
    300 # in the output json, each file regardless of filetype should have an entry like (leave mt and mte): {"fn": "actionFMSActiveServicesFetch.php","mt": "text/javascript","mte": "text","ln": null,"pl": "","arg": "","fl": "","st": ""}, for each file added, add them again with a slight modification to the json object and filename. prefix the filename with 'output-', ln should refer to the index+1 of the file when added the first time. pl is the chatgpt.xfrm plugin, and the prompt args as per this example. {"fn": "output-actionFMSActiveServicesFetch.php","mt": "text/javascript","mte": "text","ln": 1,"pl": "chatgpt.xfrm","arg": "please outline any bugs, missing variables or security issues","fl": "","st": ""}.  these files are to be output files referencing the input files. finally add 1 more entry to the object array which is the transformer referenced in the other files, just 1 shared by all: {"fn": "chatgpt.xfrm","mt": "text/javascript transformer","mte": "text","ln": null,"pl": "","arg": "","fl": "","st": ""}
Ready
5
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(strProjectName_a, arrInput_a) {
     20 strProjectName_a = strProjectName_a.replace(/\s+/g, '-');
     30 var project = {
     40 projectName: strProjectName_a,
     50 files: []
     60 };
     70 for (var i = 0; i < arrInput_a.length; i++) {
     80 var filename = arrInput_a[i];
     90 project.files.push({
    100 fn: filename,
    110 mt: "text/javascript",
    120 mte: "text",
    130 ln: i + 1,
    140 pl: "",
    150 arg: "",
    160 fl: "",
    170 st: ""
    180 });
    190 project.files.push({
    200 fn: 'output-' + filename,
    210 mt: "text/javascript",
    220 mte: "text",
    230 ln: i + 1,
    240 pl: "chatgpt.xfrm",
    250 arg: "please outline any bugs, missing variables or security issues",
    260 fl: "",
    270 st: ""
    280 });
    290 }
    300 project.files.push({
    310 fn: "chatgpt.xfrm",
    320 mt: "text/javascript transformer",
    330 mte: "text",
    340 ln: null,
    350 pl: "",
    360 arg: "",
    370 fl: "",
    380 st: ""
    390 });
    400 return project;
    410 }
    420
    430 function testCreateProject() {
    440 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    450 var expectedOutput = {
    460 projectName: 'Test-Project',
    470 files: [
    480 { fn: 'file1.txt', mt: "text/javascript", mte: "text", ln: 1, pl: "", arg: "", fl: "", st: "" },
    490 { fn: 'output-file1.txt', mt: "text/javascript", mte: "text", ln: 1, pl: "chatgpt.xfrm", arg: "please outline any bugs, missing variables or security issues", fl: "", st: "" },
    500 { fn: 'file2.txt', mt: "text/javascript", mte: "text", ln: 2, pl: "", arg: "", fl: "", st: "" },
    510 { fn: 'output-file2.txt', mt: "text/javascript", mte: "text", ln: 2, pl: "chatgpt.xfrm", arg: "please outline any bugs, missing variables or security issues", fl: "", st: "" },
    520 { fn: 'file3.txt', mt: "text/javascript", mte: "text", ln: 3, pl: "", arg: "", fl: "", st: "" },
    530 { fn: 'output-file3.txt', mt: "text/javascript", mte: "text", ln: 3, pl: "chatgpt.xfrm", arg: "please outline any bugs, missing variables or security issues", fl: "", st: "" },
    540 { fn: "chatgpt.xfrm", mt: "text/javascript transformer", mte: "text", ln: null, pl: "", arg: "", fl: "", st: "" }
    550 ]
    560 };
    570 var result = createProject('Test Project', input);
    580 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    590 console.log('Test passed!');
    600 }
    610
    620 testCreateProject();
Ready
autonumber
# in the output json, each file regardless of filetype should have an INPUT entry like (leave mt and mte): {"fn": "actionFMSActiveServicesFetch.php","mt": "text/javascript","mte": "text","ln": null,"pl": "","arg": "","fl": "","st": ""}, for each file added, add them again with a slight modification to the json object and filename. prefix the filename with 'output-', ln should refer to the index+1 of the INPUT file entry when added the first time. pl is the chatgpt.xfrm plugin, and the prompt args as per this example. {"fn": "output-actionFMSActiveServicesFetch.php","mt": "text/javascript","mte": "text","ln": 1,"pl": "chatgpt.xfrm","arg": "please outline any bugs, missing variables or security issues","fl": "","st": ""}.  these files are to be output files referencing the input files. finally add 1 more entry to the object array which is the transformer referenced in the other files, just 1 shared by all: {"fn": "chatgpt.xfrm","mt": "text/javascript transformer","mte": "text","ln": null,"pl": "","arg": "","fl": "","st": ""}
Ready
1
coder.js passes through
Ready
openai processed argument prompt process the file prompts start with # or // #
coderai.js passes through
list
     10 function createProject(strProjectName_a, arrInput_a) {
     20 strProjectName_a = strProjectName_a.replace(/\s+/g, '-');
     30 var project = {
     40 projectName: strProjectName_a,
     50 files: []
     60 };
     70 for (var i = 0; i < arrInput_a.length; i++) {
     80 var filename = arrInput_a[i];
     90 project.files.push({
    100 fn: filename,
    110 mt: "",
    120 mte: "",
    130 ln: null,
    140 pl: "",
    150 arg: "",
    160 fl: "",
    170 st: ""
    180 });
    190 project.files.push({
    200 fn: 'output-' + filename,
    210 mt: "",
    220 mte: "",
    230 ln: i + 1,
    240 pl: "chatgpt.xfrm",
    250 arg: "please outline any bugs, missing variables or security issues",
    260 fl: "",
    270 st: ""
    280 });
    290 }
    300 project.files.push({
    310 fn: "chatgpt.xfrm",
    320 mt: "text/javascript transformer",
    330 mte: "text",
    340 ln: null,
    350 pl: "",
    360 arg: "",
    370 fl: "",
    380 st: ""
    390 });
    400 return project;
    410 }
    420
    430 function testCreateProject() {
    440 var input = ['file1.txt', 'file2.txt', 'file3.txt'];
    450 var expectedOutput = {
    460 projectName: 'Test-Project',
    470 files: [
    480 { fn: 'file1.txt', mt: "", mte: "", ln: null, pl: "", arg: "", fl: "", st: "" },
    490 { fn: 'output-file1.txt', mt: "", mte: "", ln: 1, pl: "chatgpt.xfrm", arg: "please outline any bugs, missing variables or security issues", fl: "", st: "" },
    500 { fn: 'file2.txt', mt: "", mte: "", ln: null, pl: "", arg: "", fl: "", st: "" },
    510 { fn: 'output-file2.txt', mt: "", mte: "", ln: 2, pl: "chatgpt.xfrm", arg: "please outline any bugs, missing variables or security issues", fl: "", st: "" },
    520 { fn: 'file3.txt', mt: "", mte: "", ln: null, pl: "", arg: "", fl: "", st: "" },
    530 { fn: 'output-file3.txt', mt: "", mte: "", ln: 3, pl: "chatgpt.xfrm", arg: "please outline any bugs, missing variables or security issues", fl: "", st: "" },
    540 { fn: "chatgpt.xfrm", mt: "text/javascript transformer", mte: "text", ln: null, pl: "", arg: "", fl: "", st: "" }
    550 ]
    560 };
    570 var result = createProject('Test Project', input);
    580 console.assert(JSON.stringify(result) === JSON.stringify(expectedOutput), 'Test failed: expected ' + JSON.stringify(expectedOutput) + ' but got ' + JSON.stringify(result));
    590 console.log('Test passed!');
    600 }
    610
    620 testCreateProject();
Ready
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 12:28, 28 July 25
Quote from: zhulien on 19:09, 27 July 25I just created the rpggpt game.  You need to setup your provider to play it.

For those who like text adventures? now here is the ultimate play any adventure you want...  Example...

rpggpt
Enter a brief summary describing your ideal RPG game. Suggest a main plot or goal, specify the type of character you'd like to play, and describe the setting or world for your adventure. Feel free to mention any special themes, challenges, or story elements you'd like to see included in your game.
 
You're a superhero who lost their powers and must save the city using only wit and gadgets.
Enter your character's name:
Zara
 
The city of Eldoria is in turmoil. Once a bustling metropolis filled with vibrant life, it now lies shrouded in chaos. An evil mastermind known as Dr. Obsidian has unleashed a wave of destruction, leaving the authorities powerless and the citizens in despair. You, Zara, once a celebrated superhero with extraordinary abilities, now find yourself stripped of your powers and trapped in a world that desperately needs saving.

You stand on the rooftop of a crumbling skyscraper, overlooking the chaos below. Smoke billows from buildings, sirens wail in the distance, and the atmosphere crackles with tension. You can feel the weight of the city's fate resting on your shoulders, but you know you have your wits and a few gadgets at your disposal.

In your utility belt, you have:

1. **Smoke Bombs**: Perfect for creating distractions or making a quick escape.
2. **Grappling Hook**: Allows you to reach high places or swing across gaps.
3. **EMP Device**: Can disable electronics for a short time, useful against tech-based foes.
4. **Holo-Disguise Projector**: Creates a temporary illusion of another person, which can be helpful for stealth.

As you survey the city, you spot a few key locations:

- **The Central Plaza**: Crowds are gathered, panicking as Dr. Obsidian's minions wreak havoc.
- **The Old Library**: Rumored to contain ancient texts that may hold the key to defeating Dr. Obsidian.
- **The Abandoned Warehouse**: Known to be a hideout for criminals; it might be a good place to gather intel.

You need a plan. What would you like to do?
 
go to the old library
You make your way towards the Old Library, your heart pounding with the urgency of the city's plight. As you navigate through the streets, you expertly avoid the chaos, using your grappling hook to swing between buildings and evade Dr. Obsidian's minions.

Arriving at the library, you notice its grand architecture is marred by neglect; ivy climbs its stone walls, and the large wooden doors creak ominously as you push them open. The inside is dimly lit, with dusty shelves towering over you, filled with forgotten tomes. The air is thick with the scent of aged paper and mystery.

As you step further inside, you hear a faint noise. It seems like someone might be inside. You have a few options:

1. **Investigate the noise**: Approach cautiously to see who or what is making the sound.
2. **Search the shelves**: Look for any specific texts or scrolls that might provide information on Dr. Obsidian.
3. **Set a smoke bomb**: Create a diversion just in case there's danger lurking, allowing you to escape if needed.

What would you like to do?
 
set a smoke bomb then investigate the noise cautiously
You quickly reach for a smoke bomb from your utility belt, holding your breath as you pull the pin and toss it to the ground. A thick cloud of smoke billows up, filling the library with a dense haze. With your vision obscured, you feel a rush of adrenaline as you move stealthily toward the source of the noise.

As you approach, you can hear muffled voices, one of which sounds distressed. You inch closer, carefully navigating through the shelves, listening intently. The smoke provides a perfect cover; you can hear the voices more clearly now.

"Please, I didn't mean to trespass!" a frightened voice pleads. "I was just looking for a way to stop him!"

You peer around a corner of the shelf and spot a young woman, her clothes tattered and dirt smudged on her face. She's backed against a shelf, trembling. In front of her stands a cloaked figure—one of Dr. Obsidian's minions. They appear to be holding a device that looks suspiciously like the EMP device you've seen before.

You have a few options on how to proceed:

1. **Confront the minion**: Use your gadgets to take them by surprise.
2. **Try to reason with the young woman**: Find out what she knows about stopping Dr. Obsidian.
3. **Create a distraction**: Set off another smoke bomb or use your Holo-Disguise Projector to confuse the minion.

What would you like to do?
 
quickly see if there are any non-lethal objects i can see that might be able to distract the minion with
You scan the surroundings quickly, your mind racing as you try to find anything that could serve as a distraction. Your eyes dart across the shelves, noticing various items that might prove useful:

1. **Old Books**: There are several heavy books stacked precariously on a shelf nearby. You could throw one to create a noise on the other side of the room.
2. **A Glass Globe**: An ancient-looking glass globe sits on a pedestal, reflecting the dim light. If you were to knock it over, it could shatter and draw the minion's attention.
3. **Dusty Scrolls**: A pile of scrolls lies on a table, and you could easily scatter them to make a ruckus as they fall to the ground.

With these options in mind, you can choose one of them to use as a distraction. What would you like to do?
 
just run and tackle the minion
With determination coursing through you, you decide to take action. You surge forward from your hiding spot, using the smoke as cover, and launch yourself at the cloaked minion. The element of surprise is on your side as you tackle them to the ground, your momentum knocking the device from their grasp.

The minion is caught off guard, and you quickly wrestle them away, pinning them to the ground. You can feel their struggle beneath you, but you have the advantage. The young woman watches in awe, her fear turning into hope.

As you hold the minion down, you have a few options:

1. **Interrogate the minion**: Demand to know what they know about Dr. Obsidian's plans and any weaknesses he might have.
2. **Secure the minion**: Use a gadget, like your grappling hook, to tie them up temporarily.
3. **Let the minion go**: Release them but threaten them, hoping they'll spread word that you're back in action.

What would you like to do?
 
punch the minion and don't stop until he is unconcious
Fueled by a surge of adrenaline and the need to protect the young woman, you unleash a powerful punch to the minion's face. The impact reverberates through your fist, and the minion lets out a grunt of surprise.

You don't stop there. With each strike, you rain down blows, your training as a superhero kicking in despite the loss of your powers. The minion struggles beneath you, but your determination is unyielding. After a few more solid punches, the minion's resistance fades, and they fall unconscious beneath you.

Breathing heavily, you rise to your feet, glancing around to ensure the coast is clear. The young woman stands wide-eyed, clearly impressed and relieved.

"Wow! That was amazing!" she exclaims, stepping closer. "I thought I was done for. Thank you!"

You take a moment to catch your breath and assess the situation. The minion lies motionless on the ground, and the EMP device they were holding is within reach.

You can now:

1. **Examine the EMP device**: See if it can be useful for your plans against Dr. Obsidian.
2. **Talk to the young woman**: Ask her who she is and what she knows about Dr. Obsidian and his schemes.
3. **Search the minion's pockets**: Look for any clues or gadgets that might aid you in your quest.

What would you like to do?
 
ask the woman what she is doing here
You turn to the young woman, curiosity piqued by her sudden appearance in the library. "What are you doing here?" you ask, your voice steady despite the adrenaline still coursing through your veins.

She takes a deep breath, relief washing over her as she realizes she's safe for the moment. "My name is Lila," she replies, her voice trembling slightly. "I've been trying to gather information about Dr. Obsidian and his plans. I heard rumors that there are texts in this library that could hold the secrets to stopping him. I thought I could find something to help the city, but I didn't expect to run into his minions."

Her eyes widen as she glances at the unconscious minion on the floor. "You're a superhero, aren't you? I've heard stories about you, Zara! But I thought you lost your powers..."

You nod, acknowledging her recognition. "I have, but I'm determined to save this city one way or another."

Lila's determination seems to mirror yours as she continues, "I read about an ancient artifact that's hidden somewhere in the library. It's said to have the power to disrupt Dr. Obsidian's technology. If we can find it, we might be able to turn the tide!"

You sense the urgency of the situation. You can:

1. **Ask Lila for more details about the artifact**: Find out if she knows anything specific about its location or how to use it.
2. **Search the library together**: Team up with Lila to comb through the shelves for any sign of the artifact.
3. **Check the unconscious minion**: See if they have any information about the artifact or Dr. Obsidian's plans.

What would you like to do?
 
sessions
Active sessions: zara (14 entries, 19 KB)
Total memory usage: 19 KB of 256 MB
 
save zara
 
Session "zara" saved.

A tiny enhancement i need to make that you can work around for now... that is restoring your game to continue later.  For now when you are prompted for a scenario, just type continue, then type the same character name you used before 'zara'.  then type load zara.  the adventure will continue.
Title: Re: Julian's Long List of Ideas Thread
Post by: zhulien on 17:50, 28 July 25
Normal file draggin behaviour: I dragged 3 files, so 3 are dirty and will all save when I type 'saveall'.

files
Files:
  0    Run Space 0 bytes/0 lines (text/javascript:text)
  1    Unnamed File 0 bytes/0 lines (text/javascript:text)
  2  D test3.txt 45 bytes/1 lines (text/plain:text)
  3  D test2.txt 16 bytes/1 lines (text/plain:text)
  4 *D test1.txt 33 bytes/1 lines (text/plain:text)

* current file, D dirty file
Ready

Linking a transformer to the drop event:

link drop chatgpt translate to Japanese
Event link added: drop => chatgpt.xfrm:translate to Japanese
Ready

Project created from dropped files with event 'drop'.
openai processed argument prompt translate to Japanese
openai processed argument prompt translate to Japanese
openai processed argument prompt translate to Japanese
files
Project name: DroppedProject
Files:
  0    Run Space 0 bytes/0 lines (text/javascript:text)
  1 *D test1.txt 33 bytes/1 lines (text/javascript:text)
  2  D test2.txt 16 bytes/1 lines (text/javascript:text)
  3  D test3.txt 45 bytes/1 lines (text/javascript:text)
  4  D output-test1.txt 17 bytes/1 lines (text/javascript:text) Linked to 1:chatgpt.xfrm:translate to Japanese
  5  D output-test2.txt 12 bytes/1 lines (text/javascript:text) Linked to 2:chatgpt.xfrm:translate to Japanese
  6  D output-test3.txt 22 bytes/1 lines (text/javascript:text) Linked to 3:chatgpt.xfrm:translate to Japanese
  7  D chatgpt.xfrm [PLUGIN] 15544 bytes/548 lines (text/javascript transformer:text)

* current file, D dirty file
Ready
list
     10 what is the capital of Ireland?
Ready
file 4
Ready
list
     10 アイルランドの首都はダブリンです。
Ready


What happens if the drop event is configured, is when you drag files to the screen, you do lose what you were doing in order to have a new project automatically setup as displayed above.  You can use any transformers you have or create.  For example, you could customise the chatgpt one to analyse your code and log all bugs into JIRA.  Other uses are the ocr plugin, drag images or PDFs on to have them automatically OCRd.

For now drop events can only have a single transformer because i don't know how we would want to setup a project if there were multiple.  Maybe i could later create a project template idea where the files dragged are added template like, so you can then perform multiple tranformations from a single drag and drop of many files.

So today... i was able to process 83 files that would normally take me 2 days in finding bugs... I did it in less than a minute!

Powered by SMFPacks Menu Editor Mod