jostlebot Claude Opus 4.5 commited on
Commit
0b56fd7
·
1 Parent(s): 7d4dcb0

Enhanced FEEL/NEED tools + proper square breathing

Browse files

FEEL/NEED improvements:
- Expanded NVC vocabulary from Marshall Rosenberg's complete lists
- Added psychoeducation from Brené Brown, Tara Brach, Sarah Peyton
- Feelings reflection connects to needs and includes insights
- Needs reflection includes request suggestions

LOVE breathing fix:
- Proper square breathing: 5s in, 4s hold, 5s out, 4s hold
- Visual countdown during each phase
- Circle animates to match breath phase

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (1) hide show
  1. static/index.html +130 -24
static/index.html CHANGED
@@ -728,6 +728,16 @@
728
  50% { transform: scale(1.2); opacity: 1; }
729
  }
730
 
 
 
 
 
 
 
 
 
 
 
731
  .breath-text {
732
  font-size: 1.5rem;
733
  margin-bottom: 20px;
@@ -985,20 +995,44 @@
985
 
986
  let selectedTradition = null;
987
 
988
- // NVC Feelings vocabulary
989
  const FEELINGS_DATA = {
990
- 'When needs ARE met': ['Calm', 'Content', 'Grateful', 'Hopeful', 'Joyful', 'Peaceful', 'Relieved', 'Safe', 'Tender', 'Touched'],
991
- 'When needs are NOT met': ['Angry', 'Anxious', 'Confused', 'Disappointed', 'Frustrated', 'Helpless', 'Hurt', 'Lonely', 'Overwhelmed', 'Sad', 'Scared', 'Tense', 'Tired', 'Worried']
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
992
  };
993
 
994
- // NVC Needs vocabulary
995
  const NEEDS_DATA = {
996
- 'Connection': ['Acceptance', 'Belonging', 'Closeness', 'To be heard', 'To be seen', 'To be understood', 'Trust', 'Warmth'],
 
 
 
 
 
997
  'Autonomy': ['Choice', 'Freedom', 'Independence', 'Space', 'Spontaneity'],
998
- 'Meaning': ['Contribution', 'Growth', 'Purpose', 'To matter', 'Creativity'],
999
- 'Peace': ['Ease', 'Harmony', 'Order', 'Rest', 'Safety', 'Security'],
1000
- 'Honesty': ['Authenticity', 'Integrity', 'To be known', 'Transparency'],
1001
- 'Physical': ['Air', 'Food', 'Movement', 'Rest', 'Safety', 'Touch']
 
 
 
 
1002
  };
1003
 
1004
  let selectedFeelings = [];
@@ -1320,7 +1354,7 @@
1320
  const feelingsText = selectedFeelings.join(', ');
1321
  addToolMsg('user', `I'm feeling: ${feelingsText}`);
1322
 
1323
- // Get reflection from API
1324
  addToolLoading();
1325
  const isVerbose = document.getElementById('toggle-verbose')?.checked || false;
1326
  try {
@@ -1331,7 +1365,18 @@
1331
  tool: 'feelings_needs',
1332
  partner_message: lastPartnerMessage,
1333
  user_draft: '',
1334
- user_input: `The person has identified these feelings: ${feelingsText}. ${userInput ? 'They added: ' + userInput : ''} Reflect back what these feelings might be pointing to. Help them connect feelings to needs.`,
 
 
 
 
 
 
 
 
 
 
 
1335
  verbose: isVerbose
1336
  })
1337
  });
@@ -1353,7 +1398,7 @@
1353
  const needsText = selectedNeeds.join(', ');
1354
  addToolMsg('user', `I'm needing: ${needsText}`);
1355
 
1356
- // Get reflection from API
1357
  addToolLoading();
1358
  const isVerbose = document.getElementById('toggle-verbose')?.checked || false;
1359
  try {
@@ -1364,7 +1409,19 @@
1364
  tool: 'feelings_needs',
1365
  partner_message: lastPartnerMessage,
1366
  user_draft: '',
1367
- user_input: `The person has identified these needs: ${needsText}. ${userInput ? 'They added: ' + userInput : ''} Reflect back these needs. Help them think about what request might help meet these needs in the relationship.`,
 
 
 
 
 
 
 
 
 
 
 
 
1368
  verbose: isVerbose
1369
  })
1370
  });
@@ -1437,27 +1494,76 @@ Based on the themes in this conversation (conflict, connection, fear, love, boun
1437
  }
1438
 
1439
  // ============================================================================
1440
- // BREATH/LOVE TOOL
1441
  // ============================================================================
1442
  let breathInterval;
 
1443
 
