[Google Blockly] Add customized input/output connectors in Sprite Lab - #51066
Conversation
…-lab-socket-shapes
|
|
||
| export const NOTIFICATION_ALERT_TYPE = 'notification'; | ||
|
|
||
| export const BlocklyVersion = { |
There was a problem hiding this comment.
Moved this constant to blockly/constants.js.
| [outputBlockStyleTypes.BEHAVIOR_TYPE]: this.ROUND_INPUT_OUTPUT, | ||
| [outputBlockStyleTypes.LOCATION_TYPE]: this.RECT_INPUT_OUTPUT | ||
| }; | ||
| const blockStyleName = connection.getSourceBlock().styleName_; |
There was a problem hiding this comment.
I think the bug with the insertion markers is happening because insertion markers don't get the normal style name for the block they're a marker of. They are a different color so they don't have the same style. I did some testing and for insertion marker blocks, this comes up as auto_#000000 or something similar instead of sprite_blocks etc. This causes this lookup to fail and you fall back to the puzzle shape.
You should probably use the same connection.check_ value instead of trying to use the category of the block. For example, when debugging this I used text and number blocks since I don't have sprite and behavior blocks. But the text_count block outputs a number despite being in the text block category. If you went off the category of the blocks instead, you would have that block with a misleading shape. By making sure you are always basing it off the connection checks, you can make sure both sides of a connection will have the matching shape (barring edge cases like a block accepting both text and numbers, but I'll assume that can't apply to a block accepting both sprites and behaviors).
I hope this helps, sorry it took me a while to figure out the cause of this!
There was a problem hiding this comment.
Thanks so much! Yes - this makes sense. I was making things more complicated than they had to be!
I was thinking about the 'move [sprite] pixels [number] toward [location]' block which accepts a sprite, a number and a location. But at each specific connector, the type accepted will always be the same.
| */ | ||
| function makeMainPath(up) { | ||
| return Blockly.utils.svgPaths.line([ | ||
| Blockly.utils.svgPaths.point(-width, (-1 * up * height) / 2), |
There was a problem hiding this comment.
btw I wonder if this should be GoogleBlockly here and elsewhere? I'm not sure exactly what Blockly refers to since you import GoogleBlockly in this file. This is just a random drive-by comment so feel free to ignore if it's not relevant.
There was a problem hiding this comment.
Blockly is a global variable we assign here. And your comments are always welcome!
There was a problem hiding this comment.
I think that means that Blockly and GoogleBlockly are kind of just different instances of same thing?
There was a problem hiding this comment.
@fisher-alice I think that both of these will have the same utilities so it maybe doesn't matter which we use... but if it's possible to use GoogleBlockly.utils without breaking anything, that feels a little tighter/cleaner.
Currently, this just relies on that googleblockly.js script; it's not something we're likely to change but I guess it still counts as a dependency.
There was a problem hiding this comment.
That makes sense. Will do -thanks! Thanks @maribethb for the initial suggestion!
There was a problem hiding this comment.
Missed your earlier reply/screenshot. I can see that we might need to use a separate instance here (from global/window). If it breaks things, no need to change!
There was a problem hiding this comment.
Sorry late to the party here -- my immediate reaction is that I didn't think we should be referencing google blockly directly in our code -- we generally use the wrapper, which feels like the right practice to me. We don't currently reference GoogleBlockly directly anywhere else (unless we need it to subclass google blockly classes, as you are doing here), as far as I can tell?
That said, thinking about it more, I do think that using it directly in these "addons" that are only referenced in the wrapper does feel less circular than trying to use the wrapper (which we do elsewhere, and maybe should not, eg here) -- since we only are using this code in the wrapper (via the different renderers). Does that make sense to folks? Happy to chat offline if what I'm saying isn't super clear.
There was a problem hiding this comment.
I don't have a strong opinion using GoogleBlockly vs the wrapper in the 'addons', but I do think we should be consistent, and you bring up a good point about how the wrapper is being used in other `addons'.
@mikeharv , thoughts?
There was a problem hiding this comment.
After discussing offline, the group decided to reference GoogleBlockly considering comments above and also the eventual goal of using solely mainline and deprecating CDOBlockly.
mikeharv
left a comment
There was a problem hiding this comment.
Fantastic work on this, Alice! A few suggestions, mostly for comments. Since we're also slightly impacting Music Lab (in a good way), I also tagged that team so they'd have a chance to weigh in on Thrasos being a shared default across labs.
| options.renderer = Renderers.ZELOS; | ||
| } else if (experiments.isEnabled('geras')) { | ||
| options.renderer = 'cdo_renderer'; | ||
| options.renderer = Renderers.GERAS; |
There was a problem hiding this comment.
Thanks for cleaning these up with constants!
| -width * 1.5 + ', 0 ', | ||
| -width * 1.5 + ', ' + -1 * up * height + ' ', | ||
| '0, ' + -1 * up * height + ' ' | ||
| ]); |
There was a problem hiding this comment.
Is there a link we could add with documentation for how these path values can be interpreted?
There was a problem hiding this comment.
I added the link to the curve definition from mainline blockly which includes a link to MDN doc. Lmk if that is sufficient - thanks!
| 'cdo_renderer', | ||
| CdoRenderer, | ||
| Renderers.GERAS, | ||
| CdoRendererGeras, |
| ? 'cdo_renderer_zelos' | ||
| : 'cdo_renderer_thrasos', | ||
| ? Renderers.ZELOS | ||
| : Renderers.DEFAULT, |
There was a problem hiding this comment.
Calling out for Music Lab team (@breville @sanchitmalhotra126) that we recently updated our other labs to also use Thrasos as the default renderer. Thrasos is likely going to remain a firm requirement for Sprite Lab due to Alice's awesome work in this PR.
| */ | ||
| function makeMainPath(up) { | ||
| return Blockly.utils.svgPaths.line([ | ||
| Blockly.utils.svgPaths.point(-width, (-1 * up * height) / 2), |
There was a problem hiding this comment.
@fisher-alice I think that both of these will have the same utilities so it maybe doesn't matter which we use... but if it's possible to use GoogleBlockly.utils without breaking anything, that feels a little tighter/cleaner.
Currently, this just relies on that googleblockly.js script; it's not something we're likely to change but I guess it still counts as a dependency.
| GERAS: 'cdo_renderer_geras', | ||
| THRASOS: 'cdo_renderer_thrasos', | ||
| ZELOS: 'cdo_renderer_zelos', | ||
| DEFAULT: 'cdo_renderer_thrasos' |
There was a problem hiding this comment.
@breville @sanchitmalhotra126 see also ^
It's possible for Music Lab to still use Thrasos without implicitly agreeing that Music Lab is using whatever our default happens to be. Let us know if you have any concerns!
sanchitmalhotra126
left a comment
There was a problem hiding this comment.
Looks fine to me from a Music Lab perspective!
| var pathUp = makeMainPath(1); | ||
| var pathDown = makeMainPath(-1); |
There was a problem hiding this comment.
nit: do these need to be vars?
There was a problem hiding this comment.
Mainline uses var but I can update to be more consistent with our codebase.


This PR customizes the input/output connector shapes in Google Blockly labs (such as Poetry) and adds constants for the Google Blockly renderers:
geras,thrasos, andzelosand the default renderer which is nowthrasos.Currently in CDO Blockly labs, output blocks of certain types have customized connector shapes:
This PR customizes the output connector shapes of these type blocks and the input connector of blocks that accept these blocks in Google Blockly labs.
Google provides a nice Codelab tutorial on how to build a custom renderer and includes sections on how to 'Override constants' and 'Change connection shapes'.
Initially, when I added the
cdoConstantsProviderclass, it extended the Google Blockly'sgeras.ConstantProviderclass sincegeraswas our standard renderer. Then withincdoRenderer.js, I overrode themakeConstants_function. Sincegerasuses highlights, the next step would have been to extend theHighlighterandHighlightConstantProviderclasses associated with thegerasrenderer to fix the highlight paths.After consulting with @maribethb about this, she suggested using the
thrasosrenderer which is the modern version ofgerasbut doesn't have the highlights. She said thatgeraswas designed to be identical to the "legacy" rendering code (pre-2019 when the new renderer system was added) andthrasoswas designed to be the replacement. The Google Blockly team now explicitly recommends that new code usethrasos. I discussed this change with @mikeharv. He pointed out thatthrasosis already used for Music Lab and for several reasons laid out in his already merged PR, it made sense to usethrasosas our default renderer.So now,
cdoConstantsProviderclass extends the Google Blockly'sblockRendering.ConstantProviderclass. I change the name of thecdoRendererclass tocdoRendererGerassincegerasis no longer our default renderer. Then I override themakeConstants_function incdoRendererThrasosto return our customized constants provider.In
cdoConstantsProvider.js, I override theshapeForandinitfunctions. The Codelab tutorial provides an example for a rectangular connection which I use for 'location' blocks. But I also add the functions to draw the svg paths for a rounded connection and a triangular connection. I usedsvgPathsutility functions provided by mainline Blockly.In the
shapeForfunction, the input and output connector shapes are customized according to theblockTypeShapeMapand if not customized, then the standard 'puzzle' connector shape is used.I also add constants in
blockly/constants.jsfor the 3 renderers and the default renderer.For the following videos, I use a Poetry lab which is a Google Blockly lab, and then copy and paste Sprite lab blocks with customized connector shapes. In order to do this, I use the 'blocklyVersion=CDO' in the Poetry lab to be able to paste these Sprite lab blocks and then go back to mainline Blockly in the Poetry lab.
BEFORE UPDATE:
production-poetry.mp4
As a comparison, here is a video of the blocks in Sprite Lab (CDO Blockly) currently in production. Note that there are no insertion markers ('shadow' of output or next block when close to compatible block).
sprite-lab-production.mp4
AFTER UPDATE:
after-update-fix-bug.mp4
There remained a bug that @maribethb helped me figure out - The output connector insertion markers were not rendered correctly. For example, on the 'location (200, 200)' block, the insertion marker's output connector shape was incorrectly a puzzle shape:
I was using the block style to map which shape to use for the output connector. However, an insertion marker is a block whose style does not match the block it is a marker for since markers are a different color. Thus, I now use
connection.typeto determine the shape of the output connector as I do for the input connector which also simplifies the code. I was thinking about a block that accepts more than one type as input such as the 'move [sprite] pixels [number] toward [location]' block which accepts a sprite, a number and a location type. But at each specific connector, the type accepted will always be the same!Links
jira ticket - [Google Blockly] Create block socket shapes for Sprite Lab
Testing story
I tested locally.
Follow-up work
Deployment strategy
Privacy
Security
Caching
PR Checklist: