Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vibesflow.ai/llms.txt

Use this file to discover all available pages before exploring further.

Vibestream Modal

The Vibestream Modal provides the interface for creating new vibestreams, with support for both Solo and Group modes. It handles parameter validation, network-aware creation, and RTA NFT minting.

Mode Selection (Step 1)

Interface Components

// Mode selection UI in VibestreamModal.tsx
const renderStep1 = () => (
  <View style={styles.stepContainer}>
    <Text style={styles.stepTitle}>SELECT MODE</Text>
    
    <View style={styles.modeContainer}>
      <TouchableOpacity
        style={[styles.modeButton, mode === 'solo' && styles.selectedMode]}
        onPress={() => handleModeSelect('solo')}
      >
        <Text style={styles.modeText}>SOLO</Text>
      </TouchableOpacity>
      
      <TouchableOpacity
        style={[styles.modeButton, mode === 'group' && styles.selectedMode]}
        onPress={() => handleModeSelect('group')}
      >
        <Text style={styles.modeText}>GROUP</Text>
      </TouchableOpacity>
    </View>
  </View>
);

Mode Handler

// Mode selection logic
const handleModeSelect = (selectedMode) => {
  setMode(selectedMode);
  if (selectedMode === 'solo') {
    setStep(2);
  } else {
    setStep(2); // Both modes proceed to settings
  }
};

Configuration (Step 2)

Universal Settings

Settings available for both Solo and Group modes:
// Universal settings component
<TouchableOpacity
  style={styles.checkboxContainer}
  onPress={() => setStoreToFilecoin(!storeToFilecoin)}
>
  <View style={[styles.checkbox, storeToFilecoin && styles.checkedBox]}>
    {storeToFilecoin && (
      <FontAwesome name="check" size={8} color={COLORS.background} />
    )}
  </View>
  <Text style={styles.checkboxText}>STORE TO FILECOIN</Text>
</TouchableOpacity>

Group Mode Parameters

Group mode exposes additional configuration options:
// Group-specific settings
{mode === 'group' && (
  <>
    {/* Distance Configuration */}
    <View style={styles.inputGroup}>
      <Text style={styles.inputLabel}>DISTANCE (1-10 METERS)</Text>
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.textInput}
          value={distance}
          onChangeText={(text) => {
            // Contract validation: 1-10 meters only
            const num = parseInt(text);
            if (text === '' || (num >= 1 && num <= 10)) {
              setDistance(text);
            }
          }}
          keyboardType="numeric"
          maxLength={2}
        />
        <Text style={styles.inputUnit}>MT</Text>
      </View>
    </View>

    {/* Ticket Amount */}
    <View style={styles.inputGroup}>
      <Text style={styles.inputLabel}>TICKETS</Text>
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.textInput}
          value={ticketAmount}
          onChangeText={setTicketAmount}
          keyboardType="numeric"
        />
        <Text style={styles.inputUnit}>AMT</Text>
      </View>
    </View>
  </>
)}

PPM Configuration

Pay-Per-Minute settings with network-aware currency display:
// Network-aware currency display
const getCurrency = () => {
  const networkInfo = getNetworkInfo();
  return networkInfo?.type === 'metis-hyperion' ? 'tMETIS' : 'NEAR';
};

// Ticket pricing configuration
<View style={styles.inputGroup}>
  <Text style={styles.inputLabel}>TICKET PRICE?</Text>
  <View style={styles.payPerStreamContainer}>
    <TouchableOpacity
      style={styles.ynCheckboxContainer}
      onPress={() => setFreeTickets(true)}
    >
      <View style={[styles.checkbox, freeTickets && styles.checkedBox]}>
        {freeTickets && (
          <FontAwesome name="check" size={8} color={COLORS.background} />
        )}
      </View>
      <Text style={styles.ynCheckboxText}>N</Text>
    </TouchableOpacity>
    
    <TouchableOpacity
      style={styles.ynCheckboxContainer}
      onPress={() => setFreeTickets(false)}
    >
      <View style={[styles.checkbox, !freeTickets && styles.checkedBox]}>
        {!freeTickets && (
          <FontAwesome name="check" size={8} color={COLORS.background} />
        )}
      </View>
      <Text style={styles.ynCheckboxText}>Y</Text>
    </TouchableOpacity>
  </View>
  
  <View style={[styles.inputContainer, freeTickets && styles.disabledInput]}>
    <TextInput
      style={[styles.textInput, freeTickets && styles.disabledTextInput]}
      value={ticketPrice}
      onChangeText={setTicketPrice}
      keyboardType="decimal-pad"
      editable={!freeTickets}
    />
    <Text style={styles.inputUnit}>{getCurrency()}</Text>
  </View>
