@dreamboard-games/sdk 0.5.0-alpha.13 → 0.5.0-alpha.15
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.md +3 -1
- package/dist/{chunk-6ZNAIOYG.js → chunk-TJQTLYDI.js} +5 -4
- package/dist/index.d.ts +117 -1
- package/dist/index.js +151 -1
- package/dist/index.js.map +1 -1
- package/dist/reducer.js +20 -10
- package/dist/reducer.js.map +1 -1
- package/dist/testing.js +1 -1
- package/package.json +1 -1
- /package/dist/{chunk-6ZNAIOYG.js.map → chunk-TJQTLYDI.js.map} +0 -0
package/README.md
CHANGED
|
@@ -352,7 +352,9 @@ the application bundler resolves its supported React subscription dependencies.
|
|
|
352
352
|
`dragFeature`, export `useCardGesture`, `useActiveCard`, `useDropArea` and `useDragOverlay` from the
|
|
353
353
|
binding, and use the copied Hand and BoardTargets components or your own renderer.
|
|
354
354
|
The SDK prescribes no layout. Headless `game.drag` remains browser-free and handles
|
|
355
|
-
atomic domain routing. `fanLayout` computes arc positions for a hand,
|
|
355
|
+
atomic domain routing. `fanLayout` computes arc positions for a hand,
|
|
356
|
+
`handFan` adds a focused, readable card with configurable presets and timing,
|
|
357
|
+
and
|
|
356
358
|
`originsFeature` adds `card.getOrigin()` so a newly shown card can animate from
|
|
357
359
|
the zone or player it came from.
|
|
358
360
|
|
|
@@ -7098,14 +7098,15 @@ export {
|
|
|
7098
7098
|
isSparseMapSchema,
|
|
7099
7099
|
getObjectShape,
|
|
7100
7100
|
normalizeCommandParams,
|
|
7101
|
+
enumerateZoneHosts,
|
|
7102
|
+
resolveZoneAccess,
|
|
7103
|
+
assertContainmentAcyclic,
|
|
7104
|
+
assertZoneConsistency,
|
|
7101
7105
|
REDUCER_CONTRACT_VERSION,
|
|
7102
7106
|
assertReducerBundleContract,
|
|
7103
7107
|
ZoneVisibilitySchema,
|
|
7104
7108
|
TileTypeSpecSchema,
|
|
7105
7109
|
GameTopologyManifestSchema,
|
|
7106
|
-
enumerateZoneHosts,
|
|
7107
|
-
assertContainmentAcyclic,
|
|
7108
|
-
assertZoneConsistency,
|
|
7109
7110
|
collectReducerDefinitionIndex,
|
|
7110
7111
|
createIngressRuntimeCodec,
|
|
7111
7112
|
noopDiagnosticsSink,
|
|
@@ -7122,4 +7123,4 @@ export {
|
|
|
7122
7123
|
createProjectionBuilder,
|
|
7123
7124
|
createReducerBundle
|
|
7124
7125
|
};
|
|
7125
|
-
//# sourceMappingURL=chunk-
|
|
7126
|
+
//# sourceMappingURL=chunk-TJQTLYDI.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1500,6 +1500,122 @@ declare function fanLayout({ count, width, cardWidth, cardHeight, step, minStep,
|
|
|
1500
1500
|
/** Moves a fanned card outward along its own tilt, as for a selected card. */
|
|
1501
1501
|
declare function liftFanCard(card: FanCard, distance: number): FanCard;
|
|
1502
1502
|
|
|
1503
|
+
/**
|
|
1504
|
+
* How a hand rests and focuses one card. Lengths are shares of the resting
|
|
1505
|
+
* card, so one configuration fits every card size. Missing options come from
|
|
1506
|
+
* `handFanPresets.open`.
|
|
1507
|
+
*/
|
|
1508
|
+
interface HandFanOptions extends Pick<FanOptions, "angle" | "maxSpread"> {
|
|
1509
|
+
/** Distance between neighbouring cards when there is room, in card widths. Default 0.6, as `fanLayout`. */
|
|
1510
|
+
readonly spacing?: number;
|
|
1511
|
+
/** Share of each resting card's height below the hand's bottom edge. 0 shows whole cards. */
|
|
1512
|
+
readonly tuck?: number;
|
|
1513
|
+
/** Focused face width as a multiple of the resting card. */
|
|
1514
|
+
readonly focusScale?: number;
|
|
1515
|
+
/** Tallest focused face, as a share of the window height. */
|
|
1516
|
+
readonly focusMaxHeight?: number;
|
|
1517
|
+
/**
|
|
1518
|
+
* Sideways shift of the first, second, third… neighbour, in card widths.
|
|
1519
|
+
* The focused face's extra width tapers over the same neighbours.
|
|
1520
|
+
*/
|
|
1521
|
+
readonly push?: readonly number[];
|
|
1522
|
+
/** Narrowest strip of each neighbour kept visible, in card widths. */
|
|
1523
|
+
readonly exposed?: number;
|
|
1524
|
+
}
|
|
1525
|
+
/** Starting points for a hand; spread one and override what differs. */
|
|
1526
|
+
declare const handFanPresets: {
|
|
1527
|
+
/** Whole resting cards; focusing enlarges the card. */
|
|
1528
|
+
readonly open: {
|
|
1529
|
+
readonly tuck: 0;
|
|
1530
|
+
readonly focusScale: 2;
|
|
1531
|
+
readonly focusMaxHeight: 0.55;
|
|
1532
|
+
readonly push: readonly [0.29, 0.19, 0.1];
|
|
1533
|
+
readonly exposed: 0.35;
|
|
1534
|
+
};
|
|
1535
|
+
/**
|
|
1536
|
+
* Larger cards tucked below the bottom edge and spaced like a dealt hand;
|
|
1537
|
+
* focusing mostly reveals the card.
|
|
1538
|
+
*/
|
|
1539
|
+
readonly tucked: {
|
|
1540
|
+
readonly spacing: 0.75;
|
|
1541
|
+
readonly tuck: 0.4;
|
|
1542
|
+
readonly focusScale: 1.4;
|
|
1543
|
+
readonly focusMaxHeight: 0.4;
|
|
1544
|
+
readonly push: readonly [0.29, 0.19, 0.1];
|
|
1545
|
+
readonly exposed: 0.35;
|
|
1546
|
+
};
|
|
1547
|
+
/** Coarse pointers: a shallower tuck and wider strips to tap. */
|
|
1548
|
+
readonly touch: {
|
|
1549
|
+
readonly spacing: 0.75;
|
|
1550
|
+
readonly tuck: 0.2;
|
|
1551
|
+
readonly focusScale: 1.6;
|
|
1552
|
+
readonly focusMaxHeight: 0.5;
|
|
1553
|
+
readonly push: readonly [0.35, 0.2, 0.1];
|
|
1554
|
+
readonly exposed: 0.45;
|
|
1555
|
+
};
|
|
1556
|
+
};
|
|
1557
|
+
/** A card's `fanLayout` pose with its scale and stacking order. */
|
|
1558
|
+
interface HandFanPose extends FanCard {
|
|
1559
|
+
readonly scale: number;
|
|
1560
|
+
/** Stacking order: fan order, with the focused card above the rest. */
|
|
1561
|
+
readonly layer: number;
|
|
1562
|
+
}
|
|
1563
|
+
interface HandFan {
|
|
1564
|
+
/** One pose per card, in the same coordinates as `fanLayout`. */
|
|
1565
|
+
readonly cards: readonly HandFanPose[];
|
|
1566
|
+
/** The fan's width, as `fanLayout` reports it. */
|
|
1567
|
+
readonly width: number;
|
|
1568
|
+
/** The visible band: the fan's height less the tucked part of its cards. */
|
|
1569
|
+
readonly height: number;
|
|
1570
|
+
/** Space above the band that a focused face can rise into. */
|
|
1571
|
+
readonly headroom: number;
|
|
1572
|
+
}
|
|
1573
|
+
interface HandFanInput extends Pick<FanOptions, "count" | "width" | "cardWidth" | "cardHeight"> {
|
|
1574
|
+
/** Index of the focused card, or -1 for none. */
|
|
1575
|
+
readonly focused?: number;
|
|
1576
|
+
/**
|
|
1577
|
+
* The part of the fan the viewer can see after scrolling, in fan
|
|
1578
|
+
* coordinates; a focused face stays inside it. Defaults to `width`,
|
|
1579
|
+
* centred on the fan.
|
|
1580
|
+
*/
|
|
1581
|
+
readonly visible?: {
|
|
1582
|
+
readonly left: number;
|
|
1583
|
+
readonly width: number;
|
|
1584
|
+
};
|
|
1585
|
+
/** Window height in pixels; `focusMaxHeight` is a share of it. */
|
|
1586
|
+
readonly windowHeight?: number;
|
|
1587
|
+
/** Pixels above the band's bottom edge that a focused face may use. */
|
|
1588
|
+
readonly room?: number;
|
|
1589
|
+
readonly options?: HandFanOptions;
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Lays a hand on a `fanLayout` arc and focuses one card: upright on the
|
|
1593
|
+
* band's bottom edge at a readable size, with nearby cards pushed sideways.
|
|
1594
|
+
* Neighbours keep their order and at least their `exposed` strip.
|
|
1595
|
+
*/
|
|
1596
|
+
declare function handFan({ count, width, cardWidth, cardHeight, focused, visible, windowHeight, room, options, }: HandFanInput): HandFan;
|
|
1597
|
+
/**
|
|
1598
|
+
* An exponential approach to the target. An animation restarted from the
|
|
1599
|
+
* current pose continues the same curve at full speed, so retargeting never
|
|
1600
|
+
* stalls a card or overshoots.
|
|
1601
|
+
*/
|
|
1602
|
+
declare function exponentialOut(progress: number): number;
|
|
1603
|
+
/** Durations in seconds with an easing function, as Motion transitions take them. */
|
|
1604
|
+
declare const handFanTiming: {
|
|
1605
|
+
/** The focused face rises: 90% in about 45ms. */
|
|
1606
|
+
readonly focus: {
|
|
1607
|
+
readonly duration: 0.09;
|
|
1608
|
+
readonly ease: typeof exponentialOut;
|
|
1609
|
+
};
|
|
1610
|
+
/** Sideways travel, neighbours and returning cards: 90% in about 300ms. */
|
|
1611
|
+
readonly settle: {
|
|
1612
|
+
readonly duration: 0.6;
|
|
1613
|
+
readonly ease: typeof exponentialOut;
|
|
1614
|
+
};
|
|
1615
|
+
};
|
|
1616
|
+
/** An easing function as a CSS `linear()` easing, for CSS transitions and the Web Animations API. */
|
|
1617
|
+
declare function cssEasing(ease: (progress: number) => number, samples?: number): string;
|
|
1618
|
+
|
|
1503
1619
|
declare function canonicalizePluginRuntimeJson(value: unknown): RuntimeJson;
|
|
1504
1620
|
declare function encodeCanonicalPluginRuntimeJson(value: unknown): string;
|
|
1505
1621
|
declare function digestPluginRuntimeJson(value: unknown): string;
|
|
@@ -4755,4 +4871,4 @@ declare function parsePluginGameplayFrame(value: unknown): PluginGameplayFrame;
|
|
|
4755
4871
|
declare function parseHostToPluginEnvelope(value: unknown): PluginProtocolEnvelope<HostToPluginPayload>;
|
|
4756
4872
|
declare function parsePluginToHostEnvelope(value: unknown): PluginProtocolEnvelope<PluginToHostPayload>;
|
|
4757
4873
|
|
|
4758
|
-
export { ActionProps, type ActionSetVersionInput, AmbiguousTargetError, AuthAcceptedFrameSchema, AuthConnectFrameSchema, AuthRefreshFrameSchema, BoardBase, BoardCollection, BoardDataOf, BoardEdgeId, type BoardFeature, type BoardLayoutOptions, type BoardLayoutTile, BoardSpace, BoardSpaceCollection, BoardVertexId, type CancelInteractionCommand, CancelInteractionCommandSchema, Card, type CardOrigin, type ClientGameplayFrame, ClientGameplayFrameSchema, CommandSource, CoreInstance, DREAMBOARD_PLUGIN_PROTOCOL, DREAMBOARD_PLUGIN_PROTOCOL_VERSION, DREAMBOARD_SDK_PACKAGES, DREAMBOARD_SDK_PACKAGE_SET, DREAMBOARD_SDK_VERSION, type DragController, type DragState, type DreamboardSdkPackageName, type DreamboardSdkPackageSet, DropTarget, type FanCard, type FanLayout, type FanOptions, FeatureContext, Features, GESTURE_THRESHOLDS, GameEventDetailSchema, GameEventSchema, GameInstance, GameOutcomeSchema, GameSource, GameplayBackpressureFrameSchema, GameplayBackpressureOperationSchema, GameplayBackpressureReasonSchema, GameplayBasis, GameplayBasisSchema, GameplayCloseCode, type GameplayCredential, GameplayCredentialSchema, type GestureCallbacks, type GestureKind, type GestureOptions, type GesturePointer, type GestureRecognizer, type HandOptions, type HostToPluginEnvelope, HostToPluginEnvelopeSchema, type HostToPluginPayload, HostToPluginPayloadSchema, IdOf, InstanceOptions, InteractionDescriptor, type InteractionResult, InteractionResultSchema, type MaterializePluginGameplayFrameInput, type PanZoomOptions, PlayerId, PluginGameplayFrame, PluginGameplayFrameSchema, PluginPlayerSummarySchema, type PluginProtocolEnvelope, PluginSessionDescriptor, PluginSessionDescriptorSchema, type PluginToHostEnvelope, PluginToHostEnvelopeSchema, type PluginToHostPayload, PluginToHostPayloadSchema, ReducerSeatProjectionBundle, RuntimeJson, RuntimeTargetOptions, SeatBoardTopology, SeatCardId, SeatFrameSchema, SeatProjectionBundleSchema, SeatSpaceRef, SeatTileRef, type ServerGameplayFrame, ServerGameplayFrameSchema, SessionResumeFrameSchema, SessionSnapshotFrameSchema, SimultaneousPhaseSnapshotSchema, SourceSnapshot, type SubmitInteractionCommand, SubmitInteractionCommandSchema, SystemActionEventSchema, TargetOptions, type ViewportSurface, type ViewportTransform, type WheelInput, Zone, ZoneHandlesSnapshotSchema, ZoneHostId, boardFeature, canonicalizePluginRuntimeJson, computePluginActionSetVersion, createGameInstance, createGestureRecognizer, createPluginProtocolEnvelopeSchema, digestPluginCommandRequest, digestPluginGameplayFrame, digestPluginRuntimeJson, dragFeature, encodeCanonicalPluginRuntimeJson, fanLayout, handFeature, hostSource, iframeSource, liftFanCard, magneticDropPoint, materializePluginGameplayFrame, originsFeature, panZoomFeature, parseHostToPluginEnvelope, parsePluginGameplayFrame, parsePluginSessionDescriptor, parsePluginToHostEnvelope, staticSource };
|
|
4874
|
+
export { ActionProps, type ActionSetVersionInput, AmbiguousTargetError, AuthAcceptedFrameSchema, AuthConnectFrameSchema, AuthRefreshFrameSchema, BoardBase, BoardCollection, BoardDataOf, BoardEdgeId, type BoardFeature, type BoardLayoutOptions, type BoardLayoutTile, BoardSpace, BoardSpaceCollection, BoardVertexId, type CancelInteractionCommand, CancelInteractionCommandSchema, Card, type CardOrigin, type ClientGameplayFrame, ClientGameplayFrameSchema, CommandSource, CoreInstance, DREAMBOARD_PLUGIN_PROTOCOL, DREAMBOARD_PLUGIN_PROTOCOL_VERSION, DREAMBOARD_SDK_PACKAGES, DREAMBOARD_SDK_PACKAGE_SET, DREAMBOARD_SDK_VERSION, type DragController, type DragState, type DreamboardSdkPackageName, type DreamboardSdkPackageSet, DropTarget, type FanCard, type FanLayout, type FanOptions, FeatureContext, Features, GESTURE_THRESHOLDS, GameEventDetailSchema, GameEventSchema, GameInstance, GameOutcomeSchema, GameSource, GameplayBackpressureFrameSchema, GameplayBackpressureOperationSchema, GameplayBackpressureReasonSchema, GameplayBasis, GameplayBasisSchema, GameplayCloseCode, type GameplayCredential, GameplayCredentialSchema, type GestureCallbacks, type GestureKind, type GestureOptions, type GesturePointer, type GestureRecognizer, type HandFan, type HandFanInput, type HandFanOptions, type HandFanPose, type HandOptions, type HostToPluginEnvelope, HostToPluginEnvelopeSchema, type HostToPluginPayload, HostToPluginPayloadSchema, IdOf, InstanceOptions, InteractionDescriptor, type InteractionResult, InteractionResultSchema, type MaterializePluginGameplayFrameInput, type PanZoomOptions, PlayerId, PluginGameplayFrame, PluginGameplayFrameSchema, PluginPlayerSummarySchema, type PluginProtocolEnvelope, PluginSessionDescriptor, PluginSessionDescriptorSchema, type PluginToHostEnvelope, PluginToHostEnvelopeSchema, type PluginToHostPayload, PluginToHostPayloadSchema, ReducerSeatProjectionBundle, RuntimeJson, RuntimeTargetOptions, SeatBoardTopology, SeatCardId, SeatFrameSchema, SeatProjectionBundleSchema, SeatSpaceRef, SeatTileRef, type ServerGameplayFrame, ServerGameplayFrameSchema, SessionResumeFrameSchema, SessionSnapshotFrameSchema, SimultaneousPhaseSnapshotSchema, SourceSnapshot, type SubmitInteractionCommand, SubmitInteractionCommandSchema, SystemActionEventSchema, TargetOptions, type ViewportSurface, type ViewportTransform, type WheelInput, Zone, ZoneHandlesSnapshotSchema, ZoneHostId, boardFeature, canonicalizePluginRuntimeJson, computePluginActionSetVersion, createGameInstance, createGestureRecognizer, createPluginProtocolEnvelopeSchema, cssEasing, digestPluginCommandRequest, digestPluginGameplayFrame, digestPluginRuntimeJson, dragFeature, encodeCanonicalPluginRuntimeJson, exponentialOut, fanLayout, handFan, handFanPresets, handFanTiming, handFeature, hostSource, iframeSource, liftFanCard, magneticDropPoint, materializePluginGameplayFrame, originsFeature, panZoomFeature, parseHostToPluginEnvelope, parsePluginGameplayFrame, parsePluginSessionDescriptor, parsePluginToHostEnvelope, staticSource };
|
package/dist/index.js
CHANGED
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
} from "./chunk-ES74C2IN.js";
|
|
72
72
|
|
|
73
73
|
// src/package-set.ts
|
|
74
|
-
var DREAMBOARD_SDK_VERSION = true ? "0.5.0-alpha.
|
|
74
|
+
var DREAMBOARD_SDK_VERSION = true ? "0.5.0-alpha.15" : "0.0.0-development";
|
|
75
75
|
var DREAMBOARD_SDK_PACKAGES = {
|
|
76
76
|
"@dreamboard-games/sdk": DREAMBOARD_SDK_VERSION
|
|
77
77
|
};
|
|
@@ -1578,6 +1578,151 @@ function liftFanCard(card, distance) {
|
|
|
1578
1578
|
rotate: card.rotate
|
|
1579
1579
|
};
|
|
1580
1580
|
}
|
|
1581
|
+
|
|
1582
|
+
// src/headless/hand-fan.ts
|
|
1583
|
+
var handFanPresets = {
|
|
1584
|
+
/** Whole resting cards; focusing enlarges the card. */
|
|
1585
|
+
open: {
|
|
1586
|
+
tuck: 0,
|
|
1587
|
+
focusScale: 2,
|
|
1588
|
+
focusMaxHeight: 0.55,
|
|
1589
|
+
push: [0.29, 0.19, 0.1],
|
|
1590
|
+
exposed: 0.35
|
|
1591
|
+
},
|
|
1592
|
+
/**
|
|
1593
|
+
* Larger cards tucked below the bottom edge and spaced like a dealt hand;
|
|
1594
|
+
* focusing mostly reveals the card.
|
|
1595
|
+
*/
|
|
1596
|
+
tucked: {
|
|
1597
|
+
spacing: 0.75,
|
|
1598
|
+
tuck: 0.4,
|
|
1599
|
+
focusScale: 1.4,
|
|
1600
|
+
focusMaxHeight: 0.4,
|
|
1601
|
+
push: [0.29, 0.19, 0.1],
|
|
1602
|
+
exposed: 0.35
|
|
1603
|
+
},
|
|
1604
|
+
/** Coarse pointers: a shallower tuck and wider strips to tap. */
|
|
1605
|
+
touch: {
|
|
1606
|
+
spacing: 0.75,
|
|
1607
|
+
tuck: 0.2,
|
|
1608
|
+
focusScale: 1.6,
|
|
1609
|
+
focusMaxHeight: 0.5,
|
|
1610
|
+
push: [0.35, 0.2, 0.1],
|
|
1611
|
+
exposed: 0.45
|
|
1612
|
+
}
|
|
1613
|
+
};
|
|
1614
|
+
function handFan({
|
|
1615
|
+
count,
|
|
1616
|
+
width,
|
|
1617
|
+
cardWidth,
|
|
1618
|
+
cardHeight,
|
|
1619
|
+
focused = -1,
|
|
1620
|
+
visible,
|
|
1621
|
+
windowHeight = Infinity,
|
|
1622
|
+
room = Infinity,
|
|
1623
|
+
options
|
|
1624
|
+
}) {
|
|
1625
|
+
const o = { ...handFanPresets.open, ...options };
|
|
1626
|
+
const fan = fanLayout({
|
|
1627
|
+
count,
|
|
1628
|
+
width,
|
|
1629
|
+
cardWidth,
|
|
1630
|
+
cardHeight,
|
|
1631
|
+
angle: o.angle,
|
|
1632
|
+
maxSpread: o.maxSpread,
|
|
1633
|
+
step: o.spacing === void 0 ? void 0 : o.spacing * cardWidth
|
|
1634
|
+
});
|
|
1635
|
+
const band = Math.max(0, fan.height - o.tuck * cardHeight);
|
|
1636
|
+
const view = visible ?? {
|
|
1637
|
+
left: (fan.width - width) / 2,
|
|
1638
|
+
width
|
|
1639
|
+
};
|
|
1640
|
+
const exposed = cardWidth * o.exposed;
|
|
1641
|
+
const largest = Math.max(
|
|
1642
|
+
cardWidth,
|
|
1643
|
+
Math.min(
|
|
1644
|
+
cardWidth * o.focusScale,
|
|
1645
|
+
windowHeight * o.focusMaxHeight * cardWidth / cardHeight,
|
|
1646
|
+
room * cardWidth / cardHeight,
|
|
1647
|
+
view.width
|
|
1648
|
+
)
|
|
1649
|
+
);
|
|
1650
|
+
const headroom = Math.max(0, largest * cardHeight / cardWidth - band);
|
|
1651
|
+
const cards = fan.cards.map((card, index) => ({
|
|
1652
|
+
...card,
|
|
1653
|
+
scale: 1,
|
|
1654
|
+
layer: index
|
|
1655
|
+
}));
|
|
1656
|
+
if (focused < 0 || focused >= count)
|
|
1657
|
+
return { cards, width: fan.width, height: band, headroom };
|
|
1658
|
+
const leftStrip = focused > 0 ? exposed : 0;
|
|
1659
|
+
const rightStrip = focused < count - 1 ? exposed : 0;
|
|
1660
|
+
const face = Math.max(
|
|
1661
|
+
cardWidth,
|
|
1662
|
+
Math.min(largest, view.width - leftStrip - rightStrip)
|
|
1663
|
+
);
|
|
1664
|
+
const scale = face / cardWidth;
|
|
1665
|
+
const half = face / 2;
|
|
1666
|
+
const centre = Math.max(
|
|
1667
|
+
view.left + leftStrip + half,
|
|
1668
|
+
Math.min(
|
|
1669
|
+
view.left + view.width - rightStrip - half,
|
|
1670
|
+
cards[focused].x + cardWidth / 2
|
|
1671
|
+
)
|
|
1672
|
+
);
|
|
1673
|
+
cards[focused] = {
|
|
1674
|
+
x: centre - cardWidth / 2,
|
|
1675
|
+
y: band - cardHeight * (scale + 1) / 2,
|
|
1676
|
+
rotate: 0,
|
|
1677
|
+
scale,
|
|
1678
|
+
layer: count
|
|
1679
|
+
};
|
|
1680
|
+
const extra = Math.max(0, half - cardWidth / 2);
|
|
1681
|
+
const reach = o.push.length;
|
|
1682
|
+
for (const direction of [-1, 1]) {
|
|
1683
|
+
let previous = centre;
|
|
1684
|
+
for (let distance = 1, index = focused + direction; index >= 0 && index < count; distance++, index += direction) {
|
|
1685
|
+
const card = cards[index];
|
|
1686
|
+
const shift = (o.push[distance - 1] ?? 0) * cardWidth + (reach ? extra * Math.max(0, 1 - (distance - 1) / reach) : 0);
|
|
1687
|
+
const desired = card.x + cardWidth / 2 + direction * shift;
|
|
1688
|
+
const angle = card.rotate * Math.PI / 180;
|
|
1689
|
+
const halfWidth = (cardWidth * Math.cos(angle) + cardHeight * Math.abs(Math.sin(angle))) / 2;
|
|
1690
|
+
const middleHalfWidth = cardWidth * Math.cos(angle) / 2;
|
|
1691
|
+
const clearance = distance === 1 ? Math.max(exposed, half - middleHalfWidth + exposed) : exposed;
|
|
1692
|
+
const boundary = direction === 1 && distance > 1 ? Math.max(previous + clearance, centre + half + exposed + halfWidth) : previous + direction * clearance;
|
|
1693
|
+
let next = direction === 1 ? Math.max(desired, boundary) : Math.min(desired, boundary);
|
|
1694
|
+
if (distance === 1)
|
|
1695
|
+
next = direction === 1 ? Math.min(
|
|
1696
|
+
next,
|
|
1697
|
+
view.left + view.width - middleHalfWidth,
|
|
1698
|
+
centre + half + middleHalfWidth
|
|
1699
|
+
) : Math.max(
|
|
1700
|
+
next,
|
|
1701
|
+
view.left + middleHalfWidth,
|
|
1702
|
+
centre - half - middleHalfWidth
|
|
1703
|
+
);
|
|
1704
|
+
cards[index] = { ...card, x: next - cardWidth / 2 };
|
|
1705
|
+
previous = next;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
return { cards, width: fan.width, height: band, headroom };
|
|
1709
|
+
}
|
|
1710
|
+
function exponentialOut(progress) {
|
|
1711
|
+
return (1 - Math.exp(-4.5 * progress)) / (1 - Math.exp(-4.5));
|
|
1712
|
+
}
|
|
1713
|
+
var handFanTiming = {
|
|
1714
|
+
/** The focused face rises: 90% in about 45ms. */
|
|
1715
|
+
focus: { duration: 0.09, ease: exponentialOut },
|
|
1716
|
+
/** Sideways travel, neighbours and returning cards: 90% in about 300ms. */
|
|
1717
|
+
settle: { duration: 0.6, ease: exponentialOut }
|
|
1718
|
+
};
|
|
1719
|
+
function cssEasing(ease, samples = 24) {
|
|
1720
|
+
const points = Array.from(
|
|
1721
|
+
{ length: samples + 1 },
|
|
1722
|
+
(_, index) => Number(ease(index / samples).toFixed(4))
|
|
1723
|
+
);
|
|
1724
|
+
return `linear(${points.join(", ")})`;
|
|
1725
|
+
}
|
|
1581
1726
|
export {
|
|
1582
1727
|
AmbiguousTargetError,
|
|
1583
1728
|
AuthAcceptedFrameSchema,
|
|
@@ -1633,12 +1778,17 @@ export {
|
|
|
1633
1778
|
createGameInstance,
|
|
1634
1779
|
createGestureRecognizer,
|
|
1635
1780
|
createPluginProtocolEnvelopeSchema,
|
|
1781
|
+
cssEasing,
|
|
1636
1782
|
digestPluginCommandRequest,
|
|
1637
1783
|
digestPluginGameplayFrame,
|
|
1638
1784
|
digestPluginRuntimeJson,
|
|
1639
1785
|
dragFeature,
|
|
1640
1786
|
encodeCanonicalPluginRuntimeJson,
|
|
1787
|
+
exponentialOut,
|
|
1641
1788
|
fanLayout,
|
|
1789
|
+
handFan,
|
|
1790
|
+
handFanPresets,
|
|
1791
|
+
handFanTiming,
|
|
1642
1792
|
handFeature,
|
|
1643
1793
|
hostSource,
|
|
1644
1794
|
iframeSource,
|