Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ pubspec.lock
# If you don't generate documentation locally you can remove this line.
doc/api/

# Coverage output
/coverage/

# dotenv environment variables file
.env*

Expand Down
31 changes: 27 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,29 @@
## 0.1.0

Complete rewrite — `wave_screen` is now a composable, GPU-shader-driven wave
library. **Breaking:** the entire public API changed and the `WaveSkeletonizer`
module was removed.

### Added

- Composable `Wave` built from swappable traits: `WaveShape`, `WaveStyle`,
`WaveMotion`, and `WaveEffect`.
- `WaveShape.sine`, `WaveShape.gerstner` (sharpened ocean crests), and
`WaveShape.metaball` (gooey merging blobs) — each a pure, testable height field
mirrored by the fragment shader.
- `WaveMotion.drift`, `WaveMotion.pingPong` (smooth oscillation), and
`WaveMotion.still`.
- `WaveField` — GPU fragment-shader compositor with a CPU fallback.
- `PointerRippleEffect` + interactive `WaveField`: taps and drags spawn ripples
that displace the surface, with an `onRipple` callback.
- `WaveScreen` + a broad `WavePresets` gallery (14 curated presets including the
classic `violet` theme, reachable via `WavePresets.byName` / `.all`).

### Removed

- `WaveSkeletonizer` and the `skeletonizer` dependency.
- The previous `Wave`/`WaveScreen` recipe/adaptation/palette API.

## 0.0.1

- Initial release of `wave_screen`.
- Added the public `Wave`, `WaveScreen`, and `WaveSkeletonizer` exports.
- Added geometry-aware skeletonizer effects, including the tide-pool style ping-pong wave behavior.
- Added the example application and GitHub Pages workflow for publishing the web demo.
- Initial release of `wave_screen` (legacy API).
119 changes: 94 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,112 @@
# wave-screen
# wave_screen