</View>

Validation Logic

Parameter Validation

Comprehensive validation prevents invalid configurations:
// Launch validation in VibestreamModal.tsx
const isLaunchDisabled = () => {
  if (isCreatingRTA) return true;
  
  if (mode === 'group') {
    // Distance validation (1-10 meters per contract)
    const distanceNum = parseInt(distance);
    if (!distance || distance === '0' || distanceNum < 1 || distanceNum > 10) return true;
    
    // Ticket amount validation (must be at least 1)
    const ticketAmountNum = parseInt(ticketAmount);
    if (!ticketAmount || ticketAmount === '0' || ticketAmountNum < 1) return true;
    
    // PPM validation
    if (payPerStream && (!streamPrice || streamPrice === '0')) return true;
    
    // Ticket price validation  
    if (!freeTickets && (!ticketPrice || ticketPrice === '0')) return true;
  }
  return false;
};

Connection Validation

// Wallet connection check
{!connected && (
  <View style={styles.walletWarning}>
    <FontAwesome name="exclamation-triangle" size={12} color={COLORS.secondary} />
    <Text style={styles.walletWarningText}>WALLET NOT CONNECTED</Text>
  </View>
)}

RTA Creation Process

Configuration Assembly

// RTA configuration assembly
const rtaConfig = {
  mode,
  store_to_filecoin: storeToFilecoin,
  // Group mode specific fields
  distance: mode === 'group' ? parseInt(distance) : undefined,
  ticket_amount: mode === 'group' ? parseInt(ticketAmount) : undefined,
  ticket_price: mode === 'group' && !freeTickets ? ticketPrice : undefined,
  pay_per_stream: mode === 'group' ? payPerStream : false,
  stream_price: mode === 'group' && payPerStream ? streamPrice : '0',
  creator: accountIdToUse,
  created_at: Date.now(),
};

Network-Aware Creation

// Network-specific RTA creation
const handleLaunchVibestream = async () => {
  // Connection validation
  if (!connected) {
    Alert.alert('Wallet Required', 'Please connect your wallet to create a vibestream.');
    return;
  }

  const networkInfo = getNetworkInfo();
  if (!networkInfo) {
    Alert.alert('Error', 'Network information not available.');
    return;
  }

  setIsCreatingRTA(true);

  try {
    // Enable audio first
    await enableAudio();
    
    // Generate unique RTA ID
    const rawRtaId = generateRtaID();
    
    console.log(`🔥 Creating ${networkInfo.type} vibestream with config:`, rtaConfig);

    // Network-aware creation with timeout
    const creationPromise = createRTANFT(rawRtaId, rtaConfig);
    const timeoutPromise = new Promise((_, reject) => {
      setTimeout(() => reject(new Error(`${networkInfo.type} creation timeout`)), 30000);
    });

    const fullTokenId = await Promise.race([creationPromise, timeoutPromise]);
    
    console.log(`✅ ${networkInfo.type} vibestream created successfully:`, fullTokenId);
    
    // Launch vibestream
    onLaunchVibePlayer(fullTokenId, rtaConfig);
    onClose();

  } catch (error) {
    console.error('Failed to create vibestream:', error);
    // Handle errors with user-friendly messages
    handleCreationError(error);
  } finally {
    setIsCreatingRTA(false);
  }
};

Audio Initialization

Web Audio Context

// Audio context initialization for web
const enableAudio = async () => {
  if (Platform.OS === 'web' && typeof window !== 'undefined' && window.AudioContext) {
    try {
      const audioContext = new (window.AudioContext || window.webkitAudioContext)();
      if (audioContext.state === 'suspended') {
        await audioContext.resume();
      }
      
      // Test audio with brief beep
      const osc = audioContext.createOscillator();
      const gain = audioContext.createGain();
      osc.connect(gain);
      gain.connect(audioContext.destination);
      osc.frequency.value = 800;
      gain.gain.setValueAtTime(0.1, audioContext.currentTime);
      gain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.1);
      osc.start();
      osc.stop(audioContext.currentTime + 0.1);
      
      setAudioEnabled(true);
      console.log('Audio enabled successfully');
    } catch (error) {
      console.warn('Failed to enable audio:', error);
    }
  } else {
    setAudioEnabled(true);
  }
};

