Release v5.1.0 - #31
Closed
github-actions[bot] wants to merge 1 commit into
Closed
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The reference lists only what someone using the library can actually call.
Twenty-three pages documented the library's own plumbing. Nine of them took a
Processing
PGraphics—draw,drawDebug,drawShape— which nothing in thelibrary hands out, so there was no way to call them and no example to show.
addedToStage/removedFromStageare the methods that call the documentedwhenAddedToStage/whenRemovedFromStage, and having both listed invitedoverriding the wrong one; on
TextandPenthey carried no description at all,so those pages were a bare signature. The rest were
Sprite's protectedsetWidth,setHeight,setNineSlice,disableNineSlice,setUIandisUI— the seams
UISpriteis built on — plusShape.invalidateCache.The doclet now documents public members only, so a protected helper added later
cannot leak into the reference on its own.
The extension pages that have no example keep them, because the reason is
different:
File,Pixels, the recorders,Shader,SortingandTiledarereal API that simply cannot run inside a web page. Those 66 pages now say so, in
a note the doclet places from a single
@desktop-onlytag in each extension'spackage-info.java.A parity probe, so the two runtimes stop drifting apart unnoticed.
The desktop library and the browser port have disagreed several times now, and
never in a way a signature could catch: a transparency that counted the other way
round, a
getWidth()that measured the rotated bounding box rather than thecostume, a hitbox reported in screen pixels rather than around the middle of the
stage. Every one was found by running the same program in both and reading the
two outputs side by side.
That program is now written down.
src/examples/java/parity/ParityProbe.javaprints 77 values that have to read the same in both places;
./scripts/parity.shruns it on the desktop and holds it tosrc/test/resources/parity/expected.txt, and--recordwrites that file when achange is meant.
python3 scripts/parity-fixture.pycarries the stage-free half of it into theonline IDE's own test suite, where it runs on every
npm test. Only half,because a
Stageneeds WebGL and the browser's tests run in node — the rest isheld to the recorded values on the desktop, and to the same signatures in the
browser by its
ScratchTest.java. Anything that can be written without a stageshould be, because that half is checked by a machine.
Gave each class's constructor a page of its own.
A class used to be documented on the landing page of its own section, which no
navigation ever pointed at. It now has a
constructorpage carryingindex: 0,so it sits at the top of the class in the sidebar next to the methods -
Sprite()aboveaddCostume()- and reads like one of them. The classdescription, the example, the constructor syntax and the static fields all moved
there with it. The section's
indexpage is left empty; it is the landing pageof the section and nothing more.
The constructor syntax had never appeared on any page: the template asked for
constructorswhile the doclet writesconstructor, so the block was silentlyskipped. It is on the new page, under Syntax, the way a method's syntax is.
A link to a class page, e.g.
/reference/Sprite/, now arrives at an empty pagerather than at the class documentation, which has moved to
/reference/Sprite/constructor. Nothing in the book linked to one.A text shows the words it was built with, in every style.
new Text("Hello World", 0, 0, 400)put nothing on the stage. The constructorleft the text hidden, and only
showText()ever revealed it - so the obvious wayto write the obvious first program drew a blank stage. A text built with words is
visible now. One built with nothing to say still starts hidden, which is what a
speech bubble waiting for
say()and the stage's own display line both want.Speech and thought bubbles also work on a text of their own.
drawBubblegave upunless the text belonged to a sprite, because it took its position from that
sprite, so
setStyle(TextStyle.SPEAK)on a text you placed yourself drewnothing. Such a text now keeps the position it was given, the way the other two
styles do, and the bubble grows up and to the right of it.
A framed text is drawn around the words it holds rather than filling the width it
was given, which is what the browser has always done. The width is where the
words wrap:
new Text("Hello World", 0, 0, 400)wraps at 400 and comes out aswide as "Hello World", instead of as a mostly empty 400 pixel frame running off
the side of the stage. The stage's own display line still reaches from edge to
edge - it is a band, not a label.
Drawing no longer writes the measured size back into the text. A box drawn after
a bubble used to come out the size of that bubble, and
getWidth()answered withwhatever was last drawn instead of the width that was set.
setAlignworks on the framed styles. It only ever reached the words inside theframe, and the frame itself always started at the position it was given, so a
centred box was not centred on anything - and its words were centred eight pixels
from its left edge, half of them outside it. The box now sits where the alignment
asks: its left edge on the position, its middle, or its right edge.
An aligned text also sat a line too high. Choosing a horizontal alignment put the
vertical one back to the baseline, and only a text that was left alone kept the
top edge it was drawn against.
A box is rounded on all four corners. The stage's display line keeps its two
bottom corners square, because they sit on the edge of the stage, where a curve
would only show what is behind it.
💥 BREAKING CHANGE:
Window.addStage,switchStageandremoveStageare gone.They were deprecated in 4.0.0 in favour of
setStage, which holds the stage yougive it rather than a name you have to remember, and
transitionToStagewhen youwant the change to fade. Keeping them meant the window carried a second, parallel
list of stages that nothing else in the library ever looked at.
Replace
with a variable and one call:
removeStagehas no replacement and needs none: a stage the window is notshowing is not running, and one nothing refers to any more is collected.
Took the GIF recording apparatus out of the reference examples.
Every example is now the example and nothing else. The
GifRecorder, theexit()that closed the recording, and thewhile (stage.getTimer().forMillis( 3000))loop that timed it are gone; a loop that was doing the work runs on aswhile (true), and a loop that had no body at all - it only held the desktopprogram open while the GIF was taken - is gone with the rest. 28 MB of recordings
went with them, and
build.shno longer copies any.The rewriter that turns an example into an Online IDE program loses the same
amount: it existed largely to undo the recording again.
Two examples were wrong because of the recording, and are right now:
Stage.exit(),Window.exit()andWindow.whenExits()showed a program withno
exit()in it. The rewriter treated every line callingexit()asrecording scaffolding and dropped it, including the one line those three pages
are about.
Pen.up()had no interactive example and its source never calledup(). Itdraws two lines with a gap between them now.
GifRecorderitself is unchanged - it is still there for anyone recording theirown project.
Speech and thought bubbles hang off the sprite's hitbox.
They were placed from the size of the costume, at nine tenths of its width and
eleven tenths of its height. A costume is usually drawn into a canvas bigger than
what is painted on it — a standing pose in a canvas tall enough to also hold a
jumping one — so the bubble floated up and to the right of the sprite it belonged
to, with its tail pointing at nothing. It now sits on the top right corner of the
hitbox, which is the sprite as it looks.
For the built-in slime, whose painted pixels fill 88 by 62 of a 128 by 128
costume, that moves the bubble 14 pixels left and 72 pixels down, onto its
shoulder.
A built-in sprite name now works everywhere a picture is named.
new Sprite("player", "slimeGreen")threwCould not load image: slimeGreen.The constructor loaded its costume straight from a path while
addCostume()went through the built-in lookup, so the same name worked in one and not the
other - and worked in the browser, where the Online IDE has always resolved it.
The constructor now does the same lookup.
Three more places took a path where a built-in name was the natural thing to
write, and now take either:
Stage.setCursor(...), which the browser had already been resolving as abuilt-in name and nothing else
Window.useSplashLogo(...)Sprite.addCostumes(...), which cuts the named sheet into tiles. A built-insprite is a region of a shared sheet rather than a file of its own, so the
tiles are cut from inside that region instead of from the corner of the file
it happens to share.
A string with a file extension is still treated as a path, so projects that name
their own artwork keep working.
💥 BREAKING CHANGE: transparency and
modnow answer the way the Scratch block does.Both claimed a Scratch block in their documentation and then did something else.
setTransparencyis the ghost effect. It ran from 0 to 255, where 0 wasinvisible and 255 the solid sprite you start with — upside down and on the wrong
scale next to
set [ghost v] effect to, which the javadoc has always shownbeside it. It now runs from 0 to 100, 0 solid and 100 invisible, and a value
outside that is pinned rather than wrapped.
changeTransparencyused(current + step) % 255, so stepping past the end came back round or wentnegative; it now stops at the ends.
Operators.modis the Scratch modulo. It was Java's%, whose answer takesthe sign of the first input, so
mod(-7, 3)was -1 where the block says 2. Theanswer now takes the sign of the second input, which is what makes it useful for
wrapping a value into a range:
The stage's effects belong to the stage.
setTransparency,setTintandchangeTinton aStagereached only the backdrop that was showing, soswitching backdrop quietly undid them. They now apply to all of them, as
Spritehas always done with its costumes and as Scratch does.Two smaller ones that go with it:
Stage.countreturns anintrather than thelongaStreamhappened to hand back, soint coins = myStage.count(Coin.class)compiles; and
ColorhastoString,equalsandhashCode, so printing onesays
Color[r=255.0, g=128.0, b=0.0]instead oforg.openpatch.scratch.Color@35432107.Run the documentation's examples in the browser instead of watching them.
The reference pages now embed the example itself in an editor that compiles and
runs it, in place of the GIF that used to stand there. A new doclet step rewrites
each example under
src/examples/java/referenceinto the shape the Online IDEwants - no package, no imports, the constructor body as the program - so there is
still one source per example, still compiled by the build and still runnable on
the desktop. Every example uses built-in costumes and sounds, which resolve the
same way on both sides; only the Tiled map example still needs a file next to
it, because a map is not something the library bundles.
Nearly every documented method and constructor has one now, not only the hundred
that had a recording:
Sprite,Stage,Window,Text,UISprite,Pen,Color,Vector2,Operators,Random,Clock,Timer,HtmlColor,Shapeand its four kinds,Hitbox,AnimatedSpriteand theCameraextension. The ones that are only about a number - a vector's length, a random
seed - print it into the output panel next to the stage, where it can be read;
the ones that are about something on screen show it.
The tutorials gained the same thing at the point where each one first has a
finished program, so a reader can play the game before building it, and change a
number and see what happens without installing anything.
mvn testcompiles both kinds of interactive example, so one that stopscompiling fails the build rather than the reader's first click.
Also fixed in the documentation itself:
useStandardDocletOptionsis off,so the
<show>public</show>in the pom never reached javadoc and every memberarrived at the doclet - which is how
Color.HSBtoRGB(),Color.RGBtoHSB()and
Random.getRandom()came to have reference pages of their own. Fortypages for things nobody can call are gone.
Random.noise(double)was written with/*rather than/**, so itsdescription never reached the page.
Sprite.previousCostume()said "Switch to the next costume".Stage.add(Sprite)andWindow.getWidth()had no documentation at all.View on GitHublink under an example that is a single file pointed atthe directory the examples share rather than at the file.
build.shcould build the documentation with no reference section at all. Thereference pages are deleted before being written again, but the javadoc plugin
decides whether it has anything to do by looking at its own state file in
target, which the deletion left behind - so every build that did not startfrom a clean
targetskipped the run that was supposed to write the pagesback.
changePosition(double x, double y)sits alongsidechangePosition(Vector2 v).Moving by an amount only worked when the amount was already a
Vector2, eventhough
setPositionhas taken two numbers all along. Sprites moved by a stepworked out on the spot had to build a throwaway vector first, or fall back to two
changeX/changeYcalls.The documentation for the transparency methods has also been corrected.
Stage.setTransparencyclaimed a range of[0...1]; it is[0...255], and it isan opacity rather than a ghost effect — 255 is the fully solid sprite you start
with, and 0 is invisible. The reference examples for the four transparency
methods passed values that read as if the scale ran the other way.