diff --git a/Behaviors.md b/Behaviors.md index 0f7993e..03be345 100644 --- a/Behaviors.md +++ b/Behaviors.md @@ -172,7 +172,7 @@ playing use the same two words. the given object, nearer levels first, the order `Child by name` searches in), `Children` (the children of an object; with **recursive** every object below it, level by level) and `Objects of asset` (every instance of the chosen asset, spawned ones included), - `Variables`, `Properties` (every property row of the target's type, the transform rows `scale`, `rotation`, `mirrorX`, `mirrorY` included — how a graph turns a sprite), `Get position` (local and world), `Is enabled`, literals `Number`/`Text`/`Boolean`/`Texture`/`State machine`/`Sound`/`Scene`/`Animation`/`Asset`, `Add/Subtract/Multiply/Divide`, + `Variables`, `Properties` (every property row of the target's type, the transform rows `scale`, `rotation`, `mirrorX`, `mirrorY` included — how a graph turns a sprite), `Get position` (local and world), `Is enabled`, literals `Number`/`Text`/`Boolean`/`Texture`/`State machine`/`Sound`/`Scene`/`Animation`/`Asset`, `Texture size` (a texture's, frame's or pixel art's own size in pixels, 0 for none — wired into a sprite's `width`/`height`, a picture shows pixel for pixel), `Add/Subtract/Multiply/Divide`, `Min/Max/Abs/Sqrt/Clamp`, `Lerp` (from a to b as t runs from 0 to 1, t held in 0…1; the setting *Ease* bends the way: *Linear*, *In* starts slow, *Out* ends slow, *In-out* both, all quadratic, or *Curve*, which follows the [curve asset](Curves) picked in the *Curve* row and may overshoot b; diff --git a/Concepts.md b/Concepts.md index a0f1cf5..462848d 100644 --- a/Concepts.md +++ b/Concepts.md @@ -6,7 +6,7 @@ | **Font** | An uploaded typeface, worn by a text through the ordinary property `font`; no font means the editor's own. Uploaded and picked exactly like a texture, and stored the same way. See [Fonts](Fonts). | | **Sound** | An uploaded audio file. Uploaded, picked and stored exactly like a typeface — but nothing *wears* it: it is neither on screen nor in the scene, and a graph plays it with `Play sound`. Its own rows say how loud it is and whether it loops; the node scales the one and can overrule the other either way. See [Sounds](Sounds). | | **State machine** | A named set of **states**, edited as nodes in its own tab. A behavior puts it into a state with `Set state`, moves it along a named transition with `State transition` and branches on it with `State branch`. Its **Scope** says where the current state lives: **Local** gives every behavior instance one of its own, **Global** keeps a single one for the whole run. See [State machines](State-machines). | -| **Shader** | A node graph that becomes the GLSL a sprite is drawn with, edited in its own tab. A sprite wears it through `shader`; the numbers the graph declares are rows below that dropdown. See [Shaders](Shaders). | +| **Shader** | A node graph that becomes the GLSL a sprite is drawn with, edited in its own tab. A sprite, a text or a particle source wears it through `shader`; the numbers the graph declares are rows below that dropdown. See [Shaders](Shaders). | | **Particles** | A node graph that says what *one* particle is as a function of its age and of a random number drawn once for it — no forces, no simulation. Unlike the other graph assets it **is** placeable: the object made from it is a source, whose rows say how many go out and for how long they live. Because a particle is a formula, the same second always draws the same picture and the tab's slider can jump to any of them exactly. See [Particles](Particles). | | **Text** | An asset that draws a line of text (`text`, `font`, `fontSize`, `color`, `align`) — titles, HUD readouts, button labels. Its content is an ordinary property, so a `Properties` node of type Text with `text` switched to Set changes it while playing. | | **Enabled** | Every placeable asset has the switch `enabled` (default on). A disabled object is not drawn, does not collide and its behavior does not run — **and neither does anything parented below it**. Switching one instance off is a normal override, which makes a container a *screen*: switch it on to show it, off to hide it. From a graph, `Properties` with `enabled` switched to Set does it, and `Is enabled` asks (including the parents); a behavior hears the switch as `On enable` / `On disable`. | diff --git a/Development.md b/Development.md index 588416d..266b665 100644 --- a/Development.md +++ b/Development.md @@ -15,7 +15,7 @@ npm run build # writes dist/ and regenerates index.html php tools/make-user.php [admin|user] # an account; every tool signs in (see Accounts) php tests/php/accounts.test.php # the API's account rules, no server needed (CI's gate job) php tests/php/snapshots.test.php # the snapshot store (#231), the same way -node tools/seed-e2e.mjs && node tools/e2e.mjs # 1535 editor checks, screenshots in /tmp/gm-e2e-*.png +node tools/seed-e2e.mjs && node tools/e2e.mjs # 1544 editor checks, screenshots in /tmp/gm-e2e-*.png GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step ./e2e.sh start [GM_STEPS] # the same run detached, see below ./e2e.sh status # live progress, or the last run's result diff --git a/Fonts.md b/Fonts.md index 596ef7d..ba5c01b 100644 --- a/Fonts.md +++ b/Fonts.md @@ -32,7 +32,21 @@ faces and `@font-face` cannot say which, and an SVG font can carry script. dropdown of the project's font assets, with **None** for the editor's own typeface. That is also what a reference falls back to when the asset behind it is gone, so a deleted font leaves readable text rather than nothing. The row works in the scene view, in the game preview and -while playing — all three go through one place (`WorldViewport.syncText`). +while playing — all three go through one place (`WorldViewport.syncText`, which hands the text to +`TextPicture`: glyphs rasterised into a picture of the text's own, drawn like a sprite so a shader +can be worn — see [Shaders](Shaders)). + +**Filter.** A font asset has one row, **Filter**, the same as a texture's: **Linear** (the default) +draws the glyphs smooth and renders them again, sharper, as the view zooms in. **Nearest** is for +pixel fonts: the glyphs end up at one texel per world unit and are magnified without smoothing, +so at a scale or zoom of 4 every font pixel is a block of four screen pixels. To get there they are +rasterised eight times finer and brought down again, each 8x8 block becoming one texel that is +either fully inked (half the block or more) or empty. No texel is left half covered, on any +platform — Chrome on Windows smooths canvas text sideways whatever the filter, and without this +step every glyph column there had a grey fringe. The texture stays as small as at 1:1. A pixel font +looks cleanest at the size it was drawn for (8 or 16 for most); at any other size its pixels come +out hard but unevenly wide, and a font that is no pixel font loses its thinnest strokes. Every +text wearing the font follows its filter; the text itself has no filter row. **It arrives late.** A face is fetched over the network, so a text is drawn in the fallback for the first frames and then reflows into the real one. That is the same "not yet, redraw when it diff --git a/Keyboard.md b/Keyboard.md index bbbfaa3..3106f50 100644 --- a/Keyboard.md +++ b/Keyboard.md @@ -5,7 +5,7 @@ container from the selection · `Ctrl+Enter` play, and pause/resume while playin under the pointer ([Scene editing](Scene-editing), [Behaviors](Behaviors)) · `Ctrl+V` import an image from the clipboard as a texture when nothing copied fits the tab (ignored while a text field has focus) · Animation tab: `Ctrl+C` copy the picked keys, `Ctrl+V` paste them at the playhead (while keys are copied this takes `Ctrl+V` -there, so an image is pasted from another tab), `Ctrl`+drag duplicate keys · `Tab` / `Shift+Tab` cycle fields · lists: `↑`/`↓` move, +there, so an image is pasted from another tab), `Ctrl`+drag duplicate keys · `Tab` / `Shift+Tab` cycle fields (in the Game tab with no field focused, Tab is a game key like any other, and the key field of `On key down` takes it too) · lists: `↑`/`↓` move, `←`/`→` fold, `Enter` activates · number fields: drag to scrub (`Shift` x10, `Alt` x0.1, snapping to the grid of that increment, so a step-1 field lands on whole numbers), `↑`/`↓` step, shown with at most three decimals and without trailing zeros diff --git a/Shaders.md b/Shaders.md index 2a18d2e..b5a0ae1 100644 --- a/Shaders.md +++ b/Shaders.md @@ -160,6 +160,15 @@ never there to lose. The difference is what the fragment can see — a particle' age or index — and that a source, having rows of its own graph as well, keeps a name the shader also declares: the uniform then stays on its default rather than taking the row. +**A text object wears one the same way** (#169), through a *Shader* row below Align. Its glyphs are +rasterised into a picture of their own and drawn on the sprite quad, so the graph sees exactly what a +sprite's graph sees: `Texture color` is the glyph pixel in the text's colour, `Texture alpha` the +glyph's coverage, and `u`/`v` run from 0 to 1 across the rectangle of the rendered text, line +height included. A new text, face or size is rasterised again and keeps the shader. Like a source, +a text keeps a name it already has (`text`, `fontSize`, `align` …): a shader parameter of that name +gets no row. In a `Properties` node the parameters are offered under *Type: Text* as they are under +*Type: Sprite*. A shaded text is one draw call, like a shaded sprite. + ## What it costs, and where it stops A shader runs in the sprite's own draw: the mesh is drawn once, with the graph's fragment in place