Error Handling

Fallback Mode

When RTA creation fails, the system provides fallback functionality:
// Fallback handling
} catch (error) {
  console.warn(`⚠️ ${networkInfo.type} vibestream creation failed:`, error);
  console.log('🔄 Using fallback mode - vibestream will continue with mock data');
  
  // Generate fallback data
  const networkPrefix = networkInfo.type === 'metis-hyperion' ? 'metis_vibe' : 'rta';
  fullTokenId = `${networkPrefix}_${rawRtaId}`;
  creationSucceeded = false;

  // Add fallback indicators
  rtaConfig.fallback_mode = true;
  rtaConfig.fallback_reason = error.message.includes('timeout') ? 
    `${networkInfo.type}_timeout` : `${networkInfo.type}_error`;
  rtaConfig.original_error = error.message;
  rtaConfig.network = networkInfo.type;
}

User Notifications

// Success/failure notifications
if (creationSucceeded) {
  console.log(`🎉 ${networkInfo.type} vibestream created - full functionality enabled`);
  
  // Group mode success message
  if (mode === 'group' && Platform.OS === 'web') {
    const networkName = networkInfo.type === 'metis-hyperion' ? 'Metis Hyperion' : 'NEAR';
    Alert.alert(
      'Group Vibestream Created!',
      `Your Group vibestream is ready on ${networkName}!\n\n🎫 Tickets: ${freeTickets ? 'FREE' : ticketPrice + ' tokens'}\n📍 Distance: ${distance}m\n👥 Max participants: ${ticketAmount}`,
      [{ text: 'Start Vibing!', style: 'default' }]
    );
  }
} else {
  // Fallback mode notification
  const networkName = networkInfo.type === 'metis-hyperion' ? 'Metis Hyperion' : 'NEAR';
  Alert.alert(
    'Vibestream Starting (Fallback Mode)',
    `${networkName} is slow, but your vibestream will start anyway!\n\n✅ Audio chunking: Working\n✅ Backend processing: Working\n✅ Storage: Working`,
    [{ text: 'Start Vibing!', style: 'default' }]
  );
}

State Management

// Modal state management
const [step, setStep] = useState(1);
const [mode, setMode] = useState('solo');
const [storeToFilecoin, setStoreToFilecoin] = useState(true);
const [distance, setDistance] = useState('1');
const [ticketAmount, setTicketAmount] = useState('1');
const [ticketPrice, setTicketPrice] = useState('0');
const [streamPrice, setStreamPrice] = useState('0');
const [freeTickets, setFreeTickets] = useState(true);
const [payPerStream, setPayPerStream] = useState(false);
const [isCreatingRTA, setIsCreatingRTA] = useState(false);

Reset Logic

// Modal reset on close
const resetModal = () => {
  setStep(1);
  setMode('solo');
  setStoreToFilecoin(true);
  setDistance('1');
  setTicketAmount('1');
  setTicketPrice('0');
  setStreamPrice('0');
  setFreeTickets(true);
  setPayPerStream(false);
  setIsCreatingRTA(false);
};

useEffect(() => {
  if (!visible) {
    resetModal();
  }
}, [visible]);

UI Components

Loading State

// Creation loading indicator
{isCreatingRTA ? (
  <View style={styles.loadingContainer}>
    <ActivityIndicator size="small" color={COLORS.primary} />
    <Text style={styles.loadingText}>CREATING RTA...</Text>
  </View>
) : (
  <Text style={styles.actionButtonText}>
    LAUNCH
  </Text>
)}

Action Buttons

// Action buttons row
<View style={styles.actionButtonsRow}>
  <TouchableOpacity
    style={[styles.actionButton, isLaunchDisabled() && styles.disabledButton]}
    onPress={handleLaunchVibestream}
    disabled={isLaunchDisabled()}
  >
    {/* Launch button content */}
  </TouchableOpacity>
  
  <TouchableOpacity
    style={[styles.actionButton, styles.disabledButton]}
    disabled={true}
  >
    <Text style={[styles.actionButtonText, styles.disabledText]}>
      SCHEDULE
    </Text>
  </TouchableOpacity>
</View>

Next Steps

Vibe Player

Learn about the music generation interface

User Profiles

Understand profile management