1444
  function openBreath() {
1445
  document.getElementById('breath-overlay').classList.add('active');
1446
- let phase = 0;
1447
- const phases = ['Breathe in...', 'Hold...', 'Breathe out...', 'Hold...'];
1448
-
1449
- function updateBreath() {
1450
- document.getElementById('breath-text').textContent = phases[phase % 4];
1451
- phase++;
1452
- }
1453
-
1454
- updateBreath();
1455
- breathInterval = setInterval(updateBreath, 4000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1456
  }
1457
 
1458
  function closeBreath() {
1459
  document.getElementById('breath-overlay').classList.remove('active');
1460
  clearInterval(breathInterval);
 
1461
  }
1462
 
1463
  // ============================================================================
 
728
  50% { transform: scale(1.2); opacity: 1; }
729
  }
730
 
731
+ @keyframes breatheIn {
732
+ 0% { transform: scale(0.6); opacity: 0.4; }
733
+ 100% { transform: scale(1.3); opacity: 1; }
734
+ }
735
+
736
+ @keyframes breatheOut {
737
+ 0% { transform: scale(1.3); opacity: 1; }
738
+ 100% { transform: scale(0.6); opacity: 0.4; }
739
+ }
740
+
741
  .breath-text {
742
  font-size: 1.5rem;
743
  margin-bottom: 20px;
 
995
 
996
  let selectedTradition = null;
997
 
998
+ // NVC Feelings vocabulary (from Marshall Rosenberg)
999
  const FEELINGS_DATA = {
1000
+ 'When needs ARE met': [
1001
+ 'Alive', 'Amazed', 'Appreciative', 'Confident', 'Curious', 'Delighted',
1002
+ 'Eager', 'Energetic', 'Engaged', 'Excited', 'Fulfilled', 'Glad',
1003
+ 'Grateful', 'Hopeful', 'Inspired', 'Joyful', 'Loving', 'Moved',
1004
+ 'Optimistic', 'Peaceful', 'Pleased', 'Proud', 'Refreshed', 'Relaxed',
1005
+ 'Relieved', 'Satisfied', 'Secure', 'Tender', 'Thankful', 'Touched',
1006
+ 'Trusting', 'Warm'
1007
+ ],
1008
+ 'When needs are NOT met': [
1009
+ 'Afraid', 'Angry', 'Annoyed', 'Anxious', 'Ashamed', 'Bewildered',
1010
+ 'Bitter', 'Confused', 'Dejected', 'Depressed', 'Disappointed',
1011
+ 'Discouraged', 'Disgusted', 'Distressed', 'Embarrassed', 'Exhausted',
1012
+ 'Fearful', 'Frustrated', 'Grief', 'Guilty', 'Helpless', 'Hopeless',
1013
+ 'Hurt', 'Impatient', 'Irritated', 'Jealous', 'Lonely', 'Nervous',
1014
+ 'Numb', 'Overwhelmed', 'Resentful', 'Sad', 'Scared', 'Shocked',
1015
+ 'Tired', 'Uncomfortable', 'Uneasy', 'Upset', 'Worried'
1016
+ ]
1017
  };
1018
 
1019
+ // NVC Needs vocabulary (from Marshall Rosenberg)
1020
  const NEEDS_DATA = {
1021
+ 'Connection': [
1022
+ 'Acceptance', 'Affection', 'Appreciation', 'Belonging', 'Closeness',
1023
+ 'Communication', 'Companionship', 'Compassion', 'Empathy', 'Inclusion',
1024
+ 'Intimacy', 'Love', 'Respect', 'To be heard', 'To be seen',
1025
+ 'To be understood', 'Trust', 'Warmth'
1026
+ ],
1027
  'Autonomy': ['Choice', 'Freedom', 'Independence', 'Space', 'Spontaneity'],
1028
+ 'Meaning': [
1029
+ 'Awareness', 'Contribution', 'Creativity', 'Growth', 'Hope',
1030
+ 'Learning', 'Purpose', 'Self-expression', 'Stimulation', 'Understanding'
1031
+ ],
1032
+ 'Peace': ['Beauty', 'Ease', 'Equality', 'Harmony', 'Inspiration', 'Order', 'Space'],
1033
+ 'Honesty': ['Authenticity', 'Integrity', 'Presence', 'Self-connection'],
1034
+ 'Physical Well-being': ['Food', 'Movement', 'Rest', 'Safety', 'Shelter', 'Touch', 'Water'],
1035
+ 'Play': ['Fun', 'Humor', 'Joy', 'Rejuvenation']
1036
  };
1037
 
1038
  let selectedFeelings = [];
 
1354
  const feelingsText = selectedFeelings.join(', ');
1355
  addToolMsg('user', `I'm feeling: ${feelingsText}`);
1356
 
1357
+ // Get reflection from API with psychoeducation
1358
  addToolLoading();
1359
  const isVerbose = document.getElementById('toggle-verbose')?.checked || false;
1360
  try {
 
1365
  tool: 'feelings_needs',
1366
  partner_message: lastPartnerMessage,
1367
  user_draft: '',
1368
+ user_input: `The person has identified these feelings: ${feelingsText}. ${userInput ? 'They added: ' + userInput : ''}
1369
+
1370
+ TASK:
1371
+ 1. Validate these feelings - they make sense
1372
+ 2. Help connect feelings to underlying needs (NVC framework)
1373
+ 3. Include brief psychoeducation about these specific feelings - draw from:
1374
+ - Brené Brown (vulnerability, shame, connection)
1375
+ - Tara Brach (RAIN, self-compassion, presence)
1376
+ - Sarah Peyton (neuroscience of resonance, attachment)
1377
+ 4. Keep it warm, brief, and actionable
1378
+
1379
+ Format: Acknowledge → What the feelings might point to → Brief insight → Connection to needs`,
1380
  verbose: isVerbose
1381
  })
