default paintings

This commit is contained in:
33333-33333 2026-06-03 03:13:14 +09:00
commit 43b659b64b
8 changed files with 4244 additions and 46 deletions

36
DEFAULT_ART_AUDIT.md Normal file
View file

@ -0,0 +1,36 @@
# Default Art Audit
## 実施内容
`app.js``buildDefaultGalleryPack()` を確認し、初期同梱作品の品質を監査した。低品質または初期作品として弱いものは、削除対象リストで除外する方式にした。既存ローカル状態に残っている Island Team 製の該当作品も、次回ロード時に Collection / island placement / dynamic summon から除外される。
## 削除した初期作品
| 作品名 | 理由 |
|---|---|
| Shell Rock | 16×16に対して実質的な形状が小さく、島上で石・貝の識別点が弱い。 |
| Azure Minnow | 魚としての頭・尾・ヒレが弱く、単なる水色の塊に近い。 |
| Firefly Swirl | 8×8で透明部が多く、作品というより粒子エフェクトに近い。 |
| Leaf Sparrow | 鳥のシルエットが薄く、頭・翼・尾の分離が不足している。 |
| Silver Trout | 魚としては読めるが、既存の Cloud Koi / Sunset Koi より低密度で初期作品として弱い。 |
| Butterfly Fish | 小型魚としての情報量が少なく、島上で主題が読み取りにくい。 |
## 残したが改変候補に入る作品
| 作品名 | コメント |
|---|---|
| River Stones | 8×8としては成立しているが、石の影と水際の情報を足すと良い。 |
| Paper Crane | モチーフは明確だが、分断セルが多い。羽根の接続を調整できる。 |
| Linen Cottage | 読みやすいが、屋根と壁の面が単純。影と窓を増やせる。 |
| Human 系小型作品 | 役割差はあるが、体型・顔・道具の差分が弱いものがある。 |
## コード上の変更点
- `REMOVED_LOW_QUALITY_SEED_ASSET_NAMES` を追加。
- `buildDefaultGalleryPack()` の戻り値に品質フィルタを適用。
- `mergeDefaultGallery()` で既存ローカル状態の Island Team 製削除対象も除外。
- Python 側テストは `14 passed`
## 次の作業
ユーザー確認後、新しいデフォルト作品を追加する。追加時は `PIXEL_ART_QUALITY.md` の基準に従い、既存の弱いカテゴリを補う。

35
DEFAULT_ART_EXPANSION.md Normal file
View file

@ -0,0 +1,35 @@
# Default Art Expansion / Depth Lighting Tuning
## Depth tuning
Adjusted the depth-local light response so that:
- local light influence stays colorized instead of washing into a neutral gray band,
- the light source itself and nearby sprite/depth corners catch the strongest highlight,
- brightness depends less on raw source-to-pixel distance than before,
- convex edges still read clearly under nearby inspection/night lights.
Implementation areas: `depthLocalLightResponse()`, `getDepthEdgeLightBoost()`, and local-light color mixing inside `shadeAssetPixelColor()` in `app.js`.
## UI bubble correction
- Reduced the selection bubble top offset so the bubble appears closer to the selected sprite.
## New large default works
### Static / building
- Smile Portrait — 24x32
- Rosetta Stela — 24x32
- Pharaoh Mask — 24x32
- Terracotta Sentinel — 20x32
### Static / nature
- Great Wave Panel — 32x24
- Sunflower Still Life — 24x32
- Stone Circle — 32x24
## Notes
- `assets.json` and `default_assets_sheet.png` were refreshed.
- The seeded island placement list was expanded so these works appear by default.
- Save schema was bumped to `25`.

69
PIXEL_ART_QUALITY.md Normal file
View file

@ -0,0 +1,69 @@
# ドット絵品質基準 / Pixel Art Quality Standard
このプロトタイプで「良質なドット絵」と見なす基準。共有サービスの初期作品、審査、改変、削除判断で使う。
## 1. 最低条件
- **透明セルを作品の一部として設計している**:余白はただの空きではなく、シルエットを読ませるために残す。
- **1秒以内に主題が判別できる**:縮小表示、島上表示、夜間表示でも「家」「鳥」「魚」「橋」などの役割が読める。
- **接地・重心が明確**:静物は地面や水面に乗って見える。動物・人は足元または接地点が曖昧でない。
- **パレットに収まる**:任意色の多用ではなく、既存パレットコードに近い色で統一する。
- **クリック対象として破綻しない**:極端に薄い線、孤立点だけの作品、透明部分が多すぎる作品は避ける。
## 2. 具体的な評価軸
| 評価軸 | 良い状態 | 低品質と判断する状態 |
|---|---|---|
| シルエット | 背景なしでも輪郭だけで主題が読める | 点・棒・塊にしか見えない |
| 明暗 | 上面・側面・影の方向がある | 全面が同じ明度で平坦 |
| 色数 | 小物は3〜6色、中型は5〜10色程度で役割が分かれる | 1〜2色だけ、または無秩序に多色 |
| ピクセル密度 | 余白、密部、抜きのバランスがある | ほぼ空白、またはベタ塗りの矩形 |
| エッジ | 角、段差、斜線に意図がある | ガタつきが偶然に見える |
| 内部ディテール | 目、窓、葉、波、道具など識別点がある | 主題を補強する点がない |
| 島との親和性 | 地形、昼夜、他作品のサイズ感と合う | 尺度が浮く、接地しない、光源が不自然 |
| メタ情報 | building の door、light、depth、particle が主題に沿う | メタ情報がない、または見た目と矛盾する |
## 3. サイズ別の合格目安
### 8×8
- 主題は1つに絞る。
- 色は3〜5色までを目安にする。
- 透明を含めても、主題の有効ピクセルは概ね16セル以上ほしい。
- 「点の集合」ではなく、頭・胴・尾、花・葉・茎などの構造を最低2部位に分ける。
### 12×12〜16×16
- デフォルト作品の中心サイズ。
- 輪郭色、主色、中間色、ハイライト、影の5層を基本にする。
- 動物・人は顔または進行方向が読めること。
- 建物・自然物は接地線、屋根/幹/水面などの基礎形を入れる。
### 20×20以上
- 大型作品はディテール量だけでなく、遠目の大形状を優先する。
- 3〜5個の大きな面に分け、その中に小ディテールを置く。
- 光・depth・particle を使う場合、効果が主題を補強していること。
## 4. 削除・改変の判断
### 削除候補
- 何を描いたか判別できない。
- 既存の高品質作品と役割が重複し、見劣りする。
- ほぼ点、線、単色塊で、改変より作り直しが早い。
- 島上でクリックや配置の視認性を落とす。
### 改変候補
- 主題は読めるが、明暗・輪郭・接地が弱い。
- 色の階調が足りない。
- サイズに対してディテールが不足している。
- 良いアイデアはあるが、他作品群と密度が合っていない。
## 5. デフォルト作品としての追加基準
- 初回表示でサービスの品質水準を示せること。
- ユーザーがリミックスしたくなる明確なモチーフを持つこと。
- 小型、中型、大型、静物、動物、人、船、水辺、建物が偏りすぎないこと。
- 低品質作品を大量に残して作品数を稼がないこと。

View file

@ -298,3 +298,28 @@ Use this to compare minified JSON, gzip, zlib, and Brotli when available. Produc
- Added server-side `world.phase` and `dynamic.move` event helpers/tests. Shared clients should treat these events as the source of truth for day/night and autonomous dynamic positions.
- Pending shared object moves now render as temporary local interpolation only; the persistent world state is updated only by server-issued events.
- Depth shading can now use a cursor-local light source on rendered sprites at night.
## Custom update 3: colored local light fix + heritage/masterpiece gallery
- Save schema is now `25`.
- Fixed the local depth-light wash so the affected area no longer collapses into a mostly gray band; local lights now preserve more of the source color.
- Reworked depth local-light behavior so the source itself and nearby outer/depth corners catch the strongest highlights, while distance has a weaker effect on brightness than before.
- Reduced the selection bubble offset so the bubble sits noticeably closer to the top of the selected artwork.
- Added several new large default works themed around masterpieces, heritage, and artifacts: **Smile Portrait**, **Great Wave Panel**, **Sunflower Still Life**, **Rosetta Stela**, **Pharaoh Mask**, **Stone Circle**, **Terracotta Sentinel**.
- Refreshed `assets.json` and `default_assets_sheet.png` after the additions.
## Custom update 4: cursor-light smoothing + gray-bloom hotfix
- Save schema is now `26`.
- Fixed the urgent regression where a single local light could wash large parts of a sprite into a gray, low-chroma bloom.
- Reduced local-light body fill on depth sprites so highlights stay concentrated on lit edges / corners instead of flattening the whole silhouette.
- Smoothed cursor-light falloff so in-range / out-of-range transitions are less abrupt.
- Removed the always-on center fallback for the cursor inspection light and softened the visible cursor halo, which eliminates the unwanted blue circular artifact when no pointer light should be shown.
## Custom update 5: asset-light gray fix + temporary global delete + more default works
- Save schema is now `27`.
- Adjusted **asset-mounted local lights** again so they no longer wash large depth sprites into a gray body fill; their effect is concentrated much more strongly on lit edges and corners.
- Fixed the analog clock hand offset (it had been visually about 5 degrees early).
- Added a **temporary** delete override so **all collection works can be deleted** regardless of owner. This is clearly marked in `app.js` with comments and can be reverted by setting `TEMP_ALLOW_DELETE_ALL_WORKS = false`.
- Added many more default works: **Rain Bell Tower**, **Crimson Pagoda**, **Meteor Forge**, **Ink Garden Screen**, **Meadow Totem**, **Twilight Caravan**, **Pepper Fox**, **Glass Manta**, **Festival Drummer**, **Bloom Sprite**.

1286
app.js

File diff suppressed because it is too large Load diff

2815
assets.json Normal file

File diff suppressed because it is too large Load diff

BIN
default_assets_sheet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

24
extract_assets.js Normal file
View file

@ -0,0 +1,24 @@
const fs = require('fs');
const vm = require('vm');
const path = require('path');
let code = fs.readFileSync(path.join(__dirname, 'app.js'), 'utf8');
code = code.replace(/\n\s*bootstrap\(\);\s*\n\}\)\(\);\s*$/, `\n window.__PIXEL_DEBUG__ = { state, buildDefaultGalleryPack, PALETTE, PALETTE_BY_CODE, assetWidth, assetHeight };\n})();`);
function makeCtx(){
const noop=()=>{};
return new Proxy({imageSmoothingEnabled:false, canvas:{width:1,height:1}}, {get(t,p){
if(p in t) return t[p];
if(p==='measureText') return () => ({width:0});
return noop;
}, set(t,p,v){ t[p]=v; return true; }});
}
function makeEl(id){ return new Proxy({ id, width:640, height:480, style:{}, classList:{add(){},remove(){},toggle(){},contains(){return false;}}, dataset:{}, value:'', checked:false, textContent:'', innerHTML:'', append(){}, appendChild(){}, addEventListener(){}, removeEventListener(){}, setAttribute(){}, removeAttribute(){}, focus(){}, blur(){}, getBoundingClientRect(){return {left:0,top:0,width:640,height:480};}, getContext(){return makeCtx();}, querySelector(){return makeEl('q');}, querySelectorAll(){return [];}}, {get(t,p){ if(p in t) return t[p]; if(p==='children') return []; return undefined; }, set(t,p,v){ t[p]=v; return true; }}); }
const localStorage = { getItem(){return null;}, setItem(){}, removeItem(){} };
const sandbox = { console, window: {}, document: { getElementById: makeEl, createElement: makeEl, querySelector(){return makeEl('q')}, querySelectorAll(){return []}, addEventListener(){}, body: makeEl('body')}, localStorage, performance: { now: () => 0 }, Math, Date, Map, Set, Array, Object, JSON, Number, String, Boolean, RegExp, Error, Uint8Array, Int8Array, Uint16Array, URL: {createObjectURL(){return ''}, revokeObjectURL(){}}, Blob: function(){}, Image: function(){}, FileReader: function(){}, requestAnimationFrame(){}, cancelAnimationFrame(){}, setTimeout, clearTimeout, structuredClone: global.structuredClone };
sandbox.window = Object.assign(sandbox.window, { PixelIslandModules:{}, devicePixelRatio:1, addEventListener(){}, removeEventListener(){}, matchMedia(){return {matches:false, addEventListener(){}, removeEventListener(){}}}, requestAnimationFrame(){}, cancelAnimationFrame(){}, document: sandbox.document, localStorage: sandbox.localStorage });
vm.createContext(sandbox);
vm.runInContext(code, sandbox, {filename:'app.js'});
const debug = sandbox.window.__PIXEL_DEBUG__;
const assets = debug.state.assets.map(a => ({id:a.id,name:a.name,category:a.category,subtype:a.subtype,width:a.width,height:a.height,pixels:a.pixels,faces:a.faces,meta:a.meta,contentHash:a.contentHash}));
fs.writeFileSync(path.join(__dirname,'assets.json'), JSON.stringify(assets,null,2));
console.log('assets', assets.length);
console.log(assets.map(a=>`${a.name} ${a.width}x${a.height} ${a.category}/${a.subtype}`).join('\n'));