Documentation Index
Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt
Use this file to discover all available pages before exploring further.
Connection modes
- Cloud (default)
- Local
- Dedicated
Authenticates with Spectrum Cloud and connects to managed iMessage infrastructure via gRPC. Full feature set: send, receive, typing, reactions, replies, and group creation.Tokens are renewed automatically at 80% of their TTL. Requires
projectId and projectSecret on the Spectrum() call:Line model
Cloud mode routes your messages through phone numbers (“lines”) provisioned by Spectrum. Which lines you get depends on your plan, and the difference is mostly invisible to end users.| Plan | Line allocation | What end users see |
|---|---|---|
| Free / Pro | Shared pool. Each of your end users is routed through a different number from a shared pool. | A normal iMessage from a number that may differ across recipients. |
| Business | Dedicated. All of your end users text the same number, which belongs to your project. | A normal iMessage, always from the same number. |
Auto-scale
When traffic to a dedicated line approaches its per-line capacity, Spectrum can automatically provision an additional line so deliverability isn’t affected. Auto-scale is an opt-in feature on the Business plan. Enable it in your project settings if you’d rather not get paged when a line saturates.These are managed Spectrum Cloud features. If you’re on the open-source path (
imessage.config({ local: true }) or your own dedicated relay), you provide your own iCloud account and managed-line concepts don’t apply.Quotas
Space types
iMessage spaces carry atype field — "dm" or "group" — and a phone field indicating which phone number the conversation is routed through. Both are accessible through narrowing:
Creating conversations
Resolve users by phone number or email, then pass them tospace():
space() throws — the local Messages database doesn’t expose chat creation.
Per-phone routing
If your account has multiple dedicated phone numbers, you can pin a conversation to a specific line by passingphone as a space parameter:
Per-phone routing applies to dedicated lines (Business plan) only. On shared-pool plans the
phone parameter is ignored — all conversations route through the shared pool automatically.Message effects
iMessage supports bubble effects (sent message animation) and screen effects (full-screen animation on receive). Wrap any content witheffect():
attachment(...). Effects only apply on iMessage — other platforms see the inner content unchanged.
Bubble effects
Animate the sent message bubble.
Bubble effects
Animate the sent message bubble.
| Constant | Value |
|---|---|
imessage.effect.message.slam | "com.apple.MobileSMS.expressivesend.impact" |
imessage.effect.message.loud | "com.apple.MobileSMS.expressivesend.loud" |
imessage.effect.message.gentle | "com.apple.MobileSMS.expressivesend.gentle" |
imessage.effect.message.invisible | "com.apple.MobileSMS.expressivesend.invisibleink" |
Screen effects
Play a full-screen animation on the recipient's device when the message arrives.
Screen effects
Play a full-screen animation on the recipient's device when the message arrives.
| Constant | Value |
|---|---|
imessage.effect.message.confetti | "com.apple.messages.effect.CKConfettiEffect" |
imessage.effect.message.fireworks | "com.apple.messages.effect.CKFireworksEffect" |
imessage.effect.message.balloons | "com.apple.messages.effect.CKBalloonEffect" |
imessage.effect.message.heart | "com.apple.messages.effect.CKHeartEffect" |
imessage.effect.message.lasers | "com.apple.messages.effect.CKLasersEffect" |
imessage.effect.message.celebration | "com.apple.messages.effect.CKHappyBirthdayEffect" |
imessage.effect.message.sparkles | "com.apple.messages.effect.CKSparklesEffect" |
imessage.effect.message.spotlight | "com.apple.messages.effect.CKSpotlightEffect" |
imessage.effect.message.echo | "com.apple.messages.effect.CKEchoEffect" |
Chat backgrounds
Set or clear the chat background image. Importbackground from the iMessage provider and use the sugar method on a narrowed space:
space.background(...) is sugar for space.send(background(...)). The canonical form works on any space reference:
30s. The background asset is uploaded to iCloud and then distributed to the other members of the conversation. Display time is not a hard SLA: network state, iCloud state, and the Messages client state can all affect when the UI appears.
| Stage | What happens |
|---|---|
Before background(...) resolves | The provider waits until the background asset reaches a distributable state |
After background(...) resolves | The conversation has accepted the background change; iCloud distributes the asset to other members |
| Other members’ devices | The background appears after the device receives the iCloud distribution |
| Case | Result |
|---|---|
| The recipient’s network, iCloud, or Messages state is unhealthy | The background may appear late, often after reopening Messages |
| A group member has never spoken, interacted, or is treated by the system as unknown (untrusted) | Apple may not show the background UI to that member |
The second case is an Apple Messages display limit, not a Spectrum option. If one group member never sees the background, have that member send a message in the group, mark the sender as known, or reopen Messages before retrying the background change.
Chat backgrounds require cloud or dedicated mode. In local mode,
background() throws an UnsupportedError.The string
"clear" is a reserved sentinel. If you have a file literally named clear with no extension, pass "./clear" or load it as a Buffer.Tapback constants
iMessage uses a fixed set of tapback reactions. Theimessage object exposes them as constants:
| Constant | Value |
|---|---|
imessage.tapbacks.love | "love" |
imessage.tapbacks.like | "like" |
imessage.tapbacks.dislike | "dislike" |
imessage.tapbacks.laugh | "laugh" |
imessage.tapbacks.emphasize | "emphasize" |
imessage.tapbacks.question | "question" |