"Improving" Patterns

It’s kind of the opposite.

If you have the binary code, you can load just the binary code onto another PB, the PB will then generate the plain text and jpg (preview) image from that.

This is how cloning a pattern from one PB to another works (.epe files are not used).

I don’t know if the plain text is encoded in the binary code itself, but the only thing you actually need is the binary code.

Of course you can’t edit that, and the only way of making the binary code is via a PB, but a repo with just the binary code in it would work.

You wouldn’t get a preview image though.

Yes, I’m aware the bin is the key piece, and you can transfer a bin from PB #1, to a file to PB #2

But you can’t do anything with that code in plain text, like push it to a git repo, patch it, and push it back onto a PB, without (as of now) , literally cut and pasting it into a web page. That’s a huge blocker, in my mind, to using git… You can’t test and iterate your code, and git commit, without likely multiple manual steps.

The binary files are a a few files together. It has the bytecode to run, the preview animation (jpg), compressed sources, and name. The bytecode also has a list of exports.

Epe files are portable source and preview and the intended way of sharing between Pixelblazes.

No guarantee that the binary files will be compatible between models/versions.

3 Likes

So if you had the binary, you could extract the plain text, and have a preview image, but in a read only format.

For compatibility, you could just load the extracted text - in fact, you could recreate the .epe file just from the binary if we knew how to deconstruct the binary.

@Nick_W yes, which is what the UI effectively does. It requests the compressed source segment with a websocket request, decompresses with LZString, and puts together a json file with the .epe extension.

I’m still trying to figure out a workflow to use .epe s with something like github.

Right now, if I embrace putting PB patterns into github, I’m fine with editing the source text… but trying to integrate any sort of .epe is a nightmare. Any change in source would have to require a manual step to replace the .epe (cut and paste source text into UI, download .epe, assuming it actually works, and then put .epe in, replacing existing binary, and finally commit it all, and push.

vs: “I only provide source” workflow:

Edit source, git commit, push, done. Accept a patch? Done.

What’s missing is some script/ability to push that source into PB and get back a .epe, OR a script to build an epe from it directly (and I realize this is much less likely since it would mostly require reinventing/opening PB bytecode building.)

To be clear, there is nothing wrong with a epe-less github repo… but I see the plan is to provide epe files in github, and I’m wondering (other than a huge manual process, leading to a lack of github updates/patches) how you were envisioning this.

I’m thinking of how to build out my PB github repo, a task I keep putting off, and so far, I can’t see how I’d support adding .epes.

1 Like

Yes, this is how I build the .epe file, once I figured out how to unzip LZString in python.

What you could do, is have the plain text in the GitHub repo. To load it into a PB, you would have to have a script that makes this into an epe, but all that script has to do is make a binary file with a dummy .jpg preview image and dummy byte code - say with an old version number or something.

So the constructed epe would have a dummy preview jpg, the actual plain text, and a manufactured binary containing the dummy jpg, the actual text LZString compressed, and some fake byte code.

Hopefully the PB has a mechanism for recognizing that the byte code is out of date, uncompressing the text, and recreating the preview image and byte code from that.

Would that work?

The epe does not contain bytecode. You could make one with source and very little. I’ll check, but I think just about everything other than sources is optional.

This has my thoughts on a GitHub friendly pattern repo format for a destructured epe file:

Of course, just looked at the structure of an epe again.

All you need is the plain text, name, unique id and a preview jpg in a Json structure.

Easy.

Oh, I totally misunderstood .epe then… I thought it had bytecode in it. Unsure why I thought that.

Never mind. :wink:

Thanks @wizard. I should have RTFM.

Nick, if you make a python script that takes program.js and makes an .epe out of it, I’d be grateful.

#!/usr/bin/env python3
# Use this to create epe files from source files in patterns/
# assumes structure as in https://github.com/simap/pixelblaze_patterns/tree/main/patterns/example
# or source files only to be in src/

import sys, os, json, re, base64

search_dir = __file__
if len(sys.argv) > 1:
    search_dir = sys.argv[1]

script_dir = os.path.dirname(search_dir)
indirs = [os.path.join(script_dir, dir) for dir in ["patterns", "src"]]
outdir = os.path.join(script_dir, "epe")

def write_epe(epe):
    epe_name = epe.get('name')
    if epe_name:
        epe_fname = '{}.epe'.format(re.sub('[^a-zA-Z0-9\n\.]', '_', epe_name))
        if not os.path.exists(outdir):
            os.makedirs(outdir)
        with open(os.path.join(outdir, epe_fname), 'w') as f:
            f.write(json.dumps(epe, indent=2))
            print('wrote {}'.format(epe_fname))
            
def make_epe(infile, epe, name=None):
    if name:
        epe.update({'name': name})
        name = 'main'
    with open(infile, 'rb') as src:
        if infile.endswith('.js'):
            epe.setdefault('sources', {})
            if not name:
                name = os.path.basename(infile).replace('.js','')
            epe['sources'][name] = src.read().decode('UTF-8')
        elif infile.endswith('.json'):
            epe.update(json.load(src))
        elif infile.endswith('.jpg'):
            epe['preview'] = base64.b64encode(src.read()).decode('UTF-8')
    return epe

for indir in indirs:
    if os.path.isdir(indir):
        for f_or_dir in os.listdir(indir):
            epe = {}
            in_path = os.path.join(indir, f_or_dir)
            if os.path.isdir(in_path):
                print('searching: {}'.format(f_or_dir))
                for root, dirs, files in os.walk(in_path, topdown=False):
                    for name in files:
                        infile = os.path.join(root, name)
                        epe = make_epe(infile, epe)       
            else:   #its a file
                print('checking file: {}'.format(f_or_dir))
                epe = make_epe(in_path, epe, name=f_or_dir.replace('.js',''))
            write_epe(epe)

This should do it.

I can make a PR if you like, I just don’t know which repository we are using for this…

4 Likes

Awesome! Thank you for that! A PR to that repo would be very helpful (put in /tools/).

The one I linked, and will merge in @jeff s repo that we worked on for the v3 updated patterns.

I’m out of the office, so limited availability but will pull these in when I can!

2 Likes