1382
  });
 
1398
  const needsText = selectedNeeds.join(', ');
1399
  addToolMsg('user', `I'm needing: ${needsText}`);
1400
 
1401
+ // Get reflection from API with psychoeducation
1402
  addToolLoading();
1403
  const isVerbose = document.getElementById('toggle-verbose')?.checked || false;
1404
  try {
 
1409
  tool: 'feelings_needs',
1410
  partner_message: lastPartnerMessage,
1411
  user_draft: '',
1412
+ user_input: `The person has identified these needs: ${needsText}. ${userInput ? 'They added: ' + userInput : ''}
1413
+
1414
+ TASK:
1415
+ 1. Validate these needs - they are universal human needs
1416
+ 2. Help them see how these needs connect to their feelings and the relationship
1417
+ 3. Include brief psychoeducation about needs - draw from:
1418
+ - Marshall Rosenberg (NVC, universal needs, requests vs demands)
1419
+ - Brené Brown (connection, worthiness, vulnerability)
1420
+ - Attachment theory (safety, closeness, autonomy)
1421
+ 4. Suggest what a request might sound like to meet these needs
1422
+ 5. Keep it warm, brief, and actionable
1423
+
1424
+ Format: Validate → What these needs mean → Brief insight → Possible request`,
1425
  verbose: isVerbose
1426
  })
1427
  });
 
1494
  }
1495
 
1496
  // ============================================================================
1497
+ // BREATH/LOVE TOOL - Square Breathing (5 in, 4 hold, 5 out, 4 hold)
1498
  // ============================================================================
1499
  let breathInterval;
1500
+ let breathTimeout;
1501
 
1502
  function openBreath() {
1503
  document.getElementById('breath-overlay').classList.add('active');
1504
+ runBreathCycle();
1505
+ }
1506
+
1507
+ function runBreathCycle() {
1508
+ const breathText = document.getElementById('breath-text');
1509
+ const circle = document.querySelector('.breath-circle');
1510
+
1511
+ // Phase 1: Breathe in (5 seconds)
1512
+ breathText.textContent = 'Breathe in... 5';
1513
+ circle.style.animation = 'breatheIn 5s ease-out forwards';
1514
+ let count = 5;
1515
+ breathInterval = setInterval(() => {
1516
+ count--;
1517
+ if (count > 0) breathText.textContent = `Breathe in... ${count}`;
1518
+ }, 1000);
1519
+
1520
+ breathTimeout = setTimeout(() => {
1521
+ clearInterval(breathInterval);
1522
+ // Phase 2: Hold (4 seconds)
1523
+ breathText.textContent = 'Hold... 4';
1524
+ circle.style.animation = 'none';
1525
+ count = 4;
1526
+ breathInterval = setInterval(() => {
1527
+ count--;
1528
+ if (count > 0) breathText.textContent = `Hold... ${count}`;
1529
+ }, 1000);
1530
+
1531
+ breathTimeout = setTimeout(() => {
1532
+ clearInterval(breathInterval);
1533
+ // Phase 3: Breathe out (5 seconds)
1534
+ breathText.textContent = 'Breathe out... 5';
1535
+ circle.style.animation = 'breatheOut 5s ease-in forwards';
1536
+ count = 5;
1537
+ breathInterval = setInterval(() => {
1538
+ count--;
1539
+ if (count > 0) breathText.textContent = `Breathe out... ${count}`;
1540
+ }, 1000);
1541
+
1542
+ breathTimeout = setTimeout(() => {
1543
+ clearInterval(breathInterval);
1544
+ // Phase 4: Hold (4 seconds)
1545
+ breathText.textContent = 'Hold... 4';
1546
+ circle.style.animation = 'none';
1547
+ count = 4;
1548
+ breathInterval = setInterval(() => {
1549
+ count--;
1550
+ if (count > 0) breathText.textContent = `Hold... ${count}`;
1551
+ }, 1000);
1552
+
1553
+ breathTimeout = setTimeout(() => {
1554
+ clearInterval(breathInterval);
1555
+ // Repeat cycle
1556
+ runBreathCycle();
1557
+ }, 4000);
1558
+ }, 5000);
1559
+ }, 4000);
1560
+ }, 5000);
1561
  }
1562
 
1563
  function closeBreath() {
1564
  document.getElementById('breath-overlay').classList.remove('active');
1565
  clearInterval(breathInterval);
1566
+ clearTimeout(breathTimeout);
1567
  }
1568
 
1569
  // ============================================================================