-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve structure of sb-edit #53
Comments
Does |
@ThatXliner No. In this new structure it would technically be up to the importers/exporters to decide what to do with unused resources, but sb-edit core should definitely be able to represent unused resources like scripts without hat blocks. |
@PullJosh , Got it. |
Every importer would have its own unique way to "fix" ""faulty"" projects. How do we decide how these so-called faulty projects should be "fixed"? Change invalid costume menus to null? Use psychic powers to determine what menu value the user really wanted to select? If we change our mind on what to do here, or want to make it configurable, will we have to reimplement that the same way in every importer? Also, what about sound menus? Sprites must always have at least one costume, but what happens if we need to "fix" a sound menu when the sprite has zero sounds? Another problem with automagically and silently "fixing" things for the API consumer is that you'd have no guarantee that the project you get out is the same as the project you put in. In my opinion, if you import a project into sb-edit, then export that same project in the same format, its structure, or at the very least its behavior, should not change. I'm not sure this is the best representation because in Scratch, a dropdown menu (at least, the rounded type that you can drop blocks into) is just a reporter block that returns a string value (that's just what a "shadow block" is). The difference between it and other reporter blocks is that it cannot be dragged out of the block input. IIRC you can even do things like put a costume menu into a "join" block by editing the project.json. As such, IMO it would make more sense to represent those types of dropdowns as strings, or "shadow" blocks that evaluate to strings. |
I agree that projects (especially project behavior) shouldn't change when imported and re-exported. However, if a project is (supposed to be) impossible to create in the Scratch editor, or its contents are nonsensical (such as a menu that points towards something nonexistent), I don't feel that sb-edit has any obligation to preserve it exactly. I hope that I'm wrong, but it feels like there's a tradeoff here: Making sb-edit better at representing broken projects necessarily makes it worse at representing reasonable ones. A solid project representation is built on a set of abstractions that assume the world makes sense. The more weirdness sb-edit allows in a project, the less confident and solid the abstractions can be. Two ways I could be wrong:
I think you're right about this. Automatic fixes are the wrong choice. How about just throwing an error instead? |
This is something I hadn't thought of, but a |
It looks like you're thinking of "validity" from a different perspective than Scratch does. Scratch works from the assumption that any block input that you can drag a reporter into can and should be allowed to take any arbitrary value, costume and sound menus included, and if you enter something invalid, then nothing happens. It's the blocks' job to translate costume and sound names into references to actual costumes and sounds, which is why it allows and encourages you to do string manipulation on those inputs. From that perspective, it makes much more sense to represent costume menus as strings. Why should you be allowed to do "switch costume to (join (nonex) (istent costume))" but not "switch costume to (nonexistent costume)"? Perhaps for things like non-droppable menus like variable and list menus it would make more sense to forbid invalid inputs, but even there, it's incredibly easy to get into an invalid state (for example, add a "() of ()" block, set the first menu to a variable, then delete that variable), and Scratchers could accidentally reach such states while editing their projects often enough that throwing an error when that occurs could prevent a significant number of projects from being loaded. That's where the tradeoff comes into play. |
I see what you're saying. There might not be a reasonable solution that does what I'm hoping for. As a user of const myCostume = new Costume({ name: "costume1", /* ... */ });
const myVariable = new Variable({ name: "my variable", /* ... */ });
const mySprite = new Sprite({
costumes: [myCostume],
variables: [myVariables],
scripts: [
new Script([
new Blocks.SwitchCostumeTo({ costume: myCostume }),
new Blocks.SetVariable({
variable: myVariable,
value: new Blocks.Multiply({
first: Blocks.GetVariable(myVariable),
second: 2
})
})
])
]
});
// Rename costumes and variables
myCostume.name = "c1";
myVariable.name = "my cool variable";
// Scripts still work, because they reference the actual instances! 🎉 I want my project representation to be intelligent, so that updates stay in sync and making changes is simple. This requires sb-edit to understand the way a project will behave at runtime. Sometimes that's straightforward, in which case life is great. But sometimes, understanding what a project will do at runtime is a pretty gross undertaking, and it's too complicated to represent cleanly. Is this unfortunate fact the death-knell for an intelligent, live representation? I hope not, but it could be. (Also, this reminds me a little bit of Typescript--trying to capture weird runtime behavior in a compile-time process. Are there any lessons to be learned from what that team has done?) |
Improved structure? Ok! (Suggestion)I don't really know I really want to be a contributor |
You can't satisfy all the standards and ways things are implemented. It would be best to prioritize what is being used the most and developed which is sb3. It may have quirks, but it is also a practical thing to follow. These issues could be weird, but it would be better to introduce them as exception and just document what they are. If something cannot be converted, then it should be for a reason already decided on. There is also the issue of data integrity which isn't something that can be controlled. My thought would be to not destroy any of the data at all. It would be better to keep it as a sort of metadata to then recall if ever needed. This would only be able to work on the scope of the converter, but would give more flexibility with the data. You don't want to just replace something with null. It may even work by just giving an output of what was and wasn't able to be converted. When you decide to do the rework, it would be nice to have an API and documentation written out first and then implemented. When I look at a lot of the code it is just blocks of text and functions that just run in loops. It would help to maintain the project for anyone unfamiliar with the code or its design. |
Why not make a wrapper class CostumeInput or something that can point to
one of 3 things: a Costume object, a string, or a block. Exporters will
take the costume's name at compile time, making it so we can safely change
costume names. Invalid inputs will be represented as strings, and put back
the way they were. A console.warn for invalid things might be a good idea
though.
…On Mon, Jul 13, 2020, 12:38 AM Matt ***@***.***> wrote:
You can't satisfy all the standards and ways things are implemented. It
would be best to prioritize what is being used the most and developed which
is sb3. It may have quirks, but it is also a practical thing to follow.
These issues could be weird, but it would be better to introduce them as
exception and just document what they are. If something cannot be
converted, then it should be for a reason already decided on.
There is also the issue of data integrity which isn't something that can
be controlled. My thought would be to not destroy any of the data at all.
It would be better to keep it as a sort of metadata to then recall if ever
needed. This would only be able to work on the scope of the converter, but
would give more flexibility with the data. You don't want to just replace
something with null. It may even work by just giving an output of what was
and wasn't able to be converted.
When you decide to do the rework, it would be nice to have an API and
documentation written out first and then implemented. When I look at a lot
of the code it is just blocks of text and functions that just run in loops.
It would help to maintain the project for anyone unfamiliar with the code
or its design.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#53 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AFQENB4XRERMG4NUQHWLAWTR3KFTFANCNFSM4OX3THBA>
.
|
There is some early-on discussion in #4 as well. |
Right now, sb-edit inherits a lot of quirks from the sb3 format. It also isn't as modular as it should be. That was okay at first--it let us ship a Leopard translator quickly. But at this point, I think it's time to go back and rethink the structure of sb-edit.
These are just my first thoughts. I'm posting because I hope that you will have some useful feedback. Nothing is set in stone, so please tell me why this is wrong!
Fundamental Goals
sb-edit should be the platonic ideal of a Scratch file format, without inheriting any assumptions (or jank) from existing formats like sb3.
sb-edit should make it easy to...
Modularity
Right now importing/exporting scripts exist in the
/io
directory. Instead, sb-edit core should only provide the project representation structure (JS classes to represent blocks, scripts, sprites, projects, etc) and methods to create and manipulate these structures directly.All importing and exporting should happen in separate packages, and creating a new importer/exporter should never require modification to sb-edit core.
I can imagine publishing a suite of packages like this:
@sb-edit/core
@sb-edit/sb
-- Import and export .sb projects@sb-edit/sb2
-- Import and export .sb2 projects@sb-edit/sb3
-- Import and export .sb3 projects@sb-edit/tosh
-- Import and export tosh projects@sb-edit/scratchblocks
-- Import and export scratchblocks scripts (but not entire sprites or projects; users of@sb-edit/scratchblocks
can take advantage of@sb-edit/core
to generate full projects from scratchblocks code)@sb-edit/Leopard
-- Export as Leopard projects@sb-edit/snap
-- Export as Snap! projects (there are probably too many incompatible features to allow importing Snap! projects, but I hope someone proves me wrong)Of course, ordinary users (not members of @sb-edit) could also create custom import/export options using the project-creation methods provided by
@sb-edit/core
. (Ideally this could mean Leopard equivalents in languages other than JavaScript!)Design Considerations
Scratch versions represent the same functionality differently.
For example, Scratch 2.0 and Scratch 3.0 have different ways of representing "delete all of list":
Scratch 3.0 only allows you to enter a number into the top delete block. However, if you sneak in a string, it will respect the "all" and "last" options:
In addition, when the Scratch editor converts a project from Scratch 2.0 to the 3.0 format, it actually inserts the string "all" directly into the number input (rather than converting to the designated delete all block).
sb-edit should choose exactly one way to represent each behavior. As soon as there are multiple ways of representing the same thing, importers and exporters also need to support every method or else they'll become incompatible.
I'm not sure, in the list example, what the best representation is. A single block, with different input options (number, "last", "all")? Two separate blocks? In theory, sb-edit could even have three different blocks--one for numbers, one for "all", and one for "last"--even though a dedicated "delete last" block doesn't exist in any Scratch version. (Each importer/exporter would convert its version-specific Scratch representation to/from the sb-edit representation.)
Menu references
Many Scratch blocks have menus that reference specific costumes, sounds, variables, lists, sprites, etc. (Such as the "switch costume" or "set variable" blocks.)
One of the fundamental goals I listed for sb-edit is easy manipulation of projects. I think this means that renaming a costume, for example, should also update the blocks that reference it. The easiest way to do this is to make sure that in the sb-edit project representation, the block's input value is a reference to the actual
Costume
instance, rather than a string name of the costume.There are a few problems with referencing costumes (and variables, sprites, etc.) directly:
Costume
instances just to set the costume menu value in a block?)Problem 1 isn't a huge deal. Every block input can accept two values: a literal value and an optional block value. This is sort of what Scratch 3.0 does with shadow blocks (so that when you remove a block, the original literal value of the input returns). The sb-edit representation could achieve this same thing with a much cleaner representation than sb3.
Problem 2 is probably acceptable. In fact, it could be considered a feature. Every importer would be forced to fix faulty projects on import, which isn't a terrible thing. Would love to hear others' thoughts on this.
Problem 3 is the most annoying. In contexts like scratchblocks import where a full project doesn't need to be wired up, creating dummy
Costume
instances is a little annoying. (On the other hand, it does make it much easier to generate real scratch project files from scratchblocks code. Maybe this is a feature too?)Again, all of this applies to more than just costumes. Variable, list, sprite, and sound menus are affected too. Overall, I think direct instance references are the best way to store menu values, but I'd love to hear more opinions.
The text was updated successfully, but these errors were encountered: