pixel-daylight-switch-gsvegetable 3.0.0 → 3.1.1
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.
- package/README.ja.md +65 -52
- package/README.md +64 -63
- package/README.zh-CN.md +65 -52
- package/app.js +33 -3
- package/browser.mjs +4 -0
- package/docs/CHANGELOG.md +127 -0
- package/docs/GLASS_ENGINE.md +65 -0
- package/{INTEGRATIONS.md → docs/INTEGRATIONS.md} +22 -1
- package/docs/README.md +5 -0
- package/{SCENE_PLUGINS.md → docs/SCENE_PLUGINS.md} +22 -6
- package/examples/scenes/floating-island.v2.json +152 -0
- package/glass-engine.js +162 -0
- package/glass-engine.mjs +4 -0
- package/index.cjs +1 -0
- package/index.d.ts +54 -21
- package/index.mjs +2 -0
- package/llms.txt +21 -15
- package/package.json +21 -8
- package/scene-plugin.js +49 -3
- package/schemas/scene-manifest.v2.schema.json +229 -0
package/README.ja.md
CHANGED
|
@@ -12,22 +12,22 @@
|
|
|
12
12
|
|
|
13
13
|
Pixel Daylight Switch は、ドラッグ操作で昼・夕暮れ・夜を切り替えられる UI コンポーネントです。ガラスレンズの中のピクセルアートの世界が、スイッチの動きに合わせて変化します。Vanilla JavaScript、WebGL2、Canvas 2D フォールバックで構成され、実行時にサードパーティ製ライブラリを必要としません。
|
|
14
14
|
|
|
15
|
-
**[ライブデモ](https://gsvegetable.github.io/pixel-daylight-switch/)** · **[パラメーター Playground](https://gsvegetable.github.io/pixel-daylight-switch/playground.html)** · **[npm パッケージ](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable)**
|
|
15
|
+
**[ライブデモ](https://gsvegetable.github.io/pixel-daylight-switch/)** · **[パラメーター Playground](https://gsvegetable.github.io/pixel-daylight-switch/demos/playground.html)** · **[npm パッケージ](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable)**
|
|
16
16
|
|
|
17
17
|
## 目的別リンク
|
|
18
18
|
|
|
19
19
|
| 目的 | リンク |
|
|
20
20
|
| --- | --- |
|
|
21
21
|
| スイッチを体験する | [ライブデモ](https://gsvegetable.github.io/pixel-daylight-switch/) |
|
|
22
|
-
| シーンや表示を調整する | [パラメーター Playground](https://gsvegetable.github.io/pixel-daylight-switch/playground.html) |
|
|
23
|
-
| コンポーネントを見る | [Preview](https://gsvegetable.github.io/pixel-daylight-switch/preview.html) |
|
|
22
|
+
| シーンや表示を調整する | [パラメーター Playground](https://gsvegetable.github.io/pixel-daylight-switch/demos/playground.html) |
|
|
23
|
+
| コンポーネントを見る | [Preview](https://gsvegetable.github.io/pixel-daylight-switch/demos/preview.html) |
|
|
24
24
|
| Web サイトに埋め込む | [embed.js](embed.js) |
|
|
25
25
|
| JavaScript プロジェクトで使う | [npm](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable) |
|
|
26
|
-
| React / Vue の導入例 | [フレームワーク統合ガイド](INTEGRATIONS.md) |
|
|
26
|
+
| React / Vue の導入例 | [フレームワーク統合ガイド](docs/INTEGRATIONS.md) |
|
|
27
27
|
| 実装を読む | [app.js](app.js) · [style.css](style.css) |
|
|
28
28
|
| モバイルビルド | [ビルド情報](builds/README.md) · [GitHub Actions](https://github.com/GSvegetable/pixel-daylight-switch/actions/workflows/mobile-build.yml) |
|
|
29
29
|
| テスト結果 | [CI ワークフロー](https://github.com/GSvegetable/pixel-daylight-switch/actions/workflows/ci.yml) |
|
|
30
|
-
| 更新履歴 | [CHANGELOG](CHANGELOG.md) |
|
|
30
|
+
| 更新履歴 | [CHANGELOG](docs/CHANGELOG.md) |
|
|
31
31
|
| 不具合を報告する | [Issues](https://github.com/GSvegetable/pixel-daylight-switch/issues) |
|
|
32
32
|
|
|
33
33
|
## 主な機能
|
|
@@ -96,40 +96,61 @@ const PixelDaylightSwitch = require('pixel-daylight-switch-gsvegetable');
|
|
|
96
96
|
|
|
97
97
|
ESM と CommonJS の両方を提供します。SSR 環境でもインポートできますが、`mount()` はブラウザー上で対象要素が存在してから呼び出してください。
|
|
98
98
|
|
|
99
|
-
## コミュニティシーンプラグイン(v3.0.0)
|
|
100
99
|
|
|
101
|
-
|
|
100
|
+
## 独立ガラス屈折エンジン(v3.1.1)
|
|
102
101
|
|
|
103
|
-
|
|
102
|
+
ガラスレンズを昼夜スイッチから独立して利用できるようになりました。固定アスペクト比に依存せず、幅・高さ・位置・角丸・屈折・色分散・縁の厚さ・ハイライトを個別に設定できます。Canvas、画像、動画、ImageBitmap、またはそれらを返す関数を背景ソースとして指定します。[ガイド](docs/GLASS_ENGINE.md) と [ライブデモ](https://gsvegetable.github.io/pixel-daylight-switch/demos/glass-engine.html) を参照してください。
|
|
104
103
|
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
PixelDaylightSwitch.registerScene(sceneManifest);
|
|
111
|
-
</script>
|
|
104
|
+
```js
|
|
105
|
+
import { createGlass } from 'pixel-daylight-switch-gsvegetable/glass-engine';
|
|
106
|
+
const glass = createGlass(container, { source: backgroundCanvas, width: '72%', height: 180, radius: 28 });
|
|
107
|
+
glass.setOptions({ refraction: 1.3, dispersion: 0.08 });
|
|
108
|
+
glass.destroy();
|
|
112
109
|
```
|
|
113
110
|
|
|
114
|
-
|
|
111
|
+
WebGL は任意の DOM ピクセルを直接読み取れません。Web ページの背景を屈折させるには、ホストアプリが Canvas などの描画ソースを提供する必要があります。クロスオリジンメディアには CORS 制約があります。
|
|
112
|
+
|
|
113
|
+
## コミュニティシーン
|
|
114
|
+
|
|
115
|
+
コミュニティシーンは宣言型 JSON Manifest で定義し、コンポーネントのマウント前に登録します。現在の形式は **Manifest v2** です。再利用可能なピクセル素材、順序付きレイヤー、制限付きモーショントラックに対応し、既存の Manifest v1 シーンも引き続き利用できます。
|
|
116
|
+
|
|
117
|
+
### シーンの登録
|
|
118
|
+
|
|
119
|
+
npm プロジェクトの場合:
|
|
115
120
|
|
|
116
121
|
```js
|
|
117
122
|
import PixelDaylightSwitch, { registerScene } from 'pixel-daylight-switch-gsvegetable';
|
|
118
|
-
import
|
|
123
|
+
import scene from './floating-island.v2.json';
|
|
119
124
|
|
|
120
|
-
const unregister = registerScene(
|
|
125
|
+
const unregister = registerScene(scene);
|
|
121
126
|
const root = document.querySelector('[data-ld-part="toggle-daylight"]');
|
|
122
|
-
root.dataset.scene =
|
|
127
|
+
root.dataset.scene = scene.id;
|
|
123
128
|
PixelDaylightSwitch.mount(root);
|
|
124
129
|
```
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
ブラウザーで直接使用する場合は、`scene-plugin.js` を `app.js` より先に読み込み、マウント前に Manifest を登録します。
|
|
132
|
+
|
|
133
|
+
```html
|
|
134
|
+
<script src="https://gsvegetable.github.io/pixel-daylight-switch/scene-plugin.js"></script>
|
|
135
|
+
<script src="https://gsvegetable.github.io/pixel-daylight-switch/app.js"></script>
|
|
136
|
+
<div data-ld-part="toggle-daylight" data-scene="my-community-scene"></div>
|
|
137
|
+
<script>
|
|
138
|
+
PixelDaylightSwitchScenePlugins.registerScene(sceneManifest);
|
|
139
|
+
</script>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Manifest v2 の機能
|
|
143
|
+
|
|
144
|
+
- 最大 24 個の再利用可能な文字ベースのピクセル素材と、最大 16 個の順序付きレイヤー。
|
|
145
|
+
- 整数のシーン座標を使用し、後のレイヤーほど手前に合成されます。
|
|
146
|
+
- オーバーレイ素材のドット文字 `.` は透明ピクセルとして扱われます。
|
|
147
|
+
- `drift` と `bob` の決定論的なモーショントラックに対応し、X/Y 軸上で動作します。
|
|
148
|
+
- 既存の Manifest v1 と 5 つの組み込みシーンは引き続きサポートされます。
|
|
149
|
+
|
|
150
|
+
[Manifest v2 Schema](schemas/scene-manifest.v2.schema.json)、[Floating Island サンプル](examples/scenes/floating-island.v2.json)、[シーン制作ガイド](docs/SCENE_PLUGINS.md)を参照してください。互換性のため [v1 Schema](schemas/scene-manifest.v1.schema.json) も維持されています。
|
|
127
151
|
|
|
128
|
-
|
|
129
|
-
- [Manifest v1 JSON Schema](schemas/scene-manifest.v1.schema.json)
|
|
130
|
-
- [Sakura Evening サンプル](examples/scenes/sakura-evening.json)
|
|
152
|
+
現在の素材形式は文字ベースのピクセルマトリックスです。PNG/JPEG のアップロードや任意の実行コードには対応していません。
|
|
131
153
|
|
|
132
|
-
v1 は外部画像/Sprite、レイヤー式 Tile Map、独自アニメーショントラックにはまだ対応していません。これらは任意コードの実行を許可せず、将来の独立した Schema 拡張として追加します。5 つの組み込みシーンは従来の描画・アニメーション実装を維持します。
|
|
133
154
|
|
|
134
155
|
## 設定属性
|
|
135
156
|
|
|
@@ -238,35 +259,27 @@ iOS は初回に `npm run mobile:ios:init`、以降は `npm run mobile:ios` を
|
|
|
238
259
|
```text
|
|
239
260
|
pixel-daylight-switch/
|
|
240
261
|
├── .github/workflows/ # CI、モバイルビルド、npm 公開
|
|
241
|
-
├── assets/
|
|
242
|
-
|
|
243
|
-
├──
|
|
244
|
-
|
|
245
|
-
├── mobile/
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
├──
|
|
249
|
-
|
|
250
|
-
├──
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
├──
|
|
257
|
-
├──
|
|
258
|
-
├──
|
|
259
|
-
├──
|
|
260
|
-
├── preview.html # コンポーネントプレビュー
|
|
261
|
-
├── playground.html # パラメーター Playground
|
|
262
|
-
├── index.mjs / index.cjs # ESM / CommonJS エントリー
|
|
263
|
-
├── package.json # npm メタデータとスクリプト
|
|
264
|
-
├── capacitor.config.json # Capacitor 設定
|
|
265
|
-
├── playwright.config.cjs # ブラウザーテスト設定
|
|
266
|
-
├── CHANGELOG.md
|
|
267
|
-
├── llms.txt
|
|
262
|
+
├── assets/ # シーンギャラリー画像
|
|
263
|
+
├── builds/ # モバイルビルド情報
|
|
264
|
+
├── docs/ # 統合ガイド、シーン制作ガイド、変更履歴
|
|
265
|
+
├── examples/scenes/ # コミュニティシーン Manifest
|
|
266
|
+
├── mobile/ # Capacitor アプリシェル
|
|
267
|
+
├── schemas/ # Manifest v1 / v2 JSON Schema
|
|
268
|
+
├── scripts/ # モバイル準備・バージョン設定
|
|
269
|
+
├── tests/ # Node / Chromium 回帰テスト
|
|
270
|
+
├── app.js / style.css # ランタイムとコンポーネントスタイル
|
|
271
|
+
├── scene-plugin.js # シーン登録・検証 API
|
|
272
|
+
├── embed.js # Web サイト埋め込みローダー
|
|
273
|
+
├── index.html # ライブデモ
|
|
274
|
+
├── demos/ # パラメーター Playground と Preview
|
|
275
|
+
├── config/ # 開発ツール設定
|
|
276
|
+
├── index.mjs / index.cjs # ESM / CommonJS エントリー
|
|
277
|
+
├── package.json # パッケージ設定とスクリプト
|
|
278
|
+
├── capacitor.config.json # Capacitor 設定
|
|
279
|
+
├── playwright.config.cjs # ブラウザーテスト設定
|
|
280
|
+
├── llms.txt # AI 向けプロジェクトガイド
|
|
268
281
|
├── LICENSE
|
|
269
|
-
└── README*.md
|
|
282
|
+
└── README*.md # 英語・簡体字中国語・日本語 README
|
|
270
283
|
```
|
|
271
284
|
|
|
272
285
|
## ライセンス
|
package/README.md
CHANGED
|
@@ -12,23 +12,23 @@
|
|
|
12
12
|
|
|
13
13
|
Pixel Daylight Switch is a draggable day/night UI component. Move its glass control to travel between day, dusk and night while a miniature pixel-art world changes inside the lens. It uses vanilla JavaScript, WebGL2 and a Canvas 2D fallback, with no third-party runtime dependency.
|
|
14
14
|
|
|
15
|
-
**[Open the live demo](https://gsvegetable.github.io/pixel-daylight-switch/)** · **[Launch the parameter lab](https://gsvegetable.github.io/pixel-daylight-switch/playground.html)** · **[Install from npm](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable)**
|
|
15
|
+
**[Open the live demo](https://gsvegetable.github.io/pixel-daylight-switch/)** · **[Launch the parameter lab](https://gsvegetable.github.io/pixel-daylight-switch/demos/playground.html)** · **[Install from npm](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable)**
|
|
16
16
|
|
|
17
17
|
## Start here
|
|
18
18
|
|
|
19
19
|
| Goal | Direct link |
|
|
20
20
|
| --- | --- |
|
|
21
21
|
| Experience the switch | [Live demo](https://gsvegetable.github.io/pixel-daylight-switch/) |
|
|
22
|
-
| Customize scenes and visual behavior | [Interactive parameter lab](https://gsvegetable.github.io/pixel-daylight-switch/playground.html) |
|
|
23
|
-
| Inspect the component | [Preview page](https://gsvegetable.github.io/pixel-daylight-switch/preview.html) |
|
|
22
|
+
| Customize scenes and visual behavior | [Interactive parameter lab](https://gsvegetable.github.io/pixel-daylight-switch/demos/playground.html) |
|
|
23
|
+
| Inspect the component | [Preview page](https://gsvegetable.github.io/pixel-daylight-switch/demos/preview.html) |
|
|
24
24
|
| Add it to a website with one script | [Embed loader source](embed.js) |
|
|
25
25
|
| Use it in a JavaScript project | [npm package](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable) |
|
|
26
|
-
| Framework integration recipes | [React and Vue examples](INTEGRATIONS.md) |
|
|
27
|
-
| Scene plugin authoring guide | [Scene plugin guide](SCENE_PLUGINS.md) |
|
|
26
|
+
| Framework integration recipes | [React and Vue examples](docs/INTEGRATIONS.md) |\n| Standalone glass refraction | [Glass engine guide](docs/GLASS_ENGINE.md) · [Live demo](https://gsvegetable.github.io/pixel-daylight-switch/demos/glass-engine.html) |
|
|
27
|
+
| Scene plugin authoring guide | [Scene plugin guide](docs/SCENE_PLUGINS.md) |
|
|
28
28
|
| Read implementation details | [Runtime](app.js) · [Styles](style.css) |
|
|
29
29
|
| Download mobile builds | [Build notes and limitations](builds/README.md) · [GitHub Actions artifacts](https://github.com/GSvegetable/pixel-daylight-switch/actions/workflows/mobile-build.yml) |
|
|
30
30
|
| Check tests | [CI workflow](https://github.com/GSvegetable/pixel-daylight-switch/actions/workflows/ci.yml) |
|
|
31
|
-
| Review changes | [Changelog](CHANGELOG.md) |
|
|
31
|
+
| Review changes | [Changelog](docs/CHANGELOG.md) |
|
|
32
32
|
| Report a bug | [Issue tracker](https://github.com/GSvegetable/pixel-daylight-switch/issues) |
|
|
33
33
|
|
|
34
34
|
## Features
|
|
@@ -97,52 +97,61 @@ const PixelDaylightSwitch = require('pixel-daylight-switch-gsvegetable');
|
|
|
97
97
|
|
|
98
98
|
The package exposes ESM and CommonJS entry points. Importing is safe in an SSR environment; call `mount()` only in a browser after the target element exists. The package's published file list is defined in [package.json](package.json).
|
|
99
99
|
|
|
100
|
-
## Community scene plugins (v3.0.0)
|
|
101
100
|
|
|
102
|
-
|
|
101
|
+
## Standalone glass engine (v3.1.1)
|
|
103
102
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
Load the registry before the renderer when using script tags:
|
|
103
|
+
The glass lens is also available independently of the day/night switch. It accepts a canvas, image, video, bitmap, or source callback and lets you set any width, height, position, radius, refraction, dispersion, bezel and highlight values. See the [glass engine guide](docs/GLASS_ENGINE.md) and [live demo](https://gsvegetable.github.io/pixel-daylight-switch/demos/glass-engine.html).
|
|
107
104
|
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
```js
|
|
106
|
+
import { createGlass } from 'pixel-daylight-switch-gsvegetable/glass-engine';
|
|
107
|
+
const glass = createGlass(container, { source: backgroundCanvas, width: '72%', height: 180, radius: 28 });
|
|
108
|
+
glass.setOptions({ refraction: 1.3, dispersion: 0.08 });
|
|
109
|
+
glass.destroy();
|
|
112
110
|
```
|
|
113
111
|
|
|
114
|
-
|
|
112
|
+
WebGL cannot sample arbitrary DOM pixels directly. To refract a live page background, provide an origin-clean canvas/render target from your application. Cross-origin media is subject to browser CORS rules.
|
|
115
113
|
|
|
116
|
-
|
|
117
|
-
const unregister = PixelDaylightSwitchScenePlugins.registerScene(sceneManifest);
|
|
118
|
-
PixelDaylightSwitch.mount(document.querySelector('[data-ld-part="toggle-daylight"]'));
|
|
119
|
-
```
|
|
114
|
+
## Community scenes
|
|
120
115
|
|
|
121
|
-
|
|
116
|
+
Community scenes are declarative JSON manifests registered before the component is mounted. The current format is **Manifest v2**, which supports reusable pixel-matrix assets, ordered layers and bounded motion tracks. Existing Manifest v1 scenes remain compatible.
|
|
117
|
+
|
|
118
|
+
### Register a scene
|
|
119
|
+
|
|
120
|
+
For npm projects:
|
|
122
121
|
|
|
123
122
|
```js
|
|
124
123
|
import PixelDaylightSwitch, { registerScene } from 'pixel-daylight-switch-gsvegetable';
|
|
125
|
-
import
|
|
124
|
+
import scene from './floating-island.v2.json';
|
|
125
|
+
|
|
126
|
+
const unregister = registerScene(scene);
|
|
127
|
+
const root = document.querySelector('[data-ld-part="toggle-daylight"]');
|
|
128
|
+
root.dataset.scene = scene.id;
|
|
129
|
+
PixelDaylightSwitch.mount(root);
|
|
130
|
+
```
|
|
126
131
|
|
|
127
|
-
|
|
128
|
-
|
|
132
|
+
For direct browser usage, load `scene-plugin.js` before `app.js`, then register the manifest before mounting:
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<script src="https://gsvegetable.github.io/pixel-daylight-switch/scene-plugin.js"></script>
|
|
136
|
+
<script src="https://gsvegetable.github.io/pixel-daylight-switch/app.js"></script>
|
|
137
|
+
<div data-ld-part="toggle-daylight" data-scene="my-community-scene"></div>
|
|
138
|
+
<script>
|
|
139
|
+
PixelDaylightSwitchScenePlugins.registerScene(sceneManifest);
|
|
140
|
+
</script>
|
|
129
141
|
```
|
|
130
142
|
|
|
131
|
-
### Manifest
|
|
143
|
+
### Manifest v2 capabilities
|
|
132
144
|
|
|
133
|
-
|
|
145
|
+
- Up to 24 reusable pixel-matrix assets and 16 ordered layers.
|
|
146
|
+
- Integer scene coordinates; later layers are composited above earlier layers.
|
|
147
|
+
- The dot character (`.`) is transparent in overlay assets.
|
|
148
|
+
- Optional deterministic `drift` and `bob` motion tracks on either axis.
|
|
149
|
+
- Existing v1 manifests and all five built-in scenes remain supported and unchanged.
|
|
134
150
|
|
|
135
|
-
-
|
|
136
|
-
- Pixel rows must match the declared width and height.
|
|
137
|
-
- Every symbol used by the pixel map must have a color in every palette.
|
|
138
|
-
- Colors use `#RGB` or `#RRGGBB`.
|
|
139
|
-
- Timeline stops are strictly increasing and range from 0 to 24 hours.
|
|
140
|
-
- Built-in scene IDs are reserved; community IDs must be unique.
|
|
141
|
-
- The runtime accepts declarative data only. Manifest data is validated and copied on registration; it cannot run scripts.
|
|
151
|
+
See the [Manifest v2 schema](schemas/scene-manifest.v2.schema.json), [Floating Island example](examples/scenes/floating-island.v2.json) and [scene authoring guide](docs/SCENE_PLUGINS.md). The v1 schema remains available for compatibility at [schemas/scene-manifest.v1.schema.json](schemas/scene-manifest.v1.schema.json).
|
|
142
152
|
|
|
143
|
-
|
|
153
|
+
Assets currently use native character pixel matrices; PNG/JPEG uploads and arbitrary executable plugin callbacks are not part of the current format.
|
|
144
154
|
|
|
145
|
-
The first manifest release focuses on palette-driven pixel worlds. Sprite assets, layered tile maps and declarative animation tracks are planned as compatible schema extensions rather than arbitrary executable plugin code.
|
|
146
155
|
|
|
147
156
|
## Configuration
|
|
148
157
|
|
|
@@ -251,35 +260,27 @@ For iOS, use `npm run mobile:ios:init` once and `npm run mobile:ios` for later s
|
|
|
251
260
|
```text
|
|
252
261
|
pixel-daylight-switch/
|
|
253
262
|
├── .github/workflows/ # CI, native mobile builds, npm publishing
|
|
254
|
-
├── assets/
|
|
255
|
-
|
|
256
|
-
├──
|
|
257
|
-
|
|
258
|
-
├── mobile/
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
├──
|
|
262
|
-
|
|
263
|
-
├──
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
├──
|
|
270
|
-
├──
|
|
271
|
-
├──
|
|
272
|
-
├──
|
|
273
|
-
├── preview.html # Component preview
|
|
274
|
-
├── playground.html # Interactive parameter lab
|
|
275
|
-
├── index.mjs / index.cjs # ESM and CommonJS package entry points
|
|
276
|
-
├── package.json # Package metadata and scripts
|
|
277
|
-
├── capacitor.config.json # Capacitor configuration
|
|
278
|
-
├── playwright.config.cjs # Browser test configuration
|
|
279
|
-
├── CHANGELOG.md
|
|
280
|
-
├── llms.txt
|
|
263
|
+
├── assets/ # Gallery artwork
|
|
264
|
+
├── builds/ # Mobile build notes
|
|
265
|
+
├── docs/ # Integration guides, scene guide, changelog
|
|
266
|
+
├── examples/scenes/ # Community scene manifests
|
|
267
|
+
├── mobile/ # Capacitor app shell
|
|
268
|
+
├── schemas/ # Manifest v1 and v2 JSON Schemas
|
|
269
|
+
├── scripts/ # Mobile preparation/version scripts
|
|
270
|
+
├── tests/ # Node and Chromium regression tests
|
|
271
|
+
├── app.js / style.css # Runtime and component styles
|
|
272
|
+
├── scene-plugin.js # Community scene registry and validator
|
|
273
|
+
├── embed.js # One-script website embed loader
|
|
274
|
+
├── index.html # Live demo
|
|
275
|
+
├── demos/ # Public parameter lab and preview pages
|
|
276
|
+
├── config/ # Tooling configuration
|
|
277
|
+
├── index.mjs / index.cjs # ESM and CommonJS package entry points
|
|
278
|
+
├── package.json # Package metadata and scripts
|
|
279
|
+
├── capacitor.config.json # Capacitor configuration
|
|
280
|
+
├── playwright.config.cjs # Browser test configuration
|
|
281
|
+
├── llms.txt # AI-readable project guide
|
|
281
282
|
├── LICENSE
|
|
282
|
-
└── README*.md
|
|
283
|
+
└── README*.md # English, Simplified Chinese and Japanese
|
|
283
284
|
```
|
|
284
285
|
|
|
285
286
|
## License
|
package/README.zh-CN.md
CHANGED
|
@@ -12,22 +12,22 @@
|
|
|
12
12
|
|
|
13
13
|
Pixel Daylight Switch 是一个可拖动的昼夜切换 UI 组件。拖动玻璃开关,可以让内部的像素世界从白天经过黄昏切换到夜晚。项目使用原生 JavaScript、WebGL2 和 Canvas 2D 回退渲染,不依赖第三方运行时库。
|
|
14
14
|
|
|
15
|
-
**[直接体验在线演示](https://gsvegetable.github.io/pixel-daylight-switch/)** · **[打开参数实验室](https://gsvegetable.github.io/pixel-daylight-switch/playground.html)** · **[npm 安装](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable)**
|
|
15
|
+
**[直接体验在线演示](https://gsvegetable.github.io/pixel-daylight-switch/)** · **[打开参数实验室](https://gsvegetable.github.io/pixel-daylight-switch/demos/playground.html)** · **[npm 安装](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable)**
|
|
16
16
|
|
|
17
17
|
## 快速入口
|
|
18
18
|
|
|
19
19
|
| 你想做什么 | 直接打开 |
|
|
20
20
|
| --- | --- |
|
|
21
21
|
| 体验昼夜开关 | [在线演示](https://gsvegetable.github.io/pixel-daylight-switch/) |
|
|
22
|
-
| 调整场景与视觉参数 | [交互式参数实验室](https://gsvegetable.github.io/pixel-daylight-switch/playground.html) |
|
|
23
|
-
| 查看组件预览 | [Preview 页面](https://gsvegetable.github.io/pixel-daylight-switch/preview.html) |
|
|
22
|
+
| 调整场景与视觉参数 | [交互式参数实验室](https://gsvegetable.github.io/pixel-daylight-switch/demos/playground.html) |
|
|
23
|
+
| 查看组件预览 | [Preview 页面](https://gsvegetable.github.io/pixel-daylight-switch/demos/preview.html) |
|
|
24
24
|
| 用一个脚本嵌入网站 | [嵌入加载器源码](embed.js) |
|
|
25
25
|
| 在 JavaScript 项目中使用 | [npm 包](https://www.npmjs.com/package/pixel-daylight-switch-gsvegetable) |
|
|
26
|
-
| React / Vue 接入示例 | [框架集成指南](INTEGRATIONS.md) |
|
|
26
|
+
| React / Vue 接入示例 | [框架集成指南](docs/INTEGRATIONS.md) |\n| 独立玻璃折射引擎 | [引擎文档](docs/GLASS_ENGINE.md) · [在线演示](https://gsvegetable.github.io/pixel-daylight-switch/demos/glass-engine.html) |
|
|
27
27
|
| 阅读核心实现 | [运行时 app.js](app.js) · [样式 style.css](style.css) |
|
|
28
28
|
| 获取移动端构建 | [构建说明与限制](builds/README.md) · [GitHub Actions 构建任务](https://github.com/GSvegetable/pixel-daylight-switch/actions/workflows/mobile-build.yml) |
|
|
29
29
|
| 查看自动化测试 | [CI 工作流](https://github.com/GSvegetable/pixel-daylight-switch/actions/workflows/ci.yml) |
|
|
30
|
-
| 查看版本变化 | [更新日志](CHANGELOG.md) |
|
|
30
|
+
| 查看版本变化 | [更新日志](docs/CHANGELOG.md) |
|
|
31
31
|
| 反馈问题 | [GitHub Issues](https://github.com/GSvegetable/pixel-daylight-switch/issues) |
|
|
32
32
|
|
|
33
33
|
## 功能特点
|
|
@@ -96,40 +96,61 @@ const PixelDaylightSwitch = require('pixel-daylight-switch-gsvegetable');
|
|
|
96
96
|
|
|
97
97
|
npm 包提供 ESM 和 CommonJS 入口,可在 SSR 环境中安全导入;只有在浏览器中且目标元素已经存在时,才能调用 `mount()`。npm 发布文件清单以 [package.json](package.json) 为准。
|
|
98
98
|
|
|
99
|
-
## 社区场景插件(v3.0.0)
|
|
100
99
|
|
|
101
|
-
|
|
100
|
+
## 独立玻璃折射引擎(v3.1.1)
|
|
102
101
|
|
|
103
|
-
|
|
102
|
+
这次升级把玻璃镜片从昼夜开关中独立出来。现在可以单独创建一层玻璃,不再受原开关的固定宽高比和尺寸限制;可分别设置宽度、高度、位置、圆角、折射、色散、边缘厚度和高光。支持 Canvas、图片、视频、ImageBitmap 或返回这些对象的函数作为背景源。查看[完整接入文档](docs/GLASS_ENGINE.md)和[在线调参演示](https://gsvegetable.github.io/pixel-daylight-switch/demos/glass-engine.html)。
|
|
104
103
|
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
PixelDaylightSwitch.registerScene(sceneManifest);
|
|
111
|
-
</script>
|
|
104
|
+
```js
|
|
105
|
+
import { createGlass } from 'pixel-daylight-switch-gsvegetable/glass-engine';
|
|
106
|
+
const glass = createGlass(container, { source: backgroundCanvas, width: '72%', height: 180, radius: 28 });
|
|
107
|
+
glass.setOptions({ refraction: 1.3, dispersion: 0.08 });
|
|
108
|
+
glass.destroy();
|
|
112
109
|
```
|
|
113
110
|
|
|
114
|
-
|
|
111
|
+
注意:浏览器不允许 WebGL 直接读取任意网页 DOM 像素。若要折射实时网页背景,宿主应用必须提供可采样的 Canvas / 渲染目标;跨域媒体还必须满足 CORS 要求。
|
|
112
|
+
|
|
113
|
+
## 社区场景
|
|
114
|
+
|
|
115
|
+
社区场景使用声明式 JSON Manifest,在组件挂载前注册。当前采用 **Manifest v2**,支持可复用像素素材、顺序图层和受限动画轨道,同时继续兼容已有的 Manifest v1 场景。
|
|
116
|
+
|
|
117
|
+
### 注册场景
|
|
118
|
+
|
|
119
|
+
在 npm 项目中:
|
|
115
120
|
|
|
116
121
|
```js
|
|
117
122
|
import PixelDaylightSwitch, { registerScene } from 'pixel-daylight-switch-gsvegetable';
|
|
118
|
-
import
|
|
123
|
+
import scene from './floating-island.v2.json';
|
|
119
124
|
|
|
120
|
-
const unregister = registerScene(
|
|
125
|
+
const unregister = registerScene(scene);
|
|
121
126
|
const root = document.querySelector('[data-ld-part="toggle-daylight"]');
|
|
122
|
-
root.dataset.scene =
|
|
127
|
+
root.dataset.scene = scene.id;
|
|
123
128
|
PixelDaylightSwitch.mount(root);
|
|
124
129
|
```
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
直接在浏览器中使用时,先加载 `scene-plugin.js`,再加载 `app.js`,并在挂载组件前注册 Manifest:
|
|
132
|
+
|
|
133
|
+
```html
|
|
134
|
+
<script src="https://gsvegetable.github.io/pixel-daylight-switch/scene-plugin.js"></script>
|
|
135
|
+
<script src="https://gsvegetable.github.io/pixel-daylight-switch/app.js"></script>
|
|
136
|
+
<div data-ld-part="toggle-daylight" data-scene="my-community-scene"></div>
|
|
137
|
+
<script>
|
|
138
|
+
PixelDaylightSwitchScenePlugins.registerScene(sceneManifest);
|
|
139
|
+
</script>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Manifest v2 能力
|
|
143
|
+
|
|
144
|
+
- 最多 24 个可复用字符像素素材、最多 16 个顺序合成图层。
|
|
145
|
+
- 图层使用整数场景坐标,后声明的图层显示在前面图层之上。
|
|
146
|
+
- 叠加素材中的点号 `.` 表示透明像素。
|
|
147
|
+
- 支持 `drift`(往返漂移)和 `bob`(正弦浮动)两种受限动画轨道,可沿水平或垂直方向运行。
|
|
148
|
+
- 继续兼容已有 v1 Manifest,原有五个内置场景保持不变。
|
|
149
|
+
|
|
150
|
+
查看 [Manifest v2 Schema](schemas/scene-manifest.v2.schema.json)、[Floating Island 分层场景示例](examples/scenes/floating-island.v2.json) 和[场景创作指南](docs/SCENE_PLUGINS.md)。为保证兼容性,原始 [v1 Schema](schemas/scene-manifest.v1.schema.json) 仍然保留。
|
|
127
151
|
|
|
128
|
-
|
|
129
|
-
- [Manifest v1 JSON Schema](schemas/scene-manifest.v1.schema.json)
|
|
130
|
-
- [樱花黄昏示例](examples/scenes/sakura-evening.json)
|
|
152
|
+
当前素材采用字符像素矩阵,不支持 PNG/JPEG 上传,也不会执行社区提交的任意脚本。
|
|
131
153
|
|
|
132
|
-
v1 暂不支持外部图片/Sprite、分层 Tile Map 和自定义动画轨道;这些能力会通过后续独立版本的 Schema 扩展,不会开放任意代码执行。五个内置场景仍保留原有绘制与动态逻辑。
|
|
133
154
|
|
|
134
155
|
## 配置参数
|
|
135
156
|
|
|
@@ -238,35 +259,27 @@ iOS 首次创建使用 `npm run mobile:ios:init`,后续使用 `npm run mobile:
|
|
|
238
259
|
```text
|
|
239
260
|
pixel-daylight-switch/
|
|
240
261
|
├── .github/workflows/ # CI、原生移动端构建、npm 发布
|
|
241
|
-
├── assets/
|
|
242
|
-
|
|
243
|
-
├──
|
|
244
|
-
|
|
245
|
-
├── mobile/
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
├──
|
|
249
|
-
|
|
250
|
-
├──
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
├──
|
|
257
|
-
├──
|
|
258
|
-
├──
|
|
259
|
-
├──
|
|
260
|
-
├── preview.html # 组件预览
|
|
261
|
-
├── playground.html # 交互式参数实验室
|
|
262
|
-
├── index.mjs / index.cjs # ESM 与 CommonJS 包入口
|
|
263
|
-
├── package.json # npm 元数据与脚本
|
|
264
|
-
├── capacitor.config.json # Capacitor 配置
|
|
265
|
-
├── playwright.config.cjs # 浏览器测试配置
|
|
266
|
-
├── CHANGELOG.md
|
|
267
|
-
├── llms.txt
|
|
262
|
+
├── assets/ # 场景展示图片
|
|
263
|
+
├── builds/ # 移动端构建说明
|
|
264
|
+
├── docs/ # 集成指南、场景创作指南、更新日志
|
|
265
|
+
├── examples/scenes/ # 社区场景 Manifest 示例
|
|
266
|
+
├── mobile/ # Capacitor 应用外壳
|
|
267
|
+
├── schemas/ # Manifest v1 / v2 JSON Schema
|
|
268
|
+
├── scripts/ # 移动端准备与版本脚本
|
|
269
|
+
├── tests/ # Node 与 Chromium 回归测试
|
|
270
|
+
├── app.js / style.css # 运行时与组件样式
|
|
271
|
+
├── scene-plugin.js # 场景注册与校验 API
|
|
272
|
+
├── embed.js # 网站单脚本嵌入加载器
|
|
273
|
+
├── index.html # 在线演示
|
|
274
|
+
├── demos/ # 参数实验室与组件预览页面
|
|
275
|
+
├── config/ # 工具配置
|
|
276
|
+
├── index.mjs / index.cjs # ESM / CommonJS 入口
|
|
277
|
+
├── package.json # 包元数据与脚本
|
|
278
|
+
├── capacitor.config.json # Capacitor 配置
|
|
279
|
+
├── playwright.config.cjs # 浏览器测试配置
|
|
280
|
+
├── llms.txt # 面向 AI 的项目说明
|
|
268
281
|
├── LICENSE
|
|
269
|
-
└── README*.md
|
|
282
|
+
└── README*.md # 英文、简体中文和日文 README
|
|
270
283
|
```
|
|
271
284
|
|
|
272
285
|
## 许可证
|
package/app.js
CHANGED
|
@@ -931,6 +931,7 @@ function mount(root) {
|
|
|
931
931
|
Object.keys(palette).forEach((symbol) => { colors[symbol.charCodeAt(0)] = parsePluginColor(palette[symbol]); });
|
|
932
932
|
return [name, colors];
|
|
933
933
|
})) : null;
|
|
934
|
+
let pluginAnimClock = 0;
|
|
934
935
|
const renderPluginWorld = (hour) => {
|
|
935
936
|
const stops = pluginScene.timeCycle;
|
|
936
937
|
let left = stops[0]; let right = stops[stops.length - 1]; let sampleHour = hour;
|
|
@@ -945,14 +946,43 @@ function mount(root) {
|
|
|
945
946
|
const aPalette = pluginPaletteRgb[left.palette];
|
|
946
947
|
const bPalette = pluginPaletteRgb[right.palette];
|
|
947
948
|
const width = pluginScene.canvas.width; const height = pluginScene.canvas.height;
|
|
949
|
+
let scenePixels = pluginScene.pixels;
|
|
950
|
+
if (pluginScene.schemaVersion === 2 && Array.isArray(pluginScene.layers)) {
|
|
951
|
+
const composed = pluginScene.pixels.map(row => row.split(''));
|
|
952
|
+
for (const layer of pluginScene.layers) {
|
|
953
|
+
const asset = pluginScene.assets[layer.asset];
|
|
954
|
+
const motion = layer.animation;
|
|
955
|
+
let dx = 0, dy = 0;
|
|
956
|
+
if (motion) {
|
|
957
|
+
const phase = pluginAnimClock * motion.speed + (motion.phase || 0);
|
|
958
|
+
const wave = motion.type === 'drift' ? (2 / Math.PI) * Math.asin(Math.sin(phase)) : Math.sin(phase);
|
|
959
|
+
const offset = wave * motion.distance;
|
|
960
|
+
if (motion.axis === 'x') dx = Math.round(offset);
|
|
961
|
+
else dy = Math.round(offset);
|
|
962
|
+
}
|
|
963
|
+
const originX = layer.x + dx, originY = layer.y + dy;
|
|
964
|
+
for (let sy = 0; sy < asset.height; sy++) {
|
|
965
|
+
const targetY = originY + sy;
|
|
966
|
+
if (targetY < 0 || targetY >= height) continue;
|
|
967
|
+
const row = asset.pixels[sy];
|
|
968
|
+
for (let sx = 0; sx < asset.width; sx++) {
|
|
969
|
+
const targetX = originX + sx;
|
|
970
|
+
if (targetX < 0 || targetX >= width) continue;
|
|
971
|
+
const symbol = row[sx];
|
|
972
|
+
if (symbol !== '.') composed[targetY][targetX] = symbol;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
scenePixels = composed.map(row => row.join(''));
|
|
977
|
+
}
|
|
948
978
|
const scale = Math.min(bw / width, bh / height);
|
|
949
979
|
const drawW = Math.max(1, Math.round(width * scale)); const drawH = Math.max(1, Math.round(height * scale));
|
|
950
980
|
const offsetX = Math.floor((bw - drawW) / 2); const offsetY = Math.floor((bh - drawH) / 2);
|
|
951
|
-
const background =
|
|
981
|
+
const background = scenePixels[0].charCodeAt(0);
|
|
952
982
|
for (let py = 0; py < bh; py++) {
|
|
953
983
|
const insideY = py >= offsetY && py < offsetY + drawH;
|
|
954
984
|
const sy = insideY ? clamp(Math.floor(((py - offsetY) / drawH) * height), 0, height - 1) : 0;
|
|
955
|
-
const row =
|
|
985
|
+
const row = scenePixels[sy];
|
|
956
986
|
for (let px = 0; px < bw; px++) {
|
|
957
987
|
const inside = insideY && px >= offsetX && px < offsetX + drawW;
|
|
958
988
|
const sx = inside ? clamp(Math.floor(((px - offsetX) / drawW) * width), 0, width - 1) : 0;
|
|
@@ -1083,7 +1113,7 @@ function mount(root) {
|
|
|
1083
1113
|
const pickKeys = (h) => { for (let i = 0; i < KEYS.length - 1; i++) { if (h >= KEYS[i][0] && h < KEYS[i + 1][0]) { keyA = i; keyB = i + 1; keyP = clamp(((h - KEYS[i][0]) / (KEYS[i + 1][0] - KEYS[i][0]) - 0.32) / 0.36); return; } } keyA = 0; keyB = 1; keyP = 0; };
|
|
1084
1114
|
const renderWorld = (clock, dt, hurry) => {
|
|
1085
1115
|
const h = hourOf(clock);
|
|
1086
|
-
if (pluginScene) { renderPluginWorld(h); return; }
|
|
1116
|
+
if (pluginScene) { if (!calm) pluginAnimClock += dt; renderPluginWorld(h); return; }
|
|
1087
1117
|
if (!calm) anim += dt; matBuf.set(baseBuf); varBuf.fill(0); emitList.length = 0;
|
|
1088
1118
|
for (const c of sources) { c.w = 0; c.x = 0; c.y = 0; }
|
|
1089
1119
|
lampFlick = calm ? 1 : 0.95 + 0.05 * Math.sin(anim * 13) * Math.sin(anim * 5.3);
|
package/browser.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import './glass-engine.js';
|
|
1
2
|
import './scene-plugin.js';
|
|
2
3
|
|
|
3
4
|
// Browser ESM consumers need to register their scene before mounting.
|
|
@@ -10,6 +11,7 @@ try {
|
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
const api = globalThis.PixelDaylightSwitch;
|
|
14
|
+
api.createGlass = globalThis.PixelGlassEngine.createGlass;
|
|
13
15
|
const scenes = globalThis.PixelDaylightSwitchScenePlugins;
|
|
14
16
|
export const mount = api.mount;
|
|
15
17
|
export const unmount = api.unmount;
|
|
@@ -18,3 +20,5 @@ export const validateScene = scenes.validateScene;
|
|
|
18
20
|
export const getScene = scenes.getScene;
|
|
19
21
|
export const listScenes = scenes.listScenes;
|
|
20
22
|
export default api;
|
|
23
|
+
|
|
24
|
+
export const createGlass = globalThis.PixelGlassEngine.createGlass;
|