partforge 0.48.0 → 0.50.0

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/types/index.d.ts CHANGED
@@ -146,8 +146,13 @@ export interface CaptureViewOptions {
146
146
  export type AnimationStatus = "idle" | "intro" | "playing" | "paused";
147
147
 
148
148
  export interface AnimationState {
149
- /** The selected animation's key. */
150
- animation: string;
149
+ /** The active view (tab) name — animations belong to a view. */
150
+ view: string;
151
+ /**
152
+ * The selected animation's key, or `null` while the active view declares no
153
+ * animations. Switching views re-selects that view's first animation.
154
+ */
155
+ animation: string | null;
151
156
  status: AnimationStatus;
152
157
  /** Position on the timeline, 0..1 over the animation's total duration. */
153
158
  t: number;
@@ -158,12 +163,16 @@ export interface AnimationState {
158
163
  /**
159
164
  * Part-declared animation playback — the same engine the viewer's transport bar
160
165
  * drives. Playback writes real params, so exporting while paused exports the
161
- * posed state, and any user or host param edit pauses it.
166
+ * posed state, and any user or host param edit pauses it. An animation's
167
+ * `opacity` tracks are the exception: display-only, never written to params and
168
+ * never visible to export.
162
169
  */
163
170
  export interface AnimationRuntime {
164
171
  /**
165
- * Play, optionally switching to a named animation first. An unknown name
166
- * warns and does nothing rather than playing whatever is selected.
172
+ * Play, optionally switching to a named animation first. The name resolves
173
+ * within the ACTIVE view an animation declared by another view is not
174
+ * playable from here. An unknown name warns and does nothing rather than
175
+ * playing whatever is selected.
167
176
  */
168
177
  play(name?: string): void;
169
178
  pause(): void;
@@ -239,8 +248,9 @@ export interface PartRuntime {
239
248
  */
240
249
  setHostPane(pane: HostPane): void;
241
250
  /**
242
- * Part-declared animation playback, or `null` when the part declares no
243
- * `animations` block.
251
+ * Part-declared animation playback, or `null` when NO view declares an
252
+ * `animations` block. Non-null while any view does — including while the
253
+ * active view has none, where `state().animation` reads `null`.
244
254
  */
245
255
  animation: AnimationRuntime | null;
246
256
  }
package/types/part.d.ts CHANGED
@@ -308,6 +308,14 @@ export interface SubPartDefinition<P = ResolvedParams, D = Derived> {
308
308
 
309
309
  export interface ViewDefinition {
310
310
  label: string;
311
+ /**
312
+ * Named animations belonging to this view — keyframe data driving this view's
313
+ * params and sub-part opacity over time. See `AnimationSpec` below; the
314
+ * transport bar shows one view's animations at a time, and `play(name)`
315
+ * resolves within the active view. Animations live ONLY here: a top-level
316
+ * `part.animations` is a lint error and is ignored at runtime.
317
+ */
318
+ animations?: Record<string, AnimationSpec>;
311
319
  }
312
320
 
313
321
  // --- the verify block -------------------------------------------------------
@@ -430,12 +438,20 @@ export interface AnimationStep {
430
438
  /**
431
439
  * Param key -> keyframes. A param tracked nowhere keeps its current value.
432
440
  *
433
- * Optional so a step can move only the camera — an establishing shot that
434
- * holds the pose while the view swings round. `partforge lint` still requires
435
- * that at least one step in the animation carries tracks, which is a
436
- * whole-animation rule the type system can't express per step.
441
+ * Optional so a step can carry only `opacity`, or move only the camera — an
442
+ * establishing shot that holds the pose while the view swings round.
443
+ * `partforge lint` still requires that at least one step in the animation
444
+ * carries `tracks` or `opacity`, which is a whole-animation rule the type
445
+ * system can't express per step.
437
446
  */
438
447
  tracks?: Record<string, Keyframes>;
448
+ /**
449
+ * Sub-part name → opacity keyframes (values 0–1; 0 = fully hidden, mesh and
450
+ * edge lines both; multiplies any static `display.opacity`). Same keyframe
451
+ * rules as `tracks`; the same hold rule applies across steps. Display-only:
452
+ * never affects params, export, measure, or verify.
453
+ */
454
+ opacity?: Record<string, Keyframes>;
439
455
  /** Swing the camera to this angle when the step begins. */
440
456
  camera?: CameraCue;
441
457
  }
@@ -460,7 +476,7 @@ export interface AnimationSpecCommon {
460
476
  /**
461
477
  * Start this animation automatically on first show and again on each view
462
478
  * switch, until the user touches the transport. At most one animation per
463
- * part may set this; `partforge lint` enforces it
479
+ * VIEW may set this; `partforge lint` enforces it
464
480
  * (`animation-autoplay-invalid`). Not armed when the browser reports
465
481
  * `prefers-reduced-motion: reduce`.
466
482
  */
@@ -468,10 +484,12 @@ export interface AnimationSpecCommon {
468
484
  }
469
485
 
470
486
  /**
471
- * An animation is EITHER single-phase (`tracks` + `duration`) OR stepped
472
- * (`steps`) — never both, never neither. `partforge lint` enforces that
473
- * (`animation-tracks-or-steps`), and the union says the same thing, so a block
474
- * carrying both is rejected before it ever reaches lint.
487
+ * An animation is EITHER single-phase (`tracks` and/or `opacity`, plus a
488
+ * `duration`) OR stepped (`steps`) — never both, never neither. `partforge
489
+ * lint` enforces that (`animation-tracks-or-steps`), and the union says the
490
+ * same thing, so a block carrying both is rejected before it ever reaches lint.
491
+ * The first two arms are the two ways to satisfy "at least one of
492
+ * `tracks`/`opacity`".
475
493
  */
476
494
  export type AnimationSpec =
477
495
  | (AnimationSpecCommon & {
@@ -479,12 +497,22 @@ export type AnimationSpec =
479
497
  duration: number;
480
498
  /** Param key -> keyframes. */
481
499
  tracks: Record<string, Keyframes>;
500
+ /** Sub-part name -> opacity keyframes (see AnimationStep.opacity). */
501
+ opacity?: Record<string, Keyframes>;
502
+ steps?: never;
503
+ })
504
+ | (AnimationSpecCommon & {
505
+ duration: number;
506
+ tracks?: Record<string, Keyframes>;
507
+ /** An opacity-only animation is legal — a pure fade. */
508
+ opacity: Record<string, Keyframes>;
482
509
  steps?: never;
483
510
  })
484
511
  | (AnimationSpecCommon & {
485
512
  /** The multi-step form; each step carries its own relative `duration`. */
486
513
  steps: AnimationStep[];
487
514
  tracks?: never;
515
+ opacity?: never;
488
516
  duration?: never;
489
517
  });
490
518
 
@@ -510,10 +538,8 @@ export interface PartDefinition<P = ResolvedParams, D = Derived> {
510
538
  derive?: DeriveSpec<P, D>;
511
539
  /** Named sub-parts; each builds exactly one solid. */
512
540
  parts: Record<string, SubPartDefinition<P, D>>;
513
- /** The view tabs. A view is a set of sub-parts. */
541
+ /** The view tabs. A view is a set of sub-parts, and owns its own `animations`. */
514
542
  views: Record<string, ViewDefinition>;
515
543
  /** Self-verification, co-located with the schema. */
516
544
  verify?: VerifyBlock<P, D>;
517
- /** Named animations: keyframe data driving existing params over time. */
518
- animations?: Record<string, AnimationSpec>;
519
545
  }
@@ -358,5 +358,13 @@ export function renderViews(
358
358
  size?: [number, number];
359
359
  edges?: boolean;
360
360
  params?: ResolvedParams;
361
+ /** Frame suffix in the written filename (`<part>-<view>-<angle>-<tag>.png`). */
362
+ tag?: string;
363
+ /**
364
+ * Per-sub-part opacity, keyed by sub-part name (an animation `evaluate()`
365
+ * result). `0` omits the sub-part entirely; `0 < v < 1` fades it toward the
366
+ * background. Absent keys render solid.
367
+ */
368
+ opacity?: Record<string, number>;
361
369
  },
362
370
  ): Promise<string[]>;