[![Deploy Example To GitHub Pages](https://github.com/Pathverse/wave-screen/actions/workflows/deploy-example-pages.yml/badge.svg)](https://github.com/Pathverse/wave-screen/actions/workflows/deploy-example-pages.yml)

`wave_screen` is a Flutter package for animated wave-driven UI surfaces. It currently exports three main pieces:
`wave_screen` renders **composable, GPU-shader-driven animated wave surfaces** for
Flutter. A `Wave` is built from swappable traits — a **shape** (geometry), a
**style** (appearance), a **motion** (time evolution), and optional **effects**
(interaction) — and composited on the GPU via a fragment shader (with a CPU
fallback so it never blanks).

- `Wave` for standalone animated wave treatments.
- `WaveScreen` for layered screen backgrounds and surface styling.
- `WaveSkeletonizer` for geometry-aware loading states, including the tide-pool style ping-pong effect used in the example app.
## Install

## Package Exports
```yaml
dependencies:
wave_screen: ^0.1.0
```

The public entrypoint is [lib/wave_screen.dart](lib/wave_screen.dart), which exports:
## Quick start

- [lib/src/wave/wave.dart](lib/src/wave/wave.dart)
- [lib/src/screen/screen.dart](lib/src/screen/screen.dart)
- [lib/src/skeletonizer.dart](lib/src/skeletonizer.dart)
Drop in a curated preset as a full-bleed background:

## Run The Example Locally
```dart
import 'package:wave_screen/wave_screen.dart';

From the repository root:
WaveScreen(preset: WavePresets.ocean);
```

```bash
cd example
flutter pub get
flutter run -d chrome
Or compose a field from raw traits:

```dart
WaveField(
waves: [
Wave(
shape: WaveShape.gerstner(amplitude: 0.06, frequency: 1.0, steepness: 1.1),
style: const WaveStyle(fill: Color(0xFF2384A0)),
motion: WaveMotion.drift(speed: 0.3),
),
Wave(
shape: WaveShape.metaball(blobCount: 4, radius: 0.2, amplitude: 0.12),
style: const WaveStyle(fill: Color(0xFF57C4D6)),
motion: WaveMotion.pingPong(sway: 1.2, period: 6),
),
],
);
```

## The trait model

| Trait | Options |
|---|---|
| `WaveShape` | `.sine(amplitude, frequency, baseline)` · `.gerstner(…, steepness)` (sharpened ocean crests) · `.metaball(blobCount, radius, amplitude)` (gooey merging blobs) |
| `WaveStyle` | `WaveStyle(fill: Color, opacity)` |
| `WaveMotion` | `.drift(speed)` · `.pingPong(sway, period)` (smooth back-and-forth) · `.still()` |
| `WaveEffect` | `PointerRippleEffect(strength, decay, speed, wavelength)` |

Every shape is a pure height field: `shape.sampleAt(x, phase)` (and
`wave.heightAt(x, t)`) returns the exact value the shader renders, so behavior is
testable without a GPU.

## Interaction

Give any wave a `PointerRippleEffect` and its enclosing `WaveField` becomes
interactive — taps and drags send ripples across the surface:

```dart
WaveField(
waves: [
Wave(
shape: WaveShape.sine(amplitude: 0.05, frequency: 0.9),
style: const WaveStyle(fill: Color(0xFF1C6E8C)),
motion: WaveMotion.drift(speed: 0.25),
effects: const [PointerRippleEffect()],
),
],
onRipple: (normalizedPosition) { /* optional */ },
);
```

## GitHub Pages Example
## Presets

The example app in [example](example) is deployed to GitHub Pages through [.github/workflows/deploy-example-pages.yml](.github/workflows/deploy-example-pages.yml).
`WavePresets` ships a broad curated gallery — sine, Gerstner and metaball themes
plus interactive presets. Access them by name:

- Trigger: push to `main` or manual `workflow_dispatch`
- Build target: `example/build/web`
- Published URL: `https://pathverse.github.io/wave-screen/`
```dart
WaveScreen(preset: WavePresets.byName['tidepool']!);

for (final preset in WavePresets.all) { /* … */ }
```

Before the first deployment, set the repository Pages source to `GitHub Actions` in the GitHub repository settings.
Themes include `aurora`, `violet`, `dusk`, `sunset`, `neon`, `mist`, `abyss`,
`ocean`, `lagoon`, `ember`, `jelly`, `lava`, `tidepool`, and `pulse`.

## Rendering

Waves render on the GPU through `shaders/wave.frag`. If the shader cannot be
loaded (some platforms, or a stale build) the widget transparently falls back to
an equivalent CPU painter, so the surface always shows.

## Run the example

```bash
cd example
flutter pub get
flutter run -d chrome
```

## Development Notes
The example is a gallery of the milestones: **Foundation**, **Shapes**,
**Interaction**, and the full **Preset Gallery**.

- The example depends on the local package by path, so build and deployment should always run from [example/pubspec.yaml](example/pubspec.yaml).
- The Pages workflow passes `--base-href "/wave-screen/"` so the Flutter web build serves correctly from the repository subpath.
## License

Apache-2.0. See [LICENSE](LICENSE).
106 changes: 106 additions & 0 deletions REVAMP_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# wave_screen — Revamp Plan (v0.1.0, breaking)

> Durable decision record for the complete revamp of `wave_screen`.
> Reference (old): `../wave-screen`. New implementation: this repo (`wave-screen-2`).
> Built under Pathverse **flow-v1b** governance. This document is the pre-Phase-1
> scope lock; it is the source of truth for reconstructing the decisions below.

## Governance

- Constitution: pathverse-agent-governance `docs/constitution.md` (factors 2,3,7,8,10,12).
- Flow: `CLARIFY (BDD) → IMPLEMENT (TDD) → STRUCTURE → COVERAGE → COMMIT (zmem)`.
- Stack: `dart-flutter` (skills: `good-bdd-dart-flutter`, `good-tdd-dart-flutter`).
- Behavior is proven by behave scenarios bound to Flutter integration proofs
(`@proof:<id>` ↔ `proof_<id>`-tagged tests), never by inspecting source text.

## Locked decisions (from scope-lock Q&A)

1. **Rendering engine:** GPU **fragment shader** (`FragmentProgram`). The shader
receives uniforms (time, resolution, per-layer shape params, pointer) and
evaluates a per-pixel height field → SDF fill. Metaball/gooey and Gerstner are
natural fits; pointer ripple = extra uniforms.
2. **Public API model:** maximum granularity — a **`Wave` is an object composed of
swappable traits**: `WaveShape` (geometry), `WaveStyle` (appearance),
`WaveMotion` (time evolution), `List<WaveEffect>` (interaction/decoration).
3. **Compatibility:** clean-slate, breaking. No back-compat with old API.
4. **Module scope:** `Wave` + `WaveScreen` revamped. **`WaveSkeletonizer` REMOVED**
(no adoption) — delete `lib/src/skeletonizer/*`, its export, the `skeletonizer`
dependency, and its example pages/tests.
5. **New visual capabilities (all in scope):** expanded named preset library,
gooey/metaball waves, pointer-interactive ripples, Gerstner/realistic ocean.
6. **Naming vocabulary (confirmed):** `Wave`, `WaveShape`, `WaveStyle`,
`WaveMotion`, `WaveEffect`, `WaveField`, `WaveScreen`.
7. **Execution:** milestone-by-milestone. Each milestone passes the FULL governance
gate (scenarios → TDD → structure → coverage → zmem commit) and stops for review
before the next.
8. **Example requirement:** every milestone **appends a full showcase** to the
example app (cumulative, never replacing prior showcases) demonstrating that
milestone's capabilities running live. This is a per-milestone exit criterion.

## Target public API (illustrative)

```dart
class Wave {
final WaveShape shape;
final WaveStyle style;
final WaveMotion motion;
final List<WaveEffect> effects;
}

// SHAPE — height-field generator fed to the shader
WaveShape.sine({layers, amplitude, frequency, ...}); // current-style look
WaveShape.gerstner({steepness, wavelength, ...}); // realistic ocean (M2)
WaveShape.metaball({blobs, radius, gooeyness, ...}); // gooey/fluid (M2)

// STYLE — pure appearance
WaveStyle({fill: Color|Gradient, stroke?, blur?, crestHighlight?, opacity});

// MOTION — time evolution
WaveMotion.drift({speed, direction});
WaveMotion.pingPong({period, pause});
WaveMotion.still();

// EFFECTS — composable overlays (M3)
PointerRippleEffect({strength, decay});
FoamEffect({...});

// Widgets
WaveField(waves: [Wave(...), ...]); // composites via shader
WaveScreen(preset: WavePresets.lagoon); // curated arrangement
WaveScreen(background: ..., waves: [Wave(...), ...]); // full control
```

## Proposed module structure

```
lib/wave_screen.dart → public exports (Wave, traits, WaveField, WaveScreen, presets)
lib/src/wave/ → Wave object + trait types + WaveField widget
lib/src/wave/shader/ → .frag source + FragmentProgram loader/uniform packing
lib/src/screen/ → WaveScreen widget + WavePresets
shaders/ → compiled shader assets (pubspec `flutter: shaders:`)
```

## Milestones

Each milestone = full governance flow + appended example showcase + zmem commit.

- **M1 Foundation** — shader core + trait model (`Wave`, `WaveShape.sine`,
`WaveStyle`, `WaveMotion.drift`/`still`), `WaveField`, `WaveScreen` with a few
presets. Reaches parity with today's Wave/WaveScreen, on GPU. Remove the
skeletonizer module + dependency. Example: append a "Foundation" showcase page.
- **M2 Shapes** — add `WaveShape.gerstner` + `WaveShape.metaball` (gooey).
Example: append a "Shapes" showcase.
- **M3 Interaction** — pointer ripple + `WaveEffect` system + `WaveMotion.pingPong`.
Example: append an "Interaction" showcase.
- **M4 Presets & release** — expanded `WavePresets` library, docs, README/CHANGELOG,
publish prep. Example: append a "Preset Gallery" showcase.

## Open implementation risks (resolved during build, not now)

- Uniform-count vs. layer-count limits → may need multi-pass draws or texture-packed
params. Decided in M1 IMPLEMENT.
- Fragment-shader availability/fallback on all targets (web/Impeller vs others) →
confirm during M1; the reference already disabled blur on web, so web parity is a
known sensitivity.
- behave→Flutter proof harness bring-up (no `.zmem`/behave scaffold exists yet) →
established in M1 CLARIFY.
10 changes: 10 additions & 0 deletions dart_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tags:
proof_wave_field_renders_and_animates:
proof_wave_traits_drive_surface:
proof_wave_screen_preset_renders:
proof_gerstner_sharpens_crest:
proof_metaball_blobs_merge:
proof_pingpong_reverses:
proof_ripple_decays_and_propagates:
proof_pointer_spawns_ripple:
proof_preset_gallery_is_valid:
Loading
Loading