Uploads keep the name the file came with (#83)
API: name on both listings and both uploads, and what the server does to it. Textures and Fonts: tiles and rows are captioned by name, and an asset made in the picker is named after the file. Architecture: the api/ line names the libraries. Development: 780 editor checks.
1 parent
eea795fe36
commit
4619f619fa
5 files changed
+23
-8
No files matched your search
+11
-4
@@ -7,11 +7,11 @@ All routes go through `api/index.php?r=…` (the site's nginx does not pass `PAT
|
||||
| GET | `projects/{id}` | `{id,name,revision,updatedAt,project}` |
|
||||
| PUT | `projects/{id}` | `{revision, project}` → `{revision,updatedAt}` or **409** `{error,revision}` when stale |
|
||||
| DELETE | `projects/{id}` | 204 |
|
||||
| GET | `textures` | `[{file,width,height,bytes,updatedAt}]` — what the image picker offers |
|
||||
| POST | `textures` | **raw image bytes** → `{file,width,height,bytes}` (201) |
|
||||
| GET | `textures` | `[{file,name,width,height,bytes,updatedAt}]` — what the image picker offers |
|
||||
| POST | `textures&name=hero.png` | **raw image bytes** → `{file,name,width,height,bytes}` (201) |
|
||||
| DELETE | `textures/{file}` | 204 |
|
||||
| GET | `fonts` | `[{file,bytes,updatedAt}]` — what the font picker offers |
|
||||
| POST | `fonts` | **raw font bytes** → `{file,bytes}` (201) |
|
||||
| GET | `fonts` | `[{file,name,bytes,updatedAt}]` — what the font picker offers |
|
||||
| POST | `fonts&name=Serif.ttf` | **raw font bytes** → `{file,name,bytes}` (201) |
|
||||
| DELETE | `fonts/{file}` | 204 |
|
||||
|
||||
Every project document carries `formatVersion` (`PROJECT_FORMAT_VERSION` in `core/model/Project.ts`,
|
||||
@@ -25,4 +25,11 @@ files are served statically from `data/textures/` and `data/fonts/`, so reading
|
||||
PHP. An image is downscaled and re-encoded in the browser when it would not fit; a font cannot
|
||||
be, so an oversized typeface is refused rather than shrunk.
|
||||
|
||||
**`name` is the original file name**, kept beside the stored file as `{file}.json` and returned
|
||||
with it. The stored file is always `{sha256}.{ext}`, so the name is a caption and never a path:
|
||||
the server strips directories, control characters and anything not valid UTF-8, and caps it at
|
||||
120 characters. Uploading the same bytes again under a different name **renames** what the
|
||||
pickers show; an upload that carries no `name` leaves the known one alone rather than erasing it.
|
||||
A file uploaded before names were kept simply has `""`, and reads as it always did.
|
||||
|
||||
There is no authentication yet; `data/` is world-readable. Both are phase-2 topics.
|
||||
+2
-1
@@ -72,7 +72,8 @@ src/editor/animation/ AnimationEditor (header + picker), AnimationCanvas (previ
|
||||
src/editor/statemachine/ StateMachineEditor (header + picker, on the graph canvas)
|
||||
src/editor/list/ ListEditor (a row per item), slot (which list is being edited, and how it is written back)
|
||||
src/editor/console/ log (ring buffer, argument formatting, the console.* capture), ConsolePanel (the tail under the tabs)
|
||||
api/ PHP backend data/projects/ persisted projects
|
||||
api/ PHP backend: index.php (routing), lib/{Store,TextureStore,FontStore,OriginalName,Response}.php
|
||||
data/projects/ persisted projects, data/textures/ + data/fonts/ content-addressed uploads
|
||||
tests/ Vitest unit tests tools/ seed-*, e2e (steps in tools/e2e/, rig in tools/e2e/lib/), smoke-*, lib/, assets/ (the walk demo's sheet)
|
||||
```
|
||||
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs
|
||||
# code is lost (tail's is reported), so a red run reads as green
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 775 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 780 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
|
||||
@@ -151,4 +151,4 @@ widths to find click points. The **render device is not in this repo** — `/dev
|
||||
and a 1 GB `/dev/shm` come from `container.options` in the runner's own `config.yaml`, which
|
||||
applies to every job on that runner. Without them chromium falls back to llvmpipe, which gets
|
||||
WebGL 1.0 only. Measured in the job container: `ANGLE (Intel, Vulkan 1.3.230, HD Graphics 630)`,
|
||||
WebGL 2.0, and the same 775 checks as here.
|
||||
WebGL 2.0, and the same 780 checks as here.
|
||||
+2
-1
@@ -16,7 +16,8 @@ holds**, one row each. There is no thumbnail to show for a font, so each row *is
|
||||
the sample line is drawn in that very face. Picking one and pressing **Use font** makes the
|
||||
asset; **Upload…** is the way in for a face the server does not have yet. A row captioned with
|
||||
an asset name is one this project already wears, and picking it uses that asset rather than
|
||||
making a second one.
|
||||
making a second one; any other row is captioned with the name the file was uploaded under, and
|
||||
picking it names the asset after that file — `DejaVuSerif.ttf` becomes `DejaVuSerif`.
|
||||
|
||||
**Where it goes.** The bytes are uploaded to `POST ?r=fonts` and stored as
|
||||
`data/fonts/{sha256}.{ext}` — named after their own content, exactly like an image, and with
|
||||
|
||||
+6
@@ -17,6 +17,12 @@ makes a texture asset on that file; **Upload…** is the way in for a picture th
|
||||
have yet, and lands in the same import as a drop. A tile captioned with an asset name is one
|
||||
this project already wears — picking it selects that asset rather than making a second one.
|
||||
|
||||
**Tiles are captioned by name, not by hash.** A picture this project wears shows its asset name;
|
||||
any other shows the name the file was uploaded under, which the server keeps beside it (see the
|
||||
[API](API)). Picking such a file names the new asset after it — `hero-idle.png` becomes
|
||||
`hero-idle`, exactly as dropping the file would have — instead of the old `Texture 2`. Only a
|
||||
file from before names were kept still reads as its pixel size.
|
||||
|
||||
**Where it goes.** The image is uploaded as raw bytes to `POST ?r=textures` and stored as
|
||||
`data/textures/{sha256}.{ext}` — the file is named after its own content. That name buys four
|
||||
things: the same picture uploaded twice is one file, a stored file can be cached forever
|
||||
|
||||
Reference in new issue
Block a user