pixling 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pixling-0.1.0/.claude/skills/pixling/SKILL.md +80 -0
- pixling-0.1.0/.gitignore +28 -0
- pixling-0.1.0/LICENSE +21 -0
- pixling-0.1.0/PKG-INFO +105 -0
- pixling-0.1.0/README.md +85 -0
- pixling-0.1.0/docs/ARTIST.md +256 -0
- pixling-0.1.0/docs/ENVIRONMENTS.md +30 -0
- pixling-0.1.0/docs/PIPELINES.md +258 -0
- pixling-0.1.0/docs/STYLES.md +137 -0
- pixling-0.1.0/docs/WORKFLOW.md +40 -0
- pixling-0.1.0/docs/brand/README.md +65 -0
- pixling-0.1.0/docs/brand/favicon-16.png +0 -0
- pixling-0.1.0/docs/brand/favicon-32.png +0 -0
- pixling-0.1.0/docs/brand/favicon-64.png +0 -0
- pixling-0.1.0/docs/brand/fonts/DepartureMono-Regular.otf +0 -0
- pixling-0.1.0/docs/brand/fonts/DepartureMono-Regular.woff2 +0 -0
- pixling-0.1.0/docs/brand/fonts/Jersey15-OFL.txt +93 -0
- pixling-0.1.0/docs/brand/fonts/Jersey15-Regular.ttf +0 -0
- pixling-0.1.0/docs/brand/fonts/OFL.txt +93 -0
- pixling-0.1.0/docs/brand/pixling-app-icon.png +0 -0
- pixling-0.1.0/docs/brand/pixling-banner-dark.png +0 -0
- pixling-0.1.0/docs/brand/pixling-banner-dark.svg +1 -0
- pixling-0.1.0/docs/brand/pixling-banner.png +0 -0
- pixling-0.1.0/docs/brand/pixling-banner.svg +1 -0
- pixling-0.1.0/docs/brand/pixling-forge-duckling.png +0 -0
- pixling-0.1.0/docs/brand/pixling-idle.gif +0 -0
- pixling-0.1.0/docs/brand/pixling-logo-dark.png +0 -0
- pixling-0.1.0/docs/brand/pixling-logo-dark.svg +1 -0
- pixling-0.1.0/docs/brand/pixling-logo.png +0 -0
- pixling-0.1.0/docs/brand/pixling-logo.svg +1 -0
- pixling-0.1.0/docs/brand/pixling-mark-1x.png +0 -0
- pixling-0.1.0/docs/brand/pixling-mark-idle.gif +0 -0
- pixling-0.1.0/docs/brand/pixling-mark-plain.svg +1 -0
- pixling-0.1.0/docs/brand/pixling-mark.png +0 -0
- pixling-0.1.0/docs/brand/pixling-mark.svg +1 -0
- pixling-0.1.0/docs/brand/pixling-paint.gif +0 -0
- pixling-0.1.0/docs/brand/pixling-social.png +0 -0
- pixling-0.1.0/docs/brand/pixling-sprite.png +0 -0
- pixling-0.1.0/docs/brand/pixling-walk.gif +0 -0
- pixling-0.1.0/npm/README.md +12 -0
- pixling-0.1.0/painted/README.md +96 -0
- pixling-0.1.0/painted/__init__.py +2 -0
- pixling-0.1.0/painted/__main__.py +219 -0
- pixling-0.1.0/painted/bpy/assets.py +530 -0
- pixling-0.1.0/painted/bpy/hilltop.py +401 -0
- pixling-0.1.0/painted/bpy/kit.py +186 -0
- pixling-0.1.0/painted/bpy/painter.py +439 -0
- pixling-0.1.0/painted/build_game.py +125 -0
- pixling-0.1.0/painted/compose.py +108 -0
- pixling-0.1.0/painted/game.html +310 -0
- pixling-0.1.0/painted/layouts/hollow_brook.json +61 -0
- pixling-0.1.0/painted/styles/painted_cards.json +59 -0
- pixling-0.1.0/painted/textures.py +104 -0
- pixling-0.1.0/pp/__init__.py +7 -0
- pixling-0.1.0/pp/__main__.py +230 -0
- pixling-0.1.0/pp/anim.py +790 -0
- pixling-0.1.0/pp/aseprite.py +80 -0
- pixling-0.1.0/pp/blocks.py +354 -0
- pixling-0.1.0/pp/brand.py +80 -0
- pixling-0.1.0/pp/cli.py +718 -0
- pixling-0.1.0/pp/color.py +161 -0
- pixling-0.1.0/pp/detail.py +247 -0
- pixling-0.1.0/pp/flora.py +150 -0
- pixling-0.1.0/pp/forge.py +763 -0
- pixling-0.1.0/pp/inspect.py +225 -0
- pixling-0.1.0/pp/io.py +70 -0
- pixling-0.1.0/pp/iso.py +570 -0
- pixling-0.1.0/pp/iso_line.py +149 -0
- pixling-0.1.0/pp/layers.py +181 -0
- pixling-0.1.0/pp/light.py +233 -0
- pixling-0.1.0/pp/lint.py +213 -0
- pixling-0.1.0/pp/map.py +1320 -0
- pixling-0.1.0/pp/meaning.py +168 -0
- pixling-0.1.0/pp/motion.py +719 -0
- pixling-0.1.0/pp/pack.py +85 -0
- pixling-0.1.0/pp/paths.py +17 -0
- pixling-0.1.0/pp/pixcheck.py +57 -0
- pixling-0.1.0/pp/render.py +368 -0
- pixling-0.1.0/pp/review.py +87 -0
- pixling-0.1.0/pp/scenario/__init__.py +193 -0
- pixling-0.1.0/pp/scenario/auth.py +291 -0
- pixling-0.1.0/pp/scenario/mcp.py +131 -0
- pixling-0.1.0/pp/scene.py +161 -0
- pixling-0.1.0/pp/sdf.py +154 -0
- pixling-0.1.0/pp/secondary.py +78 -0
- pixling-0.1.0/pp/shade.py +348 -0
- pixling-0.1.0/pp/size.py +158 -0
- pixling-0.1.0/pp/states.py +239 -0
- pixling-0.1.0/pp/variants.py +229 -0
- pixling-0.1.0/pp/vfx.py +528 -0
- pixling-0.1.0/pyproject.toml +80 -0
- pixling-0.1.0/reel/README.md +138 -0
- pixling-0.1.0/reel/WORKFLOW.md +115 -0
- pixling-0.1.0/reel/__init__.py +0 -0
- pixling-0.1.0/reel/__main__.py +89 -0
- pixling-0.1.0/reel/chars/_template/char.json +96 -0
- pixling-0.1.0/reel/cut.py +179 -0
- pixling-0.1.0/reel/demo.py +167 -0
- pixling-0.1.0/reel/finish.py +141 -0
- pixling-0.1.0/reel/fx/black_1024.png +0 -0
- pixling-0.1.0/reel/fx/fireball_rain.json +29 -0
- pixling-0.1.0/reel/fx/necro_signet.json +24 -0
- pixling-0.1.0/reel/fx.py +137 -0
- pixling-0.1.0/reel/game.py +290 -0
- pixling-0.1.0/reel/io.py +81 -0
- pixling-0.1.0/reel/key.py +145 -0
- pixling-0.1.0/reel/keys.py +189 -0
- pixling-0.1.0/reel/pack.py +33 -0
- pixling-0.1.0/reel/page.py +130 -0
- pixling-0.1.0/reel/qc.py +249 -0
- pixling-0.1.0/reel/split.py +83 -0
- pixling-0.1.0/reel/synth.py +49 -0
- pixling-0.1.0/reel/take.py +44 -0
- pixling-0.1.0/research/motion/NOTES.md +61 -0
- pixling-0.1.0/research/reel/NOTES.md +107 -0
- pixling-0.1.0/research/reel/SCENARIO_SKILL.md +591 -0
- pixling-0.1.0/research/styles/README.md +17 -0
- pixling-0.1.0/research/styles/SHARED_LAYER.md +74 -0
- pixling-0.1.0/research/styles/img/flat_v1_v2.png +0 -0
- pixling-0.1.0/research/styles/img/marsh_compare.jpg +0 -0
- pixling-0.1.0/research/styles/img/round1_compare.jpg +0 -0
- pixling-0.1.0/research/styles/img/round3_board.jpg +0 -0
- pixling-0.1.0/research/styles/img/saffron_compare.jpg +0 -0
- pixling-0.1.0/research/styles/img/tactics_before_after_8x.png +0 -0
- pixling-0.1.0/research/styles/proto_flat_v2.md +71 -0
- pixling-0.1.0/research/styles/proto_frost_flat_v1.md +101 -0
- pixling-0.1.0/research/styles/proto_marsh.md +90 -0
- pixling-0.1.0/research/styles/proto_saffron.md +96 -0
- pixling-0.1.0/research/styles/proto_tactics_v2.md +83 -0
- pixling-0.1.0/research/styles/round1_FINDINGS.md +38 -0
- pixling-0.1.0/research/styles/round2_DNA.md +208 -0
- pixling-0.1.0/research/styles/round3_NOTES.md +38 -0
- pixling-0.1.0/site/README.md +17 -0
- pixling-0.1.0/specs/blocks/ashwyrm.json +75 -0
- pixling-0.1.0/specs/blocks/bibi.json +42 -0
- pixling-0.1.0/specs/blocks/bramblehorn.json +43 -0
- pixling-0.1.0/specs/blocks/hoot.json +62 -0
- pixling-0.1.0/specs/blocks/pip.json +47 -0
- pixling-0.1.0/specs/blocks/sludgeling.json +38 -0
- pixling-0.1.0/specs/duskborne/ashen_knight.json +1420 -0
- pixling-0.1.0/specs/duskborne/bone_grunt.json +767 -0
- pixling-0.1.0/specs/duskborne/dusk_rock.json +200 -0
- pixling-0.1.0/specs/duskborne/dusk_tree.json +424 -0
- pixling-0.1.0/specs/duskborne/grave_ghoul.json +2409 -0
- pixling-0.1.0/specs/duskborne/hollow_cultist.json +1559 -0
- pixling-0.1.0/specs/duskborne/shade_wolf.json +1234 -0
- pixling-0.1.0/specs/sunmeadow/boar.json +577 -0
- pixling-0.1.0/specs/sunmeadow/bush.json +537 -0
- pixling-0.1.0/specs/sunmeadow/bush_berry.json +577 -0
- pixling-0.1.0/specs/sunmeadow/dead_tree.json +456 -0
- pixling-0.1.0/specs/sunmeadow/deer.json +788 -0
- pixling-0.1.0/specs/sunmeadow/elder.json +803 -0
- pixling-0.1.0/specs/sunmeadow/fox.json +472 -0
- pixling-0.1.0/specs/sunmeadow/hero.json +1553 -0
- pixling-0.1.0/specs/sunmeadow/oak.json +1 -0
- pixling-0.1.0/specs/sunmeadow/oak_autumn.json +1 -0
- pixling-0.1.0/specs/sunmeadow/orc_warrior.json +852 -0
- pixling-0.1.0/specs/sunmeadow/pine.json +731 -0
- pixling-0.1.0/specs/sunmeadow/pixling.json +612 -0
- pixling-0.1.0/specs/sunmeadow/rabbit.json +403 -0
- pixling-0.1.0/specs/sunmeadow/ranger.json +1687 -0
- pixling-0.1.0/specs/sunmeadow/rock.json +155 -0
- pixling-0.1.0/specs/sunmeadow/rock_mossy.json +106 -0
- pixling-0.1.0/specs/sunmeadow/rock_small.json +107 -0
- pixling-0.1.0/specs/vermilion/antler_ward.json +579 -0
- pixling-0.1.0/specs/vermilion/cinder_imp.json +809 -0
- pixling-0.1.0/specs/vermilion/ember_brute.json +636 -0
- pixling-0.1.0/specs/vermilion/ember_tree.json +29 -0
- pixling-0.1.0/specs/vermilion/ink_stone.json +10 -0
- pixling-0.1.0/specs/vermilion/shrike_crier.json +722 -0
- pixling-0.1.0/specs/vista/chapel.json +206 -0
- pixling-0.1.0/specs/vista/fountain_small.json +109 -0
- pixling-0.1.0/specs/vista/highgate.map.json +903 -0
- pixling-0.1.0/specs/vista/highgate_hub.map.json +1829 -0
- pixling-0.1.0/specs/vista/highgate_streets.map.json +804 -0
- pixling-0.1.0/specs/vista/highgate_town.map.json +2194 -0
- pixling-0.1.0/specs/vista/house_1.json +167 -0
- pixling-0.1.0/specs/vista/house_2.json +188 -0
- pixling-0.1.0/specs/vista/house_3.json +230 -0
- pixling-0.1.0/specs/vista/house_4.json +209 -0
- pixling-0.1.0/specs/vista/house_5.json +167 -0
- pixling-0.1.0/specs/vista/house_6.json +188 -0
- pixling-0.1.0/specs/vista/house_7.json +146 -0
- pixling-0.1.0/specs/vista/house_8.json +251 -0
- pixling-0.1.0/specs/vista/keep.json +747 -0
- pixling-0.1.0/specs/vista/lighthouse.json +180 -0
- pixling-0.1.0/specs/vista/market.json +148 -0
- pixling-0.1.0/specs/vista/sailboat.json +133 -0
- pixling-0.1.0/specs/vista/streets/banner_pole_v.json +246 -0
- pixling-0.1.0/specs/vista/streets/st_arena.json +2592 -0
- pixling-0.1.0/specs/vista/streets/st_barrels.json +159 -0
- pixling-0.1.0/specs/vista/streets/st_boat.json +207 -0
- pixling-0.1.0/specs/vista/streets/st_bridge_ew.json +314 -0
- pixling-0.1.0/specs/vista/streets/st_cart.json +198 -0
- pixling-0.1.0/specs/vista/streets/st_fountain.json +290 -0
- pixling-0.1.0/specs/vista/streets/st_gate.json +521 -0
- pixling-0.1.0/specs/vista/streets/st_hall.json +976 -0
- pixling-0.1.0/specs/vista/streets/st_house_a.json +569 -0
- pixling-0.1.0/specs/vista/streets/st_house_b.json +566 -0
- pixling-0.1.0/specs/vista/streets/st_house_c.json +532 -0
- pixling-0.1.0/specs/vista/streets/st_house_d.json +511 -0
- pixling-0.1.0/specs/vista/streets/st_house_e.json +615 -0
- pixling-0.1.0/specs/vista/streets/st_house_f.json +509 -0
- pixling-0.1.0/specs/vista/streets/st_house_g.json +316 -0
- pixling-0.1.0/specs/vista/streets/st_house_h.json +730 -0
- pixling-0.1.0/specs/vista/streets/st_house_i.json +474 -0
- pixling-0.1.0/specs/vista/streets/st_house_j.json +385 -0
- pixling-0.1.0/specs/vista/streets/st_lamp.json +170 -0
- pixling-0.1.0/specs/vista/streets/st_lighthouse.json +183 -0
- pixling-0.1.0/specs/vista/streets/st_rowboat.json +190 -0
- pixling-0.1.0/specs/vista/streets/st_ship.json +378 -0
- pixling-0.1.0/specs/vista/streets/st_stall_gold.json +284 -0
- pixling-0.1.0/specs/vista/streets/st_stall_red.json +284 -0
- pixling-0.1.0/specs/vista/streets/st_stall_teal.json +284 -0
- pixling-0.1.0/specs/vista/streets/st_wall.json +271 -0
- pixling-0.1.0/specs/vista/streets/st_well.json +185 -0
- pixling-0.1.0/specs/vista/world/vale.map.json +2857 -0
- pixling-0.1.0/specs/vista/world/w_bandit_camp.json +338 -0
- pixling-0.1.0/specs/vista/world/w_banner.json +225 -0
- pixling-0.1.0/specs/vista/world/w_camp.json +220 -0
- pixling-0.1.0/specs/vista/world/w_crypt.json +324 -0
- pixling-0.1.0/specs/vista/world/w_goblin_warren.json +412 -0
- pixling-0.1.0/specs/vista/world/w_mine.json +318 -0
- pixling-0.1.0/specs/vista/world/w_portal.json +289 -0
- pixling-0.1.0/specs/vista/world/w_smuggler_cove.json +318 -0
- pixling-0.1.0/specs/vista/world/w_spire.json +350 -0
- pixling-0.1.0/specs/vista/world/w_windmill.json +247 -0
- pixling-0.1.0/specs/vista/world/w_wolf_den.json +284 -0
- pixling-0.1.0/styles/duskborne.json +453 -0
- pixling-0.1.0/styles/flat.json +94 -0
- pixling-0.1.0/styles/flat_dunes.json +94 -0
- pixling-0.1.0/styles/sunmeadow.json +519 -0
- pixling-0.1.0/styles/tactics.json +149 -0
- pixling-0.1.0/styles/tactics_autumn.json +149 -0
- pixling-0.1.0/styles/vermilion.json +215 -0
- pixling-0.1.0/styles/vista.json +329 -0
- pixling-0.1.0/tools/flat/build.py +90 -0
- pixling-0.1.0/tools/flat/kit.py +202 -0
- pixling-0.1.0/tools/flat/scenes.py +212 -0
- pixling-0.1.0/tools/make_styles.py +386 -0
- pixling-0.1.0/tools/tactics/build.py +79 -0
- pixling-0.1.0/tools/tactics/kit.py +354 -0
- pixling-0.1.0/tools/tactics/scenes.py +343 -0
- pixling-0.1.0/tools/vista/aerial.py +64 -0
- pixling-0.1.0/tools/vista/build.py +39 -0
- pixling-0.1.0/tools/vista/layout_hub.py +121 -0
- pixling-0.1.0/tools/vista/layout_streets.py +70 -0
- pixling-0.1.0/tools/vista/layout_town.py +130 -0
- pixling-0.1.0/tools/vista/layout_vale.py +124 -0
- pixling-0.1.0/tools/vista/slib.py +58 -0
- pixling-0.1.0/tools/vista/streets.py +179 -0
- pixling-0.1.0/tools/vista/vlib.py +50 -0
- pixling-0.1.0/tools/vista/world.py +116 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixling
|
|
3
|
+
description: Make game art with code using pixling (the Pixel Perfect forge), a catalogue of pipelines, styles and taste notes. Pipelines: JSON spec -> 8-direction pixel sprites; exact-iso scenes from Python kits; living maps with states, hour light and a meaning layer; VFX sheets; AI image -> video -> keyed sprite frames (Scenario + reel); Blender -> painterly sprites. Each style ships with how it was made (hand, kit code, lab notes), so you can reuse it or build a new one. Use when asked for sprites, characters, creatures, trees, buildings, spell effects, a town or world map, an iso scene, a new art style, an itch.io pack, or AI image/video generation through Scenario.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pixel Perfect (`pixling`)
|
|
7
|
+
|
|
8
|
+
You are the artist. You never paint pixels: you pick a pipeline, drive it with code (a JSON spec, a Python kit, a
|
|
9
|
+
Blender layout, video takes), and judge the images by eye. pixling is a catalogue. Run the pipelines as they are, or
|
|
10
|
+
read how they and the styles were made and take what helps into the user's own project. Run `pixling` for every command.
|
|
11
|
+
|
|
12
|
+
## Pick a pipeline
|
|
13
|
+
- `pixling pipelines`: spec (sprites), iso (exact-iso scenes), map (living maps), fx, video (image -> video ->
|
|
14
|
+
frames), painted (Blender), style (a new style from scratch). `pixling pipelines NAME` gives the steps, the code
|
|
15
|
+
and what we learned.
|
|
16
|
+
- `pixling styles NAME --how`: how a launch style (vista, tactics, flat) was made: hand, kit, code, lab notes.
|
|
17
|
+
`pixling code tactics.kit` prints a kit module and its path, so you can read it whole or copy it.
|
|
18
|
+
- `pixling guide styles "The shared taste layer"`: the rules every style keeps. Apply them to your own work too.
|
|
19
|
+
|
|
20
|
+
## Before the first asset (spec pipeline)
|
|
21
|
+
- `pixling doctor`: dependencies. If `pixling` is missing, use `python3 -m pp` from the Pixel Perfect repo.
|
|
22
|
+
- `pixling guide artist "The loop"` and `pixling guide artist "Spec format"`: how specs work. `pixling guide` lists every doc;
|
|
23
|
+
`pixling guide --grep WORD` searches them.
|
|
24
|
+
- `pixling styles` lists the styles; `pixling styles NAME` shows materials and ramps. Use the style's materials; never invent colours.
|
|
25
|
+
- `pixling specs STYLE`: copy the closest example spec and change it. Don't start from a blank file.
|
|
26
|
+
|
|
27
|
+
## The loop (minutes per asset)
|
|
28
|
+
```
|
|
29
|
+
pixling build SPEC --clips idle --dirs S,E # fast: only what you're judging
|
|
30
|
+
pixling review out/NAME --clips idle --dirs S,E # look at the PNG it prints
|
|
31
|
+
# fix the spec, rebuild, look again; then the full build:
|
|
32
|
+
pixling build SPEC
|
|
33
|
+
pixling scene out/NAME out/oak --style STYLE # next to its family and a tree, at game scale
|
|
34
|
+
pixling lint out/NAME # hints, not gates
|
|
35
|
+
```
|
|
36
|
+
Use `--out DIR` on build to write into your own project. `pixling inspect SPEC` shows what's under the pixels
|
|
37
|
+
(bone/material maps); `pixling variants SPEC --vary key=a,b,c` builds versions side by side, and `--apply N` keeps one.
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
- Judge by looking at the images (your image-reading tool), at 1x in `scene` and animated. No measurement essays.
|
|
41
|
+
- Big shapes first, details last. Prototype ONE asset, get the user's sign-off, then make the family.
|
|
42
|
+
- Done: it reads at 1x next to its family, all 8 directions are the same character, the attack reads, nothing
|
|
43
|
+
swims in idle, and you can explain every lint WARN in one sentence.
|
|
44
|
+
- If the engine can't do something, say what's missing. Don't work around it with dozens of micro-parts.
|
|
45
|
+
|
|
46
|
+
## Iso scenes (Crisp Tactics, Flat Minimal)
|
|
47
|
+
`pixling world tactics|flat [--only SCENE]` builds a style's scenes and animal sheets with its kit. For new scenes,
|
|
48
|
+
copy `tools/<style>/scenes.py` (path from `pixling code tactics.scenes`) and render with `pp.iso`; `pixling pipelines iso`.
|
|
49
|
+
|
|
50
|
+
## Board pieces (units, creatures on an iso board)
|
|
51
|
+
`pixling pipelines blocks`. Build them as block tokens (`pixling blocks`): a few chunky voxels (3 x 3 footprint, 2-4
|
|
52
|
+
layers, ~12 px: a third of a tile) in the board's exact iso, face light and cast shadow, facings by rotation. Not
|
|
53
|
+
side-view sprites, not 3D-rendered animals. Keep them small and pull the camera back rather than growing them. Judge
|
|
54
|
+
them standing in the real scene (`--on SCREENSHOT_1x.png`), and never restyle the environment to fix the pieces.
|
|
55
|
+
|
|
56
|
+
## Maps, states, light, VFX, packs
|
|
57
|
+
`pixling guide environments` and `pixling guide artist "Maps (pp.map)"`. Commands: `pixling map MAP.json --still`,
|
|
58
|
+
`pixling states SPEC`, `pixling light MAP.json --gif`, `pixling fx KIND --style S`, `pixling pack NAME DIRS --style S`.
|
|
59
|
+
|
|
60
|
+
## Scenario (AI images, video, 3D, audio)
|
|
61
|
+
- Run `pixling scenario status`. If signed out, ask the user to run `! pixling scenario login` (it opens a browser; use
|
|
62
|
+
`--device` for a code to type on another device). Sign-in is once per machine; tokens refresh themselves.
|
|
63
|
+
- Discover models with `pixling scenario call recommend '{"query": "..."}'` or `pixling scenario call models_list '{"query": "..."}'`.
|
|
64
|
+
`pixling scenario tools` lists every tool, and `pixling scenario schema TOOL` shows its inputs.
|
|
65
|
+
- Before a run: `pixling scenario call model_schema_get '{"model_id": "M"}'`, then `pixling scenario cost M '{...}'`.
|
|
66
|
+
Tell the user the cost in CU and ask before spending beyond their budget.
|
|
67
|
+
- `pixling scenario run M '{...model inputs...}' --out file.png` waits for the job and downloads the outputs.
|
|
68
|
+
File inputs are asset ids: `pixling scenario upload FILE`.
|
|
69
|
+
- Video for sprites: `pixling guide reel-workflow`. Use MiniMax H3 only.
|
|
70
|
+
|
|
71
|
+
## Painted format (not pixel art)
|
|
72
|
+
When the user wants a painterly look instead of pixels: `pixling guide painted`. Needs Blender (`pixling painted doctor`).
|
|
73
|
+
`pixling painted kit` renders a style + layout as sprites (shadow layers, sway loops, 8 headings) into
|
|
74
|
+
out/painted/<layout>/kit; `compose` lays the scene out from them; `game` packs a walkable web scene. Look at
|
|
75
|
+
`scene/kit_sheet.png` and `scene/scene.png` before showing anything. New assets are builders in painted/bpy/assets.py,
|
|
76
|
+
new colours are ramps in painted/styles/*.json, places are painted/layouts/*.json. Never mix pixel and painted sprites in one scene.
|
|
77
|
+
|
|
78
|
+
## Reading the engine
|
|
79
|
+
`pixling code` lists the modules and `pixling code forge` shows one module's functions with their docstrings. Read the
|
|
80
|
+
source only when you need it.
|
pixling-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
out/
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.mp4
|
|
5
|
+
*.zip
|
|
6
|
+
*.aseprite
|
|
7
|
+
research/**/_*/
|
|
8
|
+
packs/
|
|
9
|
+
viewer/
|
|
10
|
+
|
|
11
|
+
# local clutter
|
|
12
|
+
.DS_Store
|
|
13
|
+
.claude/*
|
|
14
|
+
!.claude/skills/
|
|
15
|
+
.env
|
|
16
|
+
# parked experiments kept local only: the toon/cutout/Blender study
|
|
17
|
+
research/toon/
|
|
18
|
+
# reel: big facing sheets stay local (the committed ref/start_<facing>.png are cut from them)
|
|
19
|
+
reel/chars/*/ref/sheet*.png
|
|
20
|
+
|
|
21
|
+
# local reference media
|
|
22
|
+
references/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
dist/
|
|
25
|
+
build/
|
|
26
|
+
|
|
27
|
+
# private/: secrets never get committed (keep them in a password manager)
|
|
28
|
+
private/secrets/
|
pixling-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Trinity Labs Pte. Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pixling-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pixling
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The pixel artist for your coding agent: pipelines, styles and taste for making game sprites with code
|
|
5
|
+
Project-URL: Homepage, https://pixling.dev
|
|
6
|
+
Project-URL: Repository, https://github.com/trinity-works/pixling
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: agents,claude-code,cli,codex,gamedev,pixel-art,procedural,sprites
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Games/Entertainment
|
|
14
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Requires-Dist: numpy>=1.24
|
|
17
|
+
Requires-Dist: pillow>=10.0
|
|
18
|
+
Requires-Dist: scipy>=1.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<picture>
|
|
23
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/brand/pixling-banner-dark.png">
|
|
24
|
+
<img src="docs/brand/pixling-banner.png" alt="pixling" width="560">
|
|
25
|
+
</picture>
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
<p align="center">
|
|
29
|
+
<b>The pixel artist for your coding agent.</b><br>
|
|
30
|
+
Pipelines, styles and taste for making game sprites with code. Works with Claude Code, Codex and Cursor.<br>
|
|
31
|
+
<a href="https://pixling.dev">pixling.dev</a>
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<p align="center">
|
|
35
|
+
<img src="docs/img/tactics_valley.gif" alt="A Crisp Tactics valley rendered by pixling" width="720">
|
|
36
|
+
</p>
|
|
37
|
+
|
|
38
|
+
Coding agents can write your game, but they can't draw. pixling gives them pipelines that render real pixel art from
|
|
39
|
+
code, curated styles that ship with how they were made, and the taste rules behind them. The agent writes a spec,
|
|
40
|
+
builds it, looks at the result and iterates, the way it does with a failing test.
|
|
41
|
+
|
|
42
|
+
## Install
|
|
43
|
+
```bash
|
|
44
|
+
uv tool install pixling # or: pipx install pixling · or: npx pixling
|
|
45
|
+
pixling agent install . # in your game repo: adds the skill and an AGENTS.md block
|
|
46
|
+
```
|
|
47
|
+
Then ask your agent:
|
|
48
|
+
|
|
49
|
+
> make a harbour town in the vista style, with lamps that light up at dusk, into assets/maps
|
|
50
|
+
|
|
51
|
+
## Quickstart
|
|
52
|
+
```bash
|
|
53
|
+
pixling new house_5 inn # start a spec from an example -> specs/inn.json
|
|
54
|
+
pixling build specs/inn.json # -> out/inn/: sprite sheets, GIFs, JSON
|
|
55
|
+
pixling review out/inn # a zoomed sheet to judge by eye
|
|
56
|
+
pixling # every command; each takes -h, the ones agents parse take --json
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Pipelines
|
|
60
|
+
| Pipeline | Makes |
|
|
61
|
+
|---|---|
|
|
62
|
+
| **spec** | 8-direction sprites, props and buildings from a JSON spec, byte-for-byte reproducible |
|
|
63
|
+
| **blocks** | small iso units and creatures from a few voxel layers, in your board's projection, light and shadow |
|
|
64
|
+
| **iso** | exact 2:1 isometric scenes and animal sheets from a Python kit |
|
|
65
|
+
| **map** | living maps: building states, hour-of-day lighting, a meaning layer, engine layers |
|
|
66
|
+
| **fx** | VFX sheets posterised to a style's palette |
|
|
67
|
+
| **video** | sprites cut from AI video into 8-direction sheets (via [Scenario](https://scenario.com), optional) |
|
|
68
|
+
| **painted** | painterly, non-pixel sprites and scenes rendered in Blender |
|
|
69
|
+
| **style** | a new art style from scratch: refs, hand, kit, review |
|
|
70
|
+
|
|
71
|
+
`pixling pipelines NAME` shows each one's steps, code and lessons. Output is engine-ready: sheets, GIFs, JSON metadata,
|
|
72
|
+
`.aseprite` files, and for maps collision, depth and light layers.
|
|
73
|
+
|
|
74
|
+
## Styles
|
|
75
|
+
Three launch styles, each with its own hand (camera, shading, line, shadows) and kit. `pixling styles NAME --how`
|
|
76
|
+
shows how each was made.
|
|
77
|
+
|
|
78
|
+
| **Vista** | **Crisp Tactics** | **Flat Minimal** |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| <img src="docs/img/highgate_town.gif" alt="Vista town" width="260"> | <img src="docs/img/tactics_valley.gif" alt="Crisp Tactics valley" width="260"> | <img src="docs/img/flat_dunes.png" alt="Flat Minimal island" width="260"> |
|
|
81
|
+
| painted aerial towns and world maps | exact isometric, flat faces, soft line | exact isometric, two hues, long flat shadows |
|
|
82
|
+
|
|
83
|
+
Everything above is rendered by the engine. Units and creatures for these boards are block tokens
|
|
84
|
+
(`pixling blocks`): a few voxels in the board's own iso, light and shadow.
|
|
85
|
+
|
|
86
|
+
## Docs
|
|
87
|
+
- [docs/PIPELINES.md](docs/PIPELINES.md): every pipeline, step by step
|
|
88
|
+
- [docs/ARTIST.md](docs/ARTIST.md): the spec format and design rules
|
|
89
|
+
- [docs/STYLES.md](docs/STYLES.md): the styles and how a new one is made
|
|
90
|
+
- [docs/ENVIRONMENTS.md](docs/ENVIRONMENTS.md): living maps
|
|
91
|
+
|
|
92
|
+
The same docs are built into the CLI: `pixling guide`.
|
|
93
|
+
|
|
94
|
+
## Develop
|
|
95
|
+
```bash
|
|
96
|
+
git clone https://github.com/trinity-works/pixling && cd pixling
|
|
97
|
+
pip install -e .
|
|
98
|
+
python3 -m unittest discover -s tests # the video tests need ffmpeg
|
|
99
|
+
```
|
|
100
|
+
Rules for agents working on the engine are in [AGENTS.md](AGENTS.md). Issues and pull requests are welcome.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
[MIT](LICENSE). Fonts in `docs/brand/fonts` and `site/fonts` are under the SIL Open Font License: wordmark in
|
|
104
|
+
[Jersey 15](https://github.com/scfried/soft-type-jersey) by the Soft Type Project, tagline in
|
|
105
|
+
[Departure Mono](https://departuremono.com) by Helena Zhang, site in Geist.
|
pixling-0.1.0/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/brand/pixling-banner-dark.png">
|
|
4
|
+
<img src="docs/brand/pixling-banner.png" alt="pixling" width="560">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<b>The pixel artist for your coding agent.</b><br>
|
|
10
|
+
Pipelines, styles and taste for making game sprites with code. Works with Claude Code, Codex and Cursor.<br>
|
|
11
|
+
<a href="https://pixling.dev">pixling.dev</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="docs/img/tactics_valley.gif" alt="A Crisp Tactics valley rendered by pixling" width="720">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
Coding agents can write your game, but they can't draw. pixling gives them pipelines that render real pixel art from
|
|
19
|
+
code, curated styles that ship with how they were made, and the taste rules behind them. The agent writes a spec,
|
|
20
|
+
builds it, looks at the result and iterates, the way it does with a failing test.
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
```bash
|
|
24
|
+
uv tool install pixling # or: pipx install pixling · or: npx pixling
|
|
25
|
+
pixling agent install . # in your game repo: adds the skill and an AGENTS.md block
|
|
26
|
+
```
|
|
27
|
+
Then ask your agent:
|
|
28
|
+
|
|
29
|
+
> make a harbour town in the vista style, with lamps that light up at dusk, into assets/maps
|
|
30
|
+
|
|
31
|
+
## Quickstart
|
|
32
|
+
```bash
|
|
33
|
+
pixling new house_5 inn # start a spec from an example -> specs/inn.json
|
|
34
|
+
pixling build specs/inn.json # -> out/inn/: sprite sheets, GIFs, JSON
|
|
35
|
+
pixling review out/inn # a zoomed sheet to judge by eye
|
|
36
|
+
pixling # every command; each takes -h, the ones agents parse take --json
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Pipelines
|
|
40
|
+
| Pipeline | Makes |
|
|
41
|
+
|---|---|
|
|
42
|
+
| **spec** | 8-direction sprites, props and buildings from a JSON spec, byte-for-byte reproducible |
|
|
43
|
+
| **blocks** | small iso units and creatures from a few voxel layers, in your board's projection, light and shadow |
|
|
44
|
+
| **iso** | exact 2:1 isometric scenes and animal sheets from a Python kit |
|
|
45
|
+
| **map** | living maps: building states, hour-of-day lighting, a meaning layer, engine layers |
|
|
46
|
+
| **fx** | VFX sheets posterised to a style's palette |
|
|
47
|
+
| **video** | sprites cut from AI video into 8-direction sheets (via [Scenario](https://scenario.com), optional) |
|
|
48
|
+
| **painted** | painterly, non-pixel sprites and scenes rendered in Blender |
|
|
49
|
+
| **style** | a new art style from scratch: refs, hand, kit, review |
|
|
50
|
+
|
|
51
|
+
`pixling pipelines NAME` shows each one's steps, code and lessons. Output is engine-ready: sheets, GIFs, JSON metadata,
|
|
52
|
+
`.aseprite` files, and for maps collision, depth and light layers.
|
|
53
|
+
|
|
54
|
+
## Styles
|
|
55
|
+
Three launch styles, each with its own hand (camera, shading, line, shadows) and kit. `pixling styles NAME --how`
|
|
56
|
+
shows how each was made.
|
|
57
|
+
|
|
58
|
+
| **Vista** | **Crisp Tactics** | **Flat Minimal** |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| <img src="docs/img/highgate_town.gif" alt="Vista town" width="260"> | <img src="docs/img/tactics_valley.gif" alt="Crisp Tactics valley" width="260"> | <img src="docs/img/flat_dunes.png" alt="Flat Minimal island" width="260"> |
|
|
61
|
+
| painted aerial towns and world maps | exact isometric, flat faces, soft line | exact isometric, two hues, long flat shadows |
|
|
62
|
+
|
|
63
|
+
Everything above is rendered by the engine. Units and creatures for these boards are block tokens
|
|
64
|
+
(`pixling blocks`): a few voxels in the board's own iso, light and shadow.
|
|
65
|
+
|
|
66
|
+
## Docs
|
|
67
|
+
- [docs/PIPELINES.md](docs/PIPELINES.md): every pipeline, step by step
|
|
68
|
+
- [docs/ARTIST.md](docs/ARTIST.md): the spec format and design rules
|
|
69
|
+
- [docs/STYLES.md](docs/STYLES.md): the styles and how a new one is made
|
|
70
|
+
- [docs/ENVIRONMENTS.md](docs/ENVIRONMENTS.md): living maps
|
|
71
|
+
|
|
72
|
+
The same docs are built into the CLI: `pixling guide`.
|
|
73
|
+
|
|
74
|
+
## Develop
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/trinity-works/pixling && cd pixling
|
|
77
|
+
pip install -e .
|
|
78
|
+
python3 -m unittest discover -s tests # the video tests need ffmpeg
|
|
79
|
+
```
|
|
80
|
+
Rules for agents working on the engine are in [AGENTS.md](AGENTS.md). Issues and pull requests are welcome.
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
[MIT](LICENSE). Fonts in `docs/brand/fonts` and `site/fonts` are under the SIL Open Font License: wordmark in
|
|
84
|
+
[Jersey 15](https://github.com/scfried/soft-type-jersey) by the Soft Type Project, tagline in
|
|
85
|
+
[Departure Mono](https://departuremono.com) by Helena Zhang, site in Geist.
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# ARTIST.md — how to make sprites with Pixel Perfect
|
|
2
|
+
|
|
3
|
+
You are the artist. You never paint pixels by hand. You **design** (concept, silhouette, proportions,
|
|
4
|
+
materials, motion feel) by writing a JSON spec, and the forge renders it into palette-locked,
|
|
5
|
+
8-direction, pixel-stable sprite sheets. Then you **look** at the result, judge it like an art
|
|
6
|
+
director, and iterate. Target quality: sellable itch.io packs next to the best hand-made ones.
|
|
7
|
+
The launch styles, how a new style is made and the taste rules every style keeps: [docs/STYLES.md](STYLES.md).
|
|
8
|
+
|
|
9
|
+
## The loop
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
python3 -m pp build specs/<style>/<name>.json # -> out/<name>/ (sheets, gifs, json, contact.png)
|
|
13
|
+
python3 -m pp review out/<name> --clips idle,attack --dirs S,E,N --scale 5 # zoomed grid on the style's bg (--bg to override)
|
|
14
|
+
python3 -m pp scene out/<a> out/<b> out/oak --style <style> # side by side on the ground at game scale
|
|
15
|
+
python3 -m pp lint out/<a> out/<b> ... # short numeric hints + family silhouette overlap
|
|
16
|
+
python3 -m pp silhouettes out/<a> out/<b> ... # white-fill silhouette row (design check)
|
|
17
|
+
python3 -m pp inspect specs/<style>/<name>.json --clip attack --dir E --frame 7 # what's under the pixels (below)
|
|
18
|
+
python3 -m pp variants specs/<style>/<name>.json --vary anim.drag=0.6,1,1.5 --clips attack --dirs E # pick by eye
|
|
19
|
+
```
|
|
20
|
+
Fast iteration: `--clips idle --dirs S,E` renders only what you're judging (seconds).
|
|
21
|
+
Look at images with your image-reading tool. **Judge by eye first; lints are hints, not gates.**
|
|
22
|
+
Don't write measurement reports. One look, one fix, rebuild.
|
|
23
|
+
|
|
24
|
+
## Design process
|
|
25
|
+
1. **Theme + family first.** A family shares palette, materials, eye/nose treatment, proportions.
|
|
26
|
+
Members differ by **one big defining feature** each (huge sword, slingshot, lantern, antlers, shield).
|
|
27
|
+
2. **Silhouette first.** Build the big shapes only (1-3 parts per bone), check `pp silhouettes`.
|
|
28
|
+
Silhouettes in a family must read apart (IoU < 0.75). Exaggerate: big weapons, big heads, odd shapes.
|
|
29
|
+
3. **Readability = gameplay.** Big = tanky/slow, small = quick, spiky = dangerous, round = friendly.
|
|
30
|
+
4. **2-3 shades per part is plenty.** Tiny parts (hands, feet, ears) get 1-2 materials max.
|
|
31
|
+
5. **Details last**: eyes, belt, trim, glow accents. One glowing accent per character (eyes, rune, lantern).
|
|
32
|
+
6. **Zoom out.** Always check the `scene` view at 3-4x, not only the 5x review.
|
|
33
|
+
7. **Attack first.** If the attack looks bad, the design is wrong — fix the design, not the animation.
|
|
34
|
+
|
|
35
|
+
## Targets
|
|
36
|
+
- Humanoid **22-30 px** tall (hero ~26), boss 34-60, critters 8-14, quadrupeds 16-24 tall.
|
|
37
|
+
- Head **0.40-0.50** of height (chibi), or deliberately the opposite ("small head, big body" brutes).
|
|
38
|
+
- **8-20 colours** per sprite. No #000 / #fff. No semi-transparency (the forge guarantees this).
|
|
39
|
+
- No black outline: edges keep their fill, darken on the shadow side, rim-light on the light side (automatic).
|
|
40
|
+
- Separate touching parts by value (ΔL ≥ 0.08): don't put two mid-grey materials next to each other.
|
|
41
|
+
- Timing is automatic: one 75 ms frame; idle 8, walk 8, run 8, attack 13 (4 anticipation / 3 raise / 1 smear / 5 recovery),
|
|
42
|
+
hit 2 (recoil + flash), death 14, cast 12.
|
|
43
|
+
|
|
44
|
+
## Spec format
|
|
45
|
+
|
|
46
|
+
```jsonc
|
|
47
|
+
{
|
|
48
|
+
"name": "ashen_knight", "style": "duskborne", "rig": "humanoid", // or "quadruped", "prop"
|
|
49
|
+
"concept": "one line: who, role, defining feature",
|
|
50
|
+
"frame": [48, 48], "anchor": [24, 40], // canvas and the feet pixel. Leave room for smears (~2x body)
|
|
51
|
+
"shadow": {"w": 13, "h": 3}, // ground contact ellipse, never wider than the body+2
|
|
52
|
+
"smear": {"color": "#ebede9", "edge": "#6ff0f0", "radius": 13, "width": 6, "height": 8}, // weapon arc
|
|
53
|
+
"fx": {"ramp": "glow_pink", "hand_h": 14, "reach": 6}, // cast charge/burst colour + where hands are
|
|
54
|
+
"anim": {"props": ["scarf_tail"], "prop_swing": 8, "attack_lunge": 3, "idle_bob": 2, "run_bounce": 0.5,
|
|
55
|
+
"raise_weapon_rot": [45, 70, 0]}, // turn a small weapon toward the camera during the wind-up
|
|
56
|
+
"materials": {"my_mat": {"ramp": "cloth_red", "shades": [0, 1, 2, 3]}}, // optional extra materials
|
|
57
|
+
"clips": ["idle", "walk", "run", "attack", "hit", "death"], // optional subset
|
|
58
|
+
"bones": [ { "name": "root" },
|
|
59
|
+
{ "name": "hips", "parent": "root", "at": [0, 0, 6], "parts": [ ...primitives... ] },
|
|
60
|
+
... ]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
Units are **pixels**. Axes: **x right, y away from the viewer (character faces −y = south), z up**.
|
|
64
|
+
Feet are at z = 0. `at` on a bone = its joint position in the parent's space (rotation pivot).
|
|
65
|
+
|
|
66
|
+
**Primitives** (in the bone's local space): every part has `shape`, `mat`, optional `at`, `rot` [deg x,y,z], `blend` (smooth-merge radius).
|
|
67
|
+
- `ellipsoid`/`sphere` `r` (number or [rx, ry, rz]) — heads, bodies, clumps
|
|
68
|
+
- `capsule` `a`, `b`, `r1`, `r2` — limbs, tails, horns, branches (tapers)
|
|
69
|
+
- `box` `half` [hx, hy, hz], `round` — blades, belts, visors, armour plates
|
|
70
|
+
- `cylinder` `r`, `h` (half height), `round`; `cone` `r`, `h` (apex at +z; add `"flat": true` or `"r_top"` for a
|
|
71
|
+
flat-based cone / frustum — robes, hats, skirts, tree tiers) — hats, ears, spikes; `torus` `R`, `r` (flat ring) — collars, scarves
|
|
72
|
+
- `roof` `half` [hx, hy], `h` (ridge height), `gable` (bool): a pitched roof on a flat base; hip roof (pyramid on a square), or vertical gable ends.
|
|
73
|
+
- `"subtract": true` carves the part out of the bone.
|
|
74
|
+
- `stamp` — exact hand-placed pixels pinned to the bone (faces, teeth, glints, runes, buttons). Not 3D:
|
|
75
|
+
`{"shape": "stamp", "at": [x,y,z], "normal": [0,-1,0], "rows": ["a.a", ".b."], "key": {"a": "pupil", "b": "bone:3"}}`
|
|
76
|
+
Drawn centred on the projected point when the normal faces the viewer (`min_facing`, default 0.2) and not behind a
|
|
77
|
+
nearer part. `.` = transparent. Key values are `material` (its brightest shade) or `material:shade`. For 3/4 views give
|
|
78
|
+
each eye its own stamp with a normal tilted outward (e.g. [-0.5,-1,0] / [0.5,-1,0]) so the far eye hides by itself.
|
|
79
|
+
For profile views lower `min_facing` (e.g. 0.05) and add `"clamp": 2` so a stamp that lands just outside the
|
|
80
|
+
silhouette slides inward onto the head instead of vanishing.
|
|
81
|
+
- `stamp_row` — a row of stamps along a wall (windows, a door), laid out on the face as drawn instead of as separate
|
|
82
|
+
3D points: `{"shape": "stamp_row", "normal": [0,-1,0], "at": [0,0,z], "count": 6, "rows": ["a"], "key": {"a": "window"}}`
|
|
83
|
+
One whole-pixel pitch between `margin` px (default 1) from the face's edges; windows are dropped rather than packed
|
|
84
|
+
closer than `min_pitch` (3); each sits z px above the face's drawn bottom edge in its own column, so a row runs
|
|
85
|
+
parallel to that edge and floors line up in columns. Skips pixels off the face (under an eave) and keeps
|
|
86
|
+
`keep_clear` px (1) from earlier rows: put the door first. `tools/vista/vlib.facade` writes these.
|
|
87
|
+
|
|
88
|
+
**Pixel-scale modelling rules**
|
|
89
|
+
- Nothing thinner than **1.2 px radius** (it disappears or flickers between frames). Eyes: r ≥ 0.6 and push them 0.3-0.6 px *out of* the face surface.
|
|
90
|
+
- Each bone is a rigid layer: **it keeps identical pixels while it only moves** — that's the anti-swim guarantee.
|
|
91
|
+
So put things that should move together on one bone, and parts that should overlap with a visible seam on different bones
|
|
92
|
+
(the forge draws a dark inner line where a nearer bone overlaps a farther one).
|
|
93
|
+
- Front details face **−y**. Put the lit side's interest on the upper-left (light comes from the upper left, front).
|
|
94
|
+
- Weapons: a `sword`/`weapon` bone parented to `armR` at the hand. It is auto-hidden on the smear frame.
|
|
95
|
+
- bone `"hidden": true` — only drawn on frames that list it in `"show": ["arrow"]` (custom clip frames): arrows,
|
|
96
|
+
thrown knives, spell orbs. A `sweep` on a bone that moves along its own axis (a loosed arrow, a thrust: pose the
|
|
97
|
+
bone's `at` far ahead on the release frame) draws a straight comet streak instead of an arc.
|
|
98
|
+
- spec `"strings"`: 1 px lines between bone points (bowstrings, ropes, chains), hidden behind nearer parts:
|
|
99
|
+
`[{"name": "bowstring", "points": [["bow", [0,1.5,10]], ["bow", [0,1.5,-10]]], "pull": ["foreR", [0,0,-3.3]],
|
|
100
|
+
"mat": "shirt:3"}]`. Frames that `"show"` the string's name bend it through `pull` (a drawn bow).
|
|
101
|
+
- Archer draw (specs/sunmeadow/ranger.json): body side-on (hips rz ~70), bow arm aimed straight at the target,
|
|
102
|
+
bow `aim` [0,1,0] + `roll` -90 (upright), draw shoulder pulled in (`armR.at`), elbow high, hand at the cheek.
|
|
103
|
+
|
|
104
|
+
**Bone & spec options (engine v2)**
|
|
105
|
+
- bone `"seam": true` — always draw a dark seam + contact shadow where this bone overlaps another (tiers, plates, layered cloth).
|
|
106
|
+
- bone `"z_bias": -2` — pull a bone toward the viewer in depth sorting (e.g. a small weapon that hides behind a big hat).
|
|
107
|
+
- material `"sky": 0.3` / `"sky_obj": 0.2` — tops of each part / of the whole object lighter, undersides darker
|
|
108
|
+
(crowns, bushes, fur backs). `"bias"` shifts all light; `"thresholds"` sets shade bands per material.
|
|
109
|
+
- spec `"view": {"yaw": {"S": 14, "N": 14}, "widen": {"S": 1.15, "N": 1.15}}` — cheat front/back views like pixel
|
|
110
|
+
artists do: turn a few degrees to show the body side, and widen on screen so long animals don't become columns.
|
|
111
|
+
- flora params: `tree_round` trunk_frac, trunk_r; `tree_pine` tips, droop; `bush` berry_r.
|
|
112
|
+
|
|
113
|
+
**Detail materials** (the fix for "too round"): add to a material
|
|
114
|
+
`"detail": {"kind": "fur|feather|cloth|plate|scale|leaf|bark|stone|hide", "scale": 1.0, "amount": 1.0}` for a surface
|
|
115
|
+
pattern (fur strands, feather scallops, cloth folds, plate seams with rivet glints, leaf clusters, bark and stone cracks,
|
|
116
|
+
hide wrinkles) and `"edge": {"kind": "fur|feather|leaf", "amount": 0.35}` for a broken silhouette (tufts, notches).
|
|
117
|
+
Patterns are painted in the part's own space, so they stick to it and stay pixel-stable while it moves. The duskborne,
|
|
118
|
+
sunmeadow style materials already carry sensible defaults; set `"detail": null` in a spec material to turn one off.
|
|
119
|
+
Optional carved shading: spec `"shading": {"facets": 14 | 26, "crease": 0.35}` (flat planes + crease lines).
|
|
120
|
+
|
|
121
|
+
**Rigs & required bone names**
|
|
122
|
+
- `humanoid`: `root > hips > torso > head`, `torso > armL, armR`, `hips > legL, legR`. Optional anything else (props list swings 2x).
|
|
123
|
+
Arms hang along −z from the shoulder; legs along −z from the hip.
|
|
124
|
+
Optional elbows: `foreL`/`foreR` bones parented to `armL`/`armR` at the elbow (hand + weapon go on the fore bone);
|
|
125
|
+
the built-in clips bend them automatically.
|
|
126
|
+
- `quadruped`: `root > body > head (> jaw, ears)`, `body > legFL, legFR, legHL, legHR, tail`. Body length along y (head at −y).
|
|
127
|
+
Clips: idle, walk, run, attack (leap-bite), hit, death.
|
|
128
|
+
- `prop`: use `"generator": "tree_round" | "tree_pine" | "bush" | "rock" | "dead_tree"` with `"params"` (see pp/flora.py),
|
|
129
|
+
or write bones yourself with `"rig": "prop"` and `"directions": ["S"]`.
|
|
130
|
+
|
|
131
|
+
**Smear options** (spec `smear` or per fx event): `"plane": "h"` (horizontal sweep) or `"v"` (overhead chop),
|
|
132
|
+
`"tilt"` degrees (diagonal), `"side"` lateral offset of a vertical arc, `"forward"` push the arc centre forward, per-event `a0`/`a1`/`thick` to shape the arc.
|
|
133
|
+
|
|
134
|
+
**In-sprite VFX**: any standalone effect can play inside a clip, one effect frame per sprite frame:
|
|
135
|
+
`{"kind": "vfx", "effect": "shockwave", "frame": 2, "at": "front|hand|feet|centre|above", "offset": [dx, dy],
|
|
136
|
+
"ramp": "stone", "params": {...}, "pivot_y": 0.6, "behind": true}` (behind = drawn under the body).
|
|
137
|
+
|
|
138
|
+
**Custom clips**: `"custom_clips": {"name": {"loop": false, "frames": [{"pose": {"armR": {"rot": [-90,0,0]}}, "hold": 2,
|
|
139
|
+
"squash": [1.1, 0.8], "root": [0,-2,0], "fx": [{"kind": "smear", "arc": "wide"}], "hide": ["sword"], "flash": false}]}}`
|
|
140
|
+
— pose values are offsets from the rest pose. `"away": true` on a frame keeps a backward fall readable: it rolls
|
|
141
|
+
sideways in S/N and falls face-down away from the camera in NE/NW (the built-in death does this, and slides
|
|
142
|
+
the feet forward `death_slide` px, default 0.4 x body height, so the body lies inside the frame). Add the clip name to `clips`.
|
|
143
|
+
|
|
144
|
+
## Size and 2D-HD maps
|
|
145
|
+
- **`"size"`** in a spec: `"tiny"` 14, `"small"` 22, `"medium"` 32, `"large"` 44, `"huge"` 58 (visible rest height in
|
|
146
|
+
px; a ~30 px humanoid hero is about medium) or `{"height": px}`. A style may override the table with `"sizes"`.
|
|
147
|
+
The forge scales the whole spec (lengths and the style's motion lengths, never angles/timing/colours), refits the
|
|
148
|
+
frame, and writes `height_px` / `width_px` / `size` into the build json. Author at any size, declare the size.
|
|
149
|
+
Check a family with `pp sizes <builds...>` (sorted lineup with class rulers); `pp lint` flags classes out of order.
|
|
150
|
+
- **`"maps": ["normal", "height"]`** (or `pp build --maps normal,height`) writes `<name>_<clip>_normal.png`
|
|
151
|
+
(RGB = world normal * 0.5 + 0.5; x right, y away, z up) and `_height.png` (grey = px above the feet x
|
|
152
|
+
`height_scale`) beside each sheet, same layout, alpha only on the model's pixels. For real-time lighting in a game
|
|
153
|
+
(2D-HD): light the finished sprite, keep the added light in a few steps so it stays pixel art.
|
|
154
|
+
|
|
155
|
+
## Motion (family feel)
|
|
156
|
+
Each style has a `motion` block, so a family moves as one. A spec's `anim` overrides any key.
|
|
157
|
+
- `gait` (walk + run, humanoid and quadruped): `stride` (classic), `hop` (both feet, off the ground; rabbits, spirits;
|
|
158
|
+
`walk_hop`/`run_hop` px), `lurch` (bent forward, hip sway, heavy footfall; quadrupeds prowl low), `bounce` (springy,
|
|
159
|
+
squash on every step), `glide` (low, level, arms still; run = low dash with arms swept back).
|
|
160
|
+
- `idle_style: "float"` + `hover` px: the body floats off the ground in every clip (shadow stays down and shrinks);
|
|
161
|
+
deaths drop to the ground. `float_bob` = idle drift px.
|
|
162
|
+
- `attack_style` (built-in attack): `slash` (13 f), `dart` (leap in, strike mid-air, drift back), `heavy` (trembling
|
|
163
|
+
wind-up, crushing impact, hit-stop), `hop` (spring up, strike on landing), `iaido` (stillness, one-frame draw, frozen
|
|
164
|
+
follow-through). `hitstop: n` freezes the impact of hand-written `custom_clips.attack` for n frames.
|
|
165
|
+
- Families: Hollow Court lurch/heavy, Meadowfolk bounce/hop, Wayfarers stride/slash,
|
|
166
|
+
Ember Spirits float + hop/dart.
|
|
167
|
+
- Walks are keyed contact (0, 4: full stride, footstep, 1 px weight shift) / passing (2, 6: body high, 2 px foot lift).
|
|
168
|
+
Runs lean `run_lean` (22) with the chest `run_lead` px (2) ahead of the hips. Props trail 1 frame and get spring
|
|
169
|
+
follow-through; weapon bones (`smear_hides`) lag the hand instead of swinging with it.
|
|
170
|
+
- **Limited animation** (stop-motion timing, on by default): built-in clips show fewer, stronger poses and hold
|
|
171
|
+
each one, like Guilty Gear Xrd / anime "on twos". Loops step on twos (walk = 8 poses x 2 frames); one-shots keep
|
|
172
|
+
their designed key poses (wind-up held 3, one-frame cut, follow-through held 3). `anim.on` sets the hold
|
|
173
|
+
(1 = every frame moves, 2 default, 3-4 choppier) or per clip `{"walk": 2, "run": 1}`; run and hit stay on ones.
|
|
174
|
+
Hand-written `custom_clips` keep their frames unless the clip sets `"on": n`. Frame counts never change.
|
|
175
|
+
- Runs are keyed contact / down (lowest, squash) / push-off (rear leg long, knee drive, stretch) / flight (both
|
|
176
|
+
feet off, highest), leaning forward `run_lean` with the hips countering the shoulders.
|
|
177
|
+
- `anim.carry = {"bow": {"aim": [x,y,z], "up": [0,0,1]}}` keeps a carried item at one body-frame angle in idle,
|
|
178
|
+
walk and run (no flailing bow or spear). `"up"` on any aim also fixes the bone's twist (its local z).
|
|
179
|
+
- Check motion with `pp review <dir> --onion`: each clip's frames overlaid (blue = first, red = last) over the ground line.
|
|
180
|
+
|
|
181
|
+
## Inspect, variants, layers
|
|
182
|
+
- **`pp inspect <spec> --clip C --dir D --frame N`**: reads the real bake of one frame. It prints a table with one
|
|
183
|
+
line per part, nearest first: pixels, bbox, value (Oklab L), materials and colours. It also lists parts hidden in
|
|
184
|
+
this view, touching parts whose values are too close (dL < 0.08), attach points, and a glyph grid (one letter per
|
|
185
|
+
part). It writes an image: sprite | part map | material map, with the same letters. Use it when you can't tell
|
|
186
|
+
what a blob is, why a part vanished, or where the hand is. Don't use it to write reports.
|
|
187
|
+
- **`pp variants <spec> --vary key=a,b,c`** (dotted path; `bones.head.parts.0.r` addresses bones by name;
|
|
188
|
+
`key=lo..hi --sample 6 --seed 3` draws keyed values) builds each row as a normal build in /tmp and shows a
|
|
189
|
+
labelled still grid plus an animated grid. Row v00 is the spec as it is. A row that renders identically to an
|
|
190
|
+
earlier one is flagged, e.g. `attack_style` under a hand-written attack. Each row lists its lint WARNs.
|
|
191
|
+
`--apply N` writes row N into the spec. Choose by looking at the animated grid, not the still.
|
|
192
|
+
- **`"attach": true`** (or `{"muzzle": ["gun", [0, -6, 0]]}`; where = `tip|joint|centre|[x,y,z]`) writes per-frame
|
|
193
|
+
points into the build json: `clips.<c>.attach.<dir>[frame] = {head, hand_R, hand_L, weapon_tip, feet: [x, y,
|
|
194
|
+
visible], box: [x0, y0, x1, y1]}`. Games use them for spawn points (spells, muzzles) and hitboxes.
|
|
195
|
+
- **Combo clips** (`"layers"`): `{"run_attack": {"base": "run", "over": [{"clip": "attack", "bones": "torso/",
|
|
196
|
+
"spine": 0.5}]}}`. The legs keep running while the torso subtree plays the attack (`name/` = the bone and its
|
|
197
|
+
children). `spine` blends the waist. The hit, smear and hitstop come from the attack (the legs freeze on impact
|
|
198
|
+
too); footsteps and ground speed come from the base. Combos are listed with the rig's clips and baked into their
|
|
199
|
+
own sheets.
|
|
200
|
+
- **Life** (`"life"` in a spec, or as a style default): small additive motion in whole pixels, off unless asked for.
|
|
201
|
+
`sway` {bones, px, frames, wave}: sideways travelling wave for crowns, flags and sails. Flora trees use it by
|
|
202
|
+
default. `flutter` {bones, px}: cloth tips flick 1 px on an 8-beat. `look` {every, deg}: every Nth idle breath
|
|
203
|
+
the head glances aside and back (the idle gets N times longer). Keep it subtle. The idle-change lint and
|
|
204
|
+
`pp review --onion` catch parts that boil.
|
|
205
|
+
- Map kits (pp.map): an object's `"build"` can be a list of **same-footprint** variants. Each placement gets a keyed
|
|
206
|
+
pick, never the same as its nearest same-kit neighbour. Don't mix sizes (rows break) and don't flip lit sprites.
|
|
207
|
+
|
|
208
|
+
## Concept sheet → sprites: what to avoid (failed "wayfarers" party, 2026-09-27)
|
|
209
|
+
- Don't force chibi. Copy the concept's proportions (lanky, small head); the chibi default killed the look first.
|
|
210
|
+
- Don't transcribe detail. At 26-30 px keep 3-4 colour blocks + skin + one accent; studs, vials, checkers, scales, trim = noise.
|
|
211
|
+
- Don't build angular designs from ellipsoids/capsules: they bake into lumpy blobs. Graphic concepts need boxes/wedges/flat cones.
|
|
212
|
+
- Don't let 8 artists invent 8 bodies. One shared base body first, then costume + one defining feature each.
|
|
213
|
+
- Don't fix "too busy" afterwards by stripping: the result is flat but generic. Decide the simple read before modelling.
|
|
214
|
+
- Prototype ONE character against the concept and get sign-off before fanning out to the family.
|
|
215
|
+
|
|
216
|
+
## Styles (styles/*.json, generated by tools/make_styles.py)
|
|
217
|
+
Materials are shared by every asset in a style — that's the consistency. Use style materials; add a spec material only
|
|
218
|
+
by pointing at an existing style ramp. List them: `python3 -m pp materials <style>`.
|
|
219
|
+
- **duskborne** — dark fantasy action. Deep desaturated bodies, near-black ink, ONE glowing accent (cyan/pink/fire).
|
|
220
|
+
- **sunmeadow** — bright cozy adventure. Warm saturated mids, soft values, coloured outlines, green ground.
|
|
221
|
+
- **vermilion** — folk-print spirits. Three inks on cream paper: black masses (`ink`, `ink_flat` for sticks),
|
|
222
|
+
red coats/flames (`red`, `canopy` for crowns), painted marks (`red_mark`, `bone_mark`), dry-brush `fur`.
|
|
223
|
+
No outline, 1-2 tones; VFX use `fx_ink` (hot core = darkest ink). Put markings on as stamps (chevrons, bands).
|
|
224
|
+
|
|
225
|
+
## VFX sheets
|
|
226
|
+
`python3 -m pp fx <kind> --style <style> --ramp <ramp> [--param k=v ...]`: kinds `slash, hit_spark, burst, eruption, aura,
|
|
227
|
+
dust, projectile, lightning, sparkle, leaves, shockwave`. Eruption takes `spike_h`, `spike_w`, `rune_r`; leaves take `leaf_size` (2 = specks, 3 = two-tone leaves), `count`;
|
|
228
|
+
aura takes `radius`, `tongues`, `tongue_w`, `tongue_h`, `motes`, `sustain`; hit_spark `scale`, `ray_w`, `rays`, `sparks`;
|
|
229
|
+
dust `puffs`, `radius`, `two_tone`; sparkle `star_size` (3 = 7 px cross), `ring_w`, `ring_r`, `stars`; shockwave `ring_w`, `chips`.
|
|
230
|
+
Poses also take per-bone `"at"` offsets (e.g. lift a hand above the head in a gesture clip). VFX dirs can be passed to `pp pack` (they land in vfx/). Posterized to the ramp; timing rules are built in (fast build, slow fragmenting decay).
|
|
231
|
+
|
|
232
|
+
## Shipping
|
|
233
|
+
`python3 -m pp pack <pack_name> out/<a> out/<b> ... --style <style>` → `packs/<pack_name>/` (sheets, gifs, .aseprite
|
|
234
|
+
sources, palette.png/.gpl, preview.png, lineup.png, README.txt). `python3 -m pp aseprite out/<a>` exports one source.
|
|
235
|
+
|
|
236
|
+
## When the engine is the problem
|
|
237
|
+
If you can't get something right with the spec (a missing primitive, a rig limit, an ugly automatic rule), write it in
|
|
238
|
+
`REQUESTS.md` (one line: what you tried, what you need, which image shows it). The engineer fixes the engine.
|
|
239
|
+
Don't hack around it with dozens of micro-parts.
|
|
240
|
+
|
|
241
|
+
## Maps (pp.map)
|
|
242
|
+
`python3 -m pp.map <map.json> [--still] [--layers]` lays built props out on painted terrain and animates them.
|
|
243
|
+
- **terrain** (in order): `fill`, `land` (optional `cliff`), `path`, `paving` (quiet slabs), `planks`, `sea` (1-3 calm tones),
|
|
244
|
+
`shore` (shallows + foam), `canopy` (forests of round clumps; `clear` keeps roads open with a row of crowns along them),
|
|
245
|
+
`massif` (one mountain range from blended summits; `valleys` cut hollows and gorges), `bridge` (a deck at any angle), `wall_face`.
|
|
246
|
+
Regions are `rect` / `ellipse` / `poly` / `path`, with a noisy edge (`rough`). Colours are ramp roles (`tones`), never hex.
|
|
247
|
+
- **objects** sort by feet y (`z` changes the order only). `place: id` + `icon` export tap bounds, an outline ring and an
|
|
248
|
+
atlas glyph; `over: true` also draws it above movers (bridges, walls). `cast_shadow` darkens the ground by a ramp step.
|
|
249
|
+
- **fx**: smoke, glints, waves, `flow` (streaks down a river path), birds, clouds; **walkers** move along paths.
|
|
250
|
+
- **fog**: `regions` (bitmask: each region's own rounded, overlapping shape, so lifting one leaves a soft edge), `ramp`
|
|
251
|
+
(the vista `mist`), a faint ghost of the land beneath; `permanent` regions never lift.
|
|
252
|
+
- `--layers` is the engine export: a delta-encoded base loop (only changed pixels), occluders, mover strips with
|
|
253
|
+
px/s speeds, sky clouds, fog + bitmask, places with outlines, extra `sprites`, and an `atlas` (the hand-drawn map, read
|
|
254
|
+
back from the rendered colours, in ink layers). Keep clip lengths divisors of the map's `frames` so the loop is seamless.
|
|
255
|
+
Vista kits, layouts and maps: `python3 tools/vista/build.py`.
|
|
256
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Environments: painted maps that live
|
|
2
|
+
|
|
3
|
+
pp paints a whole map as one picture (`pp.map`), in one locked palette. These tools turn that picture into a place.
|
|
4
|
+
|
|
5
|
+
| Command | What it gives you |
|
|
6
|
+
|---|---|
|
|
7
|
+
| `python3 -m pp states specs/vista/house_5.json` | a building's **ruin**, its **construction** stages (walls rising course by course inside a scaffold, rafters, roof) and the finished building, re-rendered by the engine from the building's own spec. Place `house_5~ruin` in a map like any object. |
|
|
8
|
+
| `python3 -m pp.map <map> --still --meaning` | the **meaning layer**: what every pixel is (material, collision, water depth, occlusion depth, object ids), written by the painters while they paint. `--layers` always includes it. |
|
|
9
|
+
| `python3 -m pp light <map> --gif` | the map at **every hour**: day, golden hour, sunset, dusk, night; windows light building by building, lamps pool warm light, water reflects it. `light.json` lets an engine do it at runtime. |
|
|
10
|
+
| `land "blades"`, `water "bank"` | painters for **grass by density** (small pixel blades, no tone patches) and **water from bank to middle** (dithered seams, flat deep middle). |
|
|
11
|
+
|
|
12
|
+
## Rules that keep a map believable
|
|
13
|
+
Learned building the open-world scenes (2026-10). They hold for any environment.
|
|
14
|
+
|
|
15
|
+
- **The vista look is the identity:** soft, painterly, aerial, muted cream walls, terracotta roofs, teal water, calm
|
|
16
|
+
forest masses. Fix what is flagged inside that language; never swap in a new style.
|
|
17
|
+
- **One painter per material, strictly.** Every tree, bush, hedge and forest in a scene comes from the same canopy
|
|
18
|
+
painter at one leaf size. A tree is a bigger crown over a short shaded trunk with a soft down-right ground shadow.
|
|
19
|
+
Mixing kit tree sprites with painted forest breaks the immersion. Check every new asset family against what is
|
|
20
|
+
already on screen for the same material.
|
|
21
|
+
- **One scale axiom.** Pick the size of a person and derive everything from it. At walk
|
|
22
|
+
scale a person is 14 px = 1.70 m and the street kit (st_house_*, lamps, fountain, stalls) agrees with it.
|
|
23
|
+
- **Paint by density, not patches.** Grass blades whose density drifts; water as a bank-to-middle gradient. Hard tone
|
|
24
|
+
patches read as jagged blotches.
|
|
25
|
+
- **Buildings carry the story.** A ruin that rebuilds in beats (scaffold, courses, roof, dust, then smoke and lit
|
|
26
|
+
windows) was the most loved moment of every scene. Light is the other one: a town answering the dusk.
|
|
27
|
+
- **Less is more.** One authored, atmospheric place beats many scenes built to a checklist; judge by "do I want to be
|
|
28
|
+
there?", not by measurements.
|
|
29
|
+
- **For a game on top:** never round the camera. Draw the world 1 px oversize, scale by a whole number and offset by
|
|
30
|
+
the camera's sub-pixel fraction; non-integer scaling is what makes pixel art look uneven.
|