Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
72 changes: 70 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Advanced iMessage Kit is a full-featured iMessage SDK for **reading**, **sending
| [Send Messages](#send-messages) | Send text messages to any contact | `messages.sendMessage()` | [message-send.ts](./examples/message-send.ts) |
| [Reply to Messages](#send-messages) | Reply inline to a specific message | `messages.sendMessage()` | [message-reply.ts](./examples/message-reply.ts) |
| [Message Effects](#send-messages) | Send with effects (confetti, fireworks, etc.) | `messages.sendMessage()` | [message-effects.ts](./examples/message-effects.ts) |
| [Text Styles](#text-styles--animations) | Bold, italic, underline, strikethrough | `messages.sendMessage()` | [message-styled.ts](./examples/message-styled.ts) |
| [Text Animations](#text-styles--animations) | Per-character animations (shake, ripple, etc.)| `messages.sendMessage()` | [message-styled.ts](./examples/message-styled.ts) |
| [Send Rich Links](#send-messages) | Send URLs with rich link previews | `messages.sendMessage()` | [message-rich-link.ts](./examples/message-rich-link.ts) |
| [Schedule Messages](#scheduled-messages) | Send once or on a recurring schedule | `scheduledMessages.createScheduledMessage()` | [scheduled-message-once.ts](./examples/scheduled-message-once.ts) |
| [Unsend Messages](#unsend-messages) | Retract a sent message | `messages.unsendMessage()` | [message-unsend.ts](./examples/message-unsend.ts) |
Expand Down Expand Up @@ -191,6 +193,71 @@ await sdk.messages.sendMessage({

> Example: [message-effects.ts](./examples/message-effects.ts)

### Text Styles & Animations

Apply per-range text formatting and whole-message character animations (requires Private API):

```typescript
// Bold a portion of text
await sdk.messages.sendMessage({
chatGuid: "iMessage;-;+1234567890",
message: "This is bold text",
textStyles: [{ start: 8, end: 12, bold: true }],
});

// Multiple styles in one message
await sdk.messages.sendMessage({
chatGuid: "iMessage;-;+1234567890",
message: "Bold here, italic there",
textStyles: [
{ start: 0, end: 9, bold: true },
{ start: 11, end: 23, italic: true },
],
});

// Character animation (applies to whole message)
await sdk.messages.sendMessage({
chatGuid: "iMessage;-;+1234567890",
message: "Ripple wave!",
textAnimation: "ripple",
});

// Combine all three layers
await sdk.messages.sendMessage({
chatGuid: "iMessage;-;+1234567890",
message: "Bold shaking fireworks!",
textStyles: [{ start: 0, end: 4, bold: true }],
textAnimation: "shake",
effectId: "com.apple.messages.effect.CKFireworksEffect",
Comment thread
Artist-MOBAI marked this conversation as resolved.
Comment thread
Artist-MOBAI marked this conversation as resolved.
});
Comment thread
Artist-MOBAI marked this conversation as resolved.
```

**Text Style Properties** (per range):

| Property | Type | Description |
| --------------- | ------- | -------------- |
| `start` | number | Start index |
| `end` | number | End index |
| `bold` | boolean | Bold |
| `italic` | boolean | Italic |
| `underline` | boolean | Underline |
| `strikethrough` | boolean | Strikethrough |

**Text Animations** (whole message):

| `textAnimation` | Description |
| --------------- | ----------- |
| `"big"` | Big |
| `"small"` | Small |
| `"shake"` | Shake |
| `"nod"` | Nod |
| `"explode"` | Explode |
| `"ripple"` | Ripple |
| `"bloom"` | Bloom |
| `"jitter"` | Jitter |

> Example: [message-styled.ts](./examples/message-styled.ts)

### Query Messages

```typescript
Expand Down Expand Up @@ -1114,8 +1181,9 @@ bun run examples/<filename>.ts
| [message-unsend.ts](./examples/message-unsend.ts) | Unsend messages |
| [message-edit.ts](./examples/message-edit.ts) | Edit messages |
| [message-reaction.ts](./examples/message-reaction.ts) | Send Tapbacks |
| [message-effects.ts](./examples/message-effects.ts) | Message effects |
| [message-search.ts](./examples/message-search.ts) | Search messages |
| [message-effects.ts](./examples/message-effects.ts) | Message effects |
| [message-styled.ts](./examples/message-styled.ts) | Text styles & animations |
| [message-search.ts](./examples/message-search.ts) | Search messages |
| [message-history.ts](./examples/message-history.ts) | Message history |
| [message-destination-caller-id.ts](./examples/message-destination-caller-id.ts) | Destination caller ID |

Expand Down
199 changes: 50 additions & 149 deletions examples/message-effects.ts
Original file line number Diff line number Diff line change
@@ -1,163 +1,64 @@
import type { BubbleEffect } from "../types";
import { createSDK, handleError } from "./utils";

const CHAT_GUID = process.env.CHAT_GUID || "any;-;+13322593374";

const MESSAGE_EFFECTS = {
confetti: "com.apple.messages.effect.CKConfettiEffect",
lasers: "com.apple.messages.effect.CKHappyBirthdayEffect",
fireworks: "com.apple.messages.effect.CKFireworksEffect",
balloons: "com.apple.messages.effect.CKBalloonEffect",
hearts: "com.apple.messages.effect.CKHeartEffect",
shootingStar: "com.apple.messages.effect.CKShootingStarEffect",
celebration: "com.apple.messages.effect.CKSparklesEffect",
echo: "com.apple.messages.effect.CKEchoEffect",
spotlight: "com.apple.messages.effect.CKSpotlightEffect",
gentle: "com.apple.MobileSMS.expressivesend.gentle",
loud: "com.apple.MobileSMS.expressivesend.loud",
slam: "com.apple.MobileSMS.expressivesend.impact",
invisible_ink: "com.apple.MobileSMS.expressivesend.invisibleink",
} as const;
const CHAT_GUID = process.env.CHAT_GUID || "any;-;+1234567890";
Comment thread
Artist-MOBAI marked this conversation as resolved.

const BUBBLE_EFFECTS: BubbleEffect[] = [
"confetti",
"lasers",
"fireworks",
"balloons",
"hearts",
"shootingStar",
"celebration",
"echo",
"spotlight",
"gentle",
"loud",
"slam",
"invisibleInk",
];

const EFFECT_MESSAGES: Record<BubbleEffect, string> = {
confetti: "Happy Birthday!",
lasers: "Pew pew pew!",
fireworks: "Celebration time!",
balloons: "Congratulations!",
hearts: "I love you!",
shootingStar: "Make a wish!",
celebration: "Amazing!",
echo: "Hello hello hello...",
spotlight: "Look at me!",
gentle: "Shh...",
loud: "IMPORTANT MESSAGE!",
slam: "BAM!",
invisibleInk: "Secret message!",
};

async function main() {
const sdk = createSDK();

sdk.on("ready", async () => {
console.log("Message effects example (requires Private API)\n");
console.log("Bubble effect examples (requires Private API)\n");

try {
// Confetti effect
const confettiMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Happy Birthday!",
effectId: MESSAGE_EFFECTS.confetti,
});
console.log(`confetti: ${confettiMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Lasers effect
const lasersMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Pew pew pew!",
effectId: MESSAGE_EFFECTS.lasers,
});
console.log(`lasers: ${lasersMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Fireworks effect
const fireworksMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Celebration time!",
effectId: MESSAGE_EFFECTS.fireworks,
});
console.log(`fireworks: ${fireworksMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Balloons effect
const balloonsMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Congratulations!",
effectId: MESSAGE_EFFECTS.balloons,
});
console.log(`balloons: ${balloonsMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Hearts effect
const heartsMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "I love you!",
effectId: MESSAGE_EFFECTS.hearts,
});
console.log(`hearts: ${heartsMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Shooting star effect
const shootingStarMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Make a wish!",
effectId: MESSAGE_EFFECTS.shootingStar,
});
console.log(`shootingStar: ${shootingStarMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Celebration effect
const celebrationMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Amazing!",
effectId: MESSAGE_EFFECTS.celebration,
});
console.log(`celebration: ${celebrationMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Echo effect
const echoMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Hello hello hello...",
effectId: MESSAGE_EFFECTS.echo,
});
console.log(`echo: ${echoMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Spotlight effect
const spotlightMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Look at me!",
effectId: MESSAGE_EFFECTS.spotlight,
});
console.log(`spotlight: ${spotlightMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Gentle effect
const gentleMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Shh...",
effectId: MESSAGE_EFFECTS.gentle,
});
console.log(`gentle: ${gentleMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Loud effect
const loudMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "IMPORTANT MESSAGE!",
effectId: MESSAGE_EFFECTS.loud,
});
console.log(`loud: ${loudMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Slam effect
const slamMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "BAM!",
effectId: MESSAGE_EFFECTS.slam,
});
console.log(`slam: ${slamMessage.guid}`);

await new Promise((resolve) => setTimeout(resolve, 5000));

// Invisible ink effect
const invisibleMessage = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: "Secret message!",
effectId: MESSAGE_EFFECTS.invisible_ink,
});
console.log(`invisible ink: ${invisibleMessage.guid}`);

console.log("\nAvailable effects:");
console.log(JSON.stringify(MESSAGE_EFFECTS, null, 2));
for (const effect of BUBBLE_EFFECTS) {
const msg = await sdk.messages.sendMessage({
chatGuid: CHAT_GUID,
message: EFFECT_MESSAGES[effect],
bubbleEffect: effect,
});
console.log(`${effect}: ${msg.guid}`);
await new Promise((resolve) => setTimeout(resolve, 5000));
}

console.log("\nAvailable bubble effects:");
for (const effect of BUBBLE_EFFECTS) {
console.log(` ${effect}`);
}
} catch (error) {
handleError(error, "Failed to send message with effect");
console.log("\nNote: Effects require Private API to be enabled");
console.log("\nNote: Bubble effects require Private API to be enabled");
}

await sdk.close();
Expand Down
Loading